Libical API Documentation 4.0 UNRELEASED Go to the stable 3.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
28#include <stdlib.h>
29
30struct icalproperty_impl {
31 char id[5];
32 icalproperty_kind kind;
33 char *x_name;
34 icalpvl_list parameters;
35 icalpvl_elem parameter_iterator;
36 icalvalue *value;
37 icalcomponent *parent;
38};
39
41LIBICAL_ICAL_EXPORT struct icalproperty_impl *icalproperty_new_impl(icalproperty_kind kind)
42{
43 icalproperty *prop;
44
45 if (!icalproperty_kind_is_valid(kind)) {
46 return NULL;
47 }
48
49 if ((prop = (icalproperty *)icalmemory_new_buffer(sizeof(icalproperty))) == 0) {
51 return 0;
52 }
53
54 memset(prop, 0, sizeof(icalproperty));
55
56 strcpy(prop->id, "prop");
57
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[0] = 'X';
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 return buf;
317}
318
319/* Determine what VALUE parameter to include. The VALUE parameters
320 are ignored in the normal parameter printing ( the block after
321 this one, so we need to do it here */
322static const char *icalproperty_get_value_kind(icalproperty *prop)
323{
324 const char *kind_string = NULL;
325 if (!prop) {
326 return kind_string;
327 }
328
329 icalvalue_kind kind = ICAL_NO_VALUE;
330 icalparameter *val_param =
331 icalproperty_get_first_parameter(prop, ICAL_VALUE_PARAMETER);
332
333 if (val_param) {
334 kind = icalparameter_value_to_value_kind(icalparameter_get_value(val_param));
335 }
336
337 if (kind == ICAL_NO_VALUE) {
338 icalvalue *value = icalproperty_get_value(prop);
339
340 kind = icalvalue_isa(value);
341
342 if (kind == ICAL_ATTACH_VALUE) {
343 icalattach *a = icalvalue_get_attach(value);
344
345 kind = icalattach_get_is_url(a) ? ICAL_URI_VALUE : ICAL_BINARY_VALUE;
346 }
347 }
348
349 if (kind != ICAL_NO_VALUE &&
350 !icalproperty_value_kind_is_default(prop->kind, kind)) {
351 /* Not the default, so it must be specified */
352 kind_string = icalvalue_kind_to_string(kind);
353 } else {
354 /* Don't include the VALUE parameter at all */
355 }
356
357 return kind_string;
358}
359
360const char *icalproperty_as_ical_string(icalproperty *prop)
361{
362 const char *buf;
363
365 icalmemory_add_tmp_buffer((char *)buf);
366 return buf;
367}
368
369char *icalproperty_as_ical_string_r(icalproperty *prop)
370{
371 icalparameter *param;
372
373 /* Create new buffer that we can append names, parameters and a
374 * value to, and reallocate as needed.
375 */
376
377 const char *property_name = 0;
378 size_t buf_size = 1024;
379 char *buf;
380 char *buf_ptr;
381 const icalvalue *value;
382 char *out_buf;
383 const char *kind_string = 0;
384 const char newline[] = "\r\n";
385
386 icalerror_check_arg_rz((prop != 0), "prop");
387
388 buf = icalmemory_new_buffer(buf_size);
389 buf_ptr = buf;
390
391 /* Append property name */
392
393 if ((prop->kind == ICAL_X_PROPERTY || prop->kind == ICAL_IANA_PROPERTY) && prop->x_name != 0) {
394 property_name = prop->x_name;
395 } else {
396 property_name = icalproperty_kind_to_string(prop->kind);
397 }
398
399 if (property_name == 0) {
400 icalerror_warn("Got a property of an unknown kind.");
402 return 0;
403 }
404
405 icalmemory_append_string(&buf, &buf_ptr, &buf_size, property_name);
406
407 kind_string = icalproperty_get_value_kind(prop);
408 if (kind_string != 0) {
409 icalmemory_append_string(&buf, &buf_ptr, &buf_size, ";VALUE=");
410 icalmemory_append_string(&buf, &buf_ptr, &buf_size, kind_string);
411 }
412
413 /* Append parameters */
414 for (param = icalproperty_get_first_parameter(prop, ICAL_ANY_PARAMETER);
415 param != 0; param = icalproperty_get_next_parameter(prop, ICAL_ANY_PARAMETER)) {
416 icalparameter_kind kind = icalparameter_isa(param);
417
418 kind_string = icalparameter_as_ical_string_r(param);
419
420 if (kind_string == 0) {
421 icalerror_warn("Got a parameter of unknown kind for the following property");
422
423 icalerror_warn((property_name) ? property_name : "(NULL)");
424 continue;
425 }
426
427 if (kind == ICAL_VALUE_PARAMETER) {
428 icalmemory_free_buffer((char *)kind_string);
429 continue;
430 }
431
432 icalmemory_append_string(&buf, &buf_ptr, &buf_size, ";");
433 icalmemory_append_string(&buf, &buf_ptr, &buf_size, kind_string);
434 icalmemory_free_buffer((char *)kind_string);
435 }
436
437 /* Append value */
438
439 icalmemory_append_string(&buf, &buf_ptr, &buf_size, ":");
440
441 value = icalproperty_get_value(prop);
442
443 if (value != 0) {
444 char *str = icalvalue_as_ical_string_r(value);
445
446 if (str != 0) {
447 icalmemory_append_string(&buf, &buf_ptr, &buf_size, str);
449 icalmemory_append_string(&buf, &buf_ptr, &buf_size, "ERROR: No Value");
450 }
453 icalmemory_append_string(&buf, &buf_ptr, &buf_size, "ERROR: No Value");
454 }
455
456 icalmemory_append_string(&buf, &buf_ptr, &buf_size, newline);
457
458 /* We now use a function to fold the line properly every 75 characters.
459 That function also adds the newline for us. */
460 out_buf = fold_property_line(buf);
461
463
464 return out_buf;
465}
466
467icalproperty_kind icalproperty_isa(const icalproperty *p)
468{
469 if (p != 0) {
470 return p->kind;
471 }
472
473 return ICAL_NO_PROPERTY;
474}
475
476bool icalproperty_isa_property(void *property)
477{
478 const icalproperty *impl = (icalproperty *)property;
479
480 icalerror_check_arg_rz((property != 0), "property");
481 if (strcmp(impl->id, "prop") == 0) {
482 return true;
483 } else {
484 return false;
485 }
486}
487
488void icalproperty_add_parameter(icalproperty *p, icalparameter *parameter)
489{
490 icalerror_check_arg_rv((p != 0), "prop");
491 icalerror_check_arg_rv((parameter != 0), "parameter");
492
493 icalpvl_push(p->parameters, parameter);
494}
495
496void icalproperty_set_parameter(icalproperty *prop, icalparameter *parameter)
497{
498 icalparameter_kind kind;
499
500 icalerror_check_arg_rv((prop != 0), "prop");
501 icalerror_check_arg_rv((parameter != 0), "parameter");
502
503 kind = icalparameter_isa(parameter);
504 if (kind == ICAL_X_PARAMETER) {
506 } else if (kind == ICAL_IANA_PARAMETER) {
508 } else {
510 }
511
512 icalproperty_add_parameter(prop, parameter);
513}
514
516 const char *name, const char *value)
517{
518 icalparameter_kind kind;
519 icalparameter *param;
520
521 icalerror_check_arg_rv((prop != 0), "prop");
522 icalerror_check_arg_rv((name != 0), "name");
523 icalerror_check_arg_rv((value != 0), "value");
524
525 kind = icalparameter_string_to_kind(name);
526
527 if (kind == ICAL_NO_PARAMETER) {
529 return;
530 }
531
532 param = icalparameter_new_from_value_string(kind, value);
533
534 if (param == 0) {
536 return;
537 }
538
539 if (kind == ICAL_X_PARAMETER) {
540 icalparameter_set_xname(param, name);
541 } else if (kind == ICAL_IANA_PARAMETER) {
542 icalparameter_set_iana_name(param, name);
543 }
544
545 icalproperty_set_parameter(prop, param);
546}
547
548const char *icalproperty_get_parameter_as_string(icalproperty *prop, const char *name)
549{
550 char *buf;
551
554 return buf;
555}
556
557char *icalproperty_get_parameter_as_string_r(icalproperty *prop, const char *name)
558{
559 icalparameter_kind kind;
560 icalparameter *param;
561 char *str;
562 const char *t;
563 const char *pv;
564 const char *pvql;
565 char *pvqr;
566
567 icalerror_check_arg_rz((prop != 0), "prop");
568 icalerror_check_arg_rz((name != 0), "name");
569
570 kind = icalparameter_string_to_kind(name);
571
572 if (kind == ICAL_NO_PARAMETER) {
573 /* icalenum_string_to_parameter_kind will set icalerrno */
574 return 0;
575 }
576
577 for (param = icalproperty_get_first_parameter(prop, kind);
578 param != 0; param = icalproperty_get_next_parameter(prop, kind)) {
579 if (kind == ICAL_X_PARAMETER) {
580 if (strcmp(icalparameter_get_xname(param), name) == 0) {
581 break;
582 }
583 } else if (kind == ICAL_IANA_PARAMETER) {
584 if (strcmp(icalparameter_get_iana_name(param), name) == 0) {
585 break;
586 }
587 } else {
588 break;
589 }
590 }
591
592 if (param == 0) {
593 return 0;
594 }
595
597
598 t = strchr(str, '=');
599
600 if (t == 0) {
603 return 0;
604 }
605
606 /* Strip the property name and the equal sign */
607 pv = icalmemory_strdup(t + 1);
609
610 /* Is the string quoted? */
611 pvql = strchr(pv, '"');
612 if (pvql == 0) {
613 return ((char *)pv); /* No quotes? Return it immediately. */
614 }
615
616 /* Strip everything up to the first quote */
617 str = icalmemory_strdup(pvql + 1);
618 icalmemory_free_buffer((char *)pv);
619
620 /* Search for the end quote */
621 pvqr = strrchr(str, '"');
622 if (pvqr == 0) {
625 return 0;
626 }
627
628 *pvqr = '\0';
629 return str;
630}
631
632void icalproperty_remove_parameter_by_kind(icalproperty *prop, icalparameter_kind kind)
633{
634 icalpvl_elem p, next;
635
636 icalerror_check_arg_rv((prop != 0), "prop");
637
638 for (p = icalpvl_head(prop->parameters); p != 0; p = next) {
639 next = icalpvl_next(p);
640
641 icalparameter *param = (icalparameter *)icalpvl_data(p);
642
643 if (icalparameter_isa(param) == kind) {
644 (void)icalpvl_remove(prop->parameters, p);
645 icalparameter_free(param);
646 }
647 }
648}
649
650void icalproperty_remove_parameter_by_name(icalproperty *prop, const char *name)
651{
652 icalpvl_elem p, next;
653
654 icalerror_check_arg_rv((prop != 0), "prop");
655
656 for (p = icalpvl_head(prop->parameters); p != 0; p = next) {
657 next = icalpvl_next(p);
658
659 icalparameter *param = (icalparameter *)icalpvl_data(p);
660 const char *kind_string;
661
662 if (icalparameter_isa(param) == ICAL_X_PARAMETER) {
663 kind_string = icalparameter_get_xname(param);
664 } else if (icalparameter_isa(param) == ICAL_IANA_PARAMETER) {
665 kind_string = icalparameter_get_iana_name(param);
666 } else {
668 }
669
670 if (!kind_string) {
671 continue;
672 }
673
674 if (0 == strcasecmp(kind_string, name)) {
675 (void)icalpvl_remove(prop->parameters, p);
676 icalparameter_free(param);
677 }
678 }
679}
680
681void icalproperty_remove_parameter_by_ref(icalproperty *prop, icalparameter *parameter)
682{
683 icalpvl_elem p;
684
685 icalerror_check_arg_rv((prop != 0), "prop");
686 icalerror_check_arg_rv((parameter != 0), "parameter");
687
688 for (p = icalpvl_head(prop->parameters); p != 0; p = icalpvl_next(p)) {
689 icalparameter *p_param = (icalparameter *)icalpvl_data(p);
690
691 if (icalparameter_has_same_name(parameter, p_param)) {
692 (void)icalpvl_remove(prop->parameters, p);
693 icalparameter_free(p_param);
694 break;
695 }
696 }
697}
698
699int icalproperty_count_parameters(const icalproperty *prop)
700{
701 if (prop != 0) {
702 return icalpvl_count(prop->parameters);
703 }
704
706 return -1;
707}
708
709icalparameter *icalproperty_get_first_parameter(icalproperty *p, icalparameter_kind kind)
710{
711 icalerror_check_arg_rz((p != 0), "prop");
712
713 p->parameter_iterator = icalpvl_head(p->parameters);
714
715 if (p->parameter_iterator == 0) {
716 return 0;
717 }
718
719 for (p->parameter_iterator = icalpvl_head(p->parameters);
720 p->parameter_iterator != 0; p->parameter_iterator = icalpvl_next(p->parameter_iterator)) {
721 icalparameter *param = (icalparameter *)icalpvl_data(p->parameter_iterator);
722
723 if (icalparameter_isa(param) == kind || kind == ICAL_ANY_PARAMETER) {
724 return param;
725 }
726 }
727
728 return 0;
729}
730
731icalparameter *icalproperty_get_next_parameter(icalproperty *p, icalparameter_kind kind)
732{
733 icalerror_check_arg_rz((p != 0), "prop");
734
735 if (p->parameter_iterator == 0) {
736 return 0;
737 }
738
739 for (p->parameter_iterator = icalpvl_next(p->parameter_iterator);
740 p->parameter_iterator != 0; p->parameter_iterator = icalpvl_next(p->parameter_iterator)) {
741 icalparameter *param = (icalparameter *)icalpvl_data(p->parameter_iterator);
742
743 if (icalparameter_isa(param) == kind || kind == ICAL_ANY_PARAMETER) {
744 return param;
745 }
746 }
747
748 return 0;
749}
750
751void icalproperty_set_value(icalproperty *p, icalvalue *value)
752{
753 icalvalue_kind kind;
754
755 icalerror_check_arg_rv((p != 0), "prop");
756 icalerror_check_arg_rv((value != 0), "value");
757
758 if (p->value != 0) {
759 icalvalue_set_parent(p->value, 0);
760 icalvalue_free(p->value);
761 p->value = 0;
762 }
763
764 p->value = value;
765
766 icalvalue_set_parent(value, p);
767
768 kind = icalvalue_isa(value);
769 if (kind == ICAL_DATE_VALUE || kind == ICAL_DATETIME_VALUE) {
770 icalparameter *val_param;
771
772 val_param = icalproperty_get_first_parameter(p, ICAL_VALUE_PARAMETER);
773
774 if (val_param &&
775 icalparameter_value_to_value_kind(icalparameter_get_value(val_param)) != kind) {
776 icalproperty_remove_parameter_by_kind(p, ICAL_VALUE_PARAMETER);
777 }
778 }
779}
780
781void icalproperty_set_value_from_string(icalproperty *prop, const char *str, const char *type)
782{
783 icalvalue *nval;
784 icalvalue_kind kind = ICAL_NO_VALUE;
785
786 icalerror_check_arg_rv((prop != 0), "prop");
787 icalerror_check_arg_rv((str != 0), "str");
788 icalerror_check_arg_rv((type != 0), "type");
789
790 if (strcmp(type, "NO") == 0) {
791 /* Get the type from the value the property already has, if it exists */
792 const icalvalue *oval = icalproperty_get_value(prop);
793 if (oval != 0) {
794 /* Use the existing value kind */
795 kind = icalvalue_isa(oval);
796 } else {
797 /* Use the default kind for the property */
799 }
800 } else {
801 /* Use the given kind string */
802 kind = icalvalue_string_to_kind(type);
803 }
804
805 if (kind == ICAL_NO_VALUE) {
807 return;
808 }
809
811 nval = icalvalue_new_from_string(kind, str);
812
813 if (nval == 0) {
814 /* icalvalue_new_from_string sets errno */
815 icalassert(icalerrno != ICAL_NO_ERROR);
816 return;
817 }
818
819 icalproperty_set_value(prop, nval);
820}
821
822icalvalue *icalproperty_get_value(const icalproperty *prop)
823{
824 icalerror_check_arg_rz((prop != 0), "prop");
825
826 return prop->value;
827}
828
829const char *icalproperty_get_value_as_string(const icalproperty *prop)
830{
831 char *buf;
832
835 return buf;
836}
837
838char *icalproperty_get_value_as_string_r(const icalproperty *prop)
839{
840 const icalvalue *value;
841
842 icalerror_check_arg_rz((prop != 0), "prop");
843
844 value = prop->value;
845
846 return icalvalue_as_ical_string_r(value);
847}
848
849void icalproperty_set_x_name(icalproperty *prop, const char *name)
850{
851 icalerror_check_arg_rv((name != 0), "name");
852 icalerror_check_arg_rv((prop != 0), "prop");
853
854 icalmemory_free_buffer(prop->x_name);
855 prop->x_name = icalmemory_strdup(name);
856
857 if (prop->x_name == 0) {
859 }
860}
861
862const char *icalproperty_get_x_name(const icalproperty *prop)
863{
864 icalerror_check_arg_rz((prop != 0), "prop");
865
866 return prop->x_name;
867}
868
869void icalproperty_set_iana_name(icalproperty *prop, const char *name)
870{
871 icalerror_check_arg_rv((name != 0), "name");
872 icalerror_check_arg_rv((prop != 0), "prop");
873 icalerror_check_arg_rv((prop->kind == ICAL_IANA_PROPERTY), "prop->kind");
874
875 icalmemory_free_buffer(prop->x_name);
876 prop->x_name = icalmemory_strdup(name);
877
878 if (prop->x_name == 0) {
880 }
881}
882
883const char *icalproperty_get_iana_name(const icalproperty *prop)
884{
885 icalerror_check_arg_rz((prop != 0), "prop");
886 icalerror_check_arg_rz((prop->kind == ICAL_IANA_PROPERTY), "prop->kind");
887
888 return prop->x_name;
889}
890
891const char *icalproperty_get_property_name(const icalproperty *prop)
892{
893 char *buf;
894
897 return buf;
898}
899
900char *icalproperty_get_property_name_r(const icalproperty *prop)
901{
902 const char *property_name = 0;
903 size_t buf_size = 256;
904 char *buf;
905 char *buf_ptr;
906
907 icalerror_check_arg_rz((prop != 0), "prop");
908
909 buf = icalmemory_new_buffer(buf_size);
910 buf_ptr = buf;
911
912 if ((prop->kind == ICAL_X_PROPERTY || prop->kind == ICAL_IANA_PROPERTY) && prop->x_name != 0) {
913 property_name = prop->x_name;
914 } else {
915 property_name = icalproperty_kind_to_string(prop->kind);
916 }
917
918 if (property_name == 0) {
921 return 0;
922
923 } else {
924 /* _append_string will automatically grow the buffer if
925 property_name is longer than the initial buffer size */
926 icalmemory_append_string(&buf, &buf_ptr, &buf_size, property_name);
927 }
928
929 return buf;
930}
931
932void icalproperty_set_parent(icalproperty *property, icalcomponent *component)
933{
934 icalerror_check_arg_rv((property != 0), "property");
935
936 property->parent = component;
937}
938
939icalcomponent *icalproperty_get_parent(const icalproperty *property)
940{
941 icalerror_check_arg_rz((property != 0), "property");
942
943 return property->parent;
944}
945
946static int param_compare(void *a, void *b)
947{
948 /* XXX Need to sort values for multi-valued parameters (e.g. MEMBER) */
949 return strcmp(icalparameter_as_ical_string((icalparameter *)a),
950 icalparameter_as_ical_string((icalparameter *)b));
951}
952
953void icalproperty_normalize(icalproperty *prop)
954{
955 icalproperty_kind prop_kind = icalproperty_isa(prop);
956 icalpvl_list sorted_params = icalpvl_newlist();
957 icalparameter *param;
958
959 /* Normalize parameters into sorted list */
960 while ((param = icalpvl_pop(prop->parameters)) != 0) {
961 int remove = 0;
962
963 /* Remove parameters having default values */
964 switch (icalparameter_isa(param)) {
965 case ICAL_VALUE_PARAMETER:
966 /* Skip VALUE parameters for default property value types */
967 switch (prop_kind) {
968 case ICAL_ATTACH_PROPERTY:
969 if (icalparameter_get_value(param) == ICAL_VALUE_URI) {
970 remove = 1;
971 }
972 break;
973
974 case ICAL_DTEND_PROPERTY:
975 case ICAL_DUE_PROPERTY:
976 case ICAL_DTSTART_PROPERTY:
977 case ICAL_EXDATE_PROPERTY:
978 case ICAL_RDATE_PROPERTY:
979 case ICAL_RECURRENCEID_PROPERTY:
980 if (icalparameter_get_value(param) == ICAL_VALUE_DATETIME) {
981 remove = 1;
982 }
983 break;
984
985 case ICAL_DURATION_PROPERTY:
986 if (icalparameter_get_value(param) == ICAL_VALUE_DURATION) {
987 remove = 1;
988 }
989 break;
990
991 case ICAL_RELATEDTO_PROPERTY:
992 if (icalparameter_get_value(param) == ICAL_VALUE_TEXT) {
993 remove = 1;
994 }
995 break;
996
997 default:
998 break;
999 }
1000 break;
1001
1002 case ICAL_CUTYPE_PARAMETER:
1003 if (icalparameter_get_cutype(param) == ICAL_CUTYPE_INDIVIDUAL) {
1004 remove = 1;
1005 }
1006 break;
1007
1008 case ICAL_ENCODING_PARAMETER:
1009 if (icalparameter_get_encoding(param) == ICAL_ENCODING_8BIT) {
1010 remove = 1;
1011 }
1012 break;
1013
1014 case ICAL_FBTYPE_PARAMETER:
1015 if (icalparameter_get_fbtype(param) == ICAL_FBTYPE_BUSY) {
1016 remove = 1;
1017 }
1018 break;
1019
1020 case ICAL_PARTSTAT_PARAMETER:
1021 if (icalparameter_get_partstat(param) == ICAL_PARTSTAT_NEEDSACTION) {
1022 remove = 1;
1023 }
1024 break;
1025
1026 case ICAL_RELATED_PARAMETER:
1027 if (icalparameter_get_related(param) == ICAL_RELATED_START) {
1028 remove = 1;
1029 }
1030 break;
1031
1032 case ICAL_RELTYPE_PARAMETER:
1033 if (icalparameter_get_reltype(param) == ICAL_RELTYPE_PARENT) {
1034 remove = 1;
1035 }
1036 break;
1037
1038 case ICAL_ROLE_PARAMETER:
1039 if (icalparameter_get_role(param) == ICAL_ROLE_REQPARTICIPANT) {
1040 remove = 1;
1041 }
1042 break;
1043
1044 case ICAL_RSVP_PARAMETER:
1045 if (icalparameter_get_rsvp(param) == ICAL_RSVP_FALSE) {
1046 remove = 1;
1047 }
1048 break;
1049
1050 case ICAL_SCHEDULEAGENT_PARAMETER:
1051 if (icalparameter_get_scheduleagent(param) == ICAL_SCHEDULEAGENT_SERVER) {
1052 remove = 1;
1053 }
1054 break;
1055
1056 default:
1057 break;
1058 }
1059
1060 if (remove) {
1061 icalparameter_set_parent(param, 0); // MUST NOT have a parent to free
1062 icalparameter_free(param);
1063 } else {
1064 icalpvl_insert_ordered(sorted_params, param_compare, param);
1065 }
1066 }
1067
1068 icalpvl_free(prop->parameters);
1069 prop->parameters = sorted_params;
1070}
1071
1073 icalcomponent *comp)
1074{
1075 icalcomponent *c;
1076 icalparameter *param;
1077 struct icaltimetype ret;
1078
1079 ret = icalvalue_get_datetime(icalproperty_get_value(prop));
1080
1081 if (icaltime_is_utc(ret)) {
1082 return ret;
1083 }
1084
1085 if ((param = icalproperty_get_first_parameter(prop, ICAL_TZID_PARAMETER)) != NULL) {
1086 const char *tzid = icalparameter_get_tzid(param);
1087 icaltimezone *tz = NULL;
1088
1089 if (!comp) {
1090 comp = icalproperty_get_parent(prop);
1091 }
1092
1093 for (c = comp; c != NULL; c = icalcomponent_get_parent(c)) {
1094 tz = icalcomponent_get_timezone(c, tzid);
1095 if (tz != NULL) {
1096 break;
1097 }
1098 }
1099
1100 if (tz == NULL) {
1102 }
1103
1104 if (tz == NULL) {
1106 }
1107
1108 if (tz != NULL) {
1109 ret = icaltime_set_timezone(&ret, tz);
1110 }
1111 }
1112
1113 return ret;
1114}
1115
1116static const icalparamiter icalparamiter_null = {ICAL_NO_PARAMETER, 0};
1117
1119icalparamiter icalproperty_begin_parameter(icalproperty *property, icalparameter_kind kind)
1120{
1121 icalerror_check_arg_re(property != 0, "property", icalparamiter_null);
1122
1123 icalpvl_elem i;
1124
1125 for (i = icalpvl_head(property->parameters); i != 0; i = icalpvl_next(i)) {
1126 icalparameter *p = (icalparameter *)icalpvl_data(i);
1127
1128 if (icalparameter_isa(p) == kind || kind == ICAL_ANY_PARAMETER) {
1129 icalparamiter itr = {kind, i};
1130 return itr;
1131 }
1132 }
1133
1134 return icalparamiter_null;
1135}
1136
1137icalparameter *icalparamiter_next(icalparamiter *i)
1138{
1139 icalerror_check_arg_rz((i != 0), "i");
1140
1141 if (i->iter == 0) {
1142 return 0;
1143 }
1144
1145 for (i->iter = icalpvl_next(i->iter); i->iter != 0; i->iter = icalpvl_next(i->iter)) {
1146 icalparameter *p = (icalparameter *)icalpvl_data(i->iter);
1147
1148 if (icalparameter_isa(p) == i->kind || i->kind == ICAL_ANY_PARAMETER) {
1149 return icalparamiter_deref(i);
1150 }
1151 }
1152
1153 return 0;
1154}
1155
1156icalparameter *icalparamiter_deref(icalparamiter *i)
1157{
1158 if (i->iter == 0) {
1159 return 0;
1160 }
1161
1162 return icalpvl_data(i->iter);
1163}
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:62
@ ICAL_NO_ERROR
Definition icalerror.h:44
@ ICAL_MALFORMEDDATA_ERROR
Definition icalerror.h:56
@ ICAL_PARSE_ERROR
Definition icalerror.h:59
@ ICAL_USAGE_ERROR
Definition icalerror.h:68
#define icalerrno
Access the current icalerrno value.
Definition icalerror.h:130
void icalmemory_free_buffer(void *buf)
Releases a buffer.
Definition icalmemory.c:353
char * icalmemory_strdup(const char *s)
Creates a duplicate of a string.
Definition icalmemory.c:240
void icalmemory_append_string(char **buf, char **pos, size_t *buf_size, const char *string)
Appends a string to a buffer.
Definition icalmemory.c:363
void * icalmemory_new_buffer(size_t size)
Creates new buffer with the specified size.
Definition icalmemory.c:313
void icalmemory_add_tmp_buffer(void *buf)
Adds an externally allocated buffer to the ring.
Definition icalmemory.c:156
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:1541
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:621
struct icaltimetype icaltime_set_timezone(struct icaltimetype *t, const icaltimezone *zone)
Definition icaltime.c:892
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:1320
bool icalvalue_isa_value(void *value)
Definition icalvalue.c:1329
icalvalue * icalvalue_clone(const icalvalue *old)
Definition icalvalue.c:65
icalvalue * icalvalue_new_from_string(icalvalue_kind kind, const char *str)
Definition icalvalue.c:788
void icalvalue_free(icalvalue *v)
Definition icalvalue.c:793
char * icalvalue_as_ical_string_r(const icalvalue *value)
Definition icalvalue.c:1220
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)