Libical API Documentation 4.0 STABLE VERSION [Visit the v3.0 documentation]
Loading...
Searching...
No Matches
icalcomponent.c
Go to the documentation of this file.
1/*======================================================================
2 FILE: icalcomponent.c
3 CREATOR: eric 28 April 1999
4
5 SPDX-FileCopyrightText: 2000, Eric Busboom <eric@civicknowledge.com>
6 SPDX-License-Identifier: LGPL-2.1-only OR MPL-2.0
7======================================================================*/
8
13
14#ifdef HAVE_CONFIG_H
15#include <config.h>
16#endif
17
18#include "icalcomponent.h"
19#include "icalerror_p.h"
20#include "icalerror.h"
21#include "icallimits.h"
22#include "icalmemory.h"
23#include "icalparser.h"
24#include "icalpvl_p.h"
25#include "icalrestriction.h"
26#include "icaltime_p.h"
27#include "icaltimezone.h"
28#include "icaltypes_p.h"
29
30#include <assert.h>
31#include <stdlib.h>
32#include <limits.h>
33
34struct icalcomponent_impl {
35 icalstructuretype id;
37 char *x_name; /* also used for ICAL_IANA_COMPONENT */
38 icalpvl_list properties;
39 icalpvl_elem property_iterator;
40 icalpvl_list components;
41 icalpvl_elem component_iterator;
42 struct icalcomponent_impl *parent;
43
48 icalarray *timezones;
49 int timezones_sorted;
50};
51
52static void icalcomponent_add_children(icalcomponent *impl, va_list args);
53static icalcomponent *icalcomponent_new_impl(icalcomponent_kind kind);
54
55static bool icalcomponent_merge_vtimezone(icalcomponent *comp,
56 icalcomponent *vtimezone, icalstrarray *tzids_to_rename);
57static void icalcomponent_handle_conflicting_vtimezones(icalcomponent *comp,
58 icalcomponent *vtimezone,
59 icalproperty *tzid_prop,
60 const char *tzid,
61 icalstrarray *tzids_to_rename);
62static size_t icalcomponent_get_tzid_prefix_len(const char *tzid);
63static void icalcomponent_rename_tzids(icalcomponent *comp, icalarray *rename_table);
64static void icalcomponent_rename_tzids_callback(icalparameter *param, void *data);
65static int icalcomponent_compare_vtimezones(icalcomponent *vtimezone1, icalcomponent *vtimezone2);
66static int icalcomponent_compare_timezone_fn(const void *elem1, const void *elem2);
67
68void icalcomponent_add_children(icalcomponent *impl, va_list args)
69{
70 void *vp;
71
72 while ((vp = va_arg(args, void *)) != 0) {
74
76 icalcomponent_add_component(impl, (icalcomponent *)vp);
77
78 } else if (icalproperty_isa_property(vp)) {
79 icalcomponent_add_property(impl, (icalproperty *)vp);
80 }
81 }
82}
83
84static icalcomponent *icalcomponent_new_impl(icalcomponent_kind kind)
85{
86 icalcomponent *comp;
87
89 return NULL;
90 }
91
92 if ((comp = (icalcomponent *)icalmemory_new_buffer(sizeof(icalcomponent))) == 0) {
94 return 0;
95 }
96
97 memset(comp, 0, sizeof(icalcomponent));
98
99 comp->id = ICAL_STRUCTURE_TYPE_COMPONENT;
100 comp->kind = kind;
101 comp->properties = icalpvl_newlist();
102 comp->components = icalpvl_newlist();
103 comp->timezones_sorted = 1;
104
105 return comp;
106}
107
109{
110 return icalcomponent_new_impl(kind);
111}
112
114{
115 /* See https://github.com/libical/libical/issues/585. Caller must pass NULL as final argument */
116
117 va_list args;
118
119 icalcomponent *impl = icalcomponent_new_impl(kind);
120
121 if (impl == 0) {
122 return 0;
123 }
124
125 va_start(args, kind);
126 icalcomponent_add_children(impl, args);
127 va_end(args);
128
129 return impl;
130}
131
132icalcomponent *icalcomponent_new_from_string(const char *str)
133{
135}
136
137icalcomponent *icalcomponent_clone(const icalcomponent *old)
138{
139 icalcomponent *clone;
140 const icalcomponent *c;
141 const icalproperty *p;
142 icalpvl_elem itr;
143
144 icalerror_check_arg_rz((old != 0), "component");
145
146 clone = icalcomponent_new_impl(old->kind);
147
148 if (clone == 0) {
149 return 0;
150 }
151
152 if (old->x_name) {
153 clone->x_name = icalmemory_strdup(old->x_name);
154 }
155
156 for (itr = icalpvl_head(old->properties); itr != 0; itr = icalpvl_next(itr)) {
157 p = (icalproperty *)icalpvl_data(itr);
159 }
160
161 for (itr = icalpvl_head(old->components); itr != 0; itr = icalpvl_next(itr)) {
162 c = (icalcomponent *)icalpvl_data(itr);
164 }
165
166 return clone;
167}
168
169icalcomponent *icalcomponent_new_x(const char *x_name)
170{
171 icalcomponent *comp = icalcomponent_new_impl(ICAL_X_COMPONENT);
172
173 if (!comp) {
174 return 0;
175 }
176 comp->x_name = icalmemory_strdup(x_name);
177 return comp;
178}
179
180icalcomponent *icalcomponent_new_iana(const char *iana_name)
181{
182 icalcomponent *comp = icalcomponent_new_impl(ICAL_IANA_COMPONENT);
183
184 if (!comp) {
185 return 0;
186 }
187 comp->x_name = icalmemory_strdup(iana_name);
188 return comp;
189}
190
191void icalcomponent_free(icalcomponent *c)
192{
193 icalcomponent *comp;
194
195 icalerror_check_arg_rv((c != 0), "component");
196
197 if (c->parent != 0) {
198 return;
199 }
200
201 if (c->properties != 0) {
202 icalproperty *prop;
203 while ((prop = icalpvl_pop(c->properties)) != 0) {
205 icalproperty_free(prop);
206 }
207 icalpvl_free(c->properties);
208 }
209
210 while ((comp = icalpvl_data(icalpvl_head(c->components))) != 0) {
212 icalcomponent_free(comp);
213 }
214
215 icalpvl_free(c->components);
216
217 icalmemory_free_buffer(c->x_name);
218
219 icaltimezone_array_free(c->timezones);
220 c->timezones = 0;
221
222 c->kind = ICAL_NO_COMPONENT;
223 c->properties = 0;
224 c->property_iterator = 0;
225 c->components = 0;
226 c->component_iterator = 0;
227 c->x_name = 0;
228 c->id = ICAL_STRUCTURE_TYPE_COMPONENT_EMPTY;
229 c->timezones = NULL;
230
232}
233
234char *icalcomponent_as_ical_string(const icalcomponent *component)
235{
236 char *buf;
237
238 buf = icalcomponent_as_ical_string_r(component);
239 if (buf) {
241 }
242 return buf;
243}
244
245char *icalcomponent_as_ical_string_r(const icalcomponent *component)
246{
247 char *buf;
248 size_t buf_size = 1024;
249 char *buf_ptr = 0;
250 icalpvl_elem itr;
251
252 /* RFC5545 explicitly says that the newline is *ALWAYS* a \r\n (CRLF)!!!! */
253 const char newline[] = "\r\n";
254
255 const icalcomponent *c;
256 icalproperty *p;
258
259 const char *kind_string;
260
261 icalerror_check_arg_rz((component != 0), "component");
262 icalerror_check_arg_rz((kind != ICAL_NO_COMPONENT), "component kind is ICAL_NO_COMPONENT");
263
265 kind_string = component->x_name;
266 } else {
267 kind_string = icalcomponent_kind_to_string(kind);
268 }
269
270 icalerror_check_arg_rz((kind_string != 0), "Unknown kind of component");
271
272 buf = icalmemory_new_buffer(buf_size);
273 if (buf == NULL) {
274 return NULL;
275 }
276
277 buf_ptr = buf;
278
279 icalmemory_append_string(&buf, &buf_ptr, &buf_size, "BEGIN:");
280 icalmemory_append_string(&buf, &buf_ptr, &buf_size, kind_string);
281 icalmemory_append_string(&buf, &buf_ptr, &buf_size, newline);
282
283 for (itr = icalpvl_head(component->properties); itr != 0; itr = icalpvl_next(itr)) {
284 char *tmp_buf;
285
286 p = (icalproperty *)icalpvl_data(itr);
287
288 icalerror_assert((p != 0), "Got a null property");
290
291 icalmemory_append_string(&buf, &buf_ptr, &buf_size, tmp_buf);
292 icalmemory_free_buffer(tmp_buf);
293 }
294
295 for (itr = icalpvl_head(component->components); itr != 0; itr = icalpvl_next(itr)) {
296 char *tmp_buf;
297
298 c = (icalcomponent *)icalpvl_data(itr);
299
301 if (tmp_buf != NULL) {
302 icalmemory_append_string(&buf, &buf_ptr, &buf_size, tmp_buf);
303 icalmemory_free_buffer(tmp_buf);
304 }
305 }
306
307 icalmemory_append_string(&buf, &buf_ptr, &buf_size, "END:");
308 icalmemory_append_string(&buf, &buf_ptr, &buf_size, kind_string);
309 icalmemory_append_string(&buf, &buf_ptr, &buf_size, newline);
310
311 return buf;
312}
313
314bool icalcomponent_is_valid(const icalcomponent *component)
315{
316 if (component) {
317 if ((component->id == ICAL_STRUCTURE_TYPE_COMPONENT) && component->kind != ICAL_NO_COMPONENT) {
318 return true;
319 }
320 }
321 return false;
322}
323
324icalcomponent_kind icalcomponent_isa(const icalcomponent *component)
325{
326 icalerror_check_arg_rx((component != 0), "component", ICAL_NO_COMPONENT);
327
328 return component->kind;
329}
330
331bool icalcomponent_isa_component(const void *component)
332{
333 const icalcomponent *impl = component;
334
335 icalerror_check_arg_rz((component != 0), "component");
336
337 return (impl->id == ICAL_STRUCTURE_TYPE_COMPONENT);
338}
339
340void icalcomponent_set_x_name(icalcomponent *comp, const char *name)
341{
342 icalerror_check_arg_rv((name != 0), "name");
343 icalerror_check_arg_rv((comp != 0), "comp");
344
345 free(comp->x_name);
346 comp->x_name = icalmemory_strdup(name);
347
348 if (comp->x_name == 0) {
350 }
351}
352
353const char *icalcomponent_get_x_name(const icalcomponent *comp)
354{
355 icalerror_check_arg_rz((comp != 0), "comp");
356
357 return comp->x_name;
358}
359
360void icalcomponent_set_iana_name(icalcomponent *comp, const char *name)
361{
362 icalerror_check_arg_rv((name != 0), "name");
363 icalerror_check_arg_rv((comp != 0), "comp");
364 icalerror_check_arg_rv((comp->kind == ICAL_IANA_COMPONENT), "comp->kind");
365
366 icalmemory_free_buffer(comp->x_name);
367 comp->x_name = icalmemory_strdup(name);
368
369 if (comp->x_name == 0) {
371 }
372}
373
374const char *icalcomponent_get_iana_name(const icalcomponent *comp)
375{
376 icalerror_check_arg_rz((comp != 0), "comp");
377 icalerror_check_arg_rz((comp->kind == ICAL_IANA_COMPONENT), "comp->kind");
378
379 return comp->x_name;
380}
381
382const char *icalcomponent_get_component_name(const icalcomponent *comp)
383{
384 char *buf;
385
388 return buf;
389}
390
391char *icalcomponent_get_component_name_r(const icalcomponent *comp)
392{
393 const char *component_name = 0;
394 size_t buf_size = 256;
395 char *buf;
396 char *buf_ptr;
397
398 icalerror_check_arg_rz((comp != 0), "comp");
399
400 buf = icalmemory_new_buffer(buf_size);
401 buf_ptr = buf;
402
403 if ((comp->kind == ICAL_X_COMPONENT || comp->kind == ICAL_IANA_COMPONENT) &&
404 comp->x_name != 0) {
405 component_name = comp->x_name;
406 } else {
407 component_name = icalcomponent_kind_to_string(comp->kind);
408 }
409
410 if (component_name == 0) {
413 return 0;
414
415 } else {
416 /* _append_string will automatically grow the buffer if
417 component_name is longer than the initial buffer size */
418 icalmemory_append_string(&buf, &buf_ptr, &buf_size, component_name);
419 }
420
421 return buf;
422}
423
424void icalcomponent_add_property(icalcomponent *component, icalproperty *property)
425{
426 icalerror_check_arg_rv((component != 0), "component");
427 icalerror_check_arg_rv((property != 0), "property");
428
429 icalerror_assert((!icalproperty_get_parent(property)),
430 "The property has already been added to a component. "
431 "Remove the property with icalcomponent_remove_property "
432 "before calling icalcomponent_add_property");
433
434 icalproperty_set_parent(property, component);
435
436 icalpvl_push(component->properties, property);
437}
438
439void icalcomponent_remove_property(icalcomponent *component, icalproperty *property)
440{
441 icalpvl_elem itr, next_itr;
442
443 icalerror_check_arg_rv((component != 0), "component");
444 icalerror_check_arg_rv((property != 0), "property");
445
446 if (icalproperty_get_parent(property) == 0) {
447 return;
448 }
449
450 for (itr = icalpvl_head(component->properties); itr != 0; itr = next_itr) {
451 next_itr = icalpvl_next(itr);
452
453 if (icalpvl_data(itr) == (void *)property) {
454 if (component->property_iterator == itr) {
455 component->property_iterator = icalpvl_next(itr);
456 }
457
458 (void)icalpvl_remove(component->properties, itr);
459 icalproperty_set_parent(property, 0);
460 }
461 }
462}
463
465{
466 icalpvl_elem itr, next_itr;
467
468 icalerror_check_arg_rv((component != 0), "component");
469
470 for (itr = icalpvl_head(component->properties); itr != 0; itr = next_itr) {
471 next_itr = icalpvl_next(itr);
472
473 icalproperty *property = icalpvl_data(itr);
474 if (kind == ICAL_ANY_PROPERTY || icalproperty_isa(property) == kind) {
475 if (component->property_iterator == itr) {
476 component->property_iterator = icalpvl_next(itr);
477 }
478
479 (void)icalpvl_remove(component->properties, itr);
480 icalproperty_set_parent(property, 0);
481 icalproperty_free(property);
482 }
483 }
484}
485
487{
488 int count = 0;
489 icalpvl_elem itr;
490
491 icalerror_check_arg_rz((component != 0), "component");
492
493 for (itr = icalpvl_head(component->properties); itr != 0; itr = icalpvl_next(itr)) {
494 if (kind == icalproperty_isa((icalproperty *)icalpvl_data(itr)) || kind == ICAL_ANY_PROPERTY) {
495 count++;
496 }
497 }
498
499 return count;
500}
501
502icalproperty *icalcomponent_get_current_property(icalcomponent *component)
503{
504 icalerror_check_arg_rz((component != 0), "component");
505
506 if (component->property_iterator == 0) {
507 return 0;
508 }
509
510 return (icalproperty *)icalpvl_data(component->property_iterator);
511}
512
514{
515 icalerror_check_arg_rz((c != 0), "component");
516
517 for (c->property_iterator = icalpvl_head(c->properties);
518 c->property_iterator != 0; c->property_iterator = icalpvl_next(c->property_iterator)) {
519 icalproperty *p = (icalproperty *)icalpvl_data(c->property_iterator);
520
522 return p;
523 }
524 }
525 return 0;
526}
527
529{
530 icalerror_check_arg_rz((c != 0), "component");
531
532 if (c->property_iterator == 0) {
533 return 0;
534 }
535
536 for (c->property_iterator = icalpvl_next(c->property_iterator);
537 c->property_iterator != 0; c->property_iterator = icalpvl_next(c->property_iterator)) {
538 icalproperty *p = (icalproperty *)icalpvl_data(c->property_iterator);
539
541 return p;
542 }
543 }
544
545 return 0;
546}
547
548void icalcomponent_add_component(icalcomponent *parent, icalcomponent *child)
549{
550 icalerror_check_arg_rv((parent != 0), "parent");
551 icalerror_check_arg_rv((child != 0), "child");
552
553 if (child->parent != 0) {
555 }
556
557 child->parent = parent;
558
559 /* Fix for Mozilla - bug 327602 */
560 if (child->kind != ICAL_VTIMEZONE_COMPONENT) {
561 icalpvl_push(parent->components, child);
562 } else {
563 /* VTIMEZONES should be first in the resulting VCALENDAR. */
564 icalpvl_unshift(parent->components, child);
565
566 /* Add the VTIMEZONE to our array. */
567 /* FIXME: Currently we are also creating this array when loading in
568 a builtin VTIMEZONE, when we don't need it. */
569 if (!parent->timezones) {
570 parent->timezones = icaltimezone_array_new();
571 }
572
573 if (parent->timezones) {
574 icaltimezone_array_append_from_vtimezone(parent->timezones, child);
575 }
576
577 /* Flag that we need to sort it before doing any binary searches. */
578 parent->timezones_sorted = 0;
579 }
580}
581
582void icalcomponent_remove_component(icalcomponent *parent, icalcomponent *child)
583{
584 icalpvl_elem itr, next_itr;
585
586 icalerror_check_arg_rv((parent != 0), "parent");
587 icalerror_check_arg_rv((child != 0), "child");
588
589 /* If the component is a VTIMEZONE, remove it from our array as well. */
590 if (child->kind == ICAL_VTIMEZONE_COMPONENT) {
591 icaltimezone *zone;
592 size_t i, num_elements;
593
594 num_elements = parent->timezones ? parent->timezones->num_elements : 0;
595 for (i = 0; i < num_elements; i++) {
596 zone = icalarray_element_at(parent->timezones, i);
597 if (icaltimezone_get_component(zone) == child) {
598 icaltimezone_free(zone, 0);
599 icalarray_remove_element_at(parent->timezones, i);
600 break;
601 }
602 }
603 }
604
605 for (itr = icalpvl_head(parent->components); itr != 0; itr = next_itr) {
606 next_itr = icalpvl_next(itr);
607
608 if (icalpvl_data(itr) == (void *)child) {
609 if (parent->component_iterator == itr) {
610 /* Don't let the current iterator become invalid */
611
612 /* HACK. The semantics for this are troubling. */
613 parent->component_iterator = icalpvl_next(parent->component_iterator);
614 }
615 (void)icalpvl_remove(parent->components, itr);
616 child->parent = 0;
617 break;
618 }
619 }
620}
621
623{
624 int count = 0;
625 icalpvl_elem itr;
626
627 icalerror_check_arg_rz((component != 0), "component");
628
629 for (itr = icalpvl_head(component->components); itr != 0; itr = icalpvl_next(itr)) {
630 if (kind == icalcomponent_isa((icalcomponent *)icalpvl_data(itr)) ||
632 count++;
633 }
634 }
635
636 return count;
637}
638
639icalcomponent *icalcomponent_get_current_component(icalcomponent *component)
640{
641 icalerror_check_arg_rz((component != 0), "component");
642
643 if (component->component_iterator == 0) {
644 return 0;
645 }
646
647 return (icalcomponent *)icalpvl_data(component->component_iterator);
648}
649
651{
652 icalerror_check_arg_rz((c != 0), "component");
653
654 for (c->component_iterator = icalpvl_head(c->components);
655 c->component_iterator != 0; c->component_iterator = icalpvl_next(c->component_iterator)) {
656 icalcomponent *p = (icalcomponent *)icalpvl_data(c->component_iterator);
657
659 return p;
660 }
661 }
662
663 return 0;
664}
665
667{
668 icalerror_check_arg_rz((c != 0), "component");
669
670 if (c->component_iterator == 0) {
671 return 0;
672 }
673
674 for (c->component_iterator = icalpvl_next(c->component_iterator);
675 c->component_iterator != 0; c->component_iterator = icalpvl_next(c->component_iterator)) {
676 icalcomponent *p = (icalcomponent *)icalpvl_data(c->component_iterator);
677
679 return p;
680 }
681 }
682
683 return 0;
684}
685
686icalcomponent *icalcomponent_get_first_real_component(const icalcomponent *c)
687{
688 icalcomponent *comp;
689 icalcomponent *cin = (icalcomponent *)c;
690
694
703 return comp;
704 }
705 }
706 return 0;
707}
708
709icaltime_span icalcomponent_get_span(icalcomponent *comp)
710{
711 const icalcomponent *inner;
713 icaltime_span span;
714 struct icaltimetype start, end;
715
716 span.start = 0;
717 span.end = 0;
718 span.is_busy = 1;
719
720 /* initial Error checking */
721 if (comp == NULL) {
722 return span;
723 }
724
725 /* FIXME this might go away */
726 kind = icalcomponent_isa(comp);
729
730 /* Maybe there is a VTIMEZONE in there */
731 if (inner == 0) {
733 }
734
735 } else {
736 inner = comp;
737 }
738
739 if (inner == 0) {
741 /*icalerror_warn("icalcomponent_get_span: no component specified, \
742or empty VCALENDAR component"); */
743 return span;
744 }
745
746 kind = icalcomponent_isa(inner);
747
748 if (!(kind == ICAL_VEVENT_COMPONENT ||
752 /*icalerror_warn("icalcomponent_get_span: no component specified, \
753or empty VCALENDAR component"); */
754 return span;
755 }
756
757 /* Get to work. starting with DTSTART */
758 start = icalcomponent_get_dtstart(comp);
759 if (icaltime_is_null_time(start)) {
760 return span;
761 }
763
764 /* The end time could be specified as either a DTEND, a DURATION, or be missing */
765 /* icalcomponent_get_dtend takes care of these cases. */
766 end = icalcomponent_get_dtend(comp);
767
769 if (icaltime_is_date(start)) {
770 /* Until the end of the day */
771 span.end -= 1;
772 }
773
774 return span;
775}
776
777bool icalproperty_recurrence_is_excluded(icalcomponent *comp,
778 struct icaltimetype *dtstart,
779 struct icaltimetype *recurtime)
780{
781 icalproperty *exdate, *exrule;
782 icalpvl_elem property_iterator;
783
784 if (comp == NULL || dtstart == NULL || recurtime == NULL || icaltime_is_null_time(*recurtime)) {
785 /* BAD DATA */
786 return true;
787 }
788
789 property_iterator = comp->property_iterator;
790
793 exdate != NULL; exdate = icalcomponent_get_next_property(comp, ICAL_EXDATE_PROPERTY)) {
794 struct icaltimetype exdatetime = icalproperty_get_datetime_with_component(exdate, comp);
795
796 if ((icaltime_is_date(exdatetime) &&
797 icaltime_compare_date_only(*recurtime, exdatetime) == 0) ||
798 (icaltime_compare(*recurtime, exdatetime) == 0)) {
800 comp->property_iterator = property_iterator;
801 return true;
802 }
803 }
804
807 exrule != NULL; exrule = icalcomponent_get_next_property(comp, ICAL_EXRULE_PROPERTY)) {
808 struct icalrecurrencetype *recur = icalproperty_get_exrule(exrule);
809 if (recur) {
810 icalrecur_iterator *exrule_itr = icalrecur_iterator_new(recur, *dtstart);
811 while (exrule_itr) {
812 int result;
813
814 struct icaltimetype exrule_time = icalrecur_iterator_next(exrule_itr);
815
816 if (icaltime_is_null_time(exrule_time)) {
817 break;
818 }
819
820 result = icaltime_compare(exrule_time, *recurtime);
821 if (result == 0) {
822 icalrecur_iterator_free(exrule_itr);
823 comp->property_iterator = property_iterator;
824 return true;
826 }
827 if (result == 1) {
828 break;
829 }
831 }
832
833 if (exrule_itr) {
834 icalrecur_iterator_free(exrule_itr);
835 }
836 }
837 }
838 comp->property_iterator = property_iterator;
839
840 return false; /* no matches */
841}
842
850static bool icalcomponent_is_busy(icalcomponent *comp)
851{
852 const icalproperty *transp;
853 enum icalproperty_status status;
854 bool ret = true;
855
858
859 /* Is this a busy time? Check the TRANSP property */
861
862 if (transp) {
863 icalvalue *transp_val = icalproperty_get_value(transp);
864
865 switch (icalvalue_get_transp(transp_val)) {
868 case ICAL_TRANSP_NONE:
869 ret = true;
870 break;
873 ret = false;
874 break;
875 default:
876 ret = false;
877 break;
878 }
879 }
880 status = icalcomponent_get_status(comp);
881 if (ret && status != ICAL_STATUS_NONE) {
882 switch (status) {
885 ret = false;
886 break;
887 default:
888 break;
889 }
890 }
891 return ret;
892}
893
894static struct icaltimetype icaltime_with_time(const struct icaltimetype t, int hour, int minutes, int seconds)
895{
896 struct icaltimetype ret = t;
897 ret.hour = hour;
898 ret.minute = minutes;
899 ret.second = seconds;
900 ret.is_date = 0;
901 return ret;
902}
903
904static struct icaltimetype icaltime_at_midnight(const struct icaltimetype t)
905{
906 return icaltime_with_time(t, 0, 0, 0);
907}
908
909static icaltime_span icaltime_span_from_time(const struct icaltimetype t, const struct icaldurationtype d)
910{
911 icaltime_span ret = {0};
912
913 ret.start =
916 ret.end =
920 return ret;
921}
922
923static icaltime_span icaltime_span_from_datetimeperiod(const struct icaldatetimeperiodtype p, const struct icaldurationtype d)
924{
925 struct icaltimetype start = p.time;
927
928 icaltime_span ret = {0};
929 if (icaltime_is_null_time(start)) {
930 start = p.period.start;
931
933 dur = p.period.duration;
934 } else {
935 ret.end =
937 p.period.end,
938 start.zone ? start.zone : icaltimezone_get_utc_timezone());
939 }
940 } else {
941 dur = d;
942 }
943
944 ret.start =
946 start,
947 start.zone ? start.zone : icaltimezone_get_utc_timezone());
948
951 icalduration_extend(start, dur),
952 start.zone ? start.zone : icaltimezone_get_utc_timezone());
953 }
954 return ret;
955}
956
957static int icaldatetimeperiod_start_compare(const void *a, const void *b)
958{
959 const struct icaldatetimeperiodtype *adtp = a, *bdtp = b;
960 const struct icaltimetype
961 at = (!icaltime_is_null_time(adtp->time) ? adtp->time : adtp->period.start),
962 bt = (!icaltime_is_null_time(bdtp->time) ? bdtp->time : bdtp->period.start);
963 return icaltime_compare(at, bt);
964}
965
966void icalcomponent_foreach_recurrence(icalcomponent *comp,
967 struct icaltimetype start,
968 struct icaltimetype end,
969 void (*callback)(icalcomponent *comp,
970 const struct icaltime_span *span,
971 void *data),
972 void *callback_data)
973{
974 struct icaltimetype dtstart, dtend, recur_time;
975 icaltime_span recurspan, basespan, limit_span,
976 rrule_span, rdate_span;
977 icaltime_t limit_start, limit_end, last_start;
978 struct icaldurationtype dtduration;
979 time_t end_timet = icaltime_as_timet_with_zone(
980 end, end.zone ? end.zone : icaltimezone_get_utc_timezone());
981 icalarray *rdates;
982 size_t rdate_idx = 0;
983
984 icalproperty *rrule, *rdate;
985 icalpvl_elem property_iterator; /* for saving the iterator */
986
987 if (comp == NULL || callback == NULL) {
988 return;
989 }
990
991 dtstart = icalcomponent_get_dtstart(comp);
992
993 if (icaltime_is_null_time(dtstart) &&
995 /* VTODO with no DTSTART - use DUE */
996 dtstart = icalcomponent_get_due(comp);
997 }
998 if (icaltime_is_null_time(dtstart)) {
999 return;
1000 }
1001
1002 /* The end time could be specified as either a DTEND, a DURATION or be missing */
1003 /* icalcomponent_get_dtend takes care of these cases. */
1004 dtend = icalcomponent_get_dtend(comp);
1005 /* Our duration may similarly be derived from DTSTART and DTEND */
1006 dtduration = icalcomponent_get_duration(comp);
1007
1008 /* Now set up the base span for this item, corresponding to the
1009 base DTSTART and DTEND */
1010 basespan = icaltime_span_new(dtstart, dtend, true);
1011
1012 basespan.is_busy = (int)icalcomponent_is_busy(comp);
1013
1014 if (start.is_date) {
1015 /* We always treat start as date-time, because we do arithmetic calculations later
1016 on that wouldn't work on date-only. As date-only values shouldn't have a timezone set,
1017 we shouldn't have any issues with potential DST changes. */
1018 start = icaltime_at_midnight(start);
1019 }
1020
1021 /* Calculate the ceiling and floor values.. */
1022 limit_start = icaltime_as_timet_with_zone(start,
1024 if (!icaltime_is_null_time(end)) {
1025 if (end.is_date) {
1026 /* Same as with start, treat as date-time to allow for arithmetic operations. */
1027 end = icaltime_at_midnight(end);
1028 }
1029
1030 limit_end = icaltime_as_timet_with_zone(end,
1032 } else {
1033#if (SIZEOF_ICALTIME_T > 4)
1034 limit_end = (icaltime_t)LONG_MAX;
1035#else
1036 limit_end = (icaltime_t)INT_MAX;
1037#endif
1038 }
1039 limit_span.start = limit_start;
1040 limit_span.end = limit_end;
1041
1042 rrule_span.start = rdate_span.start =
1043 last_start = end_timet + 1;
1044
1045 /* Do the callback for the DTSTART entry, ONLY if there is no RRULE.
1046 Otherwise, the initial occurrence will be handled by the RRULE. */
1048 if ((rrule == NULL) &&
1049 !icalproperty_recurrence_is_excluded(comp, &dtstart, &dtstart)) {
1050 last_start = basespan.start;
1051 /* call callback action */
1052 if (icaltime_span_overlaps(&basespan, &limit_span)) {
1053 (*callback)(comp, &basespan, callback_data);
1054 }
1055 }
1056
1057 /* Now cycle through the rrule and rdate entries */
1058
1059 struct icaltimetype rrule_time = icaltime_null_time();
1060 icalrecur_iterator *rrule_itr = NULL;
1061 if (rrule != NULL) {
1062 struct icalrecurrencetype *recur = icalproperty_get_rrule(rrule);
1063 if (recur) {
1064 rrule_itr = icalrecur_iterator_new(recur, dtstart);
1065
1066 if (rrule_itr) {
1067 if (recur->count == 0) {
1068 icaltimetype mystart = start;
1069
1070 /* make sure we include any recurrence that ends in timespan */
1071 /* duration should be positive */
1072 dtduration.is_neg = 1;
1073 mystart = icalduration_extend(mystart, dtduration);
1074 dtduration.is_neg = 0;
1075
1076 icalrecur_iterator_set_start(rrule_itr, mystart);
1077 }
1078 rrule_time = icalrecur_iterator_next(rrule_itr);
1079 if (!icaltime_is_null_time(rrule_time)) {
1080 rrule_span = icaltime_span_from_time(rrule_time, dtduration);
1081 }
1082 }
1083 }
1084 }
1085
1086 struct icaldatetimeperiodtype rdate_period;
1087 rdates = icalarray_new(sizeof(struct icaldatetimeperiodtype), 16);
1088 if (!rdates) {
1090 } else {
1092 rdate != NULL;
1094 rdate_period = icalproperty_get_rdate(rdate);
1095 icalarray_append(rdates, &rdate_period);
1096 }
1097 if (rdates->num_elements > 0) {
1098 icalarray_sort(rdates, icaldatetimeperiod_start_compare);
1099 rdate_period = *((struct icaldatetimeperiodtype *)icalarray_element_at(rdates, rdate_idx));
1100 rdate_span = icaltime_span_from_datetimeperiod(rdate_period, dtduration);
1101 }
1102
1103 while (rdate_idx < rdates->num_elements || !icaltime_is_null_time(rrule_time)) {
1104 if (rdate_idx >= rdates->num_elements ||
1105 (!icaltime_is_null_time(rrule_time) &&
1106 rrule_span.start < rdate_span.start)) {
1107 /* use rrule time */
1108 recurspan = rrule_span;
1109 recur_time = rrule_time;
1110
1111 rrule_time = icalrecur_iterator_next(rrule_itr);
1112 if (!icaltime_is_null_time(rrule_time)) {
1113 rrule_span = icaltime_span_from_time(rrule_time, dtduration);
1114 }
1115 } else {
1116 /* use rdate time */
1117 recurspan = rdate_span;
1118 recur_time = rdate_period.time;
1119 if (icaltime_is_null_time(recur_time)) {
1120 recur_time = rdate_period.period.start;
1121 }
1122
1123 rdate_idx++;
1124 if (rdate_idx < rdates->num_elements) {
1125 rdate_period = *((struct icaldatetimeperiodtype *)icalarray_element_at(rdates, rdate_idx));
1126 rdate_span = icaltime_span_from_datetimeperiod(rdate_period, dtduration);
1127 }
1128 }
1129
1130 if (recurspan.start > end_timet) {
1131 break;
1132 }
1133
1134 if (last_start == recurspan.start) {
1135 continue;
1136 }
1137 last_start = recurspan.start;
1138
1139 /* save the iterator ICK! */
1140 property_iterator = comp->property_iterator;
1141
1143 &dtstart, &recur_time)) {
1144 /* call callback action */
1145 if (icaltime_span_overlaps(&recurspan, &limit_span)) {
1146 (*callback)(comp, &recurspan, callback_data);
1147 }
1148 }
1149 comp->property_iterator = property_iterator;
1150 }
1151
1152 icalarray_free(rdates);
1153 }
1154
1155 if (rrule_itr != NULL) {
1156 icalrecur_iterator_free(rrule_itr);
1157 }
1158}
1159
1160bool icalcomponent_check_restrictions(icalcomponent *comp)
1161{
1162 icalerror_check_arg_rz(comp != 0, "comp");
1163 return icalrestriction_check(comp);
1164}
1165
1166int icalcomponent_count_errors(icalcomponent *component)
1167{
1168 int errors = 0;
1169 icalpvl_elem itr;
1170
1171 icalerror_check_arg_rz((component != 0), "component");
1172
1173 for (itr = icalpvl_head(component->properties); itr != 0; itr = icalpvl_next(itr)) {
1174 const icalproperty *p = (icalproperty *)icalpvl_data(itr);
1176 errors++;
1177 }
1178 }
1179
1180 for (itr = icalpvl_head(component->components); itr != 0; itr = icalpvl_next(itr)) {
1181 icalcomponent *c = (icalcomponent *)icalpvl_data(itr);
1182 errors += icalcomponent_count_errors(c);
1183 }
1184
1185 return errors;
1186}
1187
1188void icalcomponent_strip_errors(icalcomponent *component)
1189{
1190 icalpvl_elem itr, next_itr;
1191
1192 icalerror_check_arg_rv((component != 0), "component");
1193
1194 for (itr = icalpvl_head(component->properties); itr != 0; itr = next_itr) {
1195 icalproperty *p = (icalproperty *)icalpvl_data(itr);
1196 next_itr = icalpvl_next(itr);
1197
1199 icalcomponent_remove_property(component, p);
1201 }
1202 }
1203
1204 for (itr = icalpvl_head(component->components); itr != 0; itr = icalpvl_next(itr)) {
1205 icalcomponent *c = (icalcomponent *)icalpvl_data(itr);
1207 }
1208}
1209
1210/* Hack. This will change the state of the iterators */
1211void icalcomponent_convert_errors(icalcomponent *component)
1212{
1213 icalproperty *p, *next_p;
1214 icalcomponent *c;
1215
1216 for (p = icalcomponent_get_first_property(component, ICAL_ANY_PROPERTY); p != 0; p = next_p) {
1218
1220 struct icalreqstattype rst;
1221 icalparameter *param =
1223
1225 rst.desc = 0;
1226
1227 switch (icalparameter_get_xlicerrortype(param)) {
1230 break;
1231 }
1234 break;
1235 }
1238 break;
1239 }
1242 break;
1243 }
1246 break;
1247 }
1248
1249 default: {
1250 break;
1251 }
1252 }
1253 if (rst.code != ICAL_UNKNOWN_STATUS) {
1256
1257 icalcomponent_remove_property(component, p);
1259 }
1260 }
1261 }
1262
1264 c != 0; c = icalcomponent_get_next_component(component, ICAL_ANY_COMPONENT)) {
1266 }
1267}
1268
1270icalcomponent *icalcomponent_get_parent(const icalcomponent *component)
1271{
1272 return component->parent;
1273}
1274
1275void icalcomponent_set_parent(icalcomponent *component, icalcomponent *parent)
1276{
1277 component->parent = parent;
1278}
1280
1281static const icalcompiter icalcompiter_null = {ICAL_NO_COMPONENT, 0};
1282
1283static const icalpropiter icalpropiter_null = {ICAL_NO_PROPERTY, 0};
1284
1285struct icalcomponent_kind_map {
1286 icalcomponent_kind kind;
1287 char name[20];
1288};
1289
1290static const struct icalcomponent_kind_map component_map[] = {
1291 {ICAL_VEVENT_COMPONENT, "VEVENT"},
1292 {ICAL_VTODO_COMPONENT, "VTODO"},
1293 {ICAL_VJOURNAL_COMPONENT, "VJOURNAL"},
1294 {ICAL_VCALENDAR_COMPONENT, "VCALENDAR"},
1295 {ICAL_VAGENDA_COMPONENT, "VAGENDA"},
1296 {ICAL_VFREEBUSY_COMPONENT, "VFREEBUSY"},
1297 {ICAL_VTIMEZONE_COMPONENT, "VTIMEZONE"},
1298 {ICAL_VALARM_COMPONENT, "VALARM"},
1299 {ICAL_XSTANDARD_COMPONENT, "STANDARD"}, /*These are part of RFC5545 */
1300 {ICAL_XDAYLIGHT_COMPONENT, "DAYLIGHT"}, /*but are not really components */
1301 {ICAL_X_COMPONENT, "X"},
1302 {ICAL_VSCHEDULE_COMPONENT, "SCHEDULE"},
1303
1304 /* CAP components */
1305 {ICAL_VCAR_COMPONENT, "VCAR"},
1306 {ICAL_VCOMMAND_COMPONENT, "VCOMMAND"},
1307 {ICAL_VQUERY_COMPONENT, "VQUERY"},
1308 {ICAL_VREPLY_COMPONENT, "VREPLY"},
1309
1310 /* libical private components */
1311 {ICAL_XLICINVALID_COMPONENT, "X-LIC-UNKNOWN"},
1312 {ICAL_XLICMIMEPART_COMPONENT, "X-LIC-MIME-PART"},
1313 {ICAL_ANY_COMPONENT, "ANY"},
1314 {ICAL_XROOT_COMPONENT, "XROOT"},
1315
1316 /* Calendar Availability components */
1317 {ICAL_VAVAILABILITY_COMPONENT, "VAVAILABILITY"},
1318 {ICAL_XAVAILABLE_COMPONENT, "AVAILABLE"},
1319
1320 /* Consensus Scheduling components */
1321 {ICAL_VPOLL_COMPONENT, "VPOLL"},
1322 {ICAL_VVOTER_COMPONENT, "VVOTER"},
1323 {ICAL_XVOTE_COMPONENT, "VOTE"},
1324
1325 /* VPATCH components */
1326 {ICAL_VPATCH_COMPONENT, "VPATCH"},
1327 {ICAL_XPATCH_COMPONENT, "PATCH"},
1328
1329 /* Event Publishing components */
1330 {ICAL_PARTICIPANT_COMPONENT, "PARTICIPANT"},
1331 {ICAL_VLOCATION_COMPONENT, "VLOCATION"},
1332 {ICAL_VRESOURCE_COMPONENT, "VRESOURCE"},
1333
1334 /* IANA components (unknown but valid IANA token) */
1335 {ICAL_IANA_COMPONENT, "IANA"},
1336
1337 /* End of list */
1338 {ICAL_NO_COMPONENT, ""},
1339};
1340
1342{
1343 int i = 0;
1344
1345 do {
1346 if (component_map[i].kind == kind) {
1347 return true;
1348 }
1349 } while (component_map[i++].kind != ICAL_NO_COMPONENT);
1350
1351 return false;
1352}
1353
1355{
1356 int i;
1357
1358 for (i = 0; component_map[i].kind != ICAL_NO_COMPONENT; i++) {
1359 if (component_map[i].kind == kind) {
1360 return component_map[i].name;
1361 }
1362 }
1363
1364 return 0;
1365}
1366
1368{
1369 int i;
1370
1371 if (string == 0) {
1372 return ICAL_NO_COMPONENT;
1373 }
1374
1375 for (i = 0; component_map[i].kind != ICAL_NO_COMPONENT; i++) {
1376 // ignore IANA component kind, we'll fall back to using it later.
1377 if (component_map[i].kind == ICAL_IANA_COMPONENT) {
1378 continue;
1379 }
1380 if (strncasecmp(string, component_map[i].name, strlen(component_map[i].name)) == 0) {
1381 return component_map[i].kind;
1382 }
1383 }
1384
1385 if (strncasecmp(string, "X-", 2) == 0) {
1386 return ICAL_X_COMPONENT;
1387 }
1388
1389 return ICAL_IANA_COMPONENT;
1390}
1391
1392bool icalcompiter_is_valid(const icalcompiter *i)
1393{
1394 if (!i) {
1395 return false;
1396 }
1397 /* compare to icalcompiter_null */
1398 if (i->kind == ICAL_NO_COMPONENT && i->iter == 0) {
1399 return false;
1400 }
1401 return true;
1402}
1403
1404icalcompiter icalcomponent_begin_component(icalcomponent *component, icalcomponent_kind kind)
1405{
1406 icalcompiter itr;
1407 icalpvl_elem i;
1408
1409 itr.kind = kind;
1410 itr.iter = NULL;
1411
1412 icalerror_check_arg_re(component != 0, "component", icalcompiter_null);
1413
1414 for (i = icalpvl_head(component->components); i != 0; i = icalpvl_next(i)) {
1415 const icalcomponent *c = (icalcomponent *)icalpvl_data(i);
1416
1418 itr.iter = i;
1419
1420 return itr;
1421 }
1422 }
1423
1424 return icalcompiter_null;
1425}
1426
1427icalcompiter icalcomponent_end_component(icalcomponent *component, icalcomponent_kind kind)
1428{
1429 icalcompiter itr;
1430 icalpvl_elem i;
1431
1432 itr.kind = kind;
1433
1434 icalerror_check_arg_re(component != 0, "component", icalcompiter_null);
1435
1436 for (i = icalpvl_tail(component->components); i != 0; i = icalpvl_prior(i)) {
1437 const icalcomponent *c = (icalcomponent *)icalpvl_data(i);
1438
1440 itr.iter = icalpvl_next(i);
1441
1442 return itr;
1443 }
1444 }
1445
1446 return icalcompiter_null;
1447}
1448
1449icalcomponent *icalcompiter_next(icalcompiter *i)
1450{
1451 icalerror_check_arg_rz((i != 0), "i");
1452
1453 if (i->iter == 0) {
1454 return 0;
1455 }
1456
1457 for (i->iter = icalpvl_next(i->iter); i->iter != 0; i->iter = icalpvl_next(i->iter)) {
1458 const icalcomponent *c = (icalcomponent *)icalpvl_data(i->iter);
1459
1460 if (icalcomponent_isa(c) == i->kind || i->kind == ICAL_ANY_COMPONENT) {
1461 return icalcompiter_deref(i);
1462 }
1463 }
1464
1465 return 0;
1466}
1467
1468icalcomponent *icalcompiter_prior(icalcompiter *i)
1469{
1470 icalerror_check_arg_rz((i != 0), "i");
1471
1472 if (i->iter == 0) {
1473 return 0;
1474 }
1475
1476 for (i->iter = icalpvl_prior(i->iter); i->iter != 0; i->iter = icalpvl_prior(i->iter)) {
1477 const icalcomponent *c = (icalcomponent *)icalpvl_data(i->iter);
1478
1479 if (icalcomponent_isa(c) == i->kind || i->kind == ICAL_ANY_COMPONENT) {
1480 return icalcompiter_deref(i);
1481 }
1482 }
1483
1484 return 0;
1485}
1486
1487icalcomponent *icalcompiter_deref(icalcompiter *i)
1488{
1489 icalerror_check_arg_rz((i != 0), "i");
1490
1491 if (i->iter == 0) {
1492 return 0;
1493 }
1494
1495 return icalpvl_data(i->iter);
1496}
1497
1498icalpropiter icalcomponent_begin_property(icalcomponent *component, icalproperty_kind kind)
1499{
1500 icalerror_check_arg_re(component != 0, "component", icalpropiter_null);
1501
1502 icalpvl_elem i;
1503
1504 for (i = icalpvl_head(component->properties); i != 0; i = icalpvl_next(i)) {
1505 const icalproperty *p = (icalproperty *)icalpvl_data(i);
1506
1507 if (icalproperty_isa(p) == kind || kind == ICAL_ANY_PROPERTY) {
1508 icalpropiter itr = {kind, i};
1509 return itr;
1510 }
1511 }
1512
1513 return icalpropiter_null;
1514}
1515
1516bool icalpropiter_is_valid(const icalpropiter *i)
1517{
1518 if (!i) {
1519 return false;
1520 }
1521 /* compare to icalpropiter_null */
1522 if ((i->kind == ICAL_NO_PROPERTY) && (i->iter == 0)) {
1523 return false;
1524 }
1525 return true;
1526}
1527
1528icalproperty *icalpropiter_next(icalpropiter *i)
1529{
1530 icalerror_check_arg_rz((i != 0), "i");
1531
1532 if (i->iter == 0) {
1533 return 0;
1534 }
1535
1536 for (i->iter = icalpvl_next(i->iter); i->iter != 0; i->iter = icalpvl_next(i->iter)) {
1537 const icalproperty *p = (icalproperty *)icalpvl_data(i->iter);
1538
1539 if (icalproperty_isa(p) == i->kind || i->kind == ICAL_ANY_PROPERTY) {
1540 return icalpropiter_deref(i);
1541 }
1542 }
1543
1544 return 0;
1545}
1546
1547icalproperty *icalpropiter_deref(icalpropiter *i)
1548{
1549 icalerror_check_arg_rz((i != 0), "i");
1550
1551 if (i->iter == 0) {
1552 return 0;
1553 }
1554
1555 return icalpvl_data(i->iter);
1556}
1557
1558icalcomponent *icalcomponent_get_inner(icalcomponent *comp)
1559{
1562 } else {
1563 return comp;
1564 }
1565}
1566
1567void icalcomponent_set_method(icalcomponent *comp, icalproperty_method method)
1568{
1569 icalproperty *prop = icalcomponent_get_first_property(comp, ICAL_METHOD_PROPERTY);
1570
1571 if (prop == 0) {
1572 prop = icalproperty_new_method(method);
1573 icalcomponent_add_property(comp, prop);
1574 }
1575
1576 icalproperty_set_method(prop, method);
1577}
1578
1580{
1581 icalproperty *prop = icalcomponent_get_first_property(comp, ICAL_METHOD_PROPERTY);
1582
1583 if (prop == 0) {
1584 return ICAL_METHOD_NONE;
1585 }
1586
1587 return icalproperty_get_method(prop);
1588}
1589
1591#define ICALSETUPSET(p_kind) \
1592 icalcomponent *inner; \
1593 icalproperty *prop; \
1594 icalerror_check_arg_rv(comp != 0, "comp"); \
1595 inner = icalcomponent_get_inner(comp); \
1596 if (inner == 0) { \
1597 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); \
1598 return; \
1599 } \
1600 prop = icalcomponent_get_first_property(inner, p_kind);
1602
1603void icalcomponent_set_dtstart(icalcomponent *comp, struct icaltimetype v)
1604{
1605 const char *tzid;
1606
1607 ICALSETUPSET(ICAL_DTSTART_PROPERTY);
1608
1609 if (prop == 0) {
1610 prop = icalproperty_new_dtstart(v);
1611 icalcomponent_add_property(inner, prop);
1612 } else {
1614 }
1615
1616 icalproperty_set_dtstart(prop, v);
1617
1618 if ((tzid = icaltime_get_tzid(v)) != NULL && !icaltime_is_utc(v)) {
1620 }
1621}
1622
1623struct icaltimetype icalcomponent_get_dtstart(icalcomponent *comp)
1624{
1625 icalcomponent *inner = icalcomponent_get_inner(comp);
1626 icalproperty *prop;
1627
1629 if (prop == 0) {
1630 return icaltime_null_time();
1631 }
1632
1634}
1635
1636struct icaltimetype icalcomponent_get_dtend(icalcomponent *comp)
1637{
1638 icalcomponent *inner = icalcomponent_get_inner(comp);
1640 icalproperty *end_prop, *dur_prop;
1641 struct icaltimetype ret;
1642
1643 switch (kind) {
1648 break;
1649 default:
1650 return icaltime_null_time();
1651 }
1652
1655
1656 if (end_prop != 0 && dur_prop == 0) {
1657 ret = icalproperty_get_datetime_with_component(end_prop, comp);
1658 } else if (end_prop == 0 && dur_prop != 0) {
1659 struct icaltimetype start = icalcomponent_get_dtstart(inner);
1660 struct icaldurationtype duration;
1661
1662 //extra check to prevent empty durations from crashing
1663 if (icalproperty_get_value(dur_prop)) {
1664 duration = icalproperty_get_duration(dur_prop);
1665 } else {
1666 duration = icaldurationtype_null_duration();
1667 }
1668
1669 ret = icalduration_extend(start, duration);
1670 } else if (end_prop == 0 && dur_prop == 0) {
1671 if (kind == ICAL_VEVENT_COMPONENT) {
1672 struct icaltimetype start = icalcomponent_get_dtstart(inner);
1673 if (icaltime_is_date(start)) {
1675 duration.days = 1;
1676 ret = icalduration_extend(start, duration);
1677 } else {
1678 ret = start;
1679 }
1680 } else {
1681 ret = icaltime_null_time();
1682 }
1683 } else {
1684 /* Error, both duration and dtend have been specified */
1686 ret = icaltime_null_time();
1687 }
1688
1689 return ret;
1690}
1691
1692void icalcomponent_set_dtend(icalcomponent *comp, struct icaltimetype v)
1693{
1694 const char *tzid;
1695
1696 ICALSETUPSET(ICAL_DTEND_PROPERTY);
1697
1700 return;
1701 }
1702
1703 if (prop == 0) {
1704 prop = icalproperty_new_dtend(v);
1705 icalcomponent_add_property(inner, prop);
1706 } else {
1708 }
1709
1710 icalproperty_set_dtend(prop, v);
1711
1712 if ((tzid = icaltime_get_tzid(v)) != NULL && !icaltime_is_utc(v)) {
1714 }
1715}
1716
1717void icalcomponent_set_duration(icalcomponent *comp, struct icaldurationtype v)
1718{
1719 ICALSETUPSET(ICAL_DURATION_PROPERTY);
1720
1723 return;
1724 }
1725
1726 if (prop == 0) {
1727 prop = icalproperty_new_duration(v);
1728 icalcomponent_add_property(inner, prop);
1729 } else {
1731 }
1732}
1733
1735{
1736 icalcomponent *inner = icalcomponent_get_inner(comp);
1738 icalproperty *end_prop, *dur_prop;
1739 struct icaldurationtype ret;
1740
1741 switch (kind) {
1746 break;
1749 break;
1750 default:
1751 /* The libical API is used incorrectly */
1753 }
1754
1756
1757 if (dur_prop != 0 && end_prop == 0) {
1758 ret = icalproperty_get_duration(dur_prop);
1759
1760 } else if (end_prop != 0 && dur_prop == 0) {
1761 /* Get exact duration */
1762 struct icaltimetype start = icalcomponent_get_dtstart(inner);
1763 struct icaltimetype end = icalproperty_get_datetime_with_component(end_prop, comp);
1764
1765 ret = icalduration_from_times(end, start);
1766 } else if (end_prop == 0 && dur_prop == 0) {
1767 struct icaltimetype start = icalcomponent_get_dtstart(inner);
1769 if (kind == ICAL_VEVENT_COMPONENT && icaltime_is_date(start)) {
1770 ret.days = 1;
1771 }
1772 } else {
1774 /* Error, both duration and dtend have been specified */
1776 }
1777 return ret;
1778}
1779
1780void icalcomponent_set_dtstamp(icalcomponent *comp, struct icaltimetype v)
1781{
1782 ICALSETUPSET(ICAL_DTSTAMP_PROPERTY);
1783
1784 if (prop == 0) {
1785 prop = icalproperty_new_dtstamp(v);
1786 icalcomponent_add_property(inner, prop);
1787 }
1788
1789 icalproperty_set_dtstamp(prop, v);
1790}
1791
1792struct icaltimetype icalcomponent_get_dtstamp(icalcomponent *comp)
1793{
1794 icalcomponent *inner = icalcomponent_get_inner(comp);
1795 icalproperty *prop = icalcomponent_get_first_property(inner, ICAL_DTSTAMP_PROPERTY);
1796
1797 if (prop == 0) {
1798 return icaltime_null_time();
1799 }
1800
1801 return icalproperty_get_dtstamp(prop);
1802}
1803
1804void icalcomponent_set_summary(icalcomponent *comp, const char *v)
1805{
1806 ICALSETUPSET(ICAL_SUMMARY_PROPERTY)
1807
1808 if (prop == 0) {
1809 prop = icalproperty_new_summary(v);
1810 icalcomponent_add_property(inner, prop);
1811 }
1812
1813 icalproperty_set_summary(prop, v);
1814}
1815
1816const char *icalcomponent_get_summary(icalcomponent *comp)
1817{
1818 icalcomponent *inner;
1819 icalproperty *prop;
1820
1821 icalerror_check_arg_rz(comp != 0, "comp");
1822
1823 inner = icalcomponent_get_inner(comp);
1824
1825 if (inner == 0) {
1827 return 0;
1828 }
1829
1831
1832 if (prop == 0) {
1833 return 0;
1834 }
1835
1836 return icalproperty_get_summary(prop);
1837}
1838
1839void icalcomponent_set_comment(icalcomponent *comp, const char *v)
1840{
1841 ICALSETUPSET(ICAL_COMMENT_PROPERTY);
1842
1843 if (prop == 0) {
1844 prop = icalproperty_new_comment(v);
1845 icalcomponent_add_property(inner, prop);
1846 }
1847
1848 icalproperty_set_comment(prop, v);
1849}
1850
1851const char *icalcomponent_get_comment(icalcomponent *comp)
1852{
1853 icalcomponent *inner;
1854 icalproperty *prop;
1855
1856 icalerror_check_arg_rz(comp != 0, "comp");
1857
1858 inner = icalcomponent_get_inner(comp);
1859
1860 if (inner == 0) {
1862 return 0;
1863 }
1864
1866
1867 if (prop == 0) {
1868 return 0;
1869 }
1870
1871 return icalproperty_get_comment(prop);
1872}
1873
1874void icalcomponent_set_uid(icalcomponent *comp, const char *v)
1875{
1876 ICALSETUPSET(ICAL_UID_PROPERTY);
1877
1878 if (prop == 0) {
1879 prop = icalproperty_new_uid(v);
1880 icalcomponent_add_property(inner, prop);
1881 }
1882
1883 icalproperty_set_uid(prop, v);
1884}
1885
1886const char *icalcomponent_get_uid(icalcomponent *comp)
1887{
1888 icalcomponent *inner;
1889 icalproperty *prop;
1890
1891 icalerror_check_arg_rz(comp != 0, "comp");
1892
1893 inner = icalcomponent_get_inner(comp);
1894
1895 if (inner == 0) {
1897 return 0;
1898 }
1899
1901
1902 if (prop == 0) {
1903 return 0;
1904 }
1905
1906 return icalproperty_get_uid(prop);
1907}
1908
1909void icalcomponent_set_recurrenceid(icalcomponent *comp, struct icaltimetype v)
1910{
1911 const char *tzid;
1912
1913 ICALSETUPSET(ICAL_RECURRENCEID_PROPERTY);
1914
1915 if (prop == 0) {
1917 icalcomponent_add_property(inner, prop);
1918 } else {
1920 }
1921
1923
1924 if ((tzid = icaltime_get_tzid(v)) != NULL && !icaltime_is_utc(v)) {
1926 }
1927}
1928
1930{
1931 icalcomponent *inner;
1932 icalproperty *prop;
1933
1934 if (comp == 0) {
1936 return icaltime_null_time();
1937 }
1938
1939 inner = icalcomponent_get_inner(comp);
1940
1941 if (inner == 0) {
1943 return icaltime_null_time();
1944 }
1945
1947
1948 if (prop == 0) {
1949 return icaltime_null_time();
1950 }
1951
1953}
1954
1955void icalcomponent_set_description(icalcomponent *comp, const char *v)
1956{
1957 ICALSETUPSET(ICAL_DESCRIPTION_PROPERTY);
1958
1959 if (prop == 0) {
1961 icalcomponent_add_property(inner, prop);
1962 }
1963
1965}
1966
1967const char *icalcomponent_get_description(icalcomponent *comp)
1968{
1969 icalcomponent *inner;
1970 icalproperty *prop;
1971
1972 icalerror_check_arg_rz(comp != 0, "comp");
1973
1974 inner = icalcomponent_get_inner(comp);
1975
1976 if (inner == 0) {
1978 return 0;
1979 }
1980
1982
1983 if (prop == 0) {
1984 return 0;
1985 }
1986
1987 return icalproperty_get_description(prop);
1988}
1989
1990void icalcomponent_set_location(icalcomponent *comp, const char *v)
1991{
1992 ICALSETUPSET(ICAL_LOCATION_PROPERTY)
1993
1994 if (prop == 0) {
1995 prop = icalproperty_new_location(v);
1996 icalcomponent_add_property(inner, prop);
1997 }
1998
2000}
2001
2002const char *icalcomponent_get_location(icalcomponent *comp)
2003{
2004 icalcomponent *inner;
2005 icalproperty *prop;
2006
2007 icalerror_check_arg_rz(comp != 0, "comp");
2008
2009 inner = icalcomponent_get_inner(comp);
2010
2011 if (inner == 0) {
2013 return 0;
2014 }
2015
2017
2018 if (prop == 0) {
2019 return 0;
2020 }
2021
2022 return icalproperty_get_location(prop);
2023}
2024
2025void icalcomponent_set_sequence(icalcomponent *comp, int v)
2026{
2027 ICALSETUPSET(ICAL_SEQUENCE_PROPERTY);
2028
2029 if (prop == 0) {
2030 prop = icalproperty_new_sequence(v);
2031 icalcomponent_add_property(inner, prop);
2032 }
2033
2035}
2036
2037int icalcomponent_get_sequence(icalcomponent *comp)
2038{
2039 icalcomponent *inner;
2040 icalproperty *prop;
2041
2042 icalerror_check_arg_rz(comp != 0, "comp");
2043
2044 inner = icalcomponent_get_inner(comp);
2045
2046 if (inner == 0) {
2048 return 0;
2049 }
2050
2052
2053 if (prop == 0) {
2054 return 0;
2055 }
2056
2057 return icalproperty_get_sequence(prop);
2058}
2059
2060void icalcomponent_set_status(icalcomponent *comp, enum icalproperty_status v)
2061{
2062 ICALSETUPSET(ICAL_STATUS_PROPERTY);
2063
2064 if (prop == 0) {
2065 prop = icalproperty_new_status(v);
2066 icalcomponent_add_property(inner, prop);
2067 }
2068
2069 icalproperty_set_status(prop, v);
2070}
2071
2073{
2074 icalcomponent *inner;
2075 icalproperty *prop;
2076
2077 icalerror_check_arg_rz(comp != 0, "comp");
2078
2079 inner = icalcomponent_get_inner(comp);
2080
2081 if (inner == 0) {
2083 return ICAL_STATUS_NONE;
2084 }
2085
2087
2088 if (prop == 0) {
2089 return ICAL_STATUS_NONE;
2090 }
2091
2092 return icalproperty_get_status(prop);
2093}
2094
2096{
2098}
2099
2100icalcomponent *icalcomponent_new_vevent(void)
2101{
2103}
2104
2105icalcomponent *icalcomponent_new_vtodo(void)
2106{
2108}
2109
2110icalcomponent *icalcomponent_new_vjournal(void)
2111{
2113}
2114
2115icalcomponent *icalcomponent_new_valarm(void)
2116{
2118}
2119
2121{
2123}
2124
2126{
2128}
2129
2131{
2133}
2134
2136{
2138}
2139
2140icalcomponent *icalcomponent_new_vagenda(void)
2141{
2143}
2144
2145icalcomponent *icalcomponent_new_vquery(void)
2146{
2148}
2149
2150icalcomponent *icalcomponent_new_vreply(void)
2151{
2153}
2154
2159
2161{
2163}
2164
2165icalcomponent *icalcomponent_new_vpoll(void)
2166{
2168}
2169
2170icalcomponent *icalcomponent_new_vvoter(void)
2171{
2173}
2174
2175icalcomponent *icalcomponent_new_xvote(void)
2176{
2178}
2179
2180icalcomponent *icalcomponent_new_vpatch(void)
2181{
2183}
2184
2185icalcomponent *icalcomponent_new_xpatch(void)
2186{
2188}
2189
2194
2196{
2198}
2199
2201{
2203}
2204
2205/*
2206 * Timezone stuff.
2207 */
2208
2209void icalcomponent_merge_component(icalcomponent *comp, icalcomponent *comp_to_merge)
2210{
2211 icalcomponent *subcomp, *next_subcomp;
2212 icalstrarray *tzids_to_rename;
2213
2214 /* Check that both components are VCALENDAR components. */
2215 icalassert(icalcomponent_isa(comp) == ICAL_VCALENDAR_COMPONENT);
2216 icalassert(icalcomponent_isa(comp_to_merge) == ICAL_VCALENDAR_COMPONENT);
2217
2218 /* Step through each subcomponent of comp_to_merge, looking for VTIMEZONEs.
2219 For each VTIMEZONE found, check if we need to add it to comp and if we
2220 need to rename it and all TZID references to it. */
2221 tzids_to_rename = icalstrarray_new(16);
2222 if (!tzids_to_rename) {
2223 return;
2224 }
2225
2227 while (subcomp) {
2228 next_subcomp = icalcomponent_get_next_component(comp_to_merge, ICAL_VTIMEZONE_COMPONENT);
2229 /* This will add the VTIMEZONE to comp, if necessary, and also update
2230 the array of TZIDs we need to rename. */
2231 if (!icalcomponent_merge_vtimezone(comp, subcomp, tzids_to_rename)) {
2232 break;
2233 }
2234 subcomp = next_subcomp;
2235 }
2236
2237 /* If we need to do any renaming of TZIDs, do it now. */
2238 if (tzids_to_rename->num_elements != 0) {
2239 icalcomponent_rename_tzids(comp_to_merge, tzids_to_rename);
2240 }
2241 icalstrarray_free(tzids_to_rename);
2242 tzids_to_rename = 0;
2243 /* Now move all the components from comp_to_merge to comp, excluding
2244 VTIMEZONE components. */
2245 subcomp = icalcomponent_get_first_component(comp_to_merge, ICAL_ANY_COMPONENT);
2246 while (subcomp) {
2247 next_subcomp = icalcomponent_get_next_component(comp_to_merge, ICAL_ANY_COMPONENT);
2249 icalcomponent_remove_component(comp_to_merge, subcomp);
2250 icalcomponent_add_component(comp, subcomp);
2251 }
2252 subcomp = next_subcomp;
2253 }
2254
2255 /* Free comp_to_merge. We have moved most of the subcomponents over to
2256 comp now. */
2257 icalcomponent_free(comp_to_merge);
2258}
2259
2260static bool icalcomponent_merge_vtimezone(icalcomponent *comp,
2261 icalcomponent *vtimezone, icalstrarray *tzids_to_rename)
2262{
2263 icalproperty *tzid_prop;
2264 const char *tzid;
2265 char *tzid_copy;
2266 const icaltimezone *existing_vtimezone;
2267
2268 /* Get the TZID of the VTIMEZONE. */
2270 if (!tzid_prop) {
2271 return false;
2272 }
2273
2274 tzid = icalproperty_get_tzid(tzid_prop);
2275 if (!tzid) {
2276 return false;
2277 }
2278
2279 /* See if there is already a VTIMEZONE in comp with the same TZID. */
2280 existing_vtimezone = icalcomponent_get_timezone(comp, tzid);
2281
2282 /* If there is no existing VTIMEZONE with the same TZID, we can just move
2283 the VTIMEZONE to comp and return. */
2284 if (!existing_vtimezone) {
2285 icalcomponent_remove_component(icalcomponent_get_parent(vtimezone), vtimezone);
2286 icalcomponent_add_component(comp, vtimezone);
2287 return false;
2288 }
2289
2290 /* If the TZID has a '/' prefix, then we don't have to worry about the
2291 clashing TZIDs, as they are supposed to be exactly the same VTIMEZONE. */
2292 if (tzid[0] == '/') {
2293 return false;
2294 }
2295
2296 /* Now we have two VTIMEZONEs with the same TZID (which isn't a globally
2297 unique one), so we compare the VTIMEZONE components to see if they are
2298 the same. If they are, we don't need to do anything. We make a copy of
2299 the tzid, since the parameter may get modified in these calls. */
2300 tzid_copy = icalmemory_strdup(tzid);
2301 if (!tzid_copy) {
2303 return false;
2304 }
2305
2306 const int match = icalcomponent_compare_vtimezones(comp, vtimezone);
2307 if (match == 0) {
2308 /* Now we have two different VTIMEZONEs with the same TZID. */
2309 icalcomponent_handle_conflicting_vtimezones(comp, vtimezone, tzid_prop,
2310 tzid_copy, tzids_to_rename);
2311 }
2312 icalmemory_free_buffer(tzid_copy);
2313 if (match == -1) {
2314 icalstrarray_free(tzids_to_rename);
2315 return false;
2316 }
2317 return true;
2318}
2319
2320static void icalcomponent_handle_conflicting_vtimezones(icalcomponent *comp,
2321 icalcomponent *vtimezone,
2322 icalproperty *tzid_prop,
2323 const char *tzid,
2324 icalstrarray *tzids_to_rename)
2325{
2326 int max_suffix = 0;
2327 size_t i, num_elements, tzid_len;
2328 char *new_tzid, suffix_buf[32];
2329
2330 _unused(tzid_prop);
2331
2332 /* Find the length of the TZID without any trailing digits. */
2333 tzid_len = icalcomponent_get_tzid_prefix_len(tzid);
2334
2335 /* Step through each of the VTIMEZONEs in comp. We may already have the
2336 clashing VTIMEZONE in the calendar, but it may have been renamed
2337 (i.e. a unique number added on the end of the TZID, e.g. 'London2').
2338 So we compare the new VTIMEZONE with any VTIMEZONEs that have the
2339 same prefix (e.g. 'London'). If it matches any of those, we have to
2340 rename the TZIDs to that TZID, else we rename to a new TZID, using
2341 the biggest numeric suffix found + 1. */
2342 num_elements = comp->timezones ? comp->timezones->num_elements : 0;
2343 for (i = 0; i < num_elements; i++) {
2345 const char *existing_tzid;
2346 size_t existing_tzid_len;
2347
2348 zone = icalarray_element_at(comp->timezones, i);
2349 existing_tzid = icaltimezone_get_tzid(zone);
2350
2351 /* Find the length of the TZID without any trailing digits. */
2352 existing_tzid_len = icalcomponent_get_tzid_prefix_len(existing_tzid);
2353
2354 /* Check if we have the same prefix. */
2355 if (tzid_len == existing_tzid_len && (strncmp(tzid, existing_tzid, tzid_len) != 0)) {
2356 /* Compare the VTIMEZONEs. */
2357 if (icalcomponent_compare_vtimezones(icaltimezone_get_component(zone), vtimezone)) {
2358 /* The VTIMEZONEs match, so we can use the existing VTIMEZONE. But
2359 we have to rename TZIDs to this TZID. */
2360 char *tzid_copy = icalmemory_strdup(tzid);
2361 if (!tzid_copy) {
2363 return;
2364 }
2365 char *existing_tzid_copy = icalmemory_strdup(existing_tzid);
2366 if (!existing_tzid_copy) {
2368 icalmemory_free_buffer(tzid_copy);
2369 } else {
2370 icalstrarray_append(tzids_to_rename, tzid_copy);
2371 icalmemory_free_buffer(tzid_copy);
2372 icalstrarray_append(tzids_to_rename, existing_tzid_copy);
2373 icalmemory_free_buffer(existing_tzid_copy);
2374 }
2375 return;
2376 } else {
2377 /* FIXME: Handle possible NEWFAILED error. */
2378
2379 /* Convert the suffix to an integer and remember the maximum numeric suffix found. */
2380 char *t_end;
2381 const char *t = existing_tzid + existing_tzid_len;
2382 const long tmpl = strtol(t, &t_end, 10);
2383 if (t != t_end) {
2384 const int suffix = tmpl;
2385 if (max_suffix < suffix) {
2386 max_suffix = suffix;
2387 }
2388 }
2389 }
2390 }
2391 }
2392
2393 /* We didn't find a VTIMEZONE that matched, so we have to rename the TZID,
2394 using the maximum numerical suffix found + 1. */
2395 char *tzid_copy = icalmemory_strdup(tzid);
2396 if (!tzid_copy) {
2398 return;
2399 }
2400
2401 snprintf(suffix_buf, sizeof(suffix_buf), "%i", max_suffix + 1);
2402 const size_t len_new_tzid = tzid_len + strlen(suffix_buf) + 1;
2403 new_tzid = icalmemory_new_buffer(len_new_tzid);
2404 if (!new_tzid) {
2406 icalmemory_free_buffer(tzid_copy);
2407 return;
2408 }
2409 strncpy(new_tzid, tzid, tzid_len);
2410 new_tzid[tzid_len] = '\0';
2411 strncat(new_tzid, suffix_buf, len_new_tzid);
2412 new_tzid[len_new_tzid - 1] = '\0';
2413 icalstrarray_append(tzids_to_rename, tzid_copy);
2414 icalstrarray_append(tzids_to_rename, new_tzid);
2415 icalmemory_free_buffer(tzid_copy);
2416 icalmemory_free_buffer(new_tzid);
2417}
2418
2419/* Returns the length of the TZID, without any trailing digits. */
2420static size_t icalcomponent_get_tzid_prefix_len(const char *tzid)
2421{
2422 size_t len;
2423 const char *p;
2424
2425 len = strlen(tzid);
2426 p = tzid + len - 1;
2427 while (len > 0 && *p >= '0' && *p <= '9') {
2428 p--;
2429 len--;
2430 }
2431
2432 return len;
2433}
2434
2440static void icalcomponent_rename_tzids(icalcomponent *comp, icalarray *rename_table)
2441{
2442 icalcomponent_foreach_tzid(comp, icalcomponent_rename_tzids_callback, rename_table);
2443}
2444
2445static void icalcomponent_rename_tzids_callback(icalparameter *param, void *data)
2446{
2447 icalarray *rename_table = data;
2448 const char *tzid;
2449 size_t i;
2450
2451 tzid = icalparameter_get_tzid(param);
2452 if (!tzid) {
2453 return;
2454 }
2455
2456 /* Step through the rename table to see if the current TZID matches
2457 any of the ones we want to rename. */
2458 for (i = 0; i < rename_table->num_elements - 1; i += 2) {
2459 if (!strcmp(tzid, icalarray_element_at(rename_table, i))) {
2460 icalparameter_set_tzid(param, icalarray_element_at(rename_table, i + 1));
2461 break;
2462 }
2463 }
2464}
2465
2466void icalcomponent_foreach_tzid(icalcomponent *comp,
2467 void (*callback)(icalparameter *param, void *data),
2468 void *callback_data)
2469{
2470 icalproperty *prop;
2471 icalcomponent *subcomp;
2472
2473 /* First look for any TZID parameters used in this component itself. */
2475 while (prop) {
2477
2478 /* These are the only properties that can have a TZID. Note that
2479 COMPLETED, CREATED, DTSTAMP & LASTMODIFIED must be in UTC. */
2480 if (kind == ICAL_DTSTART_PROPERTY ||
2486 if (param) {
2487 (*callback)(param, callback_data);
2488 }
2489 }
2490
2492 }
2493
2494 /* Now recursively check child components. */
2496 while (subcomp) {
2497 icalcomponent_foreach_tzid(subcomp, callback, callback_data);
2499 }
2500}
2501
2502icaltimezone *icalcomponent_get_timezone(icalcomponent *comp, const char *tzid)
2503{
2505 size_t lower, upper;
2506
2507 if (!comp->timezones) {
2508 return NULL;
2509 }
2510
2511 /* Sort the array if necessary (by the TZID string). */
2512 if (!comp->timezones_sorted) {
2513 icalarray_sort(comp->timezones, icalcomponent_compare_timezone_fn);
2514 comp->timezones_sorted = 1;
2515 }
2516
2517 /* Do a simple binary search. */
2518 lower = 0;
2519 upper = comp->timezones->num_elements;
2520
2521 while (lower < upper) {
2522 size_t middle = (lower + upper) >> 1;
2523 zone = icalarray_element_at(comp->timezones, middle);
2524 const char *zone_tzid = icaltimezone_get_tzid(zone);
2525 if (zone_tzid != NULL) {
2526 int cmp = strcmp(tzid, zone_tzid);
2527 if (cmp == 0) {
2528 return zone;
2529 } else if (cmp < 0) {
2530 upper = middle;
2531 } else {
2532 lower = middle + 1;
2533 }
2534 }
2535 }
2536
2537 return NULL;
2538}
2539
2543static int icalcomponent_compare_timezone_fn(const void *elem1, const void *elem2)
2544{
2545 bool zone1_is_valid = false, zone2_is_valid = false;
2546 const char *zone1_tzid = 0, *zone2_tzid = 0;
2547
2548 icaltimezone *zone1 = (icaltimezone *)elem1;
2549 icaltimezone *zone2 = (icaltimezone *)elem2;
2550
2551 if (zone1) {
2552 zone1_tzid = icaltimezone_get_tzid(zone1);
2553 if (zone1_tzid) {
2554 zone1_is_valid = true;
2555 }
2556 }
2557 if (zone2) {
2558 zone2_tzid = icaltimezone_get_tzid(zone2);
2559 if (zone2_tzid) {
2560 zone2_is_valid = true;
2561 }
2562 }
2563
2564 if (zone1_is_valid && !zone2_is_valid) {
2565 return 1;
2566 }
2567 if (!zone1_is_valid) {
2568 if (zone2_is_valid) {
2569 return -1;
2570 } else {
2571 return 0;
2572 }
2573 }
2574
2575 return strcmp(zone1_tzid, zone2_tzid);
2576}
2577
2582static int icalcomponent_compare_vtimezones(icalcomponent *vtimezone1, icalcomponent *vtimezone2)
2583{
2584 icalproperty *prop1, *prop2;
2585 const char *tzid1, *tzid2;
2586 char *tzid2_copy, *string1, *string2;
2587 int cmp;
2588
2589 /* Get the TZID property of the first VTIMEZONE. */
2591 if (!prop1) {
2592 return -1;
2593 }
2594
2595 tzid1 = icalproperty_get_tzid(prop1);
2596 if (!tzid1) {
2597 return -1;
2598 }
2599
2600 /* Get the TZID property of the second VTIMEZONE. */
2602 if (!prop2) {
2603 return -1;
2604 }
2605
2606 tzid2 = icalproperty_get_tzid(prop2);
2607 if (!tzid2) {
2608 return -1;
2609 }
2610
2611 /* Copy the second TZID, and set the property to the same as the first
2612 TZID, since we don't care if these match of not. */
2613 tzid2_copy = icalmemory_strdup(tzid2);
2614 if (!tzid2_copy) {
2616 return 0;
2617 }
2618
2619 icalproperty_set_tzid(prop2, tzid1);
2620
2621 /* Now convert both VTIMEZONEs to strings and compare them. */
2622 string1 = icalcomponent_as_ical_string_r(vtimezone1);
2623 if (!string1) {
2624 icalmemory_free_buffer(tzid2_copy);
2625 return -1;
2626 }
2627
2628 string2 = icalcomponent_as_ical_string_r(vtimezone2);
2629 if (!string2) {
2630 icalmemory_free_buffer(string1);
2631 icalmemory_free_buffer(tzid2_copy);
2632 return -1;
2633 }
2634
2635 cmp = strcmp(string1, string2);
2636
2637 icalmemory_free_buffer(string1);
2638 icalmemory_free_buffer(string2);
2639
2640 /* Now reset the second TZID. */
2641 icalproperty_set_tzid(prop2, tzid2_copy);
2642 icalmemory_free_buffer(tzid2_copy);
2643
2644 return (cmp == 0) ? 1 : 0;
2645}
2646
2647void icalcomponent_set_relcalid(icalcomponent *comp, const char *v)
2648{
2649 ICALSETUPSET(ICAL_RELCALID_PROPERTY);
2650
2651 if (prop == 0) {
2652 prop = icalproperty_new_relcalid(v);
2653 icalcomponent_add_property(inner, prop);
2654 }
2655
2657}
2658
2659const char *icalcomponent_get_relcalid(icalcomponent *comp)
2660{
2661 icalcomponent *inner;
2662 icalproperty *prop;
2663
2664 icalerror_check_arg_rz(comp != 0, "comp");
2665
2666 inner = icalcomponent_get_inner(comp);
2667
2668 if (inner == 0) {
2669 return 0;
2670 }
2671
2673
2674 if (prop == 0) {
2675 return 0;
2676 }
2677
2678 return icalproperty_get_relcalid(prop);
2679}
2680
2681struct icaltimetype icalcomponent_get_due(icalcomponent *comp)
2682{
2683 icalcomponent *inner = icalcomponent_get_inner(comp);
2684
2685 icalproperty *due_prop = icalcomponent_get_first_property(inner, ICAL_DUE_PROPERTY);
2686
2687 icalproperty *dur_prop = icalcomponent_get_first_property(inner, ICAL_DURATION_PROPERTY);
2688
2689 if (due_prop != 0) {
2690 return icalproperty_get_datetime_with_component(due_prop, comp);
2691 } else if (dur_prop != 0) {
2692 struct icaltimetype start = icalcomponent_get_dtstart(inner);
2693 struct icaldurationtype duration = icalproperty_get_duration(dur_prop);
2694
2695 struct icaltimetype due = icalduration_extend(start, duration);
2696
2697 return due;
2698 }
2699 return icaltime_null_time();
2700}
2701
2702void icalcomponent_set_due(icalcomponent *comp, struct icaltimetype v)
2703{
2704 const char *tzid;
2705
2706 icalcomponent *inner = icalcomponent_get_inner(comp);
2707
2708 icalproperty *due_prop = icalcomponent_get_first_property(inner, ICAL_DUE_PROPERTY);
2709
2710 icalproperty *dur_prop = icalcomponent_get_first_property(inner, ICAL_DURATION_PROPERTY);
2711
2712 if (due_prop == 0 && dur_prop == 0) {
2713 due_prop = icalproperty_new_due(v);
2714 icalcomponent_add_property(inner, due_prop);
2715 } else if (due_prop != 0) {
2716 icalproperty_set_due(due_prop, v);
2718 } else if (dur_prop != 0) {
2719 struct icaltimetype start = icalcomponent_get_dtstart(inner);
2720
2721 struct icaltimetype due = icalcomponent_get_due(inner);
2722
2723 struct icaldurationtype dur = icalduration_from_times(due, start);
2724
2725 icalproperty_set_duration(dur_prop, dur);
2726 }
2727
2728 if (due_prop && (tzid = icaltime_get_tzid(v)) != NULL && !icaltime_is_utc(v)) {
2730 }
2731}
2732
2733static int strcmpsafe(const char *a, const char *b)
2734{
2735 return strcmp((a == NULL ? "" : a),
2736 (b == NULL ? "" : b));
2737}
2738
2739static int prop_compare(void *a, void *b)
2740{
2741 const icalproperty *p1 = (icalproperty *)a;
2742 const icalproperty *p2 = (icalproperty *)b;
2745 int r = (int)k1 - (int)k2;
2746
2747 if (r == 0) {
2748 if (k1 == ICAL_X_PROPERTY) {
2749 r = strcmp(icalproperty_get_x_name(p1),
2751 }
2752
2753 if (r == 0) {
2754 r = strcmpsafe(icalproperty_get_value_as_string(p1),
2756 }
2757 }
2758
2759 return r;
2760}
2761
2762static inline int compare_nullptr(const void *a, const void *b)
2763{
2764 if (!a == !b) {
2765 return 0;
2766 }
2767
2768 // non-NULL sorts before NULL
2769 return a ? -1 : 1;
2770}
2771
2772static int comp_compare(void *a, void *b)
2773{
2774 icalcomponent *c1 = (icalcomponent *)a;
2775 icalcomponent *c2 = (icalcomponent *)b;
2778 int r = (int)k1 - (int)k2;
2779
2780 if (r == 0) {
2781 if ((k1 == ICAL_X_COMPONENT || k1 == ICAL_IANA_COMPONENT) &&
2782 (c1->x_name && c2->x_name)) {
2783 r = strcmp(c1->x_name, c2->x_name);
2784 }
2785
2786 if (r == 0) {
2787 const char *u1 = icalcomponent_get_uid(c1);
2788 const char *u2 = icalcomponent_get_uid(c2);
2789
2790 if (u1 && u2) {
2791 r = strcmp(u1, u2);
2792
2793 if (r == 0) {
2796 }
2797 } else {
2798 const icalproperty *p1, *p2;
2799
2800 switch (k1) {
2806 if (p1 && p2) {
2807 r = strcmp(icalproperty_get_value_as_string(p1),
2809 if (r == 0) {
2814 if (p1 && p2) {
2815 r = strcmp(icalproperty_get_value_as_string(p1),
2817 } else {
2818 r = compare_nullptr(p1, p2);
2819 }
2820 }
2821 } else {
2822 r = compare_nullptr(p1, p2);
2823 }
2824
2825 break;
2826
2832 if (p1 && p2) {
2833 r = strcmp(icalproperty_get_value_as_string(p1),
2835 } else {
2836 r = compare_nullptr(p1, p2);
2837 }
2838 break;
2839
2846
2847 if (p1 && p2) {
2848 r = strcmp(icalproperty_get_value_as_string(p1),
2850 } else {
2851 r = compare_nullptr(p1, p2);
2852 }
2853 break;
2854
2860
2861 if (p1 && p2) {
2862 r = strcmp(icalproperty_get_value_as_string(p1),
2864 } else {
2865 r = compare_nullptr(p1, p2);
2866 }
2867 break;
2868
2874
2875 if (p1 && p2) {
2876 r = strcmp(icalproperty_get_value_as_string(p1),
2878 } else {
2879 r = compare_nullptr(p1, p2);
2880 }
2881 break;
2882
2883 default:
2884 /* XXX Anything better? */
2887 break;
2888 }
2889 }
2890 }
2891 /* Always sort VTIMEZONEs first */
2892 } else if (k1 == ICAL_VTIMEZONE_COMPONENT) {
2893 return -1;
2894 } else if (k2 == ICAL_VTIMEZONE_COMPONENT) {
2895 return 1;
2896 }
2897
2898 return r;
2899}
2900
2901void icalcomponent_normalize(icalcomponent *comp)
2902{
2903 icalproperty *prop;
2904 icalcomponent *sub;
2905 icalpvl_list sorted_props;
2906 icalpvl_list sorted_comps;
2907 size_t cnt = 0; //track properties
2908
2909 icalerror_check_arg(comp != 0, "comp");
2910 if (!comp) {
2911 return;
2912 }
2913
2914 sorted_props = icalpvl_newlist();
2915 sorted_comps = icalpvl_newlist();
2916
2917 /* oss-fuzz sets the cpu timeout at 60 seconds.
2918 * In order to meet that requirement we need to cap the number of properties.
2919 */
2920 const size_t max_properties = icallimit_get(ICAL_LIMIT_PROPERTIES);
2921 /* Normalize properties into sorted list */
2922 while ((++cnt < max_properties) && ((prop = icalpvl_pop(comp->properties)) != 0)) {
2923 int nparams, remove = 0;
2924
2926
2927 nparams = icalproperty_count_parameters(prop);
2928
2929 /* Remove un-parameterized properties having default values */
2930 if (nparams == 0) {
2931 switch (icalproperty_isa(prop)) {
2933 if (strcmp("GREGORIAN", icalproperty_get_calscale(prop)) == 0) {
2934 remove = 1;
2935 }
2936 break;
2937
2940 remove = 1;
2941 }
2942 break;
2943
2945 if (icalproperty_get_priority(prop) == 0) {
2946 remove = 1;
2947 }
2948 break;
2949
2952 remove = 1;
2953 }
2954 break;
2955
2957 if (icalproperty_get_repeat(prop) == 0) {
2958 remove = 1;
2959 }
2960 break;
2961
2963 if (icalproperty_get_sequence(prop) == 0) {
2964 remove = 1;
2965 }
2966 break;
2967
2968 default:
2969 break;
2970 }
2971 }
2972
2973 if (remove) {
2974 icalproperty_set_parent(prop, 0); // MUST NOT have a parent to free
2975 icalproperty_free(prop);
2976 } else {
2977 icalpvl_insert_ordered(sorted_props, prop_compare, prop);
2978 }
2979 }
2980
2981 /* Drain the remaining properties */
2982 if (cnt == max_properties) {
2983 while ((prop = icalpvl_pop(comp->properties)) != 0) {
2984 icalproperty_set_parent(prop, 0); // MUST NOT have a parent to free
2985 icalproperty_free(prop);
2986 }
2987 }
2988
2989 icalpvl_free(comp->properties);
2990 comp->properties = sorted_props;
2991
2992 /* Normalize sub-components into sorted list */
2993 while ((sub = icalpvl_pop(comp->components)) != 0) {
2995 icalpvl_insert_ordered(sorted_comps, comp_compare, sub);
2996 }
2997
2998 icalpvl_free(comp->components);
2999 comp->components = sorted_comps;
3000}
void * icalarray_element_at(icalarray *array, size_t position)
Access an array element.
Definition icalarray.c:135
void icalarray_free(icalarray *array)
Definition icalarray.c:104
void icalarray_sort(icalarray *array, int(*compare)(const void *, const void *))
Sorts the elements of an icalarray using the given comparison function.
Definition icalarray.c:182
void icalarray_append(icalarray *array, const void *element)
Appends an element to an array.
Definition icalarray.c:119
icalarray * icalarray_new(size_t element_size, size_t increment_size)
Definition icalarray.c:36
void icalarray_remove_element_at(icalarray *array, size_t position)
Removes a given element from an array.
Definition icalarray.c:148
void icalcomponent_remove_property_by_kind(icalcomponent *component, icalproperty_kind kind)
void icalcomponent_convert_errors(icalcomponent *component)
icalcomponent * icalcomponent_new_xstandard(void)
void icalcomponent_set_relcalid(icalcomponent *comp, const char *v)
bool icalcomponent_is_valid(const icalcomponent *component)
icalproperty * icalpropiter_deref(icalpropiter *i)
icalcomponent * icalcomponent_new_vagenda(void)
void icalcomponent_set_uid(icalcomponent *comp, const char *v)
icalcomponent_kind icalcomponent_string_to_kind(const char *string)
void icalcomponent_set_x_name(icalcomponent *comp, const char *name)
struct icaltimetype icalcomponent_get_dtend(icalcomponent *comp)
struct icaltimetype icalcomponent_get_dtstart(icalcomponent *comp)
icalcomponent * icalcomponent_new_vlocation(void)
icalproperty * icalcomponent_get_first_property(icalcomponent *c, icalproperty_kind kind)
bool icalcomponent_check_restrictions(icalcomponent *comp)
icalcomponent * icalcomponent_new_vpoll(void)
int icalcomponent_count_properties(icalcomponent *component, icalproperty_kind kind)
icalcomponent * icalcomponent_new_vavailability(void)
icalcomponent * icalcomponent_new_xpatch(void)
icalproperty_method icalcomponent_get_method(icalcomponent *comp)
bool icalcompiter_is_valid(const icalcompiter *i)
icalcomponent * icalcomponent_new_vreply(void)
void icalcomponent_set_recurrenceid(icalcomponent *comp, struct icaltimetype v)
icalcomponent * icalcomponent_new_xvote(void)
struct icaltimetype icalcomponent_get_recurrenceid(icalcomponent *comp)
icalcomponent * icalcompiter_next(icalcompiter *i)
void icalcomponent_set_location(icalcomponent *comp, const char *v)
const char * icalcomponent_get_description(icalcomponent *comp)
void icalcomponent_set_iana_name(icalcomponent *comp, const char *name)
icalcomponent * icalcomponent_get_next_component(icalcomponent *c, icalcomponent_kind kind)
icalcomponent * icalcomponent_get_first_component(icalcomponent *c, icalcomponent_kind kind)
void icalcomponent_set_dtstart(icalcomponent *comp, struct icaltimetype v)
void icalcomponent_set_dtstamp(icalcomponent *comp, struct icaltimetype v)
void icalcomponent_strip_errors(icalcomponent *component)
icalcomponent * icalcomponent_new_vcalendar(void)
void icalcomponent_normalize(icalcomponent *comp)
icalpropiter icalcomponent_begin_property(icalcomponent *component, icalproperty_kind kind)
icalcomponent * icalcomponent_get_current_component(icalcomponent *component)
void icalcomponent_remove_property(icalcomponent *component, icalproperty *property)
char * icalcomponent_as_ical_string(const icalcomponent *component)
const char * icalcomponent_kind_to_string(icalcomponent_kind kind)
enum icalproperty_status icalcomponent_get_status(icalcomponent *comp)
icalcomponent * icalcomponent_new_vjournal(void)
void icalcomponent_remove_component(icalcomponent *parent, icalcomponent *child)
icalcomponent * icalcomponent_new_vpatch(void)
icalcomponent * icalcomponent_new_vfreebusy(void)
icalproperty * icalpropiter_next(icalpropiter *i)
icalcomponent * icalcompiter_deref(icalcompiter *i)
icalcomponent * icalcomponent_vanew(icalcomponent_kind kind,...)
void icalcomponent_set_method(icalcomponent *comp, icalproperty_method method)
icalcomponent * icalcomponent_new(icalcomponent_kind kind)
void icalcomponent_set_summary(icalcomponent *comp, const char *v)
void icalcomponent_set_sequence(icalcomponent *comp, int v)
icalcomponent * icalcomponent_get_inner(icalcomponent *comp)
const char * icalcomponent_get_comment(icalcomponent *comp)
const char * icalcomponent_get_summary(icalcomponent *comp)
icaltime_span icalcomponent_get_span(icalcomponent *comp)
const char * icalcomponent_get_relcalid(icalcomponent *comp)
icalcomponent * icalcomponent_get_first_real_component(const icalcomponent *c)
icalcomponent * icalcomponent_new_vtimezone(void)
struct icaltimetype icalcomponent_get_due(icalcomponent *comp)
void icalcomponent_merge_component(icalcomponent *comp, icalcomponent *comp_to_merge)
bool icalpropiter_is_valid(const icalpropiter *i)
icalcomponent * icalcomponent_new_vresource(void)
bool icalproperty_recurrence_is_excluded(icalcomponent *comp, struct icaltimetype *dtstart, struct icaltimetype *recurtime)
Decides if a recurrence is acceptable.
const char * icalcomponent_get_x_name(const icalcomponent *comp)
int icalcomponent_count_errors(icalcomponent *component)
struct icaldurationtype icalcomponent_get_duration(icalcomponent *comp)
icalcomponent * icalcomponent_clone(const icalcomponent *old)
icalcomponent * icalcomponent_new_iana(const char *iana_name)
icalcomponent * icalcomponent_new_xavailable(void)
icalcomponent * icalcomponent_new_participant(void)
const char * icalcomponent_get_iana_name(const icalcomponent *comp)
icalproperty * icalcomponent_get_current_property(icalcomponent *component)
icaltimezone * icalcomponent_get_timezone(icalcomponent *comp, const char *tzid)
void icalcomponent_set_dtend(icalcomponent *comp, struct icaltimetype v)
const char * icalcomponent_get_uid(icalcomponent *comp)
int icalcomponent_get_sequence(icalcomponent *comp)
icalcompiter icalcomponent_end_component(icalcomponent *component, icalcomponent_kind kind)
const char * icalcomponent_get_component_name(const icalcomponent *comp)
icalcomponent * icalcomponent_new_xdaylight(void)
icalcomponent * icalcomponent_new_valarm(void)
icalcomponent * icalcomponent_new_x(const char *x_name)
void icalcomponent_add_property(icalcomponent *component, icalproperty *property)
void icalcomponent_set_duration(icalcomponent *comp, struct icaldurationtype v)
icalcompiter icalcomponent_begin_component(icalcomponent *component, icalcomponent_kind kind)
char * icalcomponent_as_ical_string_r(const icalcomponent *component)
icalcomponent_kind icalcomponent_isa(const icalcomponent *component)
icalcomponent * icalcompiter_prior(icalcompiter *i)
icalcomponent * icalcomponent_new_vtodo(void)
bool icalcomponent_kind_is_valid(const icalcomponent_kind kind)
char * icalcomponent_get_component_name_r(const icalcomponent *comp)
void icalcomponent_set_status(icalcomponent *comp, enum icalproperty_status v)
void icalcomponent_foreach_tzid(icalcomponent *comp, void(*callback)(icalparameter *param, void *data), void *callback_data)
const char * icalcomponent_get_location(icalcomponent *comp)
void icalcomponent_free(icalcomponent *c)
icalcomponent * icalcomponent_new_vevent(void)
void icalcomponent_set_due(icalcomponent *comp, struct icaltimetype v)
void icalcomponent_foreach_recurrence(icalcomponent *comp, struct icaltimetype start, struct icaltimetype end, void(*callback)(icalcomponent *comp, const struct icaltime_span *span, void *data), void *callback_data)
void icalcomponent_add_component(icalcomponent *parent, icalcomponent *child)
icalproperty * icalcomponent_get_next_property(icalcomponent *c, icalproperty_kind kind)
void icalcomponent_set_description(icalcomponent *comp, const char *v)
icalcomponent * icalcomponent_new_from_string(const char *str)
int icalcomponent_count_components(icalcomponent *component, icalcomponent_kind kind)
void icalcomponent_set_comment(icalcomponent *comp, const char *v)
icalcomponent * icalcomponent_new_vquery(void)
bool icalcomponent_isa_component(const void *component)
icalcomponent * icalcomponent_new_vvoter(void)
struct icaltimetype icalcomponent_get_dtstamp(icalcomponent *comp)
Defines the data structure for iCalendar components.
icalcomponent * icalproperty_get_parent(const icalproperty *property)
struct icaltimetype icalproperty_get_datetime_with_component(icalproperty *prop, icalcomponent *comp)
void icalproperty_set_parent(icalproperty *property, icalcomponent *component)
icalparameter_xlicerrortype icalparameter_get_xlicerrortype(const icalparameter *value)
@ ICAL_TZID_PARAMETER
@ ICAL_XLICERRORTYPE_PARAMETER
void icalparameter_set_tzid(icalparameter *value, const char *v)
const char * icalparameter_get_tzid(const icalparameter *value)
struct icalparameter_impl icalparameter
icalparameter * icalparameter_new_tzid(const char *v)
@ ICAL_XLICERRORTYPE_PROPERTYPARSEERROR
@ ICAL_XLICERRORTYPE_PARAMETERNAMEPARSEERROR
@ ICAL_XLICERRORTYPE_PARAMETERVALUEPARSEERROR
@ ICAL_XLICERRORTYPE_VALUEPARSEERROR
@ ICAL_XLICERRORTYPE_COMPONENTPARSEERROR
void icalproperty_set_dtstart(icalproperty *prop, struct icaltimetype v)
int icalproperty_get_repeat(const icalproperty *prop)
enum icalproperty_transp icalproperty_get_transp(const icalproperty *prop)
const char * icalproperty_get_uid(const icalproperty *prop)
int icalproperty_get_sequence(const icalproperty *prop)
icalproperty * icalproperty_new_comment(const char *v)
void icalproperty_set_tzid(icalproperty *prop, const char *v)
struct icaltimetype icalproperty_get_dtstamp(const icalproperty *prop)
icalproperty * icalproperty_new_description(const char *v)
icalproperty * icalproperty_new_dtend(struct icaltimetype v)
void icalproperty_set_due(icalproperty *prop, struct icaltimetype v)
icalproperty * icalproperty_new_dtstamp(struct icaltimetype v)
void icalproperty_set_uid(icalproperty *prop, const char *v)
const char * icalproperty_get_description(const icalproperty *prop)
icalproperty * icalproperty_new_sequence(int v)
void icalproperty_set_comment(icalproperty *prop, const char *v)
void icalproperty_set_sequence(icalproperty *prop, int v)
void icalproperty_set_dtend(icalproperty *prop, struct icaltimetype v)
const char * icalproperty_get_summary(const icalproperty *prop)
struct icalrecurrencetype * icalproperty_get_exrule(const icalproperty *prop)
icalproperty * icalproperty_new_method(enum icalproperty_method v)
struct icaldurationtype icalproperty_get_duration(const icalproperty *prop)
icalproperty * icalproperty_new_relcalid(const char *v)
void icalproperty_set_duration(icalproperty *prop, struct icaldurationtype v)
const char * icalproperty_get_comment(const icalproperty *prop)
void icalproperty_set_summary(icalproperty *prop, const char *v)
enum icalproperty_status icalproperty_get_status(const icalproperty *prop)
void icalproperty_set_location(icalproperty *prop, const char *v)
enum icalproperty_class icalproperty_get_class(const icalproperty *prop)
void icalproperty_set_recurrenceid(icalproperty *prop, struct icaltimetype v)
struct icalrecurrencetype * icalproperty_get_rrule(const icalproperty *prop)
icalproperty * icalproperty_new_uid(const char *v)
const char * icalproperty_get_tzid(const icalproperty *prop)
struct icaldatetimeperiodtype icalproperty_get_rdate(const icalproperty *prop)
void icalproperty_set_relcalid(icalproperty *prop, const char *v)
enum icalproperty_method icalproperty_get_method(const icalproperty *prop)
void icalproperty_set_method(icalproperty *prop, enum icalproperty_method v)
const char * icalproperty_get_calscale(const icalproperty *prop)
icalproperty * icalproperty_new_summary(const char *v)
icalproperty * icalproperty_new_location(const char *v)
void icalproperty_set_dtstamp(icalproperty *prop, struct icaltimetype v)
const char * icalproperty_get_xlicerror(const icalproperty *prop)
icalproperty * icalproperty_new_duration(struct icaldurationtype v)
icalproperty * icalproperty_new_requeststatus(struct icalreqstattype v)
icalproperty_kind
@ ICAL_CALSCALE_PROPERTY
@ ICAL_ANY_PROPERTY
@ ICAL_RELCALID_PROPERTY
@ ICAL_UID_PROPERTY
@ ICAL_RRULE_PROPERTY
@ ICAL_RDATE_PROPERTY
@ ICAL_DURATION_PROPERTY
@ ICAL_COMMENT_PROPERTY
@ ICAL_EXRULE_PROPERTY
@ ICAL_DESCRIPTION_PROPERTY
@ ICAL_TRANSP_PROPERTY
@ ICAL_XLICERROR_PROPERTY
@ ICAL_TZID_PROPERTY
@ ICAL_SUMMARY_PROPERTY
@ ICAL_SEQUENCE_PROPERTY
@ ICAL_RECURRENCEID_PROPERTY
@ ICAL_PRIORITY_PROPERTY
@ ICAL_EXDATE_PROPERTY
@ ICAL_METHOD_PROPERTY
@ ICAL_POLLITEMID_PROPERTY
@ ICAL_DUE_PROPERTY
@ ICAL_ACTION_PROPERTY
@ ICAL_VOTER_PROPERTY
@ ICAL_STATUS_PROPERTY
@ ICAL_DTSTAMP_PROPERTY
@ ICAL_LOCATION_PROPERTY
@ ICAL_DTEND_PROPERTY
@ ICAL_DTSTART_PROPERTY
@ ICAL_REPEAT_PROPERTY
@ ICAL_TRIGGER_PROPERTY
@ ICAL_X_PROPERTY
@ ICAL_CLASS_PROPERTY
@ ICAL_NO_PROPERTY
int icalproperty_get_priority(const icalproperty *prop)
void icalproperty_set_description(icalproperty *prop, const char *v)
icalproperty * icalproperty_new_dtstart(struct icaltimetype v)
const char * icalproperty_get_location(const icalproperty *prop)
void icalproperty_set_status(icalproperty *prop, enum icalproperty_status v)
icalproperty * icalproperty_new_due(struct icaltimetype v)
icalproperty * icalproperty_new_status(enum icalproperty_status v)
icalproperty * icalproperty_new_recurrenceid(struct icaltimetype v)
const char * icalproperty_get_relcalid(const icalproperty *prop)
icalproperty_status
@ ICAL_STATUS_TENTATIVE
@ ICAL_STATUS_CANCELLED
@ ICAL_STATUS_NONE
icalproperty_method
@ ICAL_METHOD_NONE
enum icalproperty_transp icalvalue_get_transp(const icalvalue *value)
@ ICAL_CLASS_PUBLIC
@ ICAL_TRANSP_TRANSPARENT
@ ICAL_TRANSP_OPAQUENOCONFLICT
@ ICAL_TRANSP_NONE
@ ICAL_TRANSP_OPAQUE
@ ICAL_TRANSP_TRANSPARENTNOCONFLICT
struct icalvalue_impl icalvalue
struct icaldurationtype icalduration_from_times(struct icaltimetype t1, struct icaltimetype t2)
Creates a duration from two icaltimetype endpoints.
struct icaltimetype icalduration_extend(struct icaltimetype t, struct icaldurationtype d)
Extends a time duration.
bool icaldurationtype_is_null_duration(struct icaldurationtype d)
Checks if a duration is a null duration.
struct icaldurationtype icaldurationtype_null_duration(void)
Creates a duration with zero length.
enum icalrequeststatus kind
Definition icalenums.c:26
const char * str
Definition icalenums.c:29
icalcomponent_kind
Definition icalenums.h:29
@ ICAL_X_COMPONENT
Definition icalenums.h:48
@ ICAL_XROOT_COMPONENT
Definition icalenums.h:32
@ ICAL_XDAYLIGHT_COMPONENT
Definition icalenums.h:47
@ ICAL_VREPLY_COMPONENT
Definition icalenums.h:51
@ ICAL_VLOCATION_COMPONENT
Definition icalenums.h:65
@ ICAL_XSTANDARD_COMPONENT
Definition icalenums.h:46
@ ICAL_NO_COMPONENT
Definition icalenums.h:30
@ ICAL_VFREEBUSY_COMPONENT
Definition icalenums.h:39
@ ICAL_VTODO_COMPONENT
Definition icalenums.h:35
@ ICAL_PARTICIPANT_COMPONENT
Definition icalenums.h:64
@ ICAL_VEVENT_COMPONENT
Definition icalenums.h:34
@ ICAL_VPATCH_COMPONENT
Definition icalenums.h:62
@ ICAL_VCALENDAR_COMPONENT
Definition icalenums.h:37
@ ICAL_VAVAILABILITY_COMPONENT
Definition icalenums.h:57
@ ICAL_IANA_COMPONENT
Definition icalenums.h:67
@ ICAL_VSCHEDULE_COMPONENT
Definition icalenums.h:49
@ ICAL_XVOTE_COMPONENT
Definition icalenums.h:61
@ ICAL_VAGENDA_COMPONENT
Definition icalenums.h:38
@ ICAL_ANY_COMPONENT
Definition icalenums.h:31
@ ICAL_VTIMEZONE_COMPONENT
Definition icalenums.h:45
@ ICAL_VJOURNAL_COMPONENT
Definition icalenums.h:36
@ ICAL_VVOTER_COMPONENT
Definition icalenums.h:60
@ ICAL_VCAR_COMPONENT
Definition icalenums.h:52
@ ICAL_VCOMMAND_COMPONENT
Definition icalenums.h:53
@ ICAL_VQUERY_COMPONENT
Definition icalenums.h:50
@ ICAL_XLICMIMEPART_COMPONENT
Definition icalenums.h:55
@ ICAL_XPATCH_COMPONENT
Definition icalenums.h:63
@ ICAL_VPOLL_COMPONENT
Definition icalenums.h:59
@ ICAL_XAVAILABLE_COMPONENT
Definition icalenums.h:58
@ ICAL_XLICINVALID_COMPONENT
Definition icalenums.h:54
@ ICAL_VRESOURCE_COMPONENT
Definition icalenums.h:66
@ ICAL_VALARM_COMPONENT
Definition icalenums.h:40
@ ICAL_3_2_INVPARAM_STATUS
Definition icalenums.h:95
@ ICAL_3_0_INVPROPNAME_STATUS
Definition icalenums.h:93
@ ICAL_3_1_INVPROPVAL_STATUS
Definition icalenums.h:94
@ ICAL_3_4_INVCOMP_STATUS
Definition icalenums.h:97
@ ICAL_3_3_INVPARAMVAL_STATUS
Definition icalenums.h:96
@ ICAL_UNKNOWN_STATUS
Definition icalenums.h:80
void icalerror_set_errno(icalerrorenum x)
Sets the icalerrno to a given error.
Definition icalerror.c:90
Error handling for libical.
@ ICAL_NEWFAILED_ERROR
Definition icalerror.h:50
@ ICAL_BADARG_ERROR
Definition icalerror.h:47
@ ICAL_ALLOCATION_ERROR
Definition icalerror.h:53
@ ICAL_MALFORMEDDATA_ERROR
Definition icalerror.h:59
@ ICAL_USAGE_ERROR
Definition icalerror.h:71
size_t icallimit_get(icallimits_kind kind)
Definition icallimits.c:29
Defines the interface for getting/setting internal library limits.
@ ICAL_LIMIT_PROPERTIES
Definition icallimits.h:30
void icalmemory_free_buffer(void *buf)
Releases a buffer.
Definition icalmemory.c:355
char * icalmemory_strdup(const char *s)
Creates a duplicate of a string.
Definition icalmemory.c:242
void icalmemory_append_string(char **buf, char **pos, size_t *buf_size, const char *string)
Appends a string to a buffer.
Definition icalmemory.c:365
void * icalmemory_new_buffer(size_t size)
Creates new buffer with the specified size.
Definition icalmemory.c:315
void icalmemory_add_tmp_buffer(void *buf)
Adds an externally allocated buffer to the ring.
Definition icalmemory.c:158
Common memory management routines.
icalcomponent * icalparser_parse_string(const char *str)
Parses a string and returns the parsed icalcomponent.
Line-oriented parsing.
icalvalue * icalproperty_get_value(const icalproperty *prop)
bool icalproperty_isa_property(void *property)
void icalproperty_free(icalproperty *p)
char * icalproperty_as_ical_string_r(icalproperty *prop)
icalproperty_kind icalproperty_isa(const icalproperty *p)
int icalproperty_count_parameters(const icalproperty *prop)
const char * icalproperty_get_value_as_string(const icalproperty *prop)
void icalproperty_remove_parameter_by_kind(icalproperty *prop, icalparameter_kind kind)
Removes all parameters with the specified kind.
icalparameter * icalproperty_get_first_parameter(icalproperty *p, icalparameter_kind kind)
void icalproperty_add_parameter(icalproperty *p, icalparameter *parameter)
void icalproperty_normalize(icalproperty *prop)
icalproperty * icalproperty_clone(const icalproperty *old)
const char * icalproperty_get_x_name(const icalproperty *prop)
void icalproperty_set_parameter(icalproperty *prop, icalparameter *parameter)
bool icalrecur_iterator_set_start(icalrecur_iterator *impl, struct icaltimetype start)
Definition icalrecur.c:4129
void icalrecur_iterator_free(icalrecur_iterator *impl)
Definition icalrecur.c:2469
icalrecur_iterator * icalrecur_iterator_new(struct icalrecurrencetype *rule, struct icaltimetype dtstart)
Definition icalrecur.c:2341
struct icaltimetype icalrecur_iterator_next(icalrecur_iterator *impl)
Definition icalrecur.c:3714
Functions to check if an icalcomponent meets the restrictions imposed by the standard.
bool icalrestriction_check(icalcomponent *comp)
Checks if a given VCALENDAR meets all the restrictions imposed by the standard.
void icalstrarray_append(icalstrarray *array, const char *elem)
Appends a string to the array.
void icalstrarray_free(icalstrarray *array)
Frees this array's memory and all its elements.
#define icalstrarray_new(increment_size)
Creates a new icalstrarray object.
bool icaltime_is_date(const struct icaltimetype t)
Definition icaltime.c:634
const char * icaltime_get_tzid(const struct icaltimetype t)
Definition icaltime.c:888
bool icaltime_is_utc(const struct icaltimetype t)
Definition icaltime.c:639
int icaltime_compare_date_only(const struct icaltimetype a_in, const struct icaltimetype b_in)
Definition icaltime.c:722
bool icaltime_is_null_time(const struct icaltimetype t)
Definition icaltime.c:644
icaltime_t icaltime_as_timet_with_zone(const struct icaltimetype tt, const icaltimezone *zone)
Definition icaltime.c:297
int icaltime_compare(const struct icaltimetype a_in, const struct icaltimetype b_in)
Definition icaltime.c:653
struct icaltimetype icaltime_null_time(void)
Definition icaltime.c:584
icalcomponent * icaltimezone_get_component(icaltimezone *zone)
const char * icaltimezone_get_tzid(icaltimezone *zone)
icaltimezone * icaltimezone_get_utc_timezone(void)
void icaltimezone_free(icaltimezone *zone, int free_struct)
Frees all memory used for the icaltimezone.
Timezone handling routines.
struct _icaltimezone icaltimezone
struct icaltimetype time
Definition icaltypes.h:30
struct icalperiodtype period
Definition icaltypes.h:31
unsigned int days
struct icaldurationtype duration
Definition icalperiod.h:36
struct icaltimetype end
Definition icalperiod.h:34
struct icaltimetype start
Definition icalperiod.h:31
const char * desc
Definition icaltypes.h:112
const char * debug
Definition icaltypes.h:113
icalrequeststatus code
Definition icaltypes.h:111
const icaltimezone * zone
Definition icaltime.h:102