Libical API Documentation 4.0 STABLE VERSION Visit the v3.0 documentation
Loading...
Searching...
No Matches
icalproperty.c
Go to the documentation of this file.
1/*======================================================================
2 FILE: icalproperty.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 "icalproperty_p.h"
19#include "icalcomponent.h"
20#include "icalerror_p.h"
21#include "icalerror.h"
22#include "icalmemory.h"
23#include "icalparser.h"
24#include "icaltimezone.h"
25#include "icalvalue.h"
26#include "icalpvl_p.h"
27#include "icaltypes_p.h"
28
29#include <stdlib.h>
30
31struct icalproperty_impl {
32 icalstructuretype id;
33 icalproperty_kind kind;
34 char *x_name;
35 icalpvl_list parameters;
36 icalpvl_elem parameter_iterator;
37 icalvalue *value;
38 icalcomponent *parent;
39};
40
42LIBICAL_ICAL_EXPORT struct icalproperty_impl *icalproperty_new_impl(icalproperty_kind kind)
43{
44 icalproperty *prop;
45
46 if (!icalproperty_kind_is_valid(kind)) {
47 return NULL;
48 }
49
50 if ((prop = (icalproperty *)icalmemory_new_buffer(sizeof(icalproperty))) == 0) {
52 return 0;
53 }
54
55 memset(prop, 0, sizeof(icalproperty));
56
57 prop->id = ICAL_STRUCTURE_TYPE_PROPERTY;
58 prop->kind = kind;
59 prop->parameters = icalpvl_newlist();
60
61 return prop;
62}
64
65static ICAL_GLOBAL_VAR bool icalprop_allow_empty_properties = false;
66
68{
69 icalprop_allow_empty_properties = enable;
70}
71
73{
74 return icalprop_allow_empty_properties;
75}
76
77void icalproperty_add_parameters(icalproperty *prop, va_list args)
78{
79 void *vp;
80
81 while ((vp = va_arg(args, void *)) != 0) {
82 if (icalvalue_isa_value(vp)) {
83 } else if (icalparameter_isa_parameter(vp)) {
84 icalproperty_add_parameter((icalproperty *)prop, (icalparameter *)vp);
85 } else {
87 }
88 }
89}
90
91icalproperty *icalproperty_new(icalproperty_kind kind)
92{
93 if (kind == ICAL_NO_PROPERTY) {
94 return 0;
95 }
96
97 return (icalproperty *)icalproperty_new_impl(kind);
98}
99
100icalproperty *icalproperty_clone(const icalproperty *old)
101{
102 icalproperty *clone;
103 icalpvl_elem p;
104
105 icalerror_check_arg_rz((old != 0), "old");
106 clone = icalproperty_new_impl(old->kind);
107 icalerror_check_arg_rz((clone != 0), "clone");
108
109 if (old->value != 0) {
110 clone->value = icalvalue_clone(old->value);
111 }
112
113 if (old->x_name != 0) {
114 clone->x_name = icalmemory_strdup(old->x_name);
115
116 if (clone->x_name == 0) {
117 icalproperty_free(clone);
119 return 0;
120 }
121 }
122
123 for (p = icalpvl_head(old->parameters); p != 0; p = icalpvl_next(p)) {
124 icalparameter *param = icalparameter_clone(icalpvl_data(p));
125
126 if (param == 0) {
127 icalproperty_free(clone);
129 return 0;
130 }
131
132 icalpvl_push(clone->parameters, param);
133 }
134
135 return clone;
136}
137
138icalproperty *icalproperty_new_from_string(const char *str)
139{
140 size_t buf_size = 1024;
141 char *buf;
142 char *buf_ptr;
143 icalproperty *prop;
144 icalcomponent *comp;
145 int errors = 0;
146
147 icalerror_check_arg_rz((str != 0), "str");
148
149 buf = icalmemory_new_buffer(buf_size);
150 buf_ptr = buf;
151
152 /* Is this a HACK or a crafty reuse of code? */
153
154 icalmemory_append_string(&buf, &buf_ptr, &buf_size, "BEGIN:VCALENDAR\r\n");
155 icalmemory_append_string(&buf, &buf_ptr, &buf_size, str);
156 icalmemory_append_string(&buf, &buf_ptr, &buf_size, "\r\n");
157 icalmemory_append_string(&buf, &buf_ptr, &buf_size, "END:VCALENDAR\r\n");
158
159 comp = icalparser_parse_string(buf);
160
161 if (comp == 0) {
164 return 0;
165 }
166
167 errors = icalcomponent_count_errors(comp);
168
169 prop = icalcomponent_get_first_property(comp, ICAL_ANY_PROPERTY);
170
172
173 icalcomponent_free(comp);
175
176 if (errors > 0) {
177 icalproperty_free(prop);
178 return 0;
179 } else {
180 return prop;
181 }
182}
183
184void icalproperty_free(icalproperty *p)
185{
186 icalparameter *param;
187
188 icalerror_check_arg_rv((p != 0), "prop");
189
190 if (p->parent != 0) {
191 return;
192 }
193
194 if (p->value != 0) {
195 icalvalue_set_parent(p->value, 0);
196 icalvalue_free(p->value);
197 }
198
199 while ((param = icalpvl_pop(p->parameters)) != 0) {
200 icalparameter_free(param);
201 }
202
203 icalpvl_free(p->parameters);
204 icalmemory_free_buffer(p->x_name);
205
206 p->kind = ICAL_NO_PROPERTY;
207 p->parameters = 0;
208 p->parameter_iterator = 0;
209 p->value = 0;
210 p->x_name = 0;
211 p->id = ICAL_STRUCTURE_TYPE_PROPERTY_EMPTY;
212
214}
215
216/* This returns where the start of the next line should be. chars_left does
217 not include the trailing '\0'. */
218static const size_t MAX_LINE_LEN = 75;
219
220static char *get_next_line_start(char *line_start, size_t chars_left)
221{
222 char *pos;
223
224 /* If we have 74 chars or less left, we can output all of them.
225 we return a pointer to the '\0' at the end of the string. */
226 if (chars_left < MAX_LINE_LEN) {
227 return line_start + chars_left;
228 }
229
230 /* Now we jump to the last possible character of the line, and step back
231 trying to find a ';' ':' or ' '. If we find one, we return the character
232 after it. */
233 pos = line_start + MAX_LINE_LEN - 2;
234 while (pos > line_start) {
235 if (*pos == ';' || *pos == ':' || *pos == ' ') {
236 return pos + 1;
237 }
238 pos--;
239 }
240 /* Now try to split on a UTF-8 boundary defined as a 7-bit
241 value or as a byte with the two high-most bits set:
242 11xxxxxx. See https://czyborra.com/utf/ */
243
244 pos = line_start + MAX_LINE_LEN - 1;
245 while (pos > line_start) {
246 /* plain ascii */
247 if ((*pos & 128) == 0) {
248 return pos;
249 }
250
251 /* utf8 escape byte */
252 if ((*pos & 192) == 192) {
253 return pos;
254 }
255
256 pos--;
257 }
258
259 /* Give up, just break at 74 chars (the 75th char is the space at
260 the start of the line). */
261
262 return line_start + MAX_LINE_LEN - 1;
263}
264
271static char *fold_property_line(char *text)
272{
273 size_t buf_size, len;
274 ssize_t chars_left;
275 char *buf, *buf_ptr, *line_start, *next_line_start;
276 int first_line;
277
278 /* Start with a buffer twice the size of our property line, so we almost
279 certainly won't overflow it. */
280 len = strlen(text);
281 buf_size = len * 2;
282 buf = icalmemory_new_buffer(buf_size);
283 buf_ptr = buf;
284
285 /* Step through the text, finding each line to add to the output. */
286 line_start = text;
287 chars_left = (ssize_t)len;
288 first_line = 1;
289 for (;;) {
290 if (chars_left <= 0) {
291 break;
292 }
293
294 /* This returns the first character for the next line. */
295 next_line_start = get_next_line_start(line_start, (size_t)chars_left);
296
297 /* If this isn't the first line, we need to output a newline and space
298 first. */
299 if (!first_line) {
300 icalmemory_append_string(&buf, &buf_ptr, &buf_size, "\r\n ");
301 }
302 first_line = 0;
303
304 /* This adds the line to our tmp buffer. We temporarily place a '\0'
305 in text, so we can copy the line in one go. */
306 char ch = *next_line_start;
307 *next_line_start = '\0';
308 icalmemory_append_string(&buf, &buf_ptr, &buf_size, line_start);
309 *next_line_start = ch;
310
311 /* Now we move on to the next line. */
312 chars_left -= (next_line_start - line_start);
313 line_start = next_line_start;
314 }
315
316 icalmemory_append_string(&buf, &buf_ptr, &buf_size, "\r\n");
317
318 return buf;
319}
320
321/* Determine what VALUE parameter to include. The VALUE parameters
322 are ignored in the normal parameter printing ( the block after
323 this one, so we need to do it here */
324static const char *icalproperty_get_value_kind(icalproperty *prop)
325{
326 const char *kind_string = NULL;
327 if (!prop) {
328 return kind_string;
329 }
330
331 icalvalue_kind kind = ICAL_NO_VALUE;
332 icalparameter *val_param =
333 icalproperty_get_first_parameter(prop, ICAL_VALUE_PARAMETER);
334
335 if (val_param) {
336 kind = icalparameter_value_to_value_kind(icalparameter_get_value(val_param));
337 }
338
339 if (kind == ICAL_NO_VALUE) {
340 icalvalue *value = icalproperty_get_value(prop);
341
342 kind = icalvalue_isa(value);
343
344 if (kind == ICAL_ATTACH_VALUE) {
345 icalattach *a = icalvalue_get_attach(value);
346
347 kind = icalattach_get_is_url(a) ? ICAL_URI_VALUE : ICAL_BINARY_VALUE;
348 }
349 }
350
351 if (kind != ICAL_NO_VALUE &&
352 !icalproperty_value_kind_is_default(prop->kind, kind)) {
353 /* Not the default, so it must be specified */
354 kind_string = icalvalue_kind_to_string(kind);
355 } else {
356 /* Don't include the VALUE parameter at all */
357 }
358
359 return kind_string;
360}
361
362const char *icalproperty_as_ical_string(icalproperty *prop)
363{
364 const char *buf;
365
367 icalmemory_add_tmp_buffer((char *)buf);
368 return buf;
369}
370
371char *icalproperty_as_ical_string_r(icalproperty *prop)
372{
373 icalparameter *param;
374
375 /* Create new buffer that we can append names, parameters and a
376 * value to, and reallocate as needed.
377 */
378
379 const char *property_name = 0;
380 size_t buf_size = 1024;
381 char *buf;
382 char *buf_ptr;
383 const icalvalue *value;
384 char *out_buf;
385 const char *kind_string = 0;
386
387 icalerror_check_arg_rz((prop != 0), "prop");
388
389 buf = icalmemory_new_buffer(buf_size);
390 buf_ptr = buf;
391
392 /* Append property name */
393
394 if ((prop->kind == ICAL_X_PROPERTY || prop->kind == ICAL_IANA_PROPERTY) && prop->x_name != 0) {
395 property_name = prop->x_name;
396 } else {
397 property_name = icalproperty_kind_to_string(prop->kind);
398 }
399
400 if (property_name == 0) {
401 icalerror_warn("Got a property of an unknown kind.");
403 return 0;
404 }
405
406 icalmemory_append_string(&buf, &buf_ptr, &buf_size, property_name);
407
408 kind_string = icalproperty_get_value_kind(prop);
409 if (kind_string != 0) {
410 icalmemory_append_string(&buf, &buf_ptr, &buf_size, ";VALUE=");
411 icalmemory_append_string(&buf, &buf_ptr, &buf_size, kind_string);
412 }
413
414 /* Append parameters */
415 for (param = icalproperty_get_first_parameter(prop, ICAL_ANY_PARAMETER);
416 param != 0; param = icalproperty_get_next_parameter(prop, ICAL_ANY_PARAMETER)) {
417 icalparameter_kind kind = icalparameter_isa(param);
418
419 kind_string = icalparameter_as_ical_string_r(param);
420
421 if (kind_string == 0) {
422 icalerror_warn("Got a parameter of unknown kind for the following property");
423
424 icalerror_warn((property_name) ? property_name : "(NULL)");
425 continue;
426 }
427
428 if (kind == ICAL_VALUE_PARAMETER) {
429 icalmemory_free_buffer((char *)kind_string);
430 continue;
431 }
432
433 icalmemory_append_string(&buf, &buf_ptr, &buf_size, ";");
434 icalmemory_append_string(&buf, &buf_ptr, &buf_size, kind_string);
435 icalmemory_free_buffer((char *)kind_string);
436 }
437
438 /* Append value */
439
440 icalmemory_append_string(&buf, &buf_ptr, &buf_size, ":");
441
442 value = icalproperty_get_value(prop);
443
444 if (value != 0) {
445 char *str = icalvalue_as_ical_string_r(value);
446
447 if (str != 0) {
448 icalmemory_append_string(&buf, &buf_ptr, &buf_size, str);
450 icalmemory_append_string(&buf, &buf_ptr, &buf_size, "ERROR: No Value");
451 }
454 icalmemory_append_string(&buf, &buf_ptr, &buf_size, "ERROR: No Value");
455 }
456
457 /* We now use a function to fold the line properly every 75 characters.
458 That function also adds the newline for us. */
459 out_buf = fold_property_line(buf);
460
462
463 return out_buf;
464}
465
466icalproperty_kind icalproperty_isa(const icalproperty *p)
467{
468 if (p != 0) {
469 return p->kind;
470 }
471
472 return ICAL_NO_PROPERTY;
473}
474
475bool icalproperty_isa_property(void *property)
476{
477 const icalproperty *impl = (icalproperty *)property;
478
479 icalerror_check_arg_rz((property != 0), "property");
480 return (impl->id == ICAL_STRUCTURE_TYPE_PROPERTY);
481}
482
483void icalproperty_add_parameter(icalproperty *p, icalparameter *parameter)
484{
485 icalerror_check_arg_rv((p != 0), "prop");
486 icalerror_check_arg_rv((parameter != 0), "parameter");
487
488 icalpvl_push(p->parameters, parameter);
489}
490
491void icalproperty_set_parameter(icalproperty *prop, icalparameter *parameter)
492{
493 icalparameter_kind kind;
494
495 icalerror_check_arg_rv((prop != 0), "prop");
496 icalerror_check_arg_rv((parameter != 0), "parameter");
497
498 kind = icalparameter_isa(parameter);
499 if (kind == ICAL_X_PARAMETER) {
501 } else if (kind == ICAL_IANA_PARAMETER) {
503 } else {
505 }
506
507 icalproperty_add_parameter(prop, parameter);
508}
509
511 const char *name, const char *value)
512{
513 icalparameter_kind kind;
514 icalparameter *param;
515
516 icalerror_check_arg_rv((prop != 0), "prop");
517 icalerror_check_arg_rv((name != 0), "name");
518 icalerror_check_arg_rv((value != 0), "value");
519
520 kind = icalparameter_string_to_kind(name);
521
522 if (kind == ICAL_NO_PARAMETER) {
524 return;
525 }
526
527 param = icalparameter_new_from_value_string(kind, value);
528
529 if (param == 0) {
531 return;
532 }
533
534 if (kind == ICAL_X_PARAMETER) {
535 icalparameter_set_xname(param, name);
536 } else if (kind == ICAL_IANA_PARAMETER) {
537 icalparameter_set_iana_name(param, name);
538 }
539
540 icalproperty_set_parameter(prop, param);
541}
542
543const char *icalproperty_get_parameter_as_string(icalproperty *prop, const char *name)
544{
545 char *buf;
546
549 return buf;
550}
551
552char *icalproperty_get_parameter_as_string_r(icalproperty *prop, const char *name)
553{
554 icalparameter_kind kind;
555 icalparameter *param;
556 char *str;
557 const char *t;
558 const char *pv;
559 const char *pvql;
560 char *pvqr;
561
562 icalerror_check_arg_rz((prop != 0), "prop");
563 icalerror_check_arg_rz((name != 0), "name");
564
565 kind = icalparameter_string_to_kind(name);
566
567 if (kind == ICAL_NO_PARAMETER) {
568 /* icalenum_string_to_parameter_kind will set icalerrno */
569 return 0;
570 }
571
572 for (param = icalproperty_get_first_parameter(prop, kind);
573 param != 0; param = icalproperty_get_next_parameter(prop, kind)) {
574 if (kind == ICAL_X_PARAMETER) {
575 if (strcmp(icalparameter_get_xname(param), name) == 0) {
576 break;
577 }
578 } else if (kind == ICAL_IANA_PARAMETER) {
579 if (strcmp(icalparameter_get_iana_name(param), name) == 0) {
580 break;
581 }
582 } else {
583 break;
584 }
585 }
586
587 if (param == 0) {
588 return 0;
589 }
590
592
593 t = strchr(str, '=');
594
595 if (t == 0) {
598 return 0;
599 }
600
601 /* Strip the property name and the equal sign */
602 pv = icalmemory_strdup(t + 1);
604
605 /* Is the string quoted? */
606 pvql = strchr(pv, '"');
607 if (pvql == 0) {
608 return ((char *)pv); /* No quotes? Return it immediately. */
609 }
610
611 /* Strip everything up to the first quote */
612 str = icalmemory_strdup(pvql + 1);
613 icalmemory_free_buffer((char *)pv);
614
615 /* Search for the end quote */
616 pvqr = strrchr(str, '"');
617 if (pvqr == 0) {
620 return 0;
621 }
622
623 *pvqr = '\0';
624 return str;
625}
626
627void icalproperty_remove_parameter_by_kind(icalproperty *prop, icalparameter_kind kind)
628{
629 icalpvl_elem p, next;
630
631 icalerror_check_arg_rv((prop != 0), "prop");
632
633 for (p = icalpvl_head(prop->parameters); p != 0; p = next) {
634 next = icalpvl_next(p);
635
636 icalparameter *param = (icalparameter *)icalpvl_data(p);
637
638 if (icalparameter_isa(param) == kind) {
639 (void)icalpvl_remove(prop->parameters, p);
640 icalparameter_free(param);
641 }
642 }
643}
644
645void icalproperty_remove_parameter_by_name(icalproperty *prop, const char *name)
646{
647 icalpvl_elem p, next;
648
649 icalerror_check_arg_rv((prop != 0), "prop");
650
651 for (p = icalpvl_head(prop->parameters); p != 0; p = next) {
652 next = icalpvl_next(p);
653
654 icalparameter *param = (icalparameter *)icalpvl_data(p);
655 const char *kind_string;
656
657 if (icalparameter_isa(param) == ICAL_X_PARAMETER) {
658 kind_string = icalparameter_get_xname(param);
659 } else if (icalparameter_isa(param) == ICAL_IANA_PARAMETER) {
660 kind_string = icalparameter_get_iana_name(param);
661 } else {
663 }
664
665 if (!kind_string) {
666 continue;
667 }
668
669 if (0 == strcasecmp(kind_string, name)) {
670 (void)icalpvl_remove(prop->parameters, p);
671 icalparameter_free(param);
672 }
673 }
674}
675
676void icalproperty_remove_parameter_by_ref(icalproperty *prop, icalparameter *parameter)
677{
678 icalpvl_elem p;
679
680 icalerror_check_arg_rv((prop != 0), "prop");
681 icalerror_check_arg_rv((parameter != 0), "parameter");
682
683 for (p = icalpvl_head(prop->parameters); p != 0; p = icalpvl_next(p)) {
684 icalparameter *p_param = (icalparameter *)icalpvl_data(p);
685
686 if (icalparameter_has_same_name(parameter, p_param)) {
687 (void)icalpvl_remove(prop->parameters, p);
688 icalparameter_free(p_param);
689 break;
690 }
691 }
692}
693
694int icalproperty_count_parameters(const icalproperty *prop)
695{
696 if (prop != 0) {
697 return icalpvl_count(prop->parameters);
698 }
699
701 return -1;
702}
703
704icalparameter *icalproperty_get_first_parameter(icalproperty *p, icalparameter_kind kind)
705{
706 icalerror_check_arg_rz((p != 0), "prop");
707
708 p->parameter_iterator = icalpvl_head(p->parameters);
709
710 if (p->parameter_iterator == 0) {
711 return 0;
712 }
713
714 for (p->parameter_iterator = icalpvl_head(p->parameters);
715 p->parameter_iterator != 0; p->parameter_iterator = icalpvl_next(p->parameter_iterator)) {
716 icalparameter *param = (icalparameter *)icalpvl_data(p->parameter_iterator);
717
718 if (icalparameter_isa(param) == kind || kind == ICAL_ANY_PARAMETER) {
719 return param;
720 }
721 }
722
723 return 0;
724}
725
726icalparameter *icalproperty_get_next_parameter(icalproperty *p, icalparameter_kind kind)
727{
728 icalerror_check_arg_rz((p != 0), "prop");
729
730 if (p->parameter_iterator == 0) {
731 return 0;
732 }
733
734 for (p->parameter_iterator = icalpvl_next(p->parameter_iterator);
735 p->parameter_iterator != 0; p->parameter_iterator = icalpvl_next(p->parameter_iterator)) {
736 icalparameter *param = (icalparameter *)icalpvl_data(p->parameter_iterator);
737
738 if (icalparameter_isa(param) == kind || kind == ICAL_ANY_PARAMETER) {
739 return param;
740 }
741 }
742
743 return 0;
744}
745
746void icalproperty_set_value(icalproperty *p, icalvalue *value)
747{
748 icalvalue_kind kind;
749
750 icalerror_check_arg_rv((p != 0), "prop");
751 icalerror_check_arg_rv((value != 0), "value");
752
753 if (p->value != 0) {
754 icalvalue_set_parent(p->value, 0);
755 icalvalue_free(p->value);
756 p->value = 0;
757 }
758
759 p->value = value;
760
761 icalvalue_set_parent(value, p);
762
763 kind = icalvalue_isa(value);
764 if (kind == ICAL_DATE_VALUE || kind == ICAL_DATETIME_VALUE) {
765 icalparameter *val_param;
766
767 val_param = icalproperty_get_first_parameter(p, ICAL_VALUE_PARAMETER);
768
769 if (val_param &&
770 icalparameter_value_to_value_kind(icalparameter_get_value(val_param)) != kind) {
771 icalproperty_remove_parameter_by_kind(p, ICAL_VALUE_PARAMETER);
772 }
773 }
774}
775
776void icalproperty_set_value_from_string(icalproperty *prop, const char *str, const char *type)
777{
778 icalvalue *nval;
779 icalvalue_kind kind = ICAL_NO_VALUE;
780
781 icalerror_check_arg_rv((prop != 0), "prop");
782 icalerror_check_arg_rv((str != 0), "str");
783 icalerror_check_arg_rv((type != 0), "type");
784
785 if (strcmp(type, "NO") == 0) {
786 /* Get the type from the value the property already has, if it exists */
787 const icalvalue *oval = icalproperty_get_value(prop);
788 if (oval != 0) {
789 /* Use the existing value kind */
790 kind = icalvalue_isa(oval);
791 } else {
792 /* Use the default kind for the property */
794 }
795 } else {
796 /* Use the given kind string */
797 kind = icalvalue_string_to_kind(type);
798 }
799
800 if (kind == ICAL_NO_VALUE) {
802 return;
803 }
804
806 nval = icalvalue_new_from_string(kind, str);
807
808 if (nval == 0) {
809 /* icalvalue_new_from_string sets errno */
810 icalassert(icalerrno != ICAL_NO_ERROR);
811 return;
812 }
813
814 icalproperty_set_value(prop, nval);
815}
816
817icalvalue *icalproperty_get_value(const icalproperty *prop)
818{
819 icalerror_check_arg_rz((prop != 0), "prop");
820
821 return prop->value;
822}
823
824const char *icalproperty_get_value_as_string(const icalproperty *prop)
825{
826 char *buf;
827
830 return buf;
831}
832
833char *icalproperty_get_value_as_string_r(const icalproperty *prop)
834{
835 const icalvalue *value;
836
837 icalerror_check_arg_rz((prop != 0), "prop");
838
839 value = prop->value;
840
841 return icalvalue_as_ical_string_r(value);
842}
843
844void icalproperty_set_x_name(icalproperty *prop, const char *name)
845{
846 icalerror_check_arg_rv((name != 0), "name");
847 icalerror_check_arg_rv((prop != 0), "prop");
848
849 icalmemory_free_buffer(prop->x_name);
850 prop->x_name = icalmemory_strdup(name);
851
852 if (prop->x_name == 0) {
854 }
855}
856
857const char *icalproperty_get_x_name(const icalproperty *prop)
858{
859 icalerror_check_arg_rz((prop != 0), "prop");
860
861 return prop->x_name;
862}
863
864void icalproperty_set_iana_name(icalproperty *prop, const char *name)
865{
866 icalerror_check_arg_rv((name != 0), "name");
867 icalerror_check_arg_rv((prop != 0), "prop");
868 icalerror_check_arg_rv((prop->kind == ICAL_IANA_PROPERTY), "prop->kind");
869
870 icalmemory_free_buffer(prop->x_name);
871 prop->x_name = icalmemory_strdup(name);
872
873 if (prop->x_name == 0) {
875 }
876}
877
878const char *icalproperty_get_iana_name(const icalproperty *prop)
879{
880 icalerror_check_arg_rz((prop != 0), "prop");
881 icalerror_check_arg_rz((prop->kind == ICAL_IANA_PROPERTY), "prop->kind");
882
883 return prop->x_name;
884}
885
886const char *icalproperty_get_property_name(const icalproperty *prop)
887{
888 char *buf;
889
892 return buf;
893}
894
895char *icalproperty_get_property_name_r(const icalproperty *prop)
896{
897 const char *property_name = 0;
898 size_t buf_size = 256;
899 char *buf;
900 char *buf_ptr;
901
902 icalerror_check_arg_rz((prop != 0), "prop");
903
904 buf = icalmemory_new_buffer(buf_size);
905 buf_ptr = buf;
906
907 if ((prop->kind == ICAL_X_PROPERTY || prop->kind == ICAL_IANA_PROPERTY) && prop->x_name != 0) {
908 property_name = prop->x_name;
909 } else {
910 property_name = icalproperty_kind_to_string(prop->kind);
911 }
912
913 if (property_name == 0) {
916 return 0;
917
918 } else {
919 /* _append_string will automatically grow the buffer if
920 property_name is longer than the initial buffer size */
921 icalmemory_append_string(&buf, &buf_ptr, &buf_size, property_name);
922 }
923
924 return buf;
925}
926
927void icalproperty_set_parent(icalproperty *property, icalcomponent *component)
928{
929 icalerror_check_arg_rv((property != 0), "property");
930
931 property->parent = component;
932}
933
934icalcomponent *icalproperty_get_parent(const icalproperty *property)
935{
936 icalerror_check_arg_rz((property != 0), "property");
937
938 return property->parent;
939}
940
941static int param_compare(void *a, void *b)
942{
943 /* XXX Need to sort values for multi-valued parameters (e.g. MEMBER) */
944 return strcmp(icalparameter_as_ical_string((icalparameter *)a),
945 icalparameter_as_ical_string((icalparameter *)b));
946}
947
948void icalproperty_normalize(icalproperty *prop)
949{
950 icalproperty_kind prop_kind = icalproperty_isa(prop);
951 icalpvl_list sorted_params = icalpvl_newlist();
952 icalparameter *param;
953
954 /* Normalize parameters into sorted list */
955 while ((param = icalpvl_pop(prop->parameters)) != 0) {
956 int remove = 0;
957
958 /* Remove parameters having default values */
959 switch (icalparameter_isa(param)) {
960 case ICAL_VALUE_PARAMETER:
961 /* Skip VALUE parameters for default property value types */
962 switch (prop_kind) {
963 case ICAL_ATTACH_PROPERTY:
964 if (icalparameter_get_value(param) == ICAL_VALUE_URI) {
965 remove = 1;
966 }
967 break;
968
969 case ICAL_DTEND_PROPERTY:
970 case ICAL_DUE_PROPERTY:
971 case ICAL_DTSTART_PROPERTY:
972 case ICAL_EXDATE_PROPERTY:
973 case ICAL_RDATE_PROPERTY:
974 case ICAL_RECURRENCEID_PROPERTY:
975 if (icalparameter_get_value(param) == ICAL_VALUE_DATETIME) {
976 remove = 1;
977 }
978 break;
979
980 case ICAL_DURATION_PROPERTY:
981 if (icalparameter_get_value(param) == ICAL_VALUE_DURATION) {
982 remove = 1;
983 }
984 break;
985
986 case ICAL_RELATEDTO_PROPERTY:
987 if (icalparameter_get_value(param) == ICAL_VALUE_TEXT) {
988 remove = 1;
989 }
990 break;
991
992 default:
993 break;
994 }
995 break;
996
997 case ICAL_CUTYPE_PARAMETER:
998 if (icalparameter_get_cutype(param) == ICAL_CUTYPE_INDIVIDUAL) {
999 remove = 1;
1000 }
1001 break;
1002
1003 case ICAL_ENCODING_PARAMETER:
1004 if (icalparameter_get_encoding(param) == ICAL_ENCODING_8BIT) {
1005 remove = 1;
1006 }
1007 break;
1008
1009 case ICAL_FBTYPE_PARAMETER:
1010 if (icalparameter_get_fbtype(param) == ICAL_FBTYPE_BUSY) {
1011 remove = 1;
1012 }
1013 break;
1014
1015 case ICAL_PARTSTAT_PARAMETER:
1016 if (icalparameter_get_partstat(param) == ICAL_PARTSTAT_NEEDSACTION) {
1017 remove = 1;
1018 }
1019 break;
1020
1021 case ICAL_RELATED_PARAMETER:
1022 if (icalparameter_get_related(param) == ICAL_RELATED_START) {
1023 remove = 1;
1024 }
1025 break;
1026
1027 case ICAL_RELTYPE_PARAMETER:
1028 if (icalparameter_get_reltype(param) == ICAL_RELTYPE_PARENT) {
1029 remove = 1;
1030 }
1031 break;
1032
1033 case ICAL_ROLE_PARAMETER:
1034 if (icalparameter_get_role(param) == ICAL_ROLE_REQPARTICIPANT) {
1035 remove = 1;
1036 }
1037 break;
1038
1039 case ICAL_RSVP_PARAMETER:
1040 if (icalparameter_get_rsvp(param) == ICAL_RSVP_FALSE) {
1041 remove = 1;
1042 }
1043 break;
1044
1045 case ICAL_SCHEDULEAGENT_PARAMETER:
1046 if (icalparameter_get_scheduleagent(param) == ICAL_SCHEDULEAGENT_SERVER) {
1047 remove = 1;
1048 }
1049 break;
1050
1051 default:
1052 break;
1053 }
1054
1055 if (remove) {
1056 icalparameter_set_parent(param, 0); // MUST NOT have a parent to free
1057 icalparameter_free(param);
1058 } else {
1059 icalpvl_insert_ordered(sorted_params, param_compare, param);
1060 }
1061 }
1062
1063 icalpvl_free(prop->parameters);
1064 prop->parameters = sorted_params;
1065}
1066
1068 icalcomponent *comp)
1069{
1070 icalcomponent *c;
1071 icalparameter *param;
1072 struct icaltimetype ret;
1073
1074 ret = icalvalue_get_datetime(icalproperty_get_value(prop));
1075
1076 if (icaltime_is_utc(ret)) {
1077 return ret;
1078 }
1079
1080 if ((param = icalproperty_get_first_parameter(prop, ICAL_TZID_PARAMETER)) != NULL) {
1081 const char *tzid = icalparameter_get_tzid(param);
1082 icaltimezone *tz = NULL;
1083
1084 if (!comp) {
1085 comp = icalproperty_get_parent(prop);
1086 }
1087
1088 for (c = comp; c != NULL; c = icalcomponent_get_parent(c)) {
1089 tz = icalcomponent_get_timezone(c, tzid);
1090 if (tz != NULL) {
1091 break;
1092 }
1093 }
1094
1095 if (tz == NULL) {
1097 }
1098
1099 if (tz == NULL) {
1101 }
1102
1103 if (tz != NULL) {
1104 ret = icaltime_set_timezone(&ret, tz);
1105 }
1106 }
1107
1108 return ret;
1109}
1110
1111static const icalparamiter icalparamiter_null = {ICAL_NO_PARAMETER, 0};
1112
1114icalparamiter icalproperty_begin_parameter(icalproperty *property, icalparameter_kind kind)
1115{
1116 icalerror_check_arg_re(property != 0, "property", icalparamiter_null);
1117
1118 icalpvl_elem i;
1119
1120 for (i = icalpvl_head(property->parameters); i != 0; i = icalpvl_next(i)) {
1121 icalparameter *p = (icalparameter *)icalpvl_data(i);
1122
1123 if (icalparameter_isa(p) == kind || kind == ICAL_ANY_PARAMETER) {
1124 icalparamiter itr = {kind, i};
1125 return itr;
1126 }
1127 }
1128
1129 return icalparamiter_null;
1130}
1131
1132icalparameter *icalparamiter_next(icalparamiter *i)
1133{
1134 icalerror_check_arg_rz((i != 0), "i");
1135
1136 if (i->iter == 0) {
1137 return 0;
1138 }
1139
1140 for (i->iter = icalpvl_next(i->iter); i->iter != 0; i->iter = icalpvl_next(i->iter)) {
1141 icalparameter *p = (icalparameter *)icalpvl_data(i->iter);
1142
1143 if (icalparameter_isa(p) == i->kind || i->kind == ICAL_ANY_PARAMETER) {
1144 return icalparamiter_deref(i);
1145 }
1146 }
1147
1148 return 0;
1149}
1150
1151icalparameter *icalparamiter_deref(icalparamiter *i)
1152{
1153 if (i->iter == 0) {
1154 return 0;
1155 }
1156
1157 return icalpvl_data(i->iter);
1158}
bool icalattach_get_is_url(const icalattach *attach)
Determines if attach is an URL.
Definition icalattach.c:115
struct icalattach_impl icalattach
An iCal attach object representing a link to a document object.
Definition icalattach.h:36
icalproperty * icalcomponent_get_first_property(icalcomponent *c, icalproperty_kind kind)
void icalcomponent_remove_property(icalcomponent *component, icalproperty *property)
int icalcomponent_count_errors(icalcomponent *component)
icaltimezone * icalcomponent_get_timezone(icalcomponent *comp, const char *tzid)
void icalcomponent_free(icalcomponent *c)
Defines the data structure for iCalendar components.
struct icaltimetype icalproperty_get_datetime_with_component(icalproperty *prop, icalcomponent *comp)
void icalerror_set_errno(icalerrorenum x)
Sets the icalerrno to a given error.
Definition icalerror.c:90
void icalerror_clear_errno(void)
Resets icalerrno to ICAL_NO_ERROR.
Definition icalerror.c:85
Error handling for libical.
@ ICAL_NEWFAILED_ERROR
Definition icalerror.h:50
@ ICAL_BADARG_ERROR
Definition icalerror.h:47
@ ICAL_INTERNAL_ERROR
Definition icalerror.h:65
@ ICAL_NO_ERROR
Definition icalerror.h:44
@ ICAL_MALFORMEDDATA_ERROR
Definition icalerror.h:59
@ ICAL_PARSE_ERROR
Definition icalerror.h:62
@ ICAL_USAGE_ERROR
Definition icalerror.h:71
#define icalerrno
Access the current icalerrno value.
Definition icalerror.h:133
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.
bool icalparameter_isa_parameter(void *parameter)
void icalparameter_free(icalparameter *param)
Frees an icalparameter object.
void icalparameter_set_xname(icalparameter *param, const char *v)
Sets the X-name of param to v.
char * icalparameter_as_ical_string_r(icalparameter *param)
Converts icalparameter into a string representation according to RFC5445/RFC6868.
const char * icalparameter_get_xname(const icalparameter *param)
Returns the X-name of param.
icalparameter_kind icalparameter_isa(const icalparameter *parameter)
icalparameter * icalparameter_clone(const icalparameter *old)
Creates new icalparameter as a clone of the given one.
bool icalparameter_has_same_name(const icalparameter *param1, const icalparameter *param2)
Determines if two parameters have the same name.
void icalparameter_set_iana_name(icalparameter *param, const char *v)
Sets the IANA name of param to v.
void icalparameter_set_parent(icalparameter *param, icalproperty *property)
const char * icalparameter_get_iana_name(const icalparameter *param)
Returns the IANA name of param.
char * icalparameter_as_ical_string(icalparameter *param)
Converts icalparameter into a string representation.
icalparameter_kind icalparameter_string_to_kind(const char *string)
Returns the icalparameter_kind for a given string.
const char * icalparameter_kind_to_string(icalparameter_kind kind)
Returns a string representing the given icalparameter_kind.
icalparameter * icalparameter_new_from_value_string(icalparameter_kind kind, const char *value)
Creates new icalparameter of a given kind with a given value.
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)
void icalproperty_add_parameters(icalproperty *prop, va_list args)
bool icalproperty_isa_property(void *property)
void icalproperty_free(icalproperty *p)
void icalproperty_set_value(icalproperty *p, icalvalue *value)
icalcomponent * icalproperty_get_parent(const icalproperty *property)
char * icalproperty_as_ical_string_r(icalproperty *prop)
icalproperty_kind icalproperty_isa(const icalproperty *p)
void icalproperty_set_parameter_from_string(icalproperty *prop, const char *name, const char *value)
char * icalproperty_get_property_name_r(const icalproperty *prop)
void icalproperty_set_allow_empty_properties(bool enable)
void icalproperty_remove_parameter_by_name(icalproperty *prop, const char *name)
Removes all parameters with the specified name.
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.
const char * icalproperty_get_property_name(const icalproperty *prop)
bool icalproperty_get_allow_empty_properties(void)
const char * icalproperty_as_ical_string(icalproperty *prop)
icalparameter * icalproperty_get_first_parameter(icalproperty *p, icalparameter_kind kind)
void icalproperty_add_parameter(icalproperty *p, icalparameter *parameter)
char * icalproperty_get_parameter_as_string_r(icalproperty *prop, const char *name)
void icalproperty_normalize(icalproperty *prop)
void icalproperty_set_parent(icalproperty *property, icalcomponent *component)
void icalproperty_remove_parameter_by_ref(icalproperty *prop, icalparameter *parameter)
Removes the specified parameter reference from the property.
char * icalproperty_get_value_as_string_r(const 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)
const char * icalproperty_get_iana_name(const icalproperty *prop)
icalproperty * icalproperty_new(icalproperty_kind kind)
void icalproperty_set_iana_name(icalproperty *prop, const char *name)
icalproperty * icalproperty_new_from_string(const char *str)
icalparameter * icalproperty_get_next_parameter(icalproperty *p, icalparameter_kind kind)
void icalproperty_set_value_from_string(icalproperty *prop, const char *str, const char *type)
const char * icalproperty_get_parameter_as_string(icalproperty *prop, const char *name)
void icalproperty_set_x_name(icalproperty *prop, const char *name)
icalvalue_kind icalparameter_value_to_value_kind(icalparameter_value value)
void icalvalue_set_parent(icalvalue *value, icalproperty *property)
Definition icalvalue.c:1544
icalvalue_kind icalproperty_kind_to_value_kind(icalproperty_kind kind)
bool icalproperty_kind_is_valid(const icalproperty_kind kind)
const char * icalproperty_kind_to_string(icalproperty_kind kind)
bool icaltime_is_utc(const struct icaltimetype t)
Definition icaltime.c:625
struct icaltimetype icaltime_set_timezone(struct icaltimetype *t, const icaltimezone *zone)
Definition icaltime.c:883
icaltimezone * icaltimezone_get_builtin_timezone(const char *location)
icaltimezone * icaltimezone_get_builtin_timezone_from_tzid(const char *tzid)
Timezone handling routines.
struct _icaltimezone icaltimezone
icalvalue_kind icalvalue_isa(const icalvalue *value)
Definition icalvalue.c:1327
bool icalvalue_isa_value(void *value)
Definition icalvalue.c:1336
icalvalue * icalvalue_clone(const icalvalue *old)
Definition icalvalue.c:65
icalvalue * icalvalue_new_from_string(icalvalue_kind kind, const char *str)
Definition icalvalue.c:791
void icalvalue_free(icalvalue *v)
Definition icalvalue.c:796
char * icalvalue_as_ical_string_r(const icalvalue *value)
Definition icalvalue.c:1226
Defines the data structure representing iCalendar parameter values.
icalvalue_kind icalvalue_string_to_kind(const char *str)
const char * icalvalue_kind_to_string(const icalvalue_kind kind)