1 /* Evolution calendar - iCalendar component object
2 *
3 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
4 *
5 * This library is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation.
8 *
9 * This library is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
12 * for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this library. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * Authors: Federico Mena-Quintero <federico@ximian.com>
18 */
19
20 /**
21 * SECTION:e-cal-component
22 * @short_description: A convenience interface for interacting with events
23 * @include: libecal/libecal.h
24 *
25 * This is the main user facing interface used for representing an event
26 * or other component in a given calendar.
27 **/
28
29 #include "evolution-data-server-config.h"
30
31 #include <string.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <glib/gi18n-lib.h>
35 #include <glib/gstdio.h>
36
37 #include <libedataserver/libedataserver.h>
38
39 #include "e-cal-component.h"
40 #include "e-cal-time-util.h"
41 #include "e-cal-util.h"
42
43 #ifdef G_OS_WIN32
44 #define getgid() 0
45 #define getppid() 0
46 #endif
47
48 struct _ECalComponentPrivate {
49 /* The icalcomponent we wrap */
50 ICalComponent *icalcomp;
51
52 /* Whether we should increment the sequence number when piping the
53 * object over the wire.
54 */
55 guint need_sequence_inc : 1;
56 };
57
G_DEFINE_TYPE_WITH_PRIVATE(ECalComponent,e_cal_component,G_TYPE_OBJECT)58 G_DEFINE_TYPE_WITH_PRIVATE (ECalComponent, e_cal_component, G_TYPE_OBJECT)
59
60 /* Frees the internal icalcomponent only if it does not have a parent. If it
61 * does, it means we don't own it and we shouldn't free it.
62 */
63 static void
64 free_icalcomponent (ECalComponent *comp,
65 gboolean free)
66 {
67 if (!comp->priv->icalcomp)
68 return;
69
70 if (free) {
71 g_clear_object (&comp->priv->icalcomp);
72 }
73
74 /* Clean up */
75 comp->priv->need_sequence_inc = FALSE;
76 }
77
78 /* The 'func' returns TRUE to continue */
79 static void
foreach_subcomponent(ICalComponent * icalcomp,ICalComponentKind comp_kind,gboolean (* func)(ICalComponent * icalcomp,ICalComponent * subcomp,gpointer user_data),gpointer user_data)80 foreach_subcomponent (ICalComponent *icalcomp,
81 ICalComponentKind comp_kind,
82 gboolean (* func) (ICalComponent *icalcomp,
83 ICalComponent *subcomp,
84 gpointer user_data),
85 gpointer user_data)
86 {
87 ICalCompIter *iter;
88 ICalComponent *subcomp;
89
90 g_return_if_fail (icalcomp != NULL);
91 g_return_if_fail (func != NULL);
92
93 iter = i_cal_component_begin_component (icalcomp, comp_kind);
94 subcomp = i_cal_comp_iter_deref (iter);
95 while (subcomp) {
96 ICalComponent *next_subcomp;
97
98 next_subcomp = i_cal_comp_iter_next (iter);
99
100 if (!func (icalcomp, subcomp, user_data)) {
101 g_clear_object (&next_subcomp);
102 g_object_unref (subcomp);
103 break;
104 }
105
106 g_object_unref (subcomp);
107 subcomp = next_subcomp;
108 }
109
110 g_clear_object (&iter);
111 }
112
113 /* The 'func' returns TRUE to continue */
114 static void
foreach_property(ICalComponent * icalcomp,ICalPropertyKind prop_kind,gboolean (* func)(ICalComponent * icalcomp,ICalProperty * prop,gpointer user_data),gpointer user_data)115 foreach_property (ICalComponent *icalcomp,
116 ICalPropertyKind prop_kind,
117 gboolean (* func) (ICalComponent *icalcomp,
118 ICalProperty *prop,
119 gpointer user_data),
120 gpointer user_data)
121 {
122 ICalProperty *prop;
123
124 g_return_if_fail (func != NULL);
125
126 for (prop = i_cal_component_get_first_property (icalcomp, prop_kind);
127 prop;
128 g_object_unref (prop), prop = i_cal_component_get_next_property (icalcomp, prop_kind)) {
129 if (!func (icalcomp, prop, user_data))
130 break;
131 }
132 }
133
134 static gboolean
gather_all_properties_cb(ICalComponent * icalcomp,ICalProperty * prop,gpointer user_data)135 gather_all_properties_cb (ICalComponent *icalcomp,
136 ICalProperty *prop,
137 gpointer user_data)
138 {
139 GSList **pprops = user_data;
140
141 g_return_val_if_fail (pprops != NULL, FALSE);
142
143 *pprops = g_slist_prepend (*pprops, g_object_ref (prop));
144
145 return TRUE;
146 }
147
148 static GSList * /* ICalProperty * */
gather_all_properties(ICalComponent * icalcomp,ICalPropertyKind prop_kind,gboolean in_original_order)149 gather_all_properties (ICalComponent *icalcomp,
150 ICalPropertyKind prop_kind,
151 gboolean in_original_order)
152 {
153 GSList *props = NULL;
154
155 foreach_property (icalcomp, prop_kind, gather_all_properties_cb, &props);
156
157 return in_original_order ? g_slist_reverse (props) : props;
158 }
159
160 static void
remove_all_properties_of_kind(ICalComponent * icalcomp,ICalPropertyKind prop_kind)161 remove_all_properties_of_kind (ICalComponent *icalcomp,
162 ICalPropertyKind prop_kind)
163 {
164 ICalProperty *prop;
165 GSList *to_remove, *link;
166
167 to_remove = gather_all_properties (icalcomp, prop_kind, FALSE);
168
169 for (link = to_remove; link; link = g_slist_next (link)) {
170 prop = link->data;
171
172 i_cal_component_remove_property (icalcomp, prop);
173 }
174
175 g_slist_free_full (to_remove, g_object_unref);
176 }
177
178 /* returns NULL when value is NULL or empty string */
179 static ECalComponentText *
get_text_from_prop(ICalProperty * prop,const gchar * (* get_prop_func)(ICalProperty * prop))180 get_text_from_prop (ICalProperty *prop,
181 const gchar *(* get_prop_func) (ICalProperty *prop))
182 {
183 ICalParameter *altrep_param;
184 const gchar *value, *altrep;
185
186 g_return_val_if_fail (prop != NULL, NULL);
187 g_return_val_if_fail (get_prop_func != NULL, NULL);
188
189 value = get_prop_func (prop);
190
191 /* Skip empty values */
192 if (!value || !*value)
193 return NULL;
194
195 altrep_param = i_cal_property_get_first_parameter (prop, I_CAL_ALTREP_PARAMETER);
196 altrep = altrep_param ? i_cal_parameter_get_altrep (altrep_param) : NULL;
197 g_clear_object (&altrep_param);
198
199 if (altrep && !*altrep)
200 altrep = NULL;
201
202 return e_cal_component_text_new (value, altrep);
203 }
204
205 static void
set_text_altrep_on_prop(ICalProperty * prop,const ECalComponentText * text)206 set_text_altrep_on_prop (ICalProperty *prop,
207 const ECalComponentText *text)
208 {
209 ICalParameter *param;
210 const gchar *altrep;
211
212 g_return_if_fail (prop != NULL);
213 g_return_if_fail (text != NULL);
214
215 altrep = e_cal_component_text_get_altrep (text);
216 param = i_cal_property_get_first_parameter (prop, I_CAL_ALTREP_PARAMETER);
217
218 if (altrep && *altrep) {
219 if (param) {
220 i_cal_parameter_set_altrep (param, (gchar *) altrep);
221 } else {
222 param = i_cal_parameter_new_altrep ((gchar *) altrep);
223 i_cal_property_take_parameter (prop, param);
224 param = NULL;
225 }
226 } else if (param) {
227 i_cal_property_remove_parameter_by_kind (prop, I_CAL_ALTREP_PARAMETER);
228 }
229
230 g_clear_object (¶m);
231 }
232
233
234 static void
cal_component_finalize(GObject * object)235 cal_component_finalize (GObject *object)
236 {
237 ECalComponent *comp = E_CAL_COMPONENT (object);
238
239 free_icalcomponent (comp, TRUE);
240
241 /* Chain up to parent's finalize() method. */
242 G_OBJECT_CLASS (e_cal_component_parent_class)->finalize (object);
243 }
244
245 /* Class initialization function for the calendar component object */
246 static void
e_cal_component_class_init(ECalComponentClass * class)247 e_cal_component_class_init (ECalComponentClass *class)
248 {
249 GObjectClass *object_class;
250
251 object_class = G_OBJECT_CLASS (class);
252 object_class->finalize = cal_component_finalize;
253 }
254
255 /* Object initialization function for the calendar component object */
256 static void
e_cal_component_init(ECalComponent * comp)257 e_cal_component_init (ECalComponent *comp)
258 {
259 comp->priv = e_cal_component_get_instance_private (comp);
260 comp->priv->icalcomp = NULL;
261 }
262
263 /**
264 * e_cal_component_new:
265 *
266 * Creates a new empty calendar component object. Once created, you should set it from an
267 * existing #icalcomponent structure by using e_cal_component_set_icalcomponent() or with a
268 * new empty component type by using e_cal_component_set_new_vtype().
269 *
270 * Returns: (transfer full): A newly-created calendar component object.
271 *
272 * Since: 3.34
273 **/
274 ECalComponent *
e_cal_component_new(void)275 e_cal_component_new (void)
276 {
277 return E_CAL_COMPONENT (g_object_new (E_TYPE_CAL_COMPONENT, NULL));
278 }
279
280 /**
281 * e_cal_component_new_vtype:
282 * @vtype: an #ECalComponentVType
283 *
284 * Creates a new #ECalComponent of type @vtype.
285 *
286 * Returns: (transfer full): A newly-created calendar component object with set @vtype.
287 *
288 * Since: 3.34
289 **/
290 ECalComponent *
e_cal_component_new_vtype(ECalComponentVType vtype)291 e_cal_component_new_vtype (ECalComponentVType vtype)
292 {
293 ECalComponent *comp;
294
295 comp = e_cal_component_new ();
296 e_cal_component_set_new_vtype (comp, vtype);
297
298 return comp;
299 }
300
301 /**
302 * e_cal_component_new_from_string:
303 * @calobj: A string representation of an iCalendar component.
304 *
305 * Creates a new calendar component object from the given iCalendar string.
306 *
307 * Returns: (transfer full): A calendar component representing the given iCalendar string on
308 * success, NULL if there was an error.
309 *
310 * Since: 3.34
311 **/
312 ECalComponent *
e_cal_component_new_from_string(const gchar * calobj)313 e_cal_component_new_from_string (const gchar *calobj)
314 {
315 ICalComponent *icalcomp;
316
317 g_return_val_if_fail (calobj != NULL, NULL);
318
319 icalcomp = i_cal_parser_parse_string (calobj);
320 if (!icalcomp)
321 return NULL;
322
323 return e_cal_component_new_from_icalcomponent (icalcomp);
324 }
325
326 /**
327 * e_cal_component_new_from_icalcomponent:
328 * @icalcomp: (transfer full): An #ICalComponent to use
329 *
330 * Creates a new #ECalComponent which will has set @icalcomp as
331 * an inner #ICalComponent. The newly created #ECalComponent takes
332 * ownership of the @icalcomp, and if the call
333 * to e_cal_component_set_icalcomponent() fails, then @icalcomp
334 * is freed.
335 *
336 * Returns: (transfer full): An #ECalComponent with @icalcomp assigned on success,
337 * NULL if the @icalcomp cannot be assigned to #ECalComponent.
338 *
339 * Since: 3.34
340 **/
341 ECalComponent *
e_cal_component_new_from_icalcomponent(ICalComponent * icalcomp)342 e_cal_component_new_from_icalcomponent (ICalComponent *icalcomp)
343 {
344 ECalComponent *comp;
345
346 g_return_val_if_fail (icalcomp != NULL, NULL);
347
348 comp = e_cal_component_new ();
349 if (!e_cal_component_set_icalcomponent (comp, icalcomp)) {
350 g_object_unref (icalcomp);
351 g_object_unref (comp);
352
353 return NULL;
354 }
355
356 return comp;
357 }
358
359 /**
360 * e_cal_component_clone:
361 * @comp: A calendar component object.
362 *
363 * Creates a new calendar component object by copying the information from
364 * another one.
365 *
366 * Returns: (transfer full): A newly-created calendar component with the same
367 * values as the original one.
368 *
369 * Since: 3.34
370 **/
371 ECalComponent *
e_cal_component_clone(ECalComponent * comp)372 e_cal_component_clone (ECalComponent *comp)
373 {
374 ECalComponent *new_comp;
375 ICalComponent *new_icalcomp;
376
377 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
378 g_return_val_if_fail (comp->priv->need_sequence_inc == FALSE, NULL);
379
380 new_comp = e_cal_component_new ();
381
382 if (comp->priv->icalcomp) {
383 new_icalcomp = i_cal_component_clone (comp->priv->icalcomp);
384 if (!new_icalcomp || !e_cal_component_set_icalcomponent (new_comp, new_icalcomp)) {
385 g_clear_object (&new_icalcomp);
386 g_clear_object (&new_comp);
387 }
388 }
389
390 return new_comp;
391 }
392
393 /* Ensures that the mandatory calendar component properties (uid, dtstamp) do
394 * exist. If they don't exist, it creates them automatically.
395 */
396 static void
ensure_mandatory_properties(ECalComponent * comp)397 ensure_mandatory_properties (ECalComponent *comp)
398 {
399 ICalProperty *prop;
400
401 g_return_if_fail (comp->priv->icalcomp != NULL);
402
403 prop = i_cal_component_get_first_property (comp->priv->icalcomp, I_CAL_UID_PROPERTY);
404 if (prop) {
405 g_object_unref (prop);
406 } else {
407 gchar *uid;
408
409 uid = e_util_generate_uid ();
410 i_cal_component_set_uid (comp->priv->icalcomp, uid);
411 g_free (uid);
412 }
413
414 prop = i_cal_component_get_first_property (comp->priv->icalcomp, I_CAL_DTSTAMP_PROPERTY);
415 if (prop) {
416 g_object_unref (prop);
417 } else {
418 ICalTime *tt;
419
420 tt = i_cal_time_new_current_with_zone (i_cal_timezone_get_utc_timezone ());
421
422 prop = i_cal_property_new_dtstamp (tt);
423 i_cal_component_take_property (comp->priv->icalcomp, prop);
424
425 g_object_unref (tt);
426 }
427 }
428
429 static gboolean
ensure_alarm_uid_cb(ICalComponent * icalcomp,ICalComponent * subcomp,gpointer user_data)430 ensure_alarm_uid_cb (ICalComponent *icalcomp,
431 ICalComponent *subcomp,
432 gpointer user_data)
433 {
434 if (!e_cal_util_component_has_x_property (subcomp, E_CAL_EVOLUTION_ALARM_UID_PROPERTY)) {
435 gchar *uid;
436
437 uid = e_util_generate_uid ();
438 e_cal_util_component_set_x_property (subcomp, E_CAL_EVOLUTION_ALARM_UID_PROPERTY, uid);
439 g_free (uid);
440 }
441
442 return TRUE;
443 }
444
445 /**
446 * e_cal_component_set_new_vtype:
447 * @comp: A calendar component object.
448 * @type: Type of calendar component to create.
449 *
450 * Clears any existing component data from a calendar component object and
451 * creates a new #ICalComponent of the specified type for it. The only property
452 * that will be set in the new component will be its unique identifier.
453 *
454 * Since: 3.34
455 **/
456 void
e_cal_component_set_new_vtype(ECalComponent * comp,ECalComponentVType type)457 e_cal_component_set_new_vtype (ECalComponent *comp,
458 ECalComponentVType type)
459 {
460 ICalComponent *icalcomp;
461 ICalComponentKind kind;
462
463 g_return_if_fail (E_IS_CAL_COMPONENT (comp));
464
465 free_icalcomponent (comp, TRUE);
466
467 if (type == E_CAL_COMPONENT_NO_TYPE)
468 return;
469
470 /* Figure out the kind and create the icalcomponent */
471
472 switch (type) {
473 case E_CAL_COMPONENT_EVENT:
474 kind = I_CAL_VEVENT_COMPONENT;
475 break;
476
477 case E_CAL_COMPONENT_TODO:
478 kind = I_CAL_VTODO_COMPONENT;
479 break;
480
481 case E_CAL_COMPONENT_JOURNAL:
482 kind = I_CAL_VJOURNAL_COMPONENT;
483 break;
484
485 case E_CAL_COMPONENT_FREEBUSY:
486 kind = I_CAL_VFREEBUSY_COMPONENT;
487 break;
488
489 case E_CAL_COMPONENT_TIMEZONE:
490 kind = I_CAL_VTIMEZONE_COMPONENT;
491 break;
492
493 default:
494 g_warn_if_reached ();
495 kind = I_CAL_NO_COMPONENT;
496 }
497
498 icalcomp = i_cal_component_new (kind);
499 if (!icalcomp) {
500 g_message ("e_cal_component_set_new_vtype(): Could not create the ICalComponent of kind %d!", kind);
501 return;
502 }
503
504 /* Scan the component to build our mapping table */
505
506 comp->priv->icalcomp = icalcomp;
507
508 /* Add missing stuff */
509
510 ensure_mandatory_properties (comp);
511 }
512
513 /**
514 * e_cal_component_get_vtype:
515 * @comp: A calendar component object.
516 *
517 * Queries the type of a calendar component object.
518 *
519 * Returns: The type of the component, as defined by RFC 2445.
520 *
521 * Since: 3.34
522 **/
523 ECalComponentVType
e_cal_component_get_vtype(ECalComponent * comp)524 e_cal_component_get_vtype (ECalComponent *comp)
525 {
526 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), E_CAL_COMPONENT_NO_TYPE);
527 g_return_val_if_fail (comp->priv->icalcomp != NULL, E_CAL_COMPONENT_NO_TYPE);
528
529 switch (i_cal_component_isa (comp->priv->icalcomp)) {
530 case I_CAL_VEVENT_COMPONENT:
531 return E_CAL_COMPONENT_EVENT;
532
533 case I_CAL_VTODO_COMPONENT:
534 return E_CAL_COMPONENT_TODO;
535
536 case I_CAL_VJOURNAL_COMPONENT:
537 return E_CAL_COMPONENT_JOURNAL;
538
539 case I_CAL_VFREEBUSY_COMPONENT:
540 return E_CAL_COMPONENT_FREEBUSY;
541
542 case I_CAL_VTIMEZONE_COMPONENT:
543 return E_CAL_COMPONENT_TIMEZONE;
544
545 default:
546 /* We should have been loaded with a supported type! */
547 g_warn_if_reached ();
548 return E_CAL_COMPONENT_NO_TYPE;
549 }
550 }
551
552 /**
553 * e_cal_component_set_icalcomponent:
554 * @comp: A calendar component object.
555 * @icalcomp: (transfer full) (nullable): An #ICalComponent.
556 *
557 * Sets the contents of a calendar component object from an #ICalComponent.
558 * If the @comp already had an #ICalComponent set into it, it will
559 * be freed automatically.
560 *
561 * Supported component types are VEVENT, VTODO, VJOURNAL, VFREEBUSY, and VTIMEZONE.
562 *
563 * Returns: %TRUE on success, %FALSE if @icalcomp is an unsupported component type.
564 *
565 * Since: 3.34
566 **/
567 gboolean
e_cal_component_set_icalcomponent(ECalComponent * comp,ICalComponent * icalcomp)568 e_cal_component_set_icalcomponent (ECalComponent *comp,
569 ICalComponent *icalcomp)
570 {
571 ICalComponentKind kind;
572
573 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), FALSE);
574
575 if (comp->priv->icalcomp == icalcomp)
576 return TRUE;
577
578 free_icalcomponent (comp, TRUE);
579
580 if (!icalcomp) {
581 comp->priv->icalcomp = NULL;
582 return TRUE;
583 }
584
585 kind = i_cal_component_isa (icalcomp);
586
587 if (!(kind == I_CAL_VEVENT_COMPONENT
588 || kind == I_CAL_VTODO_COMPONENT
589 || kind == I_CAL_VJOURNAL_COMPONENT
590 || kind == I_CAL_VFREEBUSY_COMPONENT
591 || kind == I_CAL_VTIMEZONE_COMPONENT))
592 return FALSE;
593
594 comp->priv->icalcomp = icalcomp;
595
596 ensure_mandatory_properties (comp);
597
598 foreach_subcomponent (icalcomp, I_CAL_VALARM_COMPONENT, ensure_alarm_uid_cb, NULL);
599
600 return TRUE;
601 }
602
603 /**
604 * e_cal_component_get_icalcomponent:
605 * @comp: A calendar component object.
606 *
607 * Queries the #icalcomponent structure that a calendar component object is
608 * wrapping.
609 *
610 * Returns: (transfer none) (nullable): An #ICalComponent structure, or %NULL
611 * if the @comp has no #ICalComponent set to it.
612 *
613 * Since: 3.34
614 **/
615 ICalComponent *
e_cal_component_get_icalcomponent(ECalComponent * comp)616 e_cal_component_get_icalcomponent (ECalComponent *comp)
617 {
618 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
619
620 return comp->priv->icalcomp;
621 }
622
623 /**
624 * e_cal_component_strip_errors:
625 * @comp: A calendar component object.
626 *
627 * Strips all error messages from the calendar component. Those error messages are
628 * added to the iCalendar string representation whenever an invalid is used for
629 * one of its fields.
630 *
631 * Since: 3.34
632 **/
633 void
e_cal_component_strip_errors(ECalComponent * comp)634 e_cal_component_strip_errors (ECalComponent *comp)
635 {
636 g_return_if_fail (E_IS_CAL_COMPONENT (comp));
637
638 if (comp->priv->icalcomp)
639 i_cal_component_strip_errors (comp->priv->icalcomp);
640 }
641
642 /**
643 * e_cal_component_get_as_string:
644 * @comp: A calendar component.
645 *
646 * Gets the iCalendar string representation of a calendar component. You should
647 * call e_cal_component_commit_sequence() before this function to ensure that the
648 * component's sequence number is consistent with the state of the object.
649 *
650 * Returns: String representation of the calendar component according to
651 * RFC 2445.
652 *
653 * Since: 3.34
654 **/
655 gchar *
e_cal_component_get_as_string(ECalComponent * comp)656 e_cal_component_get_as_string (ECalComponent *comp)
657 {
658 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
659 g_return_val_if_fail (comp->priv->icalcomp != NULL, NULL);
660
661 /* Ensure that the user has committed the new SEQUENCE */
662 g_return_val_if_fail (comp->priv->need_sequence_inc == FALSE, NULL);
663
664 return i_cal_component_as_ical_string (comp->priv->icalcomp);
665 }
666
667 /* Ensures that an alarm subcomponent has the mandatory properties it needs. */
668 static gboolean
ensure_alarm_properties_cb(ICalComponent * icalcomp,ICalComponent * subcomp,gpointer user_data)669 ensure_alarm_properties_cb (ICalComponent *icalcomp,
670 ICalComponent *subcomp,
671 gpointer user_data)
672 {
673 ICalProperty *prop;
674 ICalPropertyAction action;
675 const gchar *summary;
676
677 prop = i_cal_component_get_first_property (subcomp, I_CAL_ACTION_PROPERTY);
678 if (!prop)
679 return TRUE;
680
681 action = i_cal_property_get_action (prop);
682
683 g_object_unref (prop);
684
685 switch (action) {
686 case I_CAL_ACTION_DISPLAY:
687 summary = i_cal_component_get_summary (icalcomp);
688
689 /* Ensure we have a DESCRIPTION property */
690 prop = i_cal_component_get_first_property (subcomp, I_CAL_DESCRIPTION_PROPERTY);
691 if (prop) {
692 if (summary && *summary) {
693 ICalProperty *xprop;
694
695 for (xprop = i_cal_component_get_first_property (subcomp, I_CAL_X_PROPERTY);
696 xprop;
697 g_object_unref (xprop), xprop = i_cal_component_get_next_property (subcomp, I_CAL_X_PROPERTY)) {
698 const gchar *str;
699
700 str = i_cal_property_get_x_name (xprop);
701 if (!g_strcmp0 (str, "X-EVOLUTION-NEEDS-DESCRIPTION")) {
702 i_cal_property_set_description (prop, summary);
703
704 i_cal_component_remove_property (subcomp, xprop);
705 g_object_unref (xprop);
706 break;
707 }
708 }
709 }
710
711 g_object_unref (prop);
712 break;
713 }
714
715 if (!summary || !*summary) {
716 summary = _("Untitled appointment");
717
718 /* add the X-EVOLUTION-NEEDS-DESCRIPTION property */
719 prop = i_cal_property_new_x ("1");
720 i_cal_property_set_x_name (prop, "X-EVOLUTION-NEEDS-DESCRIPTION");
721 i_cal_component_take_property (subcomp, prop);
722 }
723
724 prop = i_cal_property_new_description (summary);
725 i_cal_component_take_property (subcomp, prop);
726
727 break;
728
729 default:
730 break;
731 }
732
733 return TRUE;
734 }
735
736 /**
737 * e_cal_component_commit_sequence:
738 * @comp: A calendar component object.
739 *
740 * Increments the sequence number property in a calendar component object if it
741 * needs it. This needs to be done when any of a number of properties listed in
742 * RFC 2445 change values, such as the start and end dates of a component.
743 *
744 * This function must be called before calling e_cal_component_get_as_string() to
745 * ensure that the component is fully consistent.
746 *
747 * Since: 3.34
748 **/
749 void
e_cal_component_commit_sequence(ECalComponent * comp)750 e_cal_component_commit_sequence (ECalComponent *comp)
751 {
752 ICalProperty *prop;
753
754 g_return_if_fail (E_IS_CAL_COMPONENT (comp));
755 g_return_if_fail (comp->priv->icalcomp != NULL);
756
757 foreach_subcomponent (comp->priv->icalcomp, I_CAL_VALARM_COMPONENT, ensure_alarm_properties_cb, comp);
758
759 if (!comp->priv->need_sequence_inc)
760 return;
761
762 prop = i_cal_component_get_first_property (comp->priv->icalcomp, I_CAL_SEQUENCE_PROPERTY);
763
764 if (prop) {
765 gint seq;
766
767 seq = i_cal_property_get_sequence (prop);
768 i_cal_property_set_sequence (prop, seq + 1);
769 g_object_unref (prop);
770 } else {
771 /* The component had no SEQUENCE property, so assume that the
772 * default would have been zero. Since it needed incrementing
773 * anyways, we use a value of 1 here.
774 */
775 prop = i_cal_property_new_sequence (1);
776 i_cal_component_take_property (comp->priv->icalcomp, prop);
777 }
778
779 comp->priv->need_sequence_inc = FALSE;
780 }
781
782 /**
783 * e_cal_component_abort_sequence:
784 * @comp: A calendar component object.
785 *
786 * Aborts the sequence change needed in the given calendar component,
787 * which means it will not require a sequence commit (via
788 * e_cal_component_commit_sequence()) even if the changes done require a
789 * sequence increment.
790 *
791 * Since: 3.34
792 **/
793 void
e_cal_component_abort_sequence(ECalComponent * comp)794 e_cal_component_abort_sequence (ECalComponent *comp)
795 {
796 g_return_if_fail (E_IS_CAL_COMPONENT (comp));
797
798 comp->priv->need_sequence_inc = FALSE;
799 }
800
801 /**
802 * e_cal_component_get_id:
803 * @comp: A calendar component object.
804 *
805 * Get the ID of the component as an #ECalComponentId. The return value should
806 * be freed with e_cal_component_id_free(), when no longer needed.
807 *
808 * Returns: (transfer full): the id of the component
809 *
810 * Since: 3.34
811 **/
812 ECalComponentId *
e_cal_component_get_id(ECalComponent * comp)813 e_cal_component_get_id (ECalComponent *comp)
814 {
815 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
816 g_return_val_if_fail (comp->priv->icalcomp != NULL, NULL);
817
818 return e_cal_component_id_new_take (
819 g_strdup (i_cal_component_get_uid (comp->priv->icalcomp)),
820 e_cal_component_get_recurid_as_string (comp));
821 }
822
823 /**
824 * e_cal_component_get_uid:
825 * @comp: A calendar component object.
826 *
827 * Queries the unique identifier of a calendar component object.
828 *
829 * Returns: (transfer none): the UID string
830 *
831 * Since: 3.34
832 **/
833 const gchar *
e_cal_component_get_uid(ECalComponent * comp)834 e_cal_component_get_uid (ECalComponent *comp)
835 {
836 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
837 g_return_val_if_fail (comp->priv->icalcomp != NULL, NULL);
838
839 return i_cal_component_get_uid (comp->priv->icalcomp);
840 }
841
842 /**
843 * e_cal_component_set_uid:
844 * @comp: A calendar component object.
845 * @uid: Unique identifier.
846 *
847 * Sets the unique identifier string of a calendar component object.
848 *
849 * Since: 3.34
850 **/
851 void
e_cal_component_set_uid(ECalComponent * comp,const gchar * uid)852 e_cal_component_set_uid (ECalComponent *comp,
853 const gchar *uid)
854 {
855 g_return_if_fail (E_IS_CAL_COMPONENT (comp));
856 g_return_if_fail (uid != NULL);
857 g_return_if_fail (comp->priv->icalcomp != NULL);
858
859 i_cal_component_set_uid (comp->priv->icalcomp, (gchar *) uid);
860 }
861
862 static gboolean
get_attachments_cb(ICalComponent * icalcomp,ICalProperty * prop,gpointer user_data)863 get_attachments_cb (ICalComponent *icalcomp,
864 ICalProperty *prop,
865 gpointer user_data)
866 {
867 GSList **pattaches = user_data;
868 ICalAttach *attach;
869
870 g_return_val_if_fail (pattaches != NULL, FALSE);
871
872 attach = i_cal_property_get_attach (prop);
873
874 if (attach)
875 *pattaches = g_slist_prepend (*pattaches, attach);
876
877 return TRUE;
878 }
879
880 /**
881 * e_cal_component_get_attachments:
882 * @comp: A calendar component object
883 *
884 * Queries the attachment properties as #ICalAttach objects of the calendar
885 * component object. Changes on these objects are directly affecting the component.
886 * Free the returned #GSList with g_slist_free_full (slist, g_object_unref);,
887 * when no longer needed.
888 *
889 * Returns: (transfer full) (nullable) (element-type ICalAttach): a #GSList of
890 * attachments, as #ICalAttach objects
891 *
892 * Since: 3.34
893 **/
894 GSList *
e_cal_component_get_attachments(ECalComponent * comp)895 e_cal_component_get_attachments (ECalComponent *comp)
896 {
897 GSList *attaches = NULL;
898
899 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
900 g_return_val_if_fail (comp->priv->icalcomp != NULL, NULL);
901
902 foreach_property (comp->priv->icalcomp, I_CAL_ATTACH_PROPERTY, get_attachments_cb, &attaches);
903
904 return g_slist_reverse (attaches);
905 }
906
907 /**
908 * e_cal_component_set_attachments:
909 * @comp: A calendar component object
910 * @attachments: (nullable) (element-type ICalAttach): a #GSList of an #ICalAttach,
911 * or %NULL to remove any existing
912 *
913 * Sets the attachments of the calendar component object.
914 *
915 * Since: 3.34
916 **/
917 void
e_cal_component_set_attachments(ECalComponent * comp,const GSList * attachments)918 e_cal_component_set_attachments (ECalComponent *comp,
919 const GSList *attachments)
920 {
921 GSList *link;
922
923 g_return_if_fail (E_IS_CAL_COMPONENT (comp));
924 g_return_if_fail (comp->priv->icalcomp != NULL);
925
926 remove_all_properties_of_kind (comp->priv->icalcomp, I_CAL_ATTACH_PROPERTY);
927
928 for (link = (GSList *) attachments; link; link = g_slist_next (link)) {
929 ICalAttach *attach = link->data;
930 ICalProperty *prop;
931
932 if (!attach)
933 continue;
934
935 prop = i_cal_property_new_attach (attach);
936
937 if (prop)
938 i_cal_component_take_property (comp->priv->icalcomp, prop);
939 }
940 }
941
942 /**
943 * e_cal_component_has_attachments:
944 * @comp: A calendar component object.
945 *
946 * Queries the component to see if it has attachments.
947 *
948 * Returns: TRUE if there are attachments, FALSE otherwise.
949 *
950 * Since: 3.34
951 **/
952 gboolean
e_cal_component_has_attachments(ECalComponent * comp)953 e_cal_component_has_attachments (ECalComponent *comp)
954 {
955 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), FALSE);
956 g_return_val_if_fail (comp->priv->icalcomp != NULL, FALSE);
957
958 return e_cal_util_component_has_property (comp->priv->icalcomp, I_CAL_ATTACH_PROPERTY);
959 }
960
961 /* Creates a comma-delimited string of categories */
962 static gchar *
stringify_categories(const GSList * categ_list)963 stringify_categories (const GSList *categ_list)
964 {
965 GString *str;
966 GSList *link;
967
968 str = g_string_new (NULL);
969
970 for (link = (GSList *) categ_list; link; link = g_slist_next (link)) {
971 const gchar *category = link->data;
972
973 if (category && *category) {
974 if (str->len)
975 g_string_append_c (str, ',');
976 g_string_append (str, category);
977 }
978 }
979
980 return g_string_free (str, !str->len);
981 }
982
983 /**
984 * e_cal_component_get_categories:
985 * @comp: A calendar component object.
986 *
987 * Queries the categories of the given calendar component. The categories
988 * are returned in the @categories argument, which, on success, will contain
989 * a comma-separated list of all categories set in the component.
990 * Free the returned string with g_free(), when no longer needed.
991 *
992 * Returns: (transfer full) (nullable): the categories as string, or %NULL
993 * if none are set
994 *
995 * Since: 3.34
996 **/
997 gchar *
e_cal_component_get_categories(ECalComponent * comp)998 e_cal_component_get_categories (ECalComponent *comp)
999 {
1000 GSList *categories;
1001 gchar *str;
1002
1003 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
1004 g_return_val_if_fail (comp->priv->icalcomp != NULL, NULL);
1005
1006 categories = e_cal_component_get_categories_list (comp);
1007 if (!categories)
1008 return NULL;
1009
1010 str = stringify_categories (categories);
1011
1012 g_slist_free_full (categories, g_free);
1013
1014 return str;
1015 }
1016
1017 /**
1018 * e_cal_component_set_categories:
1019 * @comp: A calendar component object.
1020 * @categories: Comma-separated list of categories.
1021 *
1022 * Sets the list of categories for a calendar component.
1023 *
1024 * Since: 3.34
1025 **/
1026 void
e_cal_component_set_categories(ECalComponent * comp,const gchar * categories)1027 e_cal_component_set_categories (ECalComponent *comp,
1028 const gchar *categories)
1029 {
1030 ICalProperty *prop;
1031
1032 g_return_if_fail (E_IS_CAL_COMPONENT (comp));
1033 g_return_if_fail (comp->priv->icalcomp != NULL);
1034
1035 remove_all_properties_of_kind (comp->priv->icalcomp, I_CAL_CATEGORIES_PROPERTY);
1036
1037 if (!categories || !*categories)
1038 return;
1039
1040 prop = i_cal_property_new_categories (categories);
1041 i_cal_component_take_property (comp->priv->icalcomp, prop);
1042 }
1043
1044 /**
1045 * e_cal_component_get_categories_list:
1046 * @comp: A calendar component object.
1047 *
1048 * Queries the list of categories of a calendar component object. Each element
1049 * in the returned categ_list is a string with the corresponding category.
1050 * Free the returned #GSList with g_slist_free_full (categories, g_free); , when
1051 * no longer needed.
1052 *
1053 * Returns: (transfer full) (element-type utf8) (nullable): the #GSList of strings, where each
1054 * string is a category, or %NULL, when no category is set.
1055 *
1056 * Since: 3.34
1057 **/
1058 GSList *
e_cal_component_get_categories_list(ECalComponent * comp)1059 e_cal_component_get_categories_list (ECalComponent *comp)
1060 {
1061 ICalProperty *prop;
1062 const gchar *categories;
1063 const gchar *p;
1064 const gchar *cat_start;
1065 GSList *categ_list = NULL;
1066 gchar *str;
1067
1068 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
1069 g_return_val_if_fail (comp->priv->icalcomp != NULL, NULL);
1070
1071 for (prop = i_cal_component_get_first_property (comp->priv->icalcomp, I_CAL_CATEGORIES_PROPERTY);
1072 prop;
1073 g_object_unref (prop), prop = i_cal_component_get_next_property (comp->priv->icalcomp, I_CAL_CATEGORIES_PROPERTY)) {
1074 categories = i_cal_property_get_categories (prop);
1075
1076 if (!categories)
1077 continue;
1078
1079 cat_start = categories;
1080
1081 for (p = categories; *p; p++) {
1082 if (*p == ',') {
1083 str = g_strndup (cat_start, p - cat_start);
1084 categ_list = g_slist_prepend (categ_list, str);
1085
1086 cat_start = p + 1;
1087 }
1088 }
1089
1090 str = g_strndup (cat_start, p - cat_start);
1091 categ_list = g_slist_prepend (categ_list, str);
1092 }
1093
1094 return g_slist_reverse (categ_list);
1095 }
1096
1097 /**
1098 * e_cal_component_set_categories_list:
1099 * @comp: A calendar component object.
1100 * @categ_list: (element-type utf8): List of strings, one for each category.
1101 *
1102 * Sets the list of categories of a calendar component object.
1103 *
1104 * Since: 3.34
1105 **/
1106 void
e_cal_component_set_categories_list(ECalComponent * comp,const GSList * categ_list)1107 e_cal_component_set_categories_list (ECalComponent *comp,
1108 const GSList *categ_list)
1109 {
1110 g_return_if_fail (E_IS_CAL_COMPONENT (comp));
1111 g_return_if_fail (comp->priv->icalcomp != NULL);
1112
1113 if (!categ_list) {
1114 e_cal_component_set_categories (comp, NULL);
1115 } else {
1116 gchar *categories_str;
1117
1118 /* Create a single string of categories */
1119 categories_str = stringify_categories (categ_list);
1120
1121 /* Set the categories */
1122 e_cal_component_set_categories (comp, categories_str);
1123 g_free (categories_str);
1124 }
1125 }
1126
1127 /**
1128 * e_cal_component_get_classification:
1129 * @comp: A calendar component object.
1130 *
1131 * Queries the classification of a calendar component object. If the
1132 * classification property is not set on this component, this function returns
1133 * #E_CAL_COMPONENT_CLASS_NONE.
1134 *
1135 * Retuurns: a classification of the @comp, as an #ECalComponentClassification
1136 *
1137 * Since: 3.34
1138 **/
1139 ECalComponentClassification
e_cal_component_get_classification(ECalComponent * comp)1140 e_cal_component_get_classification (ECalComponent *comp)
1141 {
1142 ICalProperty *prop;
1143 ECalComponentClassification classif;
1144
1145 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), E_CAL_COMPONENT_CLASS_UNKNOWN);
1146 g_return_val_if_fail (comp->priv->icalcomp != NULL, E_CAL_COMPONENT_CLASS_UNKNOWN);
1147
1148 prop = i_cal_component_get_first_property (comp->priv->icalcomp, I_CAL_CLASS_PROPERTY);
1149
1150 if (!prop)
1151 return E_CAL_COMPONENT_CLASS_NONE;
1152
1153 switch (i_cal_property_get_class (prop)) {
1154 case I_CAL_CLASS_PUBLIC:
1155 classif = E_CAL_COMPONENT_CLASS_PUBLIC;
1156 break;
1157 case I_CAL_CLASS_PRIVATE:
1158 classif = E_CAL_COMPONENT_CLASS_PRIVATE;
1159 break;
1160 case I_CAL_CLASS_CONFIDENTIAL:
1161 classif = E_CAL_COMPONENT_CLASS_CONFIDENTIAL;
1162 break;
1163 default:
1164 classif = E_CAL_COMPONENT_CLASS_UNKNOWN;
1165 break;
1166 }
1167
1168 g_object_unref (prop);
1169
1170 return classif;
1171 }
1172
1173 /**
1174 * e_cal_component_set_classification:
1175 * @comp: A calendar component object.
1176 * @classif: Classification to use.
1177 *
1178 * Sets the classification property of a calendar component object. To unset
1179 * the property, specify E_CAL_COMPONENT_CLASS_NONE for @classif.
1180 *
1181 * Since: 3.34
1182 **/
1183 void
e_cal_component_set_classification(ECalComponent * comp,ECalComponentClassification classif)1184 e_cal_component_set_classification (ECalComponent *comp,
1185 ECalComponentClassification classif)
1186 {
1187 ICalProperty_Class prop_class;
1188 ICalProperty *prop;
1189
1190 g_return_if_fail (E_IS_CAL_COMPONENT (comp));
1191 g_return_if_fail (classif != E_CAL_COMPONENT_CLASS_UNKNOWN);
1192 g_return_if_fail (comp->priv->icalcomp != NULL);
1193
1194 prop = i_cal_component_get_first_property (comp->priv->icalcomp, I_CAL_CLASS_PROPERTY);
1195
1196 if (classif == E_CAL_COMPONENT_CLASS_NONE) {
1197 if (prop) {
1198 i_cal_component_remove_property (comp->priv->icalcomp, prop);
1199 g_object_unref (prop);
1200 }
1201
1202 return;
1203 }
1204
1205 switch (classif) {
1206 case E_CAL_COMPONENT_CLASS_PUBLIC:
1207 prop_class = I_CAL_CLASS_PUBLIC;
1208 break;
1209
1210 case E_CAL_COMPONENT_CLASS_PRIVATE:
1211 prop_class = I_CAL_CLASS_PRIVATE;
1212 break;
1213
1214 case E_CAL_COMPONENT_CLASS_CONFIDENTIAL:
1215 prop_class = I_CAL_CLASS_CONFIDENTIAL;
1216 break;
1217
1218 default:
1219 g_warn_if_reached ();
1220 prop_class = I_CAL_CLASS_NONE;
1221 break;
1222 }
1223
1224 if (prop) {
1225 i_cal_property_set_class (prop, prop_class);
1226 g_object_unref (prop);
1227 } else {
1228 prop = i_cal_property_new_class (prop_class);
1229 i_cal_component_take_property (comp->priv->icalcomp, prop);
1230 }
1231 }
1232
1233 /* Gets a text list value */
1234 static GSList *
get_text_list(ICalComponent * icalcomp,ICalPropertyKind prop_kind,const gchar * (* get_prop_func)(ICalProperty * prop))1235 get_text_list (ICalComponent *icalcomp,
1236 ICalPropertyKind prop_kind,
1237 const gchar *(* get_prop_func) (ICalProperty *prop))
1238 {
1239 GSList *link, *props, *tl = NULL;
1240
1241 if (!icalcomp)
1242 return NULL;
1243
1244 props = gather_all_properties (icalcomp, prop_kind, FALSE);
1245 for (link = props; link; link = g_slist_next (link)) {
1246 ICalProperty *prop = link->data;
1247 ECalComponentText *text;
1248
1249 if (!prop)
1250 continue;
1251
1252 text = get_text_from_prop (prop, get_prop_func);
1253 if (!text)
1254 continue;
1255
1256 tl = g_slist_prepend (tl, text);
1257 }
1258
1259 g_slist_free_full (props, g_object_unref);
1260
1261 /* No need to reverse it, the props are in reverse order
1262 and processed in the reverse order, thus the result
1263 is in the expected order. */
1264 return tl;
1265 }
1266
1267 /* Sets a text list value */
1268 static void
set_text_list(ICalComponent * icalcomp,ICalPropertyKind prop_kind,ICalProperty * (* new_prop_func)(const gchar * value),const GSList * tl)1269 set_text_list (ICalComponent *icalcomp,
1270 ICalPropertyKind prop_kind,
1271 ICalProperty * (* new_prop_func) (const gchar *value),
1272 const GSList *tl)
1273 {
1274 GSList *link;
1275
1276 /* Remove old texts */
1277 remove_all_properties_of_kind (icalcomp, prop_kind);
1278
1279 /* Add in new texts */
1280
1281 for (link = (GSList *) tl; link; link = g_slist_next (link)) {
1282 ECalComponentText *text;
1283 ICalProperty *prop;
1284
1285 text = link->data;
1286 if (!text || !e_cal_component_text_get_value (text))
1287 continue;
1288
1289 prop = new_prop_func ((gchar *) e_cal_component_text_get_value (text));
1290
1291 set_text_altrep_on_prop (prop, text);
1292
1293 i_cal_component_take_property (icalcomp, prop);
1294 }
1295 }
1296
1297 /**
1298 * e_cal_component_get_comments:
1299 * @comp: A calendar component object.
1300 *
1301 * Queries the comments of a calendar component object. The comment property can
1302 * appear several times inside a calendar component, and so a list of
1303 * #ECalComponentText is returned. Free the returned #GSList with
1304 * g_slist_free_full (slist, e_cal_component_text_free);, when no longer needed.
1305 *
1306 * Returns: (transfer full) (element-type ECalComponentText) (nullable): the comment properties
1307 * and their parameters, as a list of #ECalComponentText structures; or %NULL, when
1308 * the component doesn't contain any.
1309 *
1310 * Since: 3.34
1311 **/
1312 GSList *
e_cal_component_get_comments(ECalComponent * comp)1313 e_cal_component_get_comments (ECalComponent *comp)
1314 {
1315 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
1316 g_return_val_if_fail (comp->priv->icalcomp != NULL, NULL);
1317
1318 return get_text_list (comp->priv->icalcomp, I_CAL_COMMENT_PROPERTY, i_cal_property_get_comment);
1319 }
1320
1321 /**
1322 * e_cal_component_set_comments:
1323 * @comp: A calendar component object.
1324 * @text_list: (element-type ECalComponentText): List of #ECalComponentText structures.
1325 *
1326 * Sets the comments of a calendar component object. The comment property can
1327 * appear several times inside a calendar component, and so a list of
1328 * #ECalComponentText structures is used.
1329 *
1330 * Since: 3.34
1331 **/
1332 void
e_cal_component_set_comments(ECalComponent * comp,const GSList * text_list)1333 e_cal_component_set_comments (ECalComponent *comp,
1334 const GSList *text_list)
1335 {
1336 g_return_if_fail (E_IS_CAL_COMPONENT (comp));
1337 g_return_if_fail (comp->priv->icalcomp != NULL);
1338
1339 set_text_list (comp->priv->icalcomp, I_CAL_COMMENT_PROPERTY, i_cal_property_new_comment, text_list);
1340 }
1341
1342 /**
1343 * e_cal_component_get_contacts:
1344 * @comp: A calendar component object.
1345 *
1346 * Queries the contact of a calendar component object. The contact property can
1347 * appear several times inside a calendar component, and so a list of
1348 * #ECalComponentText is returned. Free the returned #GSList with
1349 * g_slist_free_full (slist, e_cal_component_text_free);, when no longer needed.
1350 *
1351 * Returns: (transfer full) (element-type ECalComponentText): the contact properties and
1352 * their parameters, as a #GSList of #ECalComponentText structures.
1353 *
1354 * Since: 3.34
1355 **/
1356 GSList *
e_cal_component_get_contacts(ECalComponent * comp)1357 e_cal_component_get_contacts (ECalComponent *comp)
1358 {
1359 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
1360 g_return_val_if_fail (comp->priv->icalcomp != NULL, NULL);
1361
1362 return get_text_list (comp->priv->icalcomp, I_CAL_CONTACT_PROPERTY, i_cal_property_get_contact);
1363 }
1364
1365 /**
1366 * e_cal_component_set_contacts:
1367 * @comp: A calendar component object.
1368 * @text_list: (element-type ECalComponentText): List of #ECalComponentText structures.
1369 *
1370 * Sets the contact of a calendar component object. The contact property can
1371 * appear several times inside a calendar component, and so a list of
1372 * #ECalComponentText structures is used.
1373 *
1374 * Since: 3.34
1375 **/
1376 void
e_cal_component_set_contacts(ECalComponent * comp,const GSList * text_list)1377 e_cal_component_set_contacts (ECalComponent *comp,
1378 const GSList *text_list)
1379 {
1380 g_return_if_fail (E_IS_CAL_COMPONENT (comp));
1381 g_return_if_fail (comp->priv->icalcomp != NULL);
1382
1383 set_text_list (comp->priv->icalcomp, I_CAL_CONTACT_PROPERTY, i_cal_property_new_contact, text_list);
1384 }
1385
1386 /* Gets a struct icaltimetype value */
1387 static ICalTime *
get_icaltimetype(ICalComponent * icalcomp,ICalPropertyKind prop_kind,ICalTime * (* get_prop_func)(ICalProperty * prop))1388 get_icaltimetype (ICalComponent *icalcomp,
1389 ICalPropertyKind prop_kind,
1390 ICalTime * (* get_prop_func) (ICalProperty *prop))
1391 {
1392 ICalProperty *prop;
1393 ICalTime *tt;
1394
1395 prop = i_cal_component_get_first_property (icalcomp, prop_kind);
1396 if (!prop)
1397 return NULL;
1398
1399 tt = get_prop_func (prop);
1400
1401 g_object_unref (prop);
1402
1403 return tt;
1404 }
1405
1406 /* Sets a struct icaltimetype value */
1407 static void
set_icaltimetype(ICalComponent * icalcomp,ICalPropertyKind prop_kind,ICalProperty * (* prop_new_func)(ICalTime * tt),void (* prop_set_func)(ICalProperty * prop,ICalTime * tt),const ICalTime * tt)1408 set_icaltimetype (ICalComponent *icalcomp,
1409 ICalPropertyKind prop_kind,
1410 ICalProperty *(* prop_new_func) (ICalTime *tt),
1411 void (* prop_set_func) (ICalProperty *prop,
1412 ICalTime *tt),
1413 const ICalTime *tt)
1414 {
1415 ICalProperty *prop;
1416
1417 prop = i_cal_component_get_first_property (icalcomp, prop_kind);
1418
1419 if (!tt) {
1420 if (prop) {
1421 i_cal_component_remove_property (icalcomp, prop);
1422 g_clear_object (&prop);
1423 }
1424
1425 return;
1426 }
1427
1428 if (prop) {
1429 prop_set_func (prop, (ICalTime *) tt);
1430 g_object_unref (prop);
1431 } else {
1432 prop = prop_new_func ((ICalTime *) tt);
1433 i_cal_component_take_property (icalcomp, prop);
1434 }
1435 }
1436
1437 /**
1438 * e_cal_component_get_completed:
1439 * @comp: A calendar component object.
1440 *
1441 * Queries the date at which a calendar compoment object was completed.
1442 * Free the returned non-NULL pointer with g_object_unref(), when
1443 * no longer needed.
1444 *
1445 * Returns: (transfer full): the completion date, as an #ICalTime, or %NULL, when none is set
1446 *
1447 * Since: 3.34
1448 **/
1449 ICalTime *
e_cal_component_get_completed(ECalComponent * comp)1450 e_cal_component_get_completed (ECalComponent *comp)
1451 {
1452 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
1453 g_return_val_if_fail (comp->priv->icalcomp != NULL, NULL);
1454
1455 return get_icaltimetype (comp->priv->icalcomp, I_CAL_COMPLETED_PROPERTY, i_cal_property_get_completed);
1456 }
1457
1458 /**
1459 * e_cal_component_set_completed:
1460 * @comp: A calendar component object.
1461 * @tt: (nullable): Value for the completion date.
1462 *
1463 * Sets the date at which a calendar component object was completed.
1464 *
1465 * Since: 3.34
1466 **/
1467 void
e_cal_component_set_completed(ECalComponent * comp,const ICalTime * tt)1468 e_cal_component_set_completed (ECalComponent *comp,
1469 const ICalTime *tt)
1470 {
1471 ICalTime *tmp_tt = NULL;
1472
1473 g_return_if_fail (E_IS_CAL_COMPONENT (comp));
1474 g_return_if_fail (comp->priv->icalcomp != NULL);
1475
1476 if (tt && i_cal_time_is_date ((ICalTime *) tt)) {
1477 tmp_tt = i_cal_time_clone (tt);
1478 tt = tmp_tt;
1479
1480 i_cal_time_set_is_date (tmp_tt, FALSE);
1481 i_cal_time_set_hour (tmp_tt, 0);
1482 i_cal_time_set_minute (tmp_tt, 0);
1483 i_cal_time_set_second (tmp_tt, 0);
1484 i_cal_time_set_timezone (tmp_tt, i_cal_timezone_get_utc_timezone ());
1485 }
1486
1487 set_icaltimetype (comp->priv->icalcomp, I_CAL_COMPLETED_PROPERTY,
1488 i_cal_property_new_completed,
1489 i_cal_property_set_completed,
1490 tt);
1491
1492 g_clear_object (&tmp_tt);
1493 }
1494
1495 /**
1496 * e_cal_component_get_created:
1497 * @comp: A calendar component object.
1498 *
1499 * Queries the date in which a calendar component object was created in the
1500 * calendar store. Free the returned non-NULL pointer with g_object_unref(), when
1501 * no longer needed.
1502 *
1503 * Returns: (transfer full): the creation date, as an #ICalTime, or %NULL, when none is set
1504 *
1505 * Since: 3.34
1506 **/
1507 ICalTime *
e_cal_component_get_created(ECalComponent * comp)1508 e_cal_component_get_created (ECalComponent *comp)
1509 {
1510 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
1511 g_return_val_if_fail (comp->priv->icalcomp != NULL, NULL);
1512
1513 return get_icaltimetype (comp->priv->icalcomp, I_CAL_CREATED_PROPERTY, i_cal_property_get_created);
1514 }
1515
1516 /**
1517 * e_cal_component_set_created:
1518 * @comp: A calendar component object.
1519 * @tt: (nullable): Value for the creation date.
1520 *
1521 * Sets the date in which a calendar component object is created in the calendar
1522 * store. This should only be used inside a calendar store application, i.e.
1523 * not by calendar user agents.
1524 *
1525 * Since: 3.34
1526 **/
1527 void
e_cal_component_set_created(ECalComponent * comp,const ICalTime * tt)1528 e_cal_component_set_created (ECalComponent *comp,
1529 const ICalTime *tt)
1530 {
1531 g_return_if_fail (E_IS_CAL_COMPONENT (comp));
1532 g_return_if_fail (comp->priv->icalcomp != NULL);
1533
1534 set_icaltimetype (comp->priv->icalcomp, I_CAL_CREATED_PROPERTY,
1535 i_cal_property_new_created,
1536 i_cal_property_set_created,
1537 tt);
1538 }
1539
1540 /**
1541 * e_cal_component_get_descriptions:
1542 * @comp: A calendar component object.
1543 *
1544 * Queries the description of a calendar component object. Journal components
1545 * may have more than one description, and as such this function returns a list
1546 * of #ECalComponentText structures. All other types of components can have at
1547 * most one description. Free the returned #GSList with
1548 * g_slist_free_full (slist, e_cal_component_text_free);, when no longer needed.
1549 *
1550 * Returns: (transfer full) (element-type ECalComponentText) (nullable): the description
1551 * properties and their parameters, as a #GSList of #ECalComponentText structures.
1552 *
1553 * Since: 3.34
1554 **/
1555 GSList *
e_cal_component_get_descriptions(ECalComponent * comp)1556 e_cal_component_get_descriptions (ECalComponent *comp)
1557 {
1558 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
1559 g_return_val_if_fail (comp->priv->icalcomp != NULL, NULL);
1560
1561 return get_text_list (comp->priv->icalcomp, I_CAL_DESCRIPTION_PROPERTY, i_cal_property_get_description);
1562 }
1563
1564 /**
1565 * e_cal_component_set_descriptions:
1566 * @comp: A calendar component object.
1567 * @text_list: (element-type ECalComponentText): List of #ECalComponentText structures.
1568 *
1569 * Sets the description of a calendar component object. Journal components may
1570 * have more than one description, and as such this function takes in a list of
1571 * #ECalComponentText structures. All other types of components can have
1572 * at most one description.
1573 *
1574 * Since: 3.34
1575 **/
1576 void
e_cal_component_set_descriptions(ECalComponent * comp,const GSList * text_list)1577 e_cal_component_set_descriptions (ECalComponent *comp,
1578 const GSList *text_list)
1579 {
1580 g_return_if_fail (E_IS_CAL_COMPONENT (comp));
1581 g_return_if_fail (comp->priv->icalcomp != NULL);
1582
1583 set_text_list (comp->priv->icalcomp, I_CAL_DESCRIPTION_PROPERTY, i_cal_property_new_description, text_list);
1584 }
1585
1586 /* Gets a date/time and timezone pair */
1587 static ECalComponentDateTime *
get_datetime(ICalComponent * icalcomp,ICalPropertyKind prop_kind,ICalTime * (* get_prop_func)(ICalProperty * prop),ICalProperty ** out_prop)1588 get_datetime (ICalComponent *icalcomp,
1589 ICalPropertyKind prop_kind,
1590 ICalTime * (* get_prop_func) (ICalProperty *prop),
1591 ICalProperty **out_prop)
1592 {
1593 ICalProperty *prop;
1594 ICalParameter *param;
1595 ICalTime *value = NULL;
1596 gchar *tzid;
1597
1598 if (out_prop)
1599 *out_prop = NULL;
1600
1601 prop = i_cal_component_get_first_property (icalcomp, prop_kind);
1602 if (prop)
1603 value = get_prop_func (prop);
1604
1605 if (!value) {
1606 g_clear_object (&prop);
1607 return NULL;
1608 }
1609
1610 param = i_cal_property_get_first_parameter (prop, I_CAL_TZID_PARAMETER);
1611 /* If the ICalTime has is_utc set, we set "UTC" as the TZID.
1612 * This makes the timezone code simpler. */
1613 if (param)
1614 tzid = g_strdup (i_cal_parameter_get_tzid (param));
1615 else if (i_cal_time_is_utc (value))
1616 tzid = g_strdup ("UTC");
1617 else
1618 tzid = NULL;
1619
1620 g_clear_object (¶m);
1621
1622 if (out_prop)
1623 *out_prop = prop;
1624 else
1625 g_clear_object (&prop);
1626
1627 return e_cal_component_datetime_new_take (value, tzid);
1628 }
1629
1630 /* Sets a date/time and timezone pair */
1631 static void
set_datetime(ICalComponent * icalcomp,ICalPropertyKind prop_kind,ICalProperty * (* prop_new_func)(ICalTime * tt),void (* prop_set_func)(ICalProperty * prop,ICalTime * tt),const ECalComponentDateTime * dt,ICalProperty ** out_prop)1632 set_datetime (ICalComponent *icalcomp,
1633 ICalPropertyKind prop_kind,
1634 ICalProperty *(* prop_new_func) (ICalTime *tt),
1635 void (* prop_set_func) (ICalProperty *prop,
1636 ICalTime *tt),
1637 const ECalComponentDateTime *dt,
1638 ICalProperty **out_prop)
1639 {
1640 ICalProperty *prop;
1641 ICalParameter *param;
1642 ICalTime *tt;
1643 const gchar *tzid;
1644
1645 if (out_prop)
1646 *out_prop = NULL;
1647
1648 prop = i_cal_component_get_first_property (icalcomp, prop_kind);
1649
1650 /* If we are setting the property to NULL (i.e. removing it), then
1651 * we remove it if it exists. */
1652 if (!dt) {
1653 if (prop) {
1654 i_cal_component_remove_property (icalcomp, prop);
1655 g_clear_object (&prop);
1656 }
1657
1658 return;
1659 }
1660
1661 tt = e_cal_component_datetime_get_value (dt);
1662
1663 g_return_if_fail (tt != NULL);
1664
1665 tzid = e_cal_component_datetime_get_tzid (dt);
1666
1667 /* If the TZID is set to "UTC", we set the is_utc flag. */
1668 if (!g_strcmp0 (tzid, "UTC"))
1669 i_cal_time_set_timezone (tt, i_cal_timezone_get_utc_timezone ());
1670 else if (i_cal_time_is_utc (tt))
1671 i_cal_time_set_timezone (tt, NULL);
1672
1673 if (prop) {
1674 /* make sure no VALUE property is left if not needed */
1675 i_cal_property_remove_parameter_by_kind (prop, I_CAL_VALUE_PARAMETER);
1676
1677 prop_set_func (prop, tt);
1678 } else {
1679 prop = prop_new_func (tt);
1680 i_cal_component_add_property (icalcomp, prop);
1681 }
1682
1683 param = i_cal_property_get_first_parameter (prop, I_CAL_TZID_PARAMETER);
1684
1685 /* If the TZID is set to "UTC", we don't want to save the TZID. */
1686 if (tzid && g_strcmp0 (tzid, "UTC") != 0) {
1687 if (param) {
1688 i_cal_parameter_set_tzid (param, (gchar *) tzid);
1689 } else {
1690 param = i_cal_parameter_new_tzid ((gchar *) tzid);
1691 i_cal_property_add_parameter (prop, param);
1692 }
1693 } else if (param) {
1694 i_cal_property_remove_parameter_by_kind (prop, I_CAL_TZID_PARAMETER);
1695 }
1696
1697 g_clear_object (¶m);
1698
1699 if (out_prop)
1700 *out_prop = prop;
1701 else
1702 g_clear_object (&prop);
1703 }
1704
1705 /* This tries to get the DTSTART + DURATION for a VEVENT or VTODO. In a
1706 * VEVENT this is used for the DTEND if no DTEND exists, In a VTOTO it is
1707 * used for the DUE date if DUE doesn't exist. */
1708 static ECalComponentDateTime *
e_cal_component_get_start_plus_duration(ECalComponent * comp)1709 e_cal_component_get_start_plus_duration (ECalComponent *comp)
1710 {
1711 ICalDuration *duration;
1712 ICalTime *tt;
1713 ECalComponentDateTime *dt;
1714 guint dur_days, dur_hours, dur_minutes, dur_seconds;
1715
1716 duration = i_cal_component_get_duration (comp->priv->icalcomp);
1717 if (!duration || i_cal_duration_is_null_duration (duration) || i_cal_duration_is_bad_duration (duration)) {
1718 g_clear_object (&duration);
1719 return NULL;
1720 }
1721
1722 /* Get the DTSTART time. */
1723 dt = get_datetime (comp->priv->icalcomp, I_CAL_DTSTART_PROPERTY, i_cal_property_get_dtstart, NULL);
1724 if (!dt) {
1725 g_object_unref (duration);
1726 return NULL;
1727 }
1728
1729 /* The DURATION shouldn't be negative, but just return DTSTART if it
1730 * is, i.e. assume it is 0. */
1731 if (i_cal_duration_is_neg (duration)) {
1732 g_object_unref (duration);
1733 return dt;
1734 }
1735
1736 /* If DTSTART is a DATE value, then we need to check if the DURATION
1737 * includes any hours, minutes or seconds. If it does, we need to
1738 * make the DTEND/DUE a DATE-TIME value. */
1739 dur_days = i_cal_duration_get_days (duration) + (7 * i_cal_duration_get_weeks (duration));
1740 dur_hours = i_cal_duration_get_hours (duration);
1741 dur_minutes = i_cal_duration_get_minutes (duration);
1742 dur_seconds = i_cal_duration_get_seconds (duration);
1743
1744 tt = e_cal_component_datetime_get_value (dt);
1745 if (i_cal_time_is_date (tt) && (
1746 dur_hours != 0 || dur_minutes != 0 || dur_seconds != 0)) {
1747 i_cal_time_set_is_date (tt, FALSE);
1748 }
1749
1750 /* Add on the DURATION. */
1751 i_cal_time_adjust (tt, dur_days, dur_hours, dur_minutes, dur_seconds);
1752
1753 g_object_unref (duration);
1754
1755 return dt;
1756 }
1757
1758 /**
1759 * e_cal_component_get_dtend:
1760 * @comp: A calendar component object.
1761 *
1762 * Queries the date/time end of a calendar component object. In case there's no DTEND,
1763 * but only DTSTART and DURATION, then the end is computed from the later two.
1764 * Free the returned #ECalComponentDateTime with e_cal_component_datetime_free(),
1765 * when no longer needed.
1766 *
1767 * Returns: (transfer full) (nullable): the date/time end, as an #ECalComponentDateTime
1768 *
1769 * Since: 3.34
1770 **/
1771 ECalComponentDateTime *
e_cal_component_get_dtend(ECalComponent * comp)1772 e_cal_component_get_dtend (ECalComponent *comp)
1773 {
1774 ECalComponentDateTime *dt;
1775
1776 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
1777 g_return_val_if_fail (comp->priv->icalcomp != NULL, NULL);
1778
1779 dt = get_datetime (comp->priv->icalcomp, I_CAL_DTEND_PROPERTY, i_cal_property_get_dtend, NULL);
1780
1781 /* If we don't have a DTEND property, then we try to get DTSTART
1782 * + DURATION. */
1783 if (!dt)
1784 dt = e_cal_component_get_start_plus_duration (comp);
1785
1786 return dt;
1787 }
1788
1789 /**
1790 * e_cal_component_set_dtend:
1791 * @comp: A calendar component object.
1792 * @dt: (nullable): End date/time, or %NULL, to remove the property.
1793 *
1794 * Sets the date/time end property of a calendar component object.
1795 *
1796 * Since: 3.34
1797 **/
1798 void
e_cal_component_set_dtend(ECalComponent * comp,const ECalComponentDateTime * dt)1799 e_cal_component_set_dtend (ECalComponent *comp,
1800 const ECalComponentDateTime *dt)
1801 {
1802 g_return_if_fail (E_IS_CAL_COMPONENT (comp));
1803 g_return_if_fail (comp->priv->icalcomp != NULL);
1804
1805 set_datetime (comp->priv->icalcomp, I_CAL_DTEND_PROPERTY,
1806 i_cal_property_new_dtend,
1807 i_cal_property_set_dtend,
1808 dt,
1809 NULL);
1810
1811 /* Make sure we remove any existing DURATION property, as it can't be
1812 * used with a DTEND. If DTEND is set to NULL, i.e. removed, we also
1813 * want to remove any DURATION. */
1814 remove_all_properties_of_kind (comp->priv->icalcomp, I_CAL_DURATION_PROPERTY);
1815
1816 comp->priv->need_sequence_inc = TRUE;
1817 }
1818
1819 /**
1820 * e_cal_component_get_dtstamp:
1821 * @comp: A calendar component object.
1822 *
1823 * Queries the date/timestamp property of a calendar component object, which is
1824 * the last time at which the object was modified by a calendar user agent.
1825 *
1826 * Free a non-NULL returned object with g_object_unref(),
1827 * when no longer needed.
1828 *
1829 * Returns: (transfer full) (nullable): A value for the date/timestamp, or %NULL, when none found.
1830 *
1831 * Since: 3.34
1832 **/
1833 ICalTime *
e_cal_component_get_dtstamp(ECalComponent * comp)1834 e_cal_component_get_dtstamp (ECalComponent *comp)
1835 {
1836 ICalProperty *prop;
1837 ICalTime *tt;
1838
1839 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
1840 g_return_val_if_fail (comp->priv->icalcomp != NULL, NULL);
1841
1842 prop = i_cal_component_get_first_property (comp->priv->icalcomp, I_CAL_DTSTAMP_PROPERTY);
1843
1844 /* This MUST exist, since we ensured that it did */
1845 g_return_val_if_fail (prop != NULL, NULL);
1846
1847 tt = i_cal_property_get_dtstamp (prop);
1848
1849 g_clear_object (&prop);
1850
1851 return tt;
1852 }
1853
1854 /**
1855 * e_cal_component_set_dtstamp:
1856 * @comp: A calendar component object.
1857 * @tt: Date/timestamp value.
1858 *
1859 * Sets the date/timestamp of a calendar component object. This should be
1860 * called whenever a calendar user agent makes a change to a component's
1861 * properties.
1862 *
1863 * Since: 3.34
1864 **/
1865 void
e_cal_component_set_dtstamp(ECalComponent * comp,const ICalTime * tt)1866 e_cal_component_set_dtstamp (ECalComponent *comp,
1867 const ICalTime *tt)
1868 {
1869 ICalProperty *prop;
1870
1871 g_return_if_fail (E_IS_CAL_COMPONENT (comp));
1872 g_return_if_fail (I_CAL_IS_TIME ((ICalTime *) tt));
1873 g_return_if_fail (comp->priv->icalcomp != NULL);
1874
1875 prop = i_cal_component_get_first_property (comp->priv->icalcomp, I_CAL_DTSTAMP_PROPERTY);
1876
1877 /* This MUST exist, since we ensured that it did */
1878 g_return_if_fail (prop != NULL);
1879
1880 i_cal_property_set_dtstamp (prop, (ICalTime *) tt);
1881
1882 g_clear_object (&prop);
1883 }
1884
1885 /**
1886 * e_cal_component_get_dtstart:
1887 * @comp: A calendar component object.
1888 *
1889 * Queries the date/time start of a calendar component object.
1890 * Free the returned #ECalComponentDateTime with e_cal_component_datetime_free(),
1891 * when no longer needed.
1892 *
1893 * Returns: (transfer full) (nullable): the date/time start, as an #ECalComponentDateTime
1894 *
1895 * Since: 3.34
1896 **/
1897 ECalComponentDateTime *
e_cal_component_get_dtstart(ECalComponent * comp)1898 e_cal_component_get_dtstart (ECalComponent *comp)
1899 {
1900 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
1901 g_return_val_if_fail (comp->priv->icalcomp != NULL, NULL);
1902
1903 return get_datetime (comp->priv->icalcomp, I_CAL_DTSTART_PROPERTY, i_cal_property_get_dtstart, NULL);
1904 }
1905
1906 /**
1907 * e_cal_component_set_dtstart:
1908 * @comp: A calendar component object.
1909 * @dt: (nullable): Start date/time, or %NULL, to remove the property.
1910 *
1911 * Sets the date/time start property of a calendar component object.
1912 *
1913 * Since: 3.34
1914 **/
1915 void
e_cal_component_set_dtstart(ECalComponent * comp,const ECalComponentDateTime * dt)1916 e_cal_component_set_dtstart (ECalComponent *comp,
1917 const ECalComponentDateTime *dt)
1918 {
1919 g_return_if_fail (E_IS_CAL_COMPONENT (comp));
1920 g_return_if_fail (comp->priv->icalcomp != NULL);
1921
1922 set_datetime (comp->priv->icalcomp, I_CAL_DTSTART_PROPERTY,
1923 i_cal_property_new_dtstart,
1924 i_cal_property_set_dtstart,
1925 dt,
1926 NULL);
1927
1928 comp->priv->need_sequence_inc = TRUE;
1929 }
1930
1931 /**
1932 * e_cal_component_get_due:
1933 * @comp: A calendar component object.
1934 *
1935 * Queries the due date/time of a calendar component object. In case there's no DUE,
1936 * but only DTSTART and DURATION, then the due is computed from the later two.
1937 * Free the returned #ECalComponentDateTime with e_cal_component_datetime_free(),
1938 * when no longer needed.
1939 *
1940 * Returns: (transfer full) (nullable): the due date/time, as an #ECalComponentDateTime
1941 *
1942 * Since: 3.34
1943 **/
1944 ECalComponentDateTime *
e_cal_component_get_due(ECalComponent * comp)1945 e_cal_component_get_due (ECalComponent *comp)
1946 {
1947 ECalComponentDateTime *dt;
1948
1949 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
1950 g_return_val_if_fail (comp->priv->icalcomp != NULL, NULL);
1951
1952 dt = get_datetime (comp->priv->icalcomp, I_CAL_DUE_PROPERTY, i_cal_property_get_due, NULL);
1953
1954 /* If we don't have a DTEND property, then we try to get DTSTART
1955 * + DURATION. */
1956 if (!dt)
1957 dt = e_cal_component_get_start_plus_duration (comp);
1958
1959 return dt;
1960 }
1961
1962 /**
1963 * e_cal_component_set_due:
1964 * @comp: A calendar component object.
1965 * @dt: (nullable): End date/time, or %NULL, to remove the property.
1966 *
1967 * Sets the due date/time property of a calendar component object.
1968 *
1969 * Since: 3.34
1970 **/
1971 void
e_cal_component_set_due(ECalComponent * comp,const ECalComponentDateTime * dt)1972 e_cal_component_set_due (ECalComponent *comp,
1973 const ECalComponentDateTime *dt)
1974 {
1975 ICalProperty *prop;
1976
1977 g_return_if_fail (E_IS_CAL_COMPONENT (comp));
1978 g_return_if_fail (comp->priv->icalcomp != NULL);
1979
1980 set_datetime (comp->priv->icalcomp, I_CAL_DUE_PROPERTY,
1981 i_cal_property_new_due,
1982 i_cal_property_set_due,
1983 dt,
1984 NULL);
1985
1986 /* Make sure we remove any existing DURATION property, as it can't be
1987 * used with a DTEND. If DTEND is set to NULL, i.e. removed, we also
1988 * want to remove any DURATION. */
1989 prop = i_cal_component_get_first_property (comp->priv->icalcomp, I_CAL_DURATION_PROPERTY);
1990 if (prop) {
1991 i_cal_component_remove_property (comp->priv->icalcomp, prop);
1992 g_clear_object (&prop);
1993 }
1994
1995 comp->priv->need_sequence_inc = TRUE;
1996 }
1997
1998 /* Builds a list of ECalComponentPeriod structures based on a list of icalproperties */
1999 static GSList * /* ECalComponentPeriod * */
get_period_list(ICalComponent * icalcomp,ICalPropertyKind prop_kind,ICalDatetimeperiod * (* get_prop_func)(ICalProperty * prop))2000 get_period_list (ICalComponent *icalcomp,
2001 ICalPropertyKind prop_kind,
2002 ICalDatetimeperiod * (* get_prop_func) (ICalProperty *prop))
2003 {
2004 GSList *props, *link, *periods = NULL;
2005
2006 props = gather_all_properties (icalcomp, prop_kind, FALSE);
2007
2008 for (link = props; link; link = g_slist_next (link)) {
2009 ICalProperty *prop = link->data;
2010 ICalParameter *param;
2011 ICalPeriod *icalperiod;
2012 ICalDatetimeperiod *pt;
2013 ICalDuration *duration = NULL;
2014 ICalTime *start = NULL, *end = NULL;
2015 ECalComponentPeriod *period;
2016 ECalComponentPeriodKind period_kind;
2017
2018 if (!prop)
2019 continue;
2020
2021 /* Get start and end/duration */
2022 pt = get_prop_func (prop);
2023 if (!pt)
2024 continue;
2025
2026 icalperiod = i_cal_datetimeperiod_get_period (pt);
2027
2028 /* Get value parameter */
2029 param = i_cal_property_get_first_parameter (prop, I_CAL_VALUE_PARAMETER);
2030
2031 if (param) {
2032 ICalParameterValue value_type;
2033
2034 value_type = i_cal_parameter_get_value (param);
2035
2036 if (value_type == I_CAL_VALUE_DATE || value_type == I_CAL_VALUE_DATETIME) {
2037 period_kind = E_CAL_COMPONENT_PERIOD_DATETIME;
2038 } else if (value_type == I_CAL_VALUE_PERIOD) {
2039 duration = i_cal_period_get_duration (icalperiod);
2040
2041 if (!duration ||
2042 i_cal_duration_is_null_duration (duration) ||
2043 i_cal_duration_is_bad_duration (duration))
2044 period_kind = E_CAL_COMPONENT_PERIOD_DATETIME;
2045 else
2046 period_kind = E_CAL_COMPONENT_PERIOD_DURATION;
2047
2048 g_clear_object (&duration);
2049 } else {
2050 g_message ("get_period_list(): Unknown value for period %d; using DATETIME", value_type);
2051 period_kind = E_CAL_COMPONENT_PERIOD_DATETIME;
2052 }
2053 } else {
2054 period_kind = E_CAL_COMPONENT_PERIOD_DATETIME;
2055 }
2056
2057 start = i_cal_period_get_start (icalperiod);
2058
2059 if (period_kind == E_CAL_COMPONENT_PERIOD_DATETIME) {
2060 if (!start || i_cal_time_is_null_time (start)) {
2061 g_clear_object (&start);
2062 start = i_cal_datetimeperiod_get_time (pt);
2063 } else {
2064 end = i_cal_period_get_end (icalperiod);
2065 }
2066 } else /* if (period_kind == E_CAL_COMPONENT_PERIOD_DURATION) */ {
2067 duration = i_cal_period_get_duration (icalperiod);
2068 }
2069
2070 period = period_kind == E_CAL_COMPONENT_PERIOD_DATETIME ?
2071 e_cal_component_period_new_datetime (start, end) :
2072 e_cal_component_period_new_duration (start, duration);
2073
2074 if (period)
2075 periods = g_slist_prepend (periods, period);
2076
2077 g_clear_object (¶m);
2078 g_clear_object (&icalperiod);
2079 g_clear_object (&pt);
2080 g_clear_object (&duration);
2081 g_clear_object (&start);
2082 g_clear_object (&end);
2083 }
2084
2085 g_slist_free_full (props, g_object_unref);
2086
2087 /* No need to reverse it, the props are in reverse order
2088 and processed in the reverse order, thus the result
2089 is in the expected order. */
2090 return periods;
2091 }
2092
2093 /* Sets a period list value */
2094 static void
set_period_list(ICalComponent * icalcomp,ICalPropertyKind prop_kind,ICalProperty * (* new_prop_func)(ICalDatetimeperiod * period),const GSList * periods_list)2095 set_period_list (ICalComponent *icalcomp,
2096 ICalPropertyKind prop_kind,
2097 ICalProperty *(* new_prop_func) (ICalDatetimeperiod *period),
2098 const GSList *periods_list)
2099 {
2100 GSList *link;
2101
2102 /* Remove old periods */
2103
2104 remove_all_properties_of_kind (icalcomp, prop_kind);
2105
2106 /* Add in new periods */
2107
2108 for (link = (GSList *) periods_list; link; link = g_slist_next (link)) {
2109 const ECalComponentPeriod *period = link->data;
2110 ICalDatetimeperiod *ic_datetimeperiod;
2111 ICalPeriod *ic_period;
2112 ICalProperty *prop;
2113 ICalParameter *param;
2114 ICalParameterValue value_type = I_CAL_VALUE_PERIOD;
2115 ICalTime *end;
2116
2117 if (!period)
2118 continue;
2119
2120 ic_period = i_cal_period_new_null_period ();
2121 ic_datetimeperiod = i_cal_datetimeperiod_new ();
2122
2123 i_cal_period_set_start (ic_period, e_cal_component_period_get_start (period));
2124
2125 switch (e_cal_component_period_get_kind (period)) {
2126 case E_CAL_COMPONENT_PERIOD_DATETIME:
2127 end = e_cal_component_period_get_end (period);
2128 if (!end || i_cal_time_is_null_time (end)) {
2129 i_cal_datetimeperiod_set_time (ic_datetimeperiod, e_cal_component_period_get_start (period));
2130 if (i_cal_time_is_date (e_cal_component_period_get_start (period))) {
2131 value_type = I_CAL_VALUE_DATE;
2132 } else {
2133 value_type = I_CAL_VALUE_DATETIME;
2134 }
2135 } else {
2136 i_cal_period_set_end (ic_period, e_cal_component_period_get_end (period));
2137 }
2138 break;
2139 case E_CAL_COMPONENT_PERIOD_DURATION:
2140 i_cal_period_set_duration (ic_period, e_cal_component_period_get_duration (period));
2141 break;
2142 }
2143
2144 i_cal_datetimeperiod_set_period (ic_datetimeperiod, ic_period);
2145
2146 prop = new_prop_func (ic_datetimeperiod);
2147
2148 param = i_cal_parameter_new_value (value_type);
2149 i_cal_property_take_parameter (prop, param);
2150
2151 i_cal_component_take_property (icalcomp, prop);
2152
2153 g_object_unref (ic_datetimeperiod);
2154 g_object_unref (ic_period);
2155 }
2156 }
2157
2158 static gboolean
extract_exdate_properties_cb(ICalComponent * icalcomp,ICalProperty * prop,gpointer user_data)2159 extract_exdate_properties_cb (ICalComponent *icalcomp,
2160 ICalProperty *prop,
2161 gpointer user_data)
2162 {
2163 GSList **pexdates = user_data;
2164 ICalTime *tt;
2165
2166 g_return_val_if_fail (pexdates != NULL, FALSE);
2167
2168 tt = i_cal_property_get_exdate (prop);
2169 if (tt) {
2170 ICalParameter *param;
2171 gchar *tzid;
2172
2173 param = i_cal_property_get_first_parameter (prop, I_CAL_TZID_PARAMETER);
2174 if (param)
2175 tzid = g_strdup (i_cal_parameter_get_tzid (param));
2176 else
2177 tzid = NULL;
2178
2179 if (tzid && !*tzid) {
2180 g_free (tzid);
2181 tzid = NULL;
2182 }
2183
2184 *pexdates = g_slist_prepend (*pexdates, e_cal_component_datetime_new_take (tt, tzid));
2185
2186 g_clear_object (¶m);
2187 }
2188
2189 return TRUE;
2190 }
2191
2192 /**
2193 * e_cal_component_get_exdates:
2194 * @comp: A calendar component object.
2195 *
2196 * Queries the list of exception date properties in a calendar component object.
2197 * Free the returned #GSList with g_slist_free_full (exdates, e_cal_component_datetime_free);,
2198 * when no longer needed.
2199 *
2200 * Returns: (transfer full) (nullable) (element-type ECalComponentDateTime):
2201 * the list of exception dates, as a #GSList of #ECalComponentDateTime
2202 *
2203 * Since: 3.34
2204 **/
2205 GSList *
e_cal_component_get_exdates(ECalComponent * comp)2206 e_cal_component_get_exdates (ECalComponent *comp)
2207 {
2208 GSList *exdates = NULL;
2209
2210 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
2211 g_return_val_if_fail (comp->priv->icalcomp != NULL, NULL);
2212
2213 foreach_property (comp->priv->icalcomp, I_CAL_EXDATE_PROPERTY,
2214 extract_exdate_properties_cb, &exdates);
2215
2216 return g_slist_reverse (exdates);
2217 }
2218
2219 /**
2220 * e_cal_component_set_exdates:
2221 * @comp: A calendar component object.
2222 * @exdate_list: (nullable) (element-type ECalComponentDateTime): List of #ECalComponentDateTime structures.
2223 *
2224 * Sets the list of exception dates in a calendar component object.
2225 *
2226 * Since: 3.34
2227 **/
2228 void
e_cal_component_set_exdates(ECalComponent * comp,const GSList * exdate_list)2229 e_cal_component_set_exdates (ECalComponent *comp,
2230 const GSList *exdate_list)
2231 {
2232 GSList *link;
2233
2234 g_return_if_fail (E_IS_CAL_COMPONENT (comp));
2235 g_return_if_fail (comp->priv->icalcomp != NULL);
2236
2237 /* Remove old exception dates */
2238 remove_all_properties_of_kind (comp->priv->icalcomp, I_CAL_EXDATE_PROPERTY);
2239
2240 /* Add in new exception dates */
2241
2242 for (link = (GSList *) exdate_list; link; link = g_slist_next (link)) {
2243 const ECalComponentDateTime *dt = link->data;
2244 ICalProperty *prop;
2245 ICalTime *tt;
2246 const gchar *tzid;
2247
2248 if (!dt)
2249 continue;
2250
2251 tt = e_cal_component_datetime_get_value (dt);
2252 if (!tt)
2253 continue;
2254
2255 tzid = e_cal_component_datetime_get_tzid (dt);
2256
2257 prop = i_cal_property_new_exdate (tt);
2258
2259 if (tzid && *tzid) {
2260 ICalParameter *param;
2261
2262 param = i_cal_parameter_new_tzid ((gchar *) tzid);
2263 i_cal_property_take_parameter (prop, param);
2264 }
2265
2266 i_cal_component_take_property (comp->priv->icalcomp, prop);
2267 }
2268
2269 comp->priv->need_sequence_inc = TRUE;
2270 }
2271
2272 /**
2273 * e_cal_component_has_exdates:
2274 * @comp: A calendar component object.
2275 *
2276 * Queries whether a calendar component object has any exception dates defined
2277 * for it.
2278 *
2279 * Returns: TRUE if the component has exception dates, FALSE otherwise.
2280 *
2281 * Since: 3.34
2282 **/
2283 gboolean
e_cal_component_has_exdates(ECalComponent * comp)2284 e_cal_component_has_exdates (ECalComponent *comp)
2285 {
2286 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), FALSE);
2287 g_return_val_if_fail (comp->priv->icalcomp != NULL, FALSE);
2288
2289 return e_cal_util_component_has_property (comp->priv->icalcomp, I_CAL_EXDATE_PROPERTY);
2290 }
2291
2292 /* Gets a list of recurrence rules */
2293 static GSList *
get_recur_list(ICalComponent * icalcomp,ICalPropertyKind prop_kind,ICalRecurrence * (* get_prop_func)(ICalProperty * prop))2294 get_recur_list (ICalComponent *icalcomp,
2295 ICalPropertyKind prop_kind,
2296 ICalRecurrence * (* get_prop_func) (ICalProperty *prop))
2297 {
2298 GSList *props, *link, *recurs = NULL;
2299
2300 props = gather_all_properties (icalcomp, prop_kind, FALSE);
2301
2302 for (link = props; link; link = g_slist_next (link)) {
2303 ICalProperty *prop = link->data;
2304 ICalRecurrence *rt;
2305
2306 rt = get_prop_func (prop);
2307 if (rt)
2308 recurs = g_slist_prepend (recurs, rt);
2309 }
2310
2311 g_slist_free_full (props, g_object_unref);
2312
2313 /* No need to reverse it, the props are in reverse order
2314 and processed in the reverse order, thus the result
2315 is in the expected order. */
2316 return recurs;
2317 }
2318
2319 /* Sets a list of recurrence rules */
2320 static void
set_recur_list(ICalComponent * icalcomp,ICalPropertyKind prop_kind,ICalProperty * (* new_prop_func)(ICalRecurrence * recur),const GSList * rl)2321 set_recur_list (ICalComponent *icalcomp,
2322 ICalPropertyKind prop_kind,
2323 ICalProperty * (* new_prop_func) (ICalRecurrence *recur),
2324 const GSList *rl) /* ICalRecurrence * */
2325 {
2326 GSList *link;
2327
2328 /* Remove old recurrences */
2329 remove_all_properties_of_kind (icalcomp, prop_kind);
2330
2331 /* Add in new recurrences */
2332
2333 for (link = (GSList *) rl; link; link = g_slist_next (link)) {
2334 ICalProperty *prop;
2335 ICalRecurrence *recur = link->data;
2336
2337 if (recur) {
2338 prop = (* new_prop_func) (recur);
2339 i_cal_component_take_property (icalcomp, prop);
2340 }
2341 }
2342 }
2343
2344 /**
2345 * e_cal_component_get_exrules:
2346 * @comp: A calendar component object.
2347 *
2348 * Queries the list of exception rule properties of a calendar component
2349 * object. Free the returned list with g_slist_free_full (slist, g_object_unref);,
2350 * when no longer needed.
2351 *
2352 * Returns: (transfer full) (nullable) (element-type ICalRecurrence): a #GSList
2353 * of exception rules as #ICalRecurrence structures, or %NULL, when none exist.
2354 *
2355 * Since: 3.34
2356 **/
2357 GSList *
e_cal_component_get_exrules(ECalComponent * comp)2358 e_cal_component_get_exrules (ECalComponent *comp)
2359 {
2360 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
2361 g_return_val_if_fail (comp->priv->icalcomp != NULL, NULL);
2362
2363 return get_recur_list (comp->priv->icalcomp, I_CAL_EXRULE_PROPERTY, i_cal_property_get_exrule);
2364 }
2365
2366 /**
2367 * e_cal_component_get_exrule_properties:
2368 * @comp: A calendar component object.
2369 *
2370 * Queries the list of exception rule properties of a calendar component object.
2371 * Free the list with g_slist_free_full (slist, g_object_unref);, when
2372 * no longer needed.
2373 *
2374 * Returns: (transfer full) (nullable) (element-type ICalProperty): a list of exception
2375 * rule properties
2376 *
2377 * Since: 3.34
2378 **/
2379 GSList *
e_cal_component_get_exrule_properties(ECalComponent * comp)2380 e_cal_component_get_exrule_properties (ECalComponent *comp)
2381 {
2382 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
2383 g_return_val_if_fail (comp->priv->icalcomp != NULL, NULL);
2384
2385 return gather_all_properties (comp->priv->icalcomp, I_CAL_EXRULE_PROPERTY, TRUE);
2386 }
2387
2388 /**
2389 * e_cal_component_set_exrules:
2390 * @comp: A calendar component object.
2391 * @recur_list: (nullable) (element-type ICalRecurrence): a #GSList
2392 * of #ICalRecurrence structures, or %NULL.
2393 *
2394 * Sets the list of exception rules in a calendar component object.
2395 *
2396 * Since: 3.34
2397 **/
2398 void
e_cal_component_set_exrules(ECalComponent * comp,const GSList * recur_list)2399 e_cal_component_set_exrules (ECalComponent *comp,
2400 const GSList *recur_list)
2401 {
2402 g_return_if_fail (E_IS_CAL_COMPONENT (comp));
2403 g_return_if_fail (comp->priv->icalcomp != NULL);
2404
2405 set_recur_list (comp->priv->icalcomp, I_CAL_EXRULE_PROPERTY, i_cal_property_new_exrule, recur_list);
2406
2407 comp->priv->need_sequence_inc = TRUE;
2408 }
2409
2410 /**
2411 * e_cal_component_has_exrules:
2412 * @comp: A calendar component object.
2413 *
2414 * Queries whether a calendar component object has any exception rules defined
2415 * for it.
2416 *
2417 * Returns: TRUE if the component has exception rules, FALSE otherwise.
2418 *
2419 * Since: 3.34
2420 **/
2421 gboolean
e_cal_component_has_exrules(ECalComponent * comp)2422 e_cal_component_has_exrules (ECalComponent *comp)
2423 {
2424 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), FALSE);
2425 g_return_val_if_fail (comp->priv->icalcomp != NULL, FALSE);
2426
2427 return e_cal_util_component_has_property (comp->priv->icalcomp, I_CAL_EXRULE_PROPERTY);
2428 }
2429
2430 /**
2431 * e_cal_component_has_exceptions:
2432 * @comp: A calendar component object
2433 *
2434 * Queries whether a calendar component object has any exception dates
2435 * or exception rules.
2436 *
2437 * Returns: TRUE if the component has exceptions, FALSE otherwise.
2438 *
2439 * Since: 3.34
2440 **/
2441 gboolean
e_cal_component_has_exceptions(ECalComponent * comp)2442 e_cal_component_has_exceptions (ECalComponent *comp)
2443 {
2444 return e_cal_component_has_exdates (comp) || e_cal_component_has_exrules (comp);
2445 }
2446
2447 /**
2448 * e_cal_component_get_geo:
2449 * @comp: A calendar component object.
2450 *
2451 * Gets the geographic position property of a calendar component object.
2452 * Free the returned non-NULL object with g_object_unref(), when
2453 * no longer needed.
2454 *
2455 * Returns: (transfer full) (nullable): the geographic position as #ICalGeo,
2456 * or %NULL, when none set.
2457 *
2458 * Since: 3.34
2459 **/
2460 ICalGeo *
e_cal_component_get_geo(ECalComponent * comp)2461 e_cal_component_get_geo (ECalComponent *comp)
2462 {
2463 ICalProperty *prop;
2464 ICalGeo *geo;
2465
2466 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
2467 g_return_val_if_fail (comp->priv->icalcomp != NULL, NULL);
2468
2469 prop = i_cal_component_get_first_property (comp->priv->icalcomp, I_CAL_GEO_PROPERTY);
2470 if (!prop)
2471 return NULL;
2472
2473 geo = i_cal_property_get_geo (prop);
2474
2475 g_object_unref (prop);
2476
2477 return geo;
2478 }
2479
2480 /**
2481 * e_cal_component_set_geo:
2482 * @comp: A calendar component object.
2483 * @geo: (nullable): Value for the geographic position property, or %NULL to unset.
2484 *
2485 * Sets the geographic position property on a calendar component object.
2486 *
2487 * Since: 3.34
2488 **/
2489 void
e_cal_component_set_geo(ECalComponent * comp,const ICalGeo * geo)2490 e_cal_component_set_geo (ECalComponent *comp,
2491 const ICalGeo *geo)
2492 {
2493 ICalProperty *prop;
2494
2495 g_return_if_fail (E_IS_CAL_COMPONENT (comp));
2496 g_return_if_fail (comp->priv->icalcomp != NULL);
2497
2498 prop = i_cal_component_get_first_property (comp->priv->icalcomp, I_CAL_GEO_PROPERTY);
2499
2500 if (!geo) {
2501 if (prop) {
2502 i_cal_component_remove_property (comp->priv->icalcomp, prop);
2503 g_clear_object (&prop);
2504 }
2505
2506 return;
2507 }
2508
2509 if (prop) {
2510 i_cal_property_set_geo (prop, (ICalGeo *) geo);
2511 } else {
2512 prop = i_cal_property_new_geo ((ICalGeo *) geo);
2513 i_cal_component_add_property (comp->priv->icalcomp, prop);
2514 }
2515
2516 g_clear_object (&prop);
2517 }
2518
2519 /**
2520 * e_cal_component_get_last_modified:
2521 * @comp: A calendar component object.
2522 *
2523 * Queries the time at which a calendar component object was last modified in
2524 * the calendar store. Free the returned non-NULL pointer with g_object_unref(),
2525 * when no longer needed.
2526 *
2527 * Returns: (transfer full): the last modified time, as an #ICalTime, or %NULL, when none is set
2528 *
2529 * Since: 3.34
2530 **/
2531 ICalTime *
e_cal_component_get_last_modified(ECalComponent * comp)2532 e_cal_component_get_last_modified (ECalComponent *comp)
2533 {
2534 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
2535 g_return_val_if_fail (comp->priv->icalcomp != NULL, NULL);
2536
2537 return get_icaltimetype (comp->priv->icalcomp, I_CAL_LASTMODIFIED_PROPERTY, i_cal_property_get_lastmodified);
2538 }
2539
2540 /**
2541 * e_cal_component_set_last_modified:
2542 * @comp: A calendar component object.
2543 * @tt: (nullable): Value for the last time modified.
2544 *
2545 * Sets the time at which a calendar component object was last stored in the
2546 * calendar store. This should not be called by plain calendar user agents.
2547 *
2548 * Since: 3.34
2549 **/
2550 void
e_cal_component_set_last_modified(ECalComponent * comp,const ICalTime * tt)2551 e_cal_component_set_last_modified (ECalComponent *comp,
2552 const ICalTime *tt)
2553 {
2554 g_return_if_fail (E_IS_CAL_COMPONENT (comp));
2555 g_return_if_fail (comp->priv->icalcomp != NULL);
2556
2557 set_icaltimetype (comp->priv->icalcomp, I_CAL_LASTMODIFIED_PROPERTY,
2558 i_cal_property_new_lastmodified,
2559 i_cal_property_set_lastmodified,
2560 tt);
2561 }
2562
2563 /**
2564 * e_cal_component_get_organizer:
2565 * @comp: A calendar component object
2566 *
2567 * Queries the organizer property of a calendar component object.
2568 * Free the returned structure with e_cal_component_organizer_free(),
2569 * when no longer needed.
2570 *
2571 * Returns: (transfer full) (nullable): an #ECalComponentOrganizer structure
2572 * destribing the organizer, or %NULL, when none exists.
2573 *
2574 * Since: 3.34
2575 **/
2576 ECalComponentOrganizer *
e_cal_component_get_organizer(ECalComponent * comp)2577 e_cal_component_get_organizer (ECalComponent *comp)
2578 {
2579 ECalComponentOrganizer *organizer;
2580 ICalProperty *prop;
2581
2582 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
2583 g_return_val_if_fail (comp->priv->icalcomp != NULL, NULL);
2584
2585 prop = i_cal_component_get_first_property (comp->priv->icalcomp, I_CAL_ORGANIZER_PROPERTY);
2586 if (!prop)
2587 return NULL;
2588
2589 organizer = e_cal_component_organizer_new_from_property (prop);
2590
2591 g_object_unref (prop);
2592
2593 return organizer;
2594 }
2595
2596 /**
2597 * e_cal_component_set_organizer:
2598 * @comp: A calendar component object.
2599 * @organizer: (nullable): Value for the organizer property, as an #ECalComponentOrganizer
2600 *
2601 * Sets the organizer of a calendar component object
2602 *
2603 * Since: 3.34
2604 **/
2605 void
e_cal_component_set_organizer(ECalComponent * comp,const ECalComponentOrganizer * organizer)2606 e_cal_component_set_organizer (ECalComponent *comp,
2607 const ECalComponentOrganizer *organizer)
2608 {
2609 ICalProperty *prop;
2610
2611 g_return_if_fail (E_IS_CAL_COMPONENT (comp));
2612 g_return_if_fail (comp->priv->icalcomp != NULL);
2613
2614 prop = i_cal_component_get_first_property (comp->priv->icalcomp, I_CAL_ORGANIZER_PROPERTY);
2615
2616 if (!organizer) {
2617 if (prop) {
2618 i_cal_component_remove_property (comp->priv->icalcomp, prop);
2619 g_clear_object (&prop);
2620 }
2621
2622 return;
2623 }
2624
2625 if (!prop) {
2626 prop = i_cal_property_new (I_CAL_ORGANIZER_PROPERTY);
2627 i_cal_component_add_property (comp->priv->icalcomp, prop);
2628 }
2629
2630 e_cal_component_organizer_fill_property (organizer, prop);
2631
2632 g_clear_object (&prop);
2633 }
2634
2635 /**
2636 * e_cal_component_has_organizer:
2637 * @comp: A calendar component object.
2638 *
2639 * Check whether a calendar component object has an organizer or not.
2640 *
2641 * Returns: TRUE if there is an organizer, FALSE otherwise.
2642 *
2643 * Since: 3.34
2644 **/
2645 gboolean
e_cal_component_has_organizer(ECalComponent * comp)2646 e_cal_component_has_organizer (ECalComponent *comp)
2647 {
2648 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), FALSE);
2649
2650 return e_cal_util_component_has_property (comp->priv->icalcomp, I_CAL_ORGANIZER_PROPERTY);
2651 }
2652
2653 /**
2654 * e_cal_component_get_percent_complete:
2655 * @comp: A calendar component object.
2656 *
2657 * Queries the percent-complete property of a calendar component object.
2658 *
2659 * Returns: the percent-complete property value, or -1 if not found
2660 *
2661 * Since: 3.34
2662 **/
2663 gint
e_cal_component_get_percent_complete(ECalComponent * comp)2664 e_cal_component_get_percent_complete (ECalComponent *comp)
2665 {
2666 ICalProperty *prop;
2667 gint percent;
2668
2669 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), -1);
2670 g_return_val_if_fail (comp->priv->icalcomp != NULL, -1);
2671
2672 prop = i_cal_component_get_first_property (comp->priv->icalcomp, I_CAL_PERCENTCOMPLETE_PROPERTY);
2673 if (!prop)
2674 return -1;
2675
2676 percent = i_cal_property_get_percentcomplete (prop);
2677
2678 g_object_unref (prop);
2679
2680 return percent;
2681 }
2682
2683 /**
2684 * e_cal_component_set_percent_complete:
2685 * @comp: an #ECalComponent
2686 * @percent: a percent to set, or -1 to remove the property
2687 *
2688 * Sets percent complete. The @percent can be between 0 and 100, inclusive.
2689 * A special value -1 can be used to remove the percent complete property.
2690 *
2691 * Since: 3.34
2692 **/
2693 void
e_cal_component_set_percent_complete(ECalComponent * comp,gint percent)2694 e_cal_component_set_percent_complete (ECalComponent *comp,
2695 gint percent)
2696 {
2697 ICalProperty *prop;
2698
2699 g_return_if_fail (E_IS_CAL_COMPONENT (comp));
2700 g_return_if_fail (comp->priv->icalcomp != NULL);
2701 g_return_if_fail (percent >= -1 && percent <= 100);
2702
2703 prop = i_cal_component_get_first_property (comp->priv->icalcomp, I_CAL_PERCENTCOMPLETE_PROPERTY);
2704
2705 if (percent == -1) {
2706 if (prop) {
2707 i_cal_component_remove_property (comp->priv->icalcomp, prop);
2708 g_clear_object (&prop);
2709 }
2710
2711 return;
2712 }
2713
2714 if (prop) {
2715 i_cal_property_set_percentcomplete (prop, percent);
2716 g_clear_object (&prop);
2717 } else {
2718 prop = i_cal_property_new_percentcomplete (percent);
2719 i_cal_component_take_property (comp->priv->icalcomp, prop);
2720 }
2721 }
2722
2723 /**
2724 * e_cal_component_get_priority:
2725 * @comp: A calendar component object.
2726 *
2727 * Queries the priority property of a calendar component object.
2728 *
2729 * Returns: the priority property value, or -1, if not found
2730 *
2731 * Since: 3.34
2732 **/
2733 gint
e_cal_component_get_priority(ECalComponent * comp)2734 e_cal_component_get_priority (ECalComponent *comp)
2735 {
2736 ICalProperty *prop;
2737 gint priority;
2738
2739 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), -1);
2740 g_return_val_if_fail (comp->priv->icalcomp != NULL, -1);
2741
2742 prop = i_cal_component_get_first_property (comp->priv->icalcomp, I_CAL_PRIORITY_PROPERTY);
2743 if (!prop)
2744 return -1;
2745
2746 priority = i_cal_property_get_priority (prop);
2747
2748 g_object_unref (prop);
2749
2750 return priority;
2751 }
2752
2753 /**
2754 * e_cal_component_set_priority:
2755 * @comp: A calendar component object.
2756 * @priority: Value for the priority property.
2757 *
2758 * Sets the priority property of a calendar component object.
2759 * The @priority can be between 0 and 9, inclusive.
2760 * A special value -1 can be used to remove the priority property.
2761 *
2762 * Since: 3.34
2763 **/
2764 void
e_cal_component_set_priority(ECalComponent * comp,gint priority)2765 e_cal_component_set_priority (ECalComponent *comp,
2766 gint priority)
2767 {
2768 ICalProperty *prop;
2769
2770 g_return_if_fail (E_IS_CAL_COMPONENT (comp));
2771 g_return_if_fail (comp->priv->icalcomp != NULL);
2772 g_return_if_fail (priority >= -1 && priority <= 9);
2773
2774 prop = i_cal_component_get_first_property (comp->priv->icalcomp, I_CAL_PRIORITY_PROPERTY);
2775
2776 if (priority == -1) {
2777 if (prop) {
2778 i_cal_component_remove_property (comp->priv->icalcomp, prop);
2779 g_clear_object (&prop);
2780 }
2781
2782 return;
2783 }
2784
2785 if (prop) {
2786 i_cal_property_set_priority (prop, priority);
2787 g_clear_object (&prop);
2788 } else {
2789 prop = i_cal_property_new_priority (priority);
2790 i_cal_component_take_property (comp->priv->icalcomp, prop);
2791 }
2792 }
2793
2794 /**
2795 * e_cal_component_get_recurid:
2796 * @comp: A calendar component object.
2797 *
2798 * Queries the recurrence id property of a calendar component object.
2799 * Free the returned #ECalComponentRange with e_cal_component_range_free(),
2800 * whe no longer needed.
2801 *
2802 * Returns: (transfer full) (nullable): the recurrence id property, as an #ECalComponentRange
2803 *
2804 * Since: 3.34
2805 **/
2806 ECalComponentRange *
e_cal_component_get_recurid(ECalComponent * comp)2807 e_cal_component_get_recurid (ECalComponent *comp)
2808 {
2809 ECalComponentDateTime *dt;
2810 ECalComponentRangeKind range_kind;
2811 ICalProperty *prop = NULL;
2812 ICalParameter *param;
2813
2814 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
2815 g_return_val_if_fail (comp->priv->icalcomp != NULL, NULL);
2816
2817 dt = get_datetime (comp->priv->icalcomp, I_CAL_RECURRENCEID_PROPERTY, i_cal_property_get_recurrenceid, &prop);
2818
2819 if (!dt) {
2820 g_clear_object (&prop);
2821 return NULL;
2822 }
2823
2824 range_kind = E_CAL_COMPONENT_RANGE_SINGLE;
2825 param = i_cal_property_get_first_parameter (prop, I_CAL_RANGE_PARAMETER);
2826
2827 /* RFC 5545 says it can use only THIS_AND_FUTURE here */
2828 if (param && i_cal_parameter_get_range (param) == I_CAL_RANGE_THISANDFUTURE)
2829 range_kind = E_CAL_COMPONENT_RANGE_THISFUTURE;
2830
2831 g_clear_object (¶m);
2832 g_clear_object (&prop);
2833
2834 return e_cal_component_range_new_take (range_kind, dt);
2835 }
2836
2837 /**
2838 * e_cal_component_get_recurid_as_string:
2839 * @comp: A calendar component object.
2840 *
2841 * Gets the recurrence ID property as a string.
2842 *
2843 * Returns: the recurrence ID as a string.
2844 *
2845 * Since: 3.34
2846 **/
2847 gchar *
e_cal_component_get_recurid_as_string(ECalComponent * comp)2848 e_cal_component_get_recurid_as_string (ECalComponent *comp)
2849 {
2850 return e_cal_util_component_get_recurid_as_string (comp->priv->icalcomp);
2851 }
2852
2853 /**
2854 * e_cal_component_set_recurid:
2855 * @comp: A calendar component object.
2856 * @recur_id: (nullable): Value for the recurrence id property, or %NULL, to remove the property.
2857 *
2858 * Sets the recurrence id property of a calendar component object.
2859 *
2860 * Since: 3.34
2861 **/
2862 void
e_cal_component_set_recurid(ECalComponent * comp,const ECalComponentRange * recur_id)2863 e_cal_component_set_recurid (ECalComponent *comp,
2864 const ECalComponentRange *recur_id)
2865 {
2866 ECalComponentDateTime *dt;
2867 ICalProperty *prop = NULL;
2868
2869 g_return_if_fail (E_IS_CAL_COMPONENT (comp));
2870 g_return_if_fail (comp->priv->icalcomp != NULL);
2871
2872 dt = recur_id ? e_cal_component_range_get_datetime (recur_id) : NULL;
2873
2874 set_datetime (comp->priv->icalcomp, I_CAL_RECURRENCEID_PROPERTY,
2875 i_cal_property_new_recurrenceid,
2876 i_cal_property_set_recurrenceid,
2877 dt,
2878 &prop);
2879
2880 if (prop) {
2881 ICalParameter *param;
2882
2883 param = i_cal_property_get_first_parameter (prop, I_CAL_RANGE_PARAMETER);
2884
2885 /* RFC 5545 says it can use only THIS_AND_FUTURE here */
2886 if (e_cal_component_range_get_kind (recur_id) == E_CAL_COMPONENT_RANGE_THISFUTURE) {
2887 if (param) {
2888 i_cal_parameter_set_range (param, I_CAL_RANGE_THISANDFUTURE);
2889 } else {
2890 param = i_cal_parameter_new_range (I_CAL_RANGE_THISANDFUTURE);
2891 i_cal_property_add_parameter (prop, param);
2892 }
2893 } else if (param) {
2894 i_cal_property_remove_parameter_by_ref (prop, param);
2895 }
2896
2897 g_clear_object (¶m);
2898 g_clear_object (&prop);
2899 }
2900 }
2901
2902 /**
2903 * e_cal_component_get_rdates:
2904 * @comp: A calendar component object.
2905 *
2906 * Queries the list of recurrence date properties in a calendar component
2907 * object. Free the returned #GSList with g_slist_free_full (slist, e_cal_component_period_free);,
2908 * when no longer needed.
2909 *
2910 * Returns: (transfer full) (nullable) (element-type ECalComponentPeriod): the list
2911 * of recurrence dates, as a #GSList of #ECalComponentPeriod structures.
2912 *
2913 * Since: 3.34
2914 **/
2915 GSList *
e_cal_component_get_rdates(ECalComponent * comp)2916 e_cal_component_get_rdates (ECalComponent *comp)
2917 {
2918 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
2919 g_return_val_if_fail (comp->priv->icalcomp != NULL, NULL);
2920
2921 return get_period_list (comp->priv->icalcomp, I_CAL_RDATE_PROPERTY, i_cal_property_get_rdate);
2922 }
2923
2924 /**
2925 * e_cal_component_set_rdates:
2926 * @comp: A calendar component object.
2927 * @rdate_list: (nullable) (element-type ECalComponentPeriod): List of
2928 * #ECalComponentPeriod structures, or %NULL to set none
2929 *
2930 * Sets the list of recurrence dates in a calendar component object.
2931 *
2932 * Since: 3.34
2933 **/
2934 void
e_cal_component_set_rdates(ECalComponent * comp,const GSList * rdate_list)2935 e_cal_component_set_rdates (ECalComponent *comp,
2936 const GSList *rdate_list)
2937 {
2938 g_return_if_fail (E_IS_CAL_COMPONENT (comp));
2939 g_return_if_fail (comp->priv->icalcomp != NULL);
2940
2941 set_period_list (comp->priv->icalcomp, I_CAL_RDATE_PROPERTY, i_cal_property_new_rdate, rdate_list);
2942
2943 comp->priv->need_sequence_inc = TRUE;
2944 }
2945
2946 /**
2947 * e_cal_component_has_rdates:
2948 * @comp: A calendar component object.
2949 *
2950 * Queries whether a calendar component object has any recurrence dates defined
2951 * for it.
2952 *
2953 * Returns: TRUE if the component has recurrence dates, FALSE otherwise.
2954 *
2955 * Since: 3.34
2956 **/
2957 gboolean
e_cal_component_has_rdates(ECalComponent * comp)2958 e_cal_component_has_rdates (ECalComponent *comp)
2959 {
2960 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), FALSE);
2961 g_return_val_if_fail (comp->priv->icalcomp != NULL, FALSE);
2962
2963 return e_cal_util_component_has_property (comp->priv->icalcomp, I_CAL_RDATE_PROPERTY);
2964 }
2965
2966 /**
2967 * e_cal_component_get_rrules:
2968 * @comp: A calendar component object.
2969 *
2970 * Queries the list of recurrence rule properties of a calendar component
2971 * object. Free the returned list with g_slist_free_full (slist, g_object_unref);,
2972 * when no longer needed.
2973 *
2974 * Returns: (transfer full) (nullable) (element-type ICalRecurrence): a #GSList
2975 * of recurrence rules as #ICalRecurrence structures, or %NULL, when none exist.
2976 *
2977 * Since: 3.34
2978 **/
2979 GSList *
e_cal_component_get_rrules(ECalComponent * comp)2980 e_cal_component_get_rrules (ECalComponent *comp)
2981 {
2982 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
2983 g_return_val_if_fail (comp->priv->icalcomp != NULL, NULL);
2984
2985 return get_recur_list (comp->priv->icalcomp, I_CAL_RRULE_PROPERTY, i_cal_property_get_rrule);
2986 }
2987
2988 /**
2989 * e_cal_component_get_rrule_properties:
2990 * @comp: A calendar component object.
2991 *
2992 * Queries a list of recurrence rule properties of a calendar component object.
2993 * Free the list with g_slist_free_full (slist, g_object_unref);, when
2994 * no longer needed.
2995 *
2996 * Returns: (transfer full) (nullable) (element-type ICalProperty): a list of recurrence
2997 * rule properties
2998 *
2999 * Since: 3.34
3000 **/
3001 GSList *
e_cal_component_get_rrule_properties(ECalComponent * comp)3002 e_cal_component_get_rrule_properties (ECalComponent *comp)
3003 {
3004 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
3005 g_return_val_if_fail (comp->priv->icalcomp != NULL, NULL);
3006
3007 return gather_all_properties (comp->priv->icalcomp, I_CAL_RRULE_PROPERTY, TRUE);
3008 }
3009
3010 /**
3011 * e_cal_component_set_rrules:
3012 * @comp: A calendar component object.
3013 * @recur_list: (nullable) (element-type ICalRecurrence): List of #ICalRecurrence structures, or %NULL.
3014 *
3015 * Sets the list of recurrence rules in a calendar component object.
3016 *
3017 * Since: 3.34
3018 **/
3019 void
e_cal_component_set_rrules(ECalComponent * comp,const GSList * recur_list)3020 e_cal_component_set_rrules (ECalComponent *comp,
3021 const GSList *recur_list)
3022 {
3023 g_return_if_fail (E_IS_CAL_COMPONENT (comp));
3024 g_return_if_fail (comp->priv->icalcomp != NULL);
3025
3026 set_recur_list (comp->priv->icalcomp, I_CAL_RRULE_PROPERTY, i_cal_property_new_rrule, recur_list);
3027
3028 comp->priv->need_sequence_inc = TRUE;
3029 }
3030
3031 /**
3032 * e_cal_component_has_rrules:
3033 * @comp: A calendar component object.
3034 *
3035 * Queries whether a calendar component object has any recurrence rules defined
3036 * for it.
3037 *
3038 * Returns: TRUE if the component has recurrence rules, FALSE otherwise.
3039 *
3040 * Since: 3.34
3041 **/
3042 gboolean
e_cal_component_has_rrules(ECalComponent * comp)3043 e_cal_component_has_rrules (ECalComponent *comp)
3044 {
3045 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), FALSE);
3046 g_return_val_if_fail (comp->priv->icalcomp != NULL, FALSE);
3047
3048 return e_cal_util_component_has_property (comp->priv->icalcomp, I_CAL_RRULE_PROPERTY);
3049 }
3050
3051 /**
3052 * e_cal_component_has_recurrences:
3053 * @comp: A calendar component object
3054 *
3055 * Queries whether a calendar component object has any recurrence dates or
3056 * recurrence rules.
3057 *
3058 * Returns: TRUE if the component has recurrences, FALSE otherwise.
3059 *
3060 * Since: 3.34
3061 **/
3062 gboolean
e_cal_component_has_recurrences(ECalComponent * comp)3063 e_cal_component_has_recurrences (ECalComponent *comp)
3064 {
3065 return e_cal_component_has_rdates (comp) || e_cal_component_has_rrules (comp);
3066 }
3067
3068 /* Counts the elements in the by_xxx fields of an ICalRecurrence;
3069 it also frees the 'field' array*/
3070 static gint
count_by_xxx_and_free(GArray * field)3071 count_by_xxx_and_free (GArray *field) /* gshort */
3072 {
3073 gint ii;
3074
3075 if (!field)
3076 return 0;
3077
3078 for (ii = 0; ii < field->len; ii++) {
3079 if (g_array_index (field, gshort, ii) == I_CAL_RECURRENCE_ARRAY_MAX)
3080 break;
3081 }
3082
3083 g_array_unref (field);
3084
3085 return ii;
3086 }
3087
3088 /**
3089 * e_cal_component_has_simple_recurrence:
3090 * @comp: A calendar component object.
3091 *
3092 * Checks whether the given calendar component object has simple recurrence
3093 * rules or more complicated ones.
3094 *
3095 * Returns: TRUE if it has a simple recurrence rule, FALSE otherwise.
3096 *
3097 * Since: 3.34
3098 **/
3099 gboolean
e_cal_component_has_simple_recurrence(ECalComponent * comp)3100 e_cal_component_has_simple_recurrence (ECalComponent *comp)
3101 {
3102 GSList *rrule_list;
3103 ICalRecurrence *rt;
3104 gint n_by_second, n_by_minute, n_by_hour;
3105 gint n_by_day, n_by_month_day, n_by_year_day;
3106 gint n_by_week_no, n_by_month, n_by_set_pos;
3107 gint len, i;
3108 gboolean simple = FALSE;
3109
3110 if (!e_cal_component_has_recurrences (comp))
3111 return TRUE;
3112
3113 rrule_list = e_cal_component_get_rrules (comp);
3114 len = g_slist_length (rrule_list);
3115 if (len > 1 || !rrule_list ||
3116 e_cal_component_has_rdates (comp) ||
3117 e_cal_component_has_exrules (comp))
3118 goto cleanup;
3119
3120 /* Down to one rule, so test that one */
3121 rt = rrule_list->data;
3122
3123 /* Any funky frequency? */
3124 if (i_cal_recurrence_get_freq (rt) == I_CAL_SECONDLY_RECURRENCE ||
3125 i_cal_recurrence_get_freq (rt) == I_CAL_MINUTELY_RECURRENCE ||
3126 i_cal_recurrence_get_freq (rt) == I_CAL_HOURLY_RECURRENCE)
3127 goto cleanup;
3128
3129 /* Any funky BY_* */
3130 #define N_HAS_BY(field) (count_by_xxx_and_free (field))
3131
3132 n_by_second = N_HAS_BY (i_cal_recurrence_get_by_second_array (rt));
3133 n_by_minute = N_HAS_BY (i_cal_recurrence_get_by_minute_array (rt));
3134 n_by_hour = N_HAS_BY (i_cal_recurrence_get_by_hour_array (rt));
3135 n_by_day = N_HAS_BY (i_cal_recurrence_get_by_day_array (rt));
3136 n_by_month_day = N_HAS_BY (i_cal_recurrence_get_by_month_day_array (rt));
3137 n_by_year_day = N_HAS_BY (i_cal_recurrence_get_by_year_day_array (rt));
3138 n_by_week_no = N_HAS_BY (i_cal_recurrence_get_by_week_no_array (rt));
3139 n_by_month = N_HAS_BY (i_cal_recurrence_get_by_month_array (rt));
3140 n_by_set_pos = N_HAS_BY (i_cal_recurrence_get_by_set_pos_array (rt));
3141
3142 if (n_by_second != 0
3143 || n_by_minute != 0
3144 || n_by_hour != 0)
3145 goto cleanup;
3146
3147 switch (i_cal_recurrence_get_freq (rt)) {
3148 case I_CAL_DAILY_RECURRENCE:
3149 if (n_by_day != 0
3150 || n_by_month_day != 0
3151 || n_by_year_day != 0
3152 || n_by_week_no != 0
3153 || n_by_month != 0
3154 || n_by_set_pos != 0)
3155 goto cleanup;
3156
3157 simple = TRUE;
3158 break;
3159
3160 case I_CAL_WEEKLY_RECURRENCE:
3161 if (n_by_month_day != 0
3162 || n_by_year_day != 0
3163 || n_by_week_no != 0
3164 || n_by_month != 0
3165 || n_by_set_pos != 0)
3166 goto cleanup;
3167
3168 for (i = 0; i < 8; i++) {
3169 gint pos;
3170 gshort byday = i_cal_recurrence_get_by_day (rt, i);
3171
3172 if (byday == I_CAL_RECURRENCE_ARRAY_MAX)
3173 break;
3174
3175 pos = i_cal_recurrence_day_position (byday);
3176
3177 if (pos != 0)
3178 goto cleanup;
3179 }
3180
3181 simple = TRUE;
3182 break;
3183
3184 case I_CAL_MONTHLY_RECURRENCE:
3185 if (n_by_year_day != 0
3186 || n_by_week_no != 0
3187 || n_by_month != 0
3188 || n_by_set_pos > 1)
3189 goto cleanup;
3190
3191 if (n_by_month_day == 1) {
3192 gint nth;
3193
3194 if (n_by_set_pos != 0)
3195 goto cleanup;
3196
3197 nth = i_cal_recurrence_get_by_month_day (rt, 0);
3198 if (nth < 1 && nth != -1)
3199 goto cleanup;
3200
3201 } else if (n_by_day == 1) {
3202 ICalRecurrenceWeekday weekday;
3203 gint pos;
3204
3205 /* Outlook 2000 uses BYDAY=TU;BYSETPOS=2, and will not
3206 * accept BYDAY=2TU. So we now use the same as Outlook
3207 * by default. */
3208
3209 weekday = i_cal_recurrence_day_day_of_week (i_cal_recurrence_get_by_day (rt, 0));
3210 pos = i_cal_recurrence_day_position (i_cal_recurrence_get_by_day (rt, 0));
3211
3212 if (pos == 0) {
3213 if (n_by_set_pos != 1)
3214 goto cleanup;
3215 pos = i_cal_recurrence_get_by_set_pos (rt, 0);
3216 }
3217
3218 if (pos < 0)
3219 goto cleanup;
3220
3221 switch (weekday) {
3222 case I_CAL_MONDAY_WEEKDAY:
3223 case I_CAL_TUESDAY_WEEKDAY:
3224 case I_CAL_WEDNESDAY_WEEKDAY:
3225 case I_CAL_THURSDAY_WEEKDAY:
3226 case I_CAL_FRIDAY_WEEKDAY:
3227 case I_CAL_SATURDAY_WEEKDAY:
3228 case I_CAL_SUNDAY_WEEKDAY:
3229 break;
3230
3231 default:
3232 goto cleanup;
3233 }
3234 } else {
3235 goto cleanup;
3236 }
3237
3238 simple = TRUE;
3239 break;
3240
3241 case I_CAL_YEARLY_RECURRENCE:
3242 if (n_by_day != 0
3243 || n_by_month_day != 0
3244 || n_by_year_day != 0
3245 || n_by_week_no != 0
3246 || n_by_month != 0
3247 || n_by_set_pos != 0)
3248 goto cleanup;
3249
3250 simple = TRUE;
3251 break;
3252
3253 default:
3254 goto cleanup;
3255 }
3256
3257 cleanup:
3258 g_slist_free_full (rrule_list, g_object_unref);
3259
3260 return simple;
3261 }
3262
3263 /**
3264 * e_cal_component_is_instance:
3265 * @comp: A calendar component object.
3266 *
3267 * Checks whether a calendar component object is an instance of a recurring
3268 * event.
3269 *
3270 * Returns: TRUE if it is an instance, FALSE if not.
3271 *
3272 * Since: 3.34
3273 **/
3274 gboolean
e_cal_component_is_instance(ECalComponent * comp)3275 e_cal_component_is_instance (ECalComponent *comp)
3276 {
3277 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), FALSE);
3278
3279 return e_cal_util_component_has_property (comp->priv->icalcomp, I_CAL_RECURRENCEID_PROPERTY);
3280 }
3281
3282 /**
3283 * e_cal_component_get_sequence:
3284 * @comp: A calendar component object.
3285 *
3286 * Queries the sequence number of a calendar component object.
3287 *
3288 * Returns: the sequence number, or -1 if not found
3289 *
3290 * Since: 3.34
3291 **/
3292 gint
e_cal_component_get_sequence(ECalComponent * comp)3293 e_cal_component_get_sequence (ECalComponent *comp)
3294 {
3295 ICalProperty *prop;
3296 gint sequence;
3297
3298 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), -1);
3299 g_return_val_if_fail (comp->priv->icalcomp != NULL, -1);
3300
3301 prop = i_cal_component_get_first_property (comp->priv->icalcomp, I_CAL_SEQUENCE_PROPERTY);
3302 if (!prop)
3303 return -1;
3304
3305 sequence = i_cal_property_get_sequence (prop);
3306
3307 g_object_unref (prop);
3308
3309 return sequence;
3310 }
3311
3312 /**
3313 * e_cal_component_set_sequence:
3314 * @comp: A calendar component object.
3315 * @sequence: a sequence number to set, or -1 to remove the property
3316 *
3317 * Sets the sequence number of a calendar component object.
3318 * A special value -1 can be used to remove the sequence number property.
3319 *
3320 * Normally this function should not be called, since the sequence number
3321 * is incremented automatically at the proper times.
3322 *
3323 * Since: 3.34
3324 **/
3325 void
e_cal_component_set_sequence(ECalComponent * comp,gint sequence)3326 e_cal_component_set_sequence (ECalComponent *comp,
3327 gint sequence)
3328 {
3329 g_return_if_fail (E_IS_CAL_COMPONENT (comp));
3330 g_return_if_fail (comp->priv->icalcomp != NULL);
3331
3332 comp->priv->need_sequence_inc = FALSE;
3333
3334 if (sequence <= -1) {
3335 ICalProperty *prop;
3336
3337 prop = i_cal_component_get_first_property (comp->priv->icalcomp, I_CAL_SEQUENCE_PROPERTY);
3338 if (prop) {
3339 i_cal_component_remove_property (comp->priv->icalcomp, prop);
3340 g_object_unref (prop);
3341 }
3342
3343 return;
3344 }
3345
3346 i_cal_component_set_sequence (comp->priv->icalcomp, sequence);
3347 }
3348
3349 /**
3350 * e_cal_component_get_status:
3351 * @comp: A calendar component object.
3352 *
3353 * Queries the status property of a calendar component object.
3354 *
3355 * Returns: the status value; or %I_CAL_STATUS_NONE, if the component
3356 * has no status property
3357 *
3358 * Since: 3.34
3359 **/
3360 ICalPropertyStatus
e_cal_component_get_status(ECalComponent * comp)3361 e_cal_component_get_status (ECalComponent *comp)
3362 {
3363 ICalProperty *prop;
3364 ICalPropertyStatus status;
3365
3366 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), I_CAL_STATUS_NONE);
3367 g_return_val_if_fail (comp->priv->icalcomp != NULL, I_CAL_STATUS_NONE);
3368
3369 prop = i_cal_component_get_first_property (comp->priv->icalcomp, I_CAL_STATUS_PROPERTY);
3370
3371 if (!prop)
3372 return I_CAL_STATUS_NONE;
3373
3374 status = i_cal_property_get_status (prop);
3375
3376 g_object_unref (prop);
3377
3378 return status;
3379 }
3380
3381 /**
3382 * e_cal_component_set_status:
3383 * @comp: A calendar component object.
3384 * @status: Status value, as an #ICalPropertyStatus. Use %I_CAL_STATUS_NONE, to unset the property
3385 *
3386 * Sets the status property of a calendar component object.
3387 *
3388 * Since: 3.34
3389 **/
3390 void
e_cal_component_set_status(ECalComponent * comp,ICalPropertyStatus status)3391 e_cal_component_set_status (ECalComponent *comp,
3392 ICalPropertyStatus status)
3393 {
3394 ICalProperty *prop;
3395
3396 g_return_if_fail (E_IS_CAL_COMPONENT (comp));
3397 g_return_if_fail (comp->priv->icalcomp != NULL);
3398
3399 comp->priv->need_sequence_inc = TRUE;
3400
3401 prop = i_cal_component_get_first_property (comp->priv->icalcomp, I_CAL_STATUS_PROPERTY);
3402
3403 if (status == I_CAL_STATUS_NONE) {
3404 if (prop) {
3405 i_cal_component_remove_property (comp->priv->icalcomp, prop);
3406 g_object_unref (prop);
3407 }
3408
3409 return;
3410 }
3411
3412 if (prop) {
3413 i_cal_property_set_status (prop, status);
3414 g_object_unref (prop);
3415 } else {
3416 prop = i_cal_property_new_status (status);
3417 i_cal_component_take_property (comp->priv->icalcomp, prop);
3418 }
3419 }
3420
3421 /**
3422 * e_cal_component_get_summary:
3423 * @comp: A calendar component object.
3424 *
3425 * Queries the summary of a calendar component object.
3426 * Free the returned pointer withe_cal_component_text_free(),
3427 * when no longer needed.
3428 *
3429 * Returns: (transfer full) (nullable): the summary, as an #ECalComponentText,
3430 * or %NULL, when none is set
3431 *
3432 * Since: 3.34
3433 **/
3434 ECalComponentText *
e_cal_component_get_summary(ECalComponent * comp)3435 e_cal_component_get_summary (ECalComponent *comp)
3436 {
3437 ECalComponentText *text;
3438 ICalProperty *prop;
3439
3440 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
3441 g_return_val_if_fail (comp->priv->icalcomp != NULL, NULL);
3442
3443 prop = i_cal_component_get_first_property (comp->priv->icalcomp, I_CAL_SUMMARY_PROPERTY);
3444 if (!prop)
3445 return NULL;
3446
3447 text = get_text_from_prop (prop, i_cal_property_get_summary);
3448
3449 g_object_unref (prop);
3450
3451 return text;
3452 }
3453
3454 typedef struct {
3455 gchar *old_summary;
3456 const gchar *new_summary;
3457 } SetAlarmDescriptionData;
3458
3459 static gboolean
set_alarm_description_cb(ICalComponent * icalcomp,ICalComponent * subcomp,gpointer user_data)3460 set_alarm_description_cb (ICalComponent *icalcomp,
3461 ICalComponent *subcomp,
3462 gpointer user_data)
3463 {
3464 ICalProperty *icalprop, *desc_prop;
3465 SetAlarmDescriptionData *sadd = user_data;
3466 gboolean changed = FALSE;
3467 const gchar *old_summary = NULL;
3468
3469 g_return_val_if_fail (sadd != NULL, FALSE);
3470
3471 /* set the new description on the alarm */
3472 desc_prop = i_cal_component_get_first_property (subcomp, I_CAL_DESCRIPTION_PROPERTY);
3473 if (desc_prop) {
3474 old_summary = i_cal_property_get_description (desc_prop);
3475 } else {
3476 desc_prop = i_cal_property_new_description (sadd->new_summary);
3477 }
3478
3479 /* remove the X-EVOLUTION-NEEDS_DESCRIPTION property */
3480 icalprop = i_cal_component_get_first_property (subcomp, I_CAL_X_PROPERTY);
3481 while (icalprop) {
3482 const gchar *x_name;
3483
3484 x_name = i_cal_property_get_x_name (icalprop);
3485 if (!g_strcmp0 (x_name, "X-EVOLUTION-NEEDS-DESCRIPTION")) {
3486 i_cal_component_remove_property (subcomp, icalprop);
3487 g_object_unref (icalprop);
3488
3489 i_cal_property_set_description (desc_prop, sadd->new_summary);
3490 changed = TRUE;
3491 break;
3492 }
3493
3494 g_object_unref (icalprop);
3495 icalprop = i_cal_component_get_next_property (subcomp, I_CAL_X_PROPERTY);
3496 }
3497
3498 if (!changed) {
3499 if (!g_strcmp0 (old_summary ? old_summary : "", sadd->old_summary ? sadd->old_summary : "")) {
3500 i_cal_property_set_description (desc_prop, sadd->new_summary);
3501 }
3502 }
3503
3504 g_object_unref (desc_prop);
3505
3506 return TRUE;
3507 }
3508
3509 /**
3510 * e_cal_component_set_summary:
3511 * @comp: A calendar component object.
3512 * @summary: Summary property and its parameters.
3513 *
3514 * Sets the summary of a calendar component object.
3515 *
3516 * Since: 3.34
3517 **/
3518 void
e_cal_component_set_summary(ECalComponent * comp,const ECalComponentText * summary)3519 e_cal_component_set_summary (ECalComponent *comp,
3520 const ECalComponentText *summary)
3521 {
3522 ICalProperty *prop;
3523 SetAlarmDescriptionData sadd;
3524
3525 g_return_if_fail (E_IS_CAL_COMPONENT (comp));
3526 g_return_if_fail (comp->priv->icalcomp != NULL);
3527
3528 prop = i_cal_component_get_first_property (comp->priv->icalcomp, I_CAL_SUMMARY_PROPERTY);
3529
3530 if (!summary) {
3531 if (prop) {
3532 i_cal_component_remove_property (comp->priv->icalcomp, prop);
3533 g_object_unref (prop);
3534 }
3535
3536 return;
3537 }
3538
3539 if (!e_cal_component_text_get_value (summary)) {
3540 g_clear_object (&prop);
3541 return;
3542 }
3543
3544 if (prop) {
3545 /* Make a copy, to avoid use-after-free */
3546 sadd.old_summary = g_strdup (i_cal_property_get_summary (prop));
3547 i_cal_property_set_summary (prop, (gchar *) e_cal_component_text_get_value (summary));
3548 set_text_altrep_on_prop (prop, summary);
3549 } else {
3550 sadd.old_summary = NULL;
3551 prop = i_cal_property_new_summary ((gchar *) e_cal_component_text_get_value (summary));
3552 set_text_altrep_on_prop (prop, summary);
3553 i_cal_component_take_property (comp->priv->icalcomp, prop);
3554 prop = NULL;
3555 }
3556
3557 g_clear_object (&prop);
3558
3559 /* look for alarms that need a description */
3560 sadd.new_summary = e_cal_component_text_get_value (summary);
3561
3562 foreach_subcomponent (comp->priv->icalcomp, I_CAL_VALARM_COMPONENT, set_alarm_description_cb, &sadd);
3563
3564 g_free (sadd.old_summary);
3565 }
3566
3567 /**
3568 * e_cal_component_get_transparency:
3569 * @comp: A calendar component object.
3570 *
3571 * Queries the time transparency of a calendar component object.
3572 *
3573 * Returns: the time transparency, as an #ECalComponentTransparency;
3574 * value #E_CAL_COMPONENT_TRANSP_NONE is returned when none is set
3575 *
3576 * Since: 3.34
3577 **/
3578 ECalComponentTransparency
e_cal_component_get_transparency(ECalComponent * comp)3579 e_cal_component_get_transparency (ECalComponent *comp)
3580 {
3581 ECalComponentTransparency transp;
3582 ICalProperty *prop;
3583
3584 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), E_CAL_COMPONENT_TRANSP_NONE);
3585 g_return_val_if_fail (comp->priv->icalcomp != NULL, E_CAL_COMPONENT_TRANSP_NONE);
3586
3587 prop = i_cal_component_get_first_property (comp->priv->icalcomp, I_CAL_TRANSP_PROPERTY);
3588
3589 if (!prop)
3590 return E_CAL_COMPONENT_TRANSP_NONE;
3591
3592 switch (i_cal_property_get_transp (prop)) {
3593 case I_CAL_TRANSP_TRANSPARENT:
3594 case I_CAL_TRANSP_TRANSPARENTNOCONFLICT:
3595 transp = E_CAL_COMPONENT_TRANSP_TRANSPARENT;
3596 break;
3597
3598 case I_CAL_TRANSP_OPAQUE:
3599 case I_CAL_TRANSP_OPAQUENOCONFLICT:
3600 transp = E_CAL_COMPONENT_TRANSP_OPAQUE;
3601 break;
3602
3603 default:
3604 transp = E_CAL_COMPONENT_TRANSP_UNKNOWN;
3605 break;
3606 }
3607
3608 g_object_unref (prop);
3609
3610 return transp;
3611 }
3612
3613 /**
3614 * e_cal_component_set_transparency:
3615 * @comp: A calendar component object.
3616 * @transp: Time transparency value.
3617 *
3618 * Sets the time transparency of a calendar component object.
3619 * Use %E_CAL_COMPONENT_TRANSP_NONE to unset the property.
3620 *
3621 * Since: 3.34
3622 **/
3623 void
e_cal_component_set_transparency(ECalComponent * comp,ECalComponentTransparency transp)3624 e_cal_component_set_transparency (ECalComponent *comp,
3625 ECalComponentTransparency transp)
3626 {
3627 ICalProperty *prop;
3628 ICalPropertyTransp ical_transp;
3629
3630 g_return_if_fail (E_IS_CAL_COMPONENT (comp));
3631 g_return_if_fail (transp != E_CAL_COMPONENT_TRANSP_UNKNOWN);
3632 g_return_if_fail (comp->priv->icalcomp != NULL);
3633
3634 prop = i_cal_component_get_first_property (comp->priv->icalcomp, I_CAL_TRANSP_PROPERTY);
3635
3636 if (transp == E_CAL_COMPONENT_TRANSP_NONE) {
3637 if (prop) {
3638 i_cal_component_remove_property (comp->priv->icalcomp, prop);
3639 g_object_unref (prop);
3640 }
3641
3642 return;
3643 }
3644
3645 switch (transp) {
3646 case E_CAL_COMPONENT_TRANSP_TRANSPARENT:
3647 ical_transp = I_CAL_TRANSP_TRANSPARENT;
3648 break;
3649
3650 case E_CAL_COMPONENT_TRANSP_OPAQUE:
3651 ical_transp = I_CAL_TRANSP_OPAQUE;
3652 break;
3653
3654 default:
3655 g_warn_if_reached ();
3656 ical_transp = I_CAL_TRANSP_NONE;
3657 break;
3658 }
3659
3660 if (prop) {
3661 i_cal_property_set_transp (prop, ical_transp);
3662 g_object_unref (prop);
3663 } else {
3664 prop = i_cal_property_new_transp (ical_transp);
3665 i_cal_component_take_property (comp->priv->icalcomp, prop);
3666 }
3667 }
3668
3669 /**
3670 * e_cal_component_get_url:
3671 * @comp: A calendar component object.
3672 *
3673 * Queries the uniform resource locator property of a calendar component object.
3674 * Free the returned URL with g_free(), when no longer needed.
3675 *
3676 * Returns: (transfer full) (nullable): the URL, or %NULL, when none is set
3677 *
3678 * Since: 3.34
3679 **/
3680 gchar *
e_cal_component_get_url(ECalComponent * comp)3681 e_cal_component_get_url (ECalComponent *comp)
3682 {
3683 ICalProperty *prop;
3684 gchar *url;
3685
3686 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
3687 g_return_val_if_fail (comp->priv->icalcomp != NULL, NULL);
3688
3689 prop = i_cal_component_get_first_property (comp->priv->icalcomp, I_CAL_URL_PROPERTY);
3690 if (!prop)
3691 return NULL;
3692
3693 url = g_strdup (i_cal_property_get_url (prop));
3694
3695 g_object_unref (prop);
3696
3697 return url;
3698 }
3699
3700 /**
3701 * e_cal_component_set_url:
3702 * @comp: A calendar component object.
3703 * @url: (nullable): URL value.
3704 *
3705 * Sets the uniform resource locator property of a calendar component object.
3706 * A %NULL or an empty string removes the property.
3707 *
3708 * Since: 3.34
3709 **/
3710 void
e_cal_component_set_url(ECalComponent * comp,const gchar * url)3711 e_cal_component_set_url (ECalComponent *comp,
3712 const gchar *url)
3713 {
3714 ICalProperty *prop;
3715
3716 g_return_if_fail (E_IS_CAL_COMPONENT (comp));
3717 g_return_if_fail (comp->priv->icalcomp != NULL);
3718
3719 prop = i_cal_component_get_first_property (comp->priv->icalcomp, I_CAL_URL_PROPERTY);
3720
3721 if (!url || !(*url)) {
3722 if (prop) {
3723 i_cal_component_remove_property (comp->priv->icalcomp, prop);
3724 g_object_unref (prop);
3725 }
3726
3727 return;
3728 }
3729
3730 if (prop) {
3731 i_cal_property_set_url (prop, (gchar *) url);
3732 g_object_unref (prop);
3733 } else {
3734 prop = i_cal_property_new_url ((gchar *) url);
3735 i_cal_component_take_property (comp->priv->icalcomp, prop);
3736 }
3737 }
3738
3739 static gboolean
get_attendee_list_cb(ICalComponent * icalcomp,ICalProperty * prop,gpointer user_data)3740 get_attendee_list_cb (ICalComponent *icalcomp,
3741 ICalProperty *prop,
3742 gpointer user_data)
3743 {
3744 GSList **pattendees = user_data;
3745 ECalComponentAttendee *attendee;
3746
3747 g_return_val_if_fail (pattendees != NULL, FALSE);
3748
3749 attendee = e_cal_component_attendee_new_from_property (prop);
3750
3751 if (attendee)
3752 *pattendees = g_slist_prepend (*pattendees, attendee);
3753
3754 return TRUE;
3755 }
3756
3757 /**
3758 * e_cal_component_get_attendees:
3759 * @comp: A calendar component object.
3760 *
3761 * Queries the attendee properties of the calendar component object.
3762 * Free the returned #GSList with g_slist_free_full (slist, e_cal_component_attendee_free);,
3763 * when no longer needed.
3764 *
3765 * Returns: (transfer full) (nullable) (element-type ECalComponentAttendee):
3766 * the attendees, as a #GSList of an #ECalComponentAttendee, or %NULL,
3767 * when none are set
3768 *
3769 * Since: 3.34
3770 **/
3771 GSList *
e_cal_component_get_attendees(ECalComponent * comp)3772 e_cal_component_get_attendees (ECalComponent *comp)
3773 {
3774 GSList *attendees = NULL;
3775
3776 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
3777 g_return_val_if_fail (comp->priv->icalcomp != NULL, NULL);
3778
3779 foreach_property (comp->priv->icalcomp, I_CAL_ATTENDEE_PROPERTY, get_attendee_list_cb, &attendees);
3780
3781 return g_slist_reverse (attendees);
3782 }
3783
3784 /**
3785 * e_cal_component_set_attendees:
3786 * @comp: A calendar component object.
3787 * @attendee_list: (nullable) (element-type ECalComponentAttendee): Values for attendee
3788 * properties, or %NULL to unset
3789 *
3790 * Sets the attendees of a calendar component object
3791 *
3792 * Since: 3.34
3793 **/
3794 void
e_cal_component_set_attendees(ECalComponent * comp,const GSList * attendee_list)3795 e_cal_component_set_attendees (ECalComponent *comp,
3796 const GSList *attendee_list)
3797 {
3798 GSList *link;
3799
3800 g_return_if_fail (E_IS_CAL_COMPONENT (comp));
3801 g_return_if_fail (comp->priv->icalcomp != NULL);
3802
3803 remove_all_properties_of_kind (comp->priv->icalcomp, I_CAL_ATTENDEE_PROPERTY);
3804
3805 for (link = (GSList *) attendee_list; link; link = g_slist_next (link)) {
3806 const ECalComponentAttendee *attendee = link->data;
3807 ICalProperty *prop;
3808
3809 if (!attendee)
3810 continue;
3811
3812 prop = e_cal_component_attendee_get_as_property (attendee);
3813 if (!prop)
3814 continue;
3815
3816 i_cal_component_take_property (comp->priv->icalcomp, prop);
3817 }
3818 }
3819
3820 /**
3821 * e_cal_component_has_attendees:
3822 * @comp: A calendar component object.
3823 *
3824 * Queries a calendar component object for the existence of attendees.
3825 *
3826 * Returns: TRUE if there are attendees, FALSE if not.
3827 *
3828 * Since: 3.34
3829 */
3830 gboolean
e_cal_component_has_attendees(ECalComponent * comp)3831 e_cal_component_has_attendees (ECalComponent *comp)
3832 {
3833 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), FALSE);
3834
3835 return e_cal_util_component_has_property (comp->priv->icalcomp, I_CAL_ATTENDEE_PROPERTY);
3836 }
3837
3838 /**
3839 * e_cal_component_get_location:
3840 * @comp: A calendar component object
3841 *
3842 * Queries the location property of a calendar component object.
3843 *
3844 * Returns: (transfer full) (nullable): the locatio, or %NULL, if none is set
3845 *
3846 * Since: 3.34
3847 **/
3848 gchar *
e_cal_component_get_location(ECalComponent * comp)3849 e_cal_component_get_location (ECalComponent *comp)
3850 {
3851 ICalProperty *prop;
3852 gchar *location;
3853
3854 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
3855 g_return_val_if_fail (comp->priv->icalcomp != NULL, NULL);
3856
3857 prop = i_cal_component_get_first_property (comp->priv->icalcomp, I_CAL_LOCATION_PROPERTY);
3858
3859 if (!prop)
3860 return NULL;
3861
3862 location = g_strdup (i_cal_property_get_location (prop));
3863
3864 g_object_unref (prop);
3865
3866 return location;
3867 }
3868
3869 /**
3870 * e_cal_component_set_location:
3871 * @comp: A calendar component object.
3872 * @location: (nullable): Location value. Use %NULL or empty string, to unset the property.
3873 *
3874 * Sets the location property of a calendar component object.
3875 *
3876 * Since: 3.34
3877 **/
3878 void
e_cal_component_set_location(ECalComponent * comp,const gchar * location)3879 e_cal_component_set_location (ECalComponent *comp,
3880 const gchar *location)
3881 {
3882 ICalProperty *prop;
3883
3884 g_return_if_fail (E_IS_CAL_COMPONENT (comp));
3885 g_return_if_fail (comp->priv->icalcomp != NULL);
3886
3887 prop = i_cal_component_get_first_property (comp->priv->icalcomp, I_CAL_LOCATION_PROPERTY);
3888
3889 if (!location || !*location) {
3890 if (prop) {
3891 i_cal_component_remove_property (comp->priv->icalcomp, prop);
3892 g_object_unref (prop);
3893 }
3894
3895 return;
3896 }
3897
3898 if (prop) {
3899 i_cal_property_set_location (prop, (gchar *) location);
3900 g_object_unref (prop);
3901 } else {
3902 prop = i_cal_property_new_location ((gchar *) location);
3903 i_cal_component_take_property (comp->priv->icalcomp, prop);
3904 }
3905 }
3906
3907 /**
3908 * e_cal_component_has_alarms:
3909 * @comp: A calendar component object.
3910 *
3911 * Checks whether the component has any alarms.
3912 *
3913 * Returns: TRUE if the component has any alarms.
3914 *
3915 * Since: 3.34
3916 **/
3917 gboolean
e_cal_component_has_alarms(ECalComponent * comp)3918 e_cal_component_has_alarms (ECalComponent *comp)
3919 {
3920 ICalComponent *subcomp;
3921
3922 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), FALSE);
3923 g_return_val_if_fail (comp->priv->icalcomp != NULL, FALSE);
3924
3925 subcomp = i_cal_component_get_first_component (comp->priv->icalcomp, I_CAL_VALARM_COMPONENT);
3926 if (subcomp) {
3927 g_object_unref (subcomp);
3928 return TRUE;
3929 }
3930
3931 return FALSE;
3932 }
3933
3934 static gchar *
dup_alarm_uid_from_component(ICalComponent * valarm)3935 dup_alarm_uid_from_component (ICalComponent *valarm)
3936 {
3937 ICalProperty *prop;
3938 gchar *auid = NULL;
3939
3940 g_return_val_if_fail (valarm != NULL, NULL);
3941
3942 for (prop = i_cal_component_get_first_property (valarm, I_CAL_X_PROPERTY);
3943 prop;
3944 g_object_unref (prop), prop = i_cal_component_get_next_property (valarm, I_CAL_X_PROPERTY)) {
3945 const gchar *xname;
3946
3947 xname = i_cal_property_get_x_name (prop);
3948
3949 if (g_strcmp0 (xname, E_CAL_EVOLUTION_ALARM_UID_PROPERTY) == 0) {
3950 const gchar *xvalue;
3951
3952 xvalue = i_cal_property_get_x (prop);
3953 if (xvalue) {
3954 auid = g_strdup (xvalue);
3955 g_object_unref (prop);
3956 break;
3957 }
3958 }
3959 }
3960
3961 return auid;
3962 }
3963
3964 /**
3965 * e_cal_component_add_alarm:
3966 * @comp: A calendar component.
3967 * @alarm: (transfer none): an alarm, as an #ECalComponentAlarm
3968 *
3969 * Adds an alarm subcomponent to a calendar component. You should have created
3970 * the @alarm by using e_cal_component_alarm_new(); it is invalid to use an
3971 * #ECalComponentAlarm structure that came from e_cal_component_get_alarm(). After
3972 * adding the alarm, the @alarm structure is no longer valid because the
3973 * internal structures may change and you should get rid of it by using
3974 * e_cal_component_alarm_free().
3975 *
3976 * Since: 3.34
3977 **/
3978 void
e_cal_component_add_alarm(ECalComponent * comp,ECalComponentAlarm * alarm)3979 e_cal_component_add_alarm (ECalComponent *comp,
3980 ECalComponentAlarm *alarm)
3981 {
3982 GSList *existing_uids, *link;
3983 ICalComponent *valarm;
3984 const gchar *auid;
3985
3986 g_return_if_fail (E_IS_CAL_COMPONENT (comp));
3987 g_return_if_fail (alarm != NULL);
3988 g_return_if_fail (comp->priv->icalcomp);
3989
3990 auid = e_cal_component_alarm_get_uid (alarm);
3991
3992 existing_uids = e_cal_component_get_alarm_uids (comp);
3993
3994 for (link = existing_uids; link; link = g_slist_next (link)) {
3995 const gchar *existing_auid = link->data;
3996
3997 if (g_strcmp0 (auid, existing_auid) == 0)
3998 break;
3999 }
4000
4001 g_slist_free_full (existing_uids, g_free);
4002
4003 /* Not NULL, when found an alarm with the same UID */
4004 if (link) {
4005 /* This generates new UID for the alarm */
4006 e_cal_component_alarm_set_uid (alarm, NULL);
4007 }
4008
4009 valarm = e_cal_component_alarm_get_as_component (alarm);
4010 if (valarm)
4011 i_cal_component_take_component (comp->priv->icalcomp, valarm);
4012 }
4013
4014 static gboolean
remove_alarm_cb(ICalComponent * icalcomp,ICalComponent * subcomp,gpointer user_data)4015 remove_alarm_cb (ICalComponent *icalcomp,
4016 ICalComponent *subcomp,
4017 gpointer user_data)
4018 {
4019 const gchar *auid = user_data;
4020 gchar *existing;
4021
4022 g_return_val_if_fail (auid != NULL, FALSE);
4023
4024 existing = dup_alarm_uid_from_component (subcomp);
4025 if (g_strcmp0 (existing, auid) == 0) {
4026 g_free (existing);
4027 i_cal_component_remove_component (icalcomp, subcomp);
4028 return FALSE;
4029 }
4030
4031 g_free (existing);
4032
4033 return TRUE;
4034 }
4035
4036 /**
4037 * e_cal_component_remove_alarm:
4038 * @comp: A calendar component.
4039 * @auid: UID of the alarm to remove.
4040 *
4041 * Removes an alarm subcomponent from a calendar component. If the alarm that
4042 * corresponds to the specified @auid had been fetched with
4043 * e_cal_component_get_alarm(), then those alarm structures will be invalid; you
4044 * should get rid of them with e_cal_component_alarm_free() before using this
4045 * function.
4046 *
4047 * Since: 3.34
4048 **/
4049 void
e_cal_component_remove_alarm(ECalComponent * comp,const gchar * auid)4050 e_cal_component_remove_alarm (ECalComponent *comp,
4051 const gchar *auid)
4052 {
4053 g_return_if_fail (E_IS_CAL_COMPONENT (comp));
4054 g_return_if_fail (auid != NULL);
4055 g_return_if_fail (comp->priv->icalcomp != NULL);
4056
4057 foreach_subcomponent (comp->priv->icalcomp, I_CAL_VALARM_COMPONENT, remove_alarm_cb, (gpointer) auid);
4058 }
4059
4060 static gboolean
remove_all_alarms_cb(ICalComponent * icalcomp,ICalComponent * subcomp,gpointer user_data)4061 remove_all_alarms_cb (ICalComponent *icalcomp,
4062 ICalComponent *subcomp,
4063 gpointer user_data)
4064 {
4065 i_cal_component_remove_component (icalcomp, subcomp);
4066
4067 return TRUE;
4068 }
4069
4070 /**
4071 * e_cal_component_remove_all_alarms:
4072 * @comp: A calendar component
4073 *
4074 * Remove all alarms from the calendar component
4075 *
4076 * Since: 3.34
4077 **/
4078 void
e_cal_component_remove_all_alarms(ECalComponent * comp)4079 e_cal_component_remove_all_alarms (ECalComponent *comp)
4080 {
4081 g_return_if_fail (E_IS_CAL_COMPONENT (comp));
4082 g_return_if_fail (comp->priv->icalcomp != NULL);
4083
4084 foreach_subcomponent (comp->priv->icalcomp, I_CAL_VALARM_COMPONENT, remove_all_alarms_cb, NULL);
4085 }
4086
4087 static gboolean
get_alarm_uids_cb(ICalComponent * icalcomp,ICalComponent * subcomp,gpointer user_data)4088 get_alarm_uids_cb (ICalComponent *icalcomp,
4089 ICalComponent *subcomp,
4090 gpointer user_data)
4091 {
4092 GSList **puids = user_data;
4093 gchar *auid;
4094
4095 g_return_val_if_fail (puids != NULL, FALSE);
4096
4097 auid = dup_alarm_uid_from_component (subcomp);
4098 if (auid)
4099 *puids = g_slist_prepend (*puids, auid);
4100
4101 return TRUE;
4102 }
4103
4104 /**
4105 * e_cal_component_get_alarm_uids:
4106 * @comp: A calendar component.
4107 *
4108 * Builds a list of the unique identifiers of the alarm subcomponents inside a
4109 * calendar component. Free the returned #GSList with
4110 * g_slist_free_full (slist, g_free);, when no longer needed.
4111 *
4112 * Returns: (transfer full) (nullable) (element-type utf8): a #GSList of unique
4113 * identifiers for alarms.
4114 *
4115 * Since: 3.34
4116 **/
4117 GSList *
e_cal_component_get_alarm_uids(ECalComponent * comp)4118 e_cal_component_get_alarm_uids (ECalComponent *comp)
4119 {
4120 GSList *uids = NULL;
4121
4122 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
4123 g_return_val_if_fail (comp->priv->icalcomp != NULL, NULL);
4124
4125 foreach_subcomponent (comp->priv->icalcomp, I_CAL_VALARM_COMPONENT, get_alarm_uids_cb, &uids);
4126
4127 return g_slist_reverse (uids);
4128 }
4129
4130 struct GetAlarmData {
4131 const gchar *auid;
4132 ICalComponent *valarm;
4133 };
4134
4135 static gboolean
get_alarm_cb(ICalComponent * icalcomp,ICalComponent * subcomp,gpointer user_data)4136 get_alarm_cb (ICalComponent *icalcomp,
4137 ICalComponent *subcomp,
4138 gpointer user_data)
4139 {
4140 struct GetAlarmData *gad = user_data;
4141 gchar *auid;
4142
4143 g_return_val_if_fail (gad != NULL, FALSE);
4144
4145 auid = dup_alarm_uid_from_component (subcomp);
4146 if (g_strcmp0 (auid, gad->auid) == 0) {
4147 gad->valarm = g_object_ref (subcomp);
4148 }
4149
4150 g_free (auid);
4151
4152 return !gad->valarm;
4153 }
4154
4155 /**
4156 * e_cal_component_get_alarm:
4157 * @comp: A calendar component.
4158 * @auid: Unique identifier for the sought alarm subcomponent.
4159 *
4160 * Queries a particular alarm subcomponent of a calendar component.
4161 * Free the returned pointer with e_cal_component_alarm_free(),
4162 * when no longer needed.
4163 *
4164 * Returns: (transfer full) (nullable): the alarm subcomponent that corresponds
4165 * to the specified @auid, or %NULL if no alarm exists with that UID
4166 *
4167 * Since: 3.34
4168 **/
4169 ECalComponentAlarm *
e_cal_component_get_alarm(ECalComponent * comp,const gchar * auid)4170 e_cal_component_get_alarm (ECalComponent *comp,
4171 const gchar *auid)
4172 {
4173 ECalComponentAlarm *alarm = NULL;
4174 struct GetAlarmData gad;
4175
4176 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
4177 g_return_val_if_fail (comp->priv->icalcomp != NULL, NULL);
4178 g_return_val_if_fail (auid != NULL, NULL);
4179
4180 gad.auid = auid;
4181 gad.valarm = NULL;
4182
4183 foreach_subcomponent (comp->priv->icalcomp, I_CAL_VALARM_COMPONENT, get_alarm_cb, &gad);
4184
4185 if (gad.valarm) {
4186 alarm = e_cal_component_alarm_new_from_component (gad.valarm);
4187 g_object_unref (gad.valarm);
4188 }
4189
4190 return alarm;
4191 }
4192
4193 static gboolean
get_all_alarms_cb(ICalComponent * icalcomp,ICalComponent * subcomp,gpointer user_data)4194 get_all_alarms_cb (ICalComponent *icalcomp,
4195 ICalComponent *subcomp,
4196 gpointer user_data)
4197 {
4198 GSList **palarms = user_data;
4199 ECalComponentAlarm *alarm;
4200
4201 g_return_val_if_fail (palarms != NULL, FALSE);
4202
4203 alarm = e_cal_component_alarm_new_from_component (subcomp);
4204 if (alarm)
4205 *palarms = g_slist_prepend (*palarms, alarm);
4206
4207 return TRUE;
4208 }
4209
4210 /**
4211 * e_cal_component_get_all_alarms:
4212 * @comp: A calendar component.
4213 *
4214 * Queries all alarm subcomponents of a calendar component.
4215 * Free the returned #GSList with g_slist_free_full (slist, e_cal_component_alarm_free);,
4216 * when no longer needed.
4217 *
4218 * Returns: (transfer full) (nullable) (element-type ECalComponentAlarm): the alarm subcomponents
4219 * as a #GSList of #ECalComponentAlarm, or %NULL, if no alarm exists
4220 *
4221 * Since: 3.34
4222 **/
4223 GSList *
e_cal_component_get_all_alarms(ECalComponent * comp)4224 e_cal_component_get_all_alarms (ECalComponent *comp)
4225 {
4226 GSList *alarms = NULL;
4227
4228 g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
4229 g_return_val_if_fail (comp->priv->icalcomp != NULL, NULL);
4230
4231 foreach_subcomponent (comp->priv->icalcomp, I_CAL_VALARM_COMPONENT, get_all_alarms_cb, &alarms);
4232
4233 return g_slist_reverse (alarms);
4234 }
4235