Libical API Documentation 4.0 STABLE VERSION Visit the v3.0 documentation
Loading...
Searching...
No Matches
icalvalue.c
Go to the documentation of this file.
1/*======================================================================
2 FILE: icalvalue.c
3 CREATOR: eric 02 May 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 Contributions from:
9 Graham Davison <g.m.davison@computer.org>
10======================================================================*/
11
16
17#ifdef HAVE_CONFIG_H
18#include <config.h>
19#endif
20
21#include "icalvalue.h"
22#include "icalvalueimpl.h"
23#include "icalerror_p.h"
24#include "icallimits.h"
25#include "icalmemory.h"
26#include "icaltime.h"
27
28#include <ctype.h>
29#include <locale.h>
30#include <stdlib.h>
31
33#define TMP_BUF_SIZE 1024
34
35LIBICAL_ICAL_EXPORT struct icalvalue_impl *icalvalue_new_impl(icalvalue_kind kind)
36{
37 struct icalvalue_impl *v;
38
39 if (!icalvalue_kind_is_valid(kind)) {
40 return NULL;
41 }
42
43 if ((v = (struct icalvalue_impl *)icalmemory_new_buffer(sizeof(struct icalvalue_impl))) == 0) {
45 return 0;
46 }
47
48 strcpy(v->id, "val");
49
50 v->kind = kind;
51 v->size = 0;
52 v->parent = 0;
53 v->x_value = 0;
54 memset(&(v->data), 0, sizeof(v->data));
55
56 return v;
57}
59
60icalvalue *icalvalue_new(icalvalue_kind kind)
61{
62 return (icalvalue *)icalvalue_new_impl(kind);
63}
64
65icalvalue *icalvalue_clone(const icalvalue *old)
66{
67 struct icalvalue_impl *clone;
68
69 clone = icalvalue_new_impl(old->kind);
70
71 if (clone == 0) {
72 return 0;
73 }
74 // id is a LIBICAL_ICALVALUE_ID_LENGTH-char string (see icalvalue_impl def)
75 memset(clone->id, 0, LIBICAL_ICALVALUE_ID_LENGTH);
76 strncpy(clone->id, old->id, LIBICAL_ICALVALUE_ID_LENGTH);
77 clone->kind = old->kind;
78 clone->size = old->size;
79
80 switch (clone->kind) {
81 case ICAL_ATTACH_VALUE:
82 case ICAL_BINARY_VALUE: {
83 /* Hmm. We just ref the attach value, which may not be the right
84 * thing to do. We cannot quite copy the data, anyways, since we
85 * don't know how long it is.
86 */
87 clone->data.v_attach = old->data.v_attach;
88 if (clone->data.v_attach) {
89 icalattach_ref(clone->data.v_attach);
90 }
91
92 break;
93 }
94 case ICAL_QUERY_VALUE:
95 case ICAL_COLOR_VALUE:
96 case ICAL_STRING_VALUE:
97 case ICAL_TEXT_VALUE:
98 case ICAL_CALADDRESS_VALUE:
99 case ICAL_UID_VALUE:
100 case ICAL_XMLREFERENCE_VALUE:
101 case ICAL_URI_VALUE: {
102 if (old->data.v_string != 0) {
103 clone->data.v_string = icalmemory_strdup(old->data.v_string);
104
105 if (clone->data.v_string == 0) {
106 clone->parent = 0;
107 icalvalue_free(clone);
108 return 0;
109 }
110 }
111 break;
112 }
113 case ICAL_ACTION_VALUE: {
114 clone->data = old->data;
115
116 if (old->data.v_enum == ICAL_ACTION_X) {
117 //preserve the custom action string
118 if (old->x_value != 0) {
119 clone->x_value = icalmemory_strdup(old->x_value);
120
121 if (clone->x_value == 0) {
122 clone->parent = 0;
123 icalvalue_free(clone);
124 return 0;
125 }
126 }
127 }
128 break;
129 }
130 case ICAL_RECUR_VALUE: {
131 if (old->data.v_recur != 0) {
132 clone->data.v_recur = icalrecurrencetype_clone(old->data.v_recur);
133 if (clone->data.v_recur == 0) {
134 icalvalue_free(clone);
135 return 0;
136 }
137 }
138 break;
139 }
140
141 case ICAL_X_VALUE: {
142 if (old->x_value != 0) {
143 clone->x_value = icalmemory_strdup(old->x_value);
144
145 if (clone->x_value == 0) {
146 clone->parent = 0;
147 icalvalue_free(clone);
148 return 0;
149 }
150 }
151
152 break;
153 }
154
155 case ICAL_REQUESTSTATUS_VALUE: {
156 clone->data = old->data;
157 if (old->data.v_requeststatus.debug != 0) {
158 clone->data.v_requeststatus.debug = icalmemory_strdup(old->data.v_requeststatus.debug);
159 if (clone->data.v_requeststatus.debug == 0) {
160 clone->parent = 0;
161 icalvalue_free(clone);
162 return 0;
163 }
164 }
165 break;
166 }
167
168 default: {
169 /* all of the other types are stored as values, not
170 pointers, so we can just copy the whole structure. */
171
172 clone->data = old->data;
173 }
174 }
175
176 return clone;
177}
178
179static char *icalmemory_strdup_and_dequote(const char *str)
180{
181 const char *p;
182 char *out = (char *)icalmemory_new_buffer(sizeof(char) * strlen(str) + 1);
183 char *pout;
184 int wroteNull = 0;
185
186 if (out == 0) {
187 return 0;
188 }
189
190 pout = out;
191
192 /* Stop the loop when encountering a terminator in the source string
193 or if a null has been written to the destination. This prevents
194 reading past the end of the source string if the last character
195 is a backslash. */
196 for (p = str; !wroteNull && *p != 0; p++) {
197 if (*p == '\\') {
198 p++;
199 switch (*p) {
200 case 0: {
201 wroteNull = 1; //stops iteration so p isn't incremented past the end of str
202 *pout = '\0';
203 break;
204 }
205 case 'n':
206 case 'N': {
207 *pout = '\n';
208 break;
209 }
210 case 't':
211 case 'T': {
212 *pout = '\t';
213 break;
214 }
215 case 'r':
216 case 'R': {
217 *pout = '\r';
218 break;
219 }
220 case 'b':
221 case 'B': {
222 *pout = '\b';
223 break;
224 }
225 case 'f':
226 case 'F': {
227 *pout = '\f';
228 break;
229 }
230 case ';':
231 case ',':
232 case '"':
233 case '\\': {
234 *pout = *p;
235 break;
236 }
237 default: {
238 *pout = ' ';
239 }
240 }
241 } else {
242 *pout = *p;
243 }
244
245 pout++;
246 }
247
248 *pout = '\0';
249
250 return out;
251}
252
253/*
254 * Returns a quoted copy of a string
255 * @todo This is not RFC5545 compliant.
256 * The RFC only allows:
257 * TSAFE-CHAR = %x20-21 / %x23-2B / %x2D-39 / %x3C-5B / %x5D-7E / NON-US-ASCII
258 * As such, \t\r\b\f are not allowed, not even escaped
259 */
260static char *icalmemory_strdup_and_quote(const icalvalue *value, const char *unquoted_str)
261{
262 char *str;
263 char *str_p;
264 const char *p;
265 size_t buf_sz;
266 size_t cnt = 0; //track iterations
267
268 buf_sz = strlen(unquoted_str) + 1;
269
270 str_p = str = (char *)icalmemory_new_buffer(buf_sz);
271
272 if (str_p == 0) {
273 return 0;
274 }
275
276 const size_t max_value_chars = icallimit_get(ICAL_LIMIT_VALUE_CHARS);
277 for (p = unquoted_str; *p != 0 && cnt < max_value_chars; p++, cnt++) {
278 switch (*p) {
279 case '\n': {
280 icalmemory_append_string(&str, &str_p, &buf_sz, "\\n");
281 break;
282 }
283
284 /*issue74: \t is not escaped, but embedded literally.*/
285 case '\t': {
286 icalmemory_append_string(&str, &str_p, &buf_sz, "\t");
287 break;
288 }
289
290 /*issue74: \r, \b and \f are not whitespace and are trashed.*/
291 case '\r': {
292 /*icalmemory_append_string(&str,&str_p,&buf_sz,"\\r"); */
293 break;
294 }
295 case '\b': {
296 /*icalmemory_append_string(&str,&str_p,&buf_sz,"\\b"); */
297 break;
298 }
299 case '\f': {
300 /*icalmemory_append_string(&str,&str_p,&buf_sz,"\\f"); */
301 break;
302 }
303
304 case ';':
305 case ',':
306 /* unescaped COMMA is allowed in CATEGORIES property as its
307 considered a list delimiter here, see:
308 https://tools.ietf.org/html/rfc5545#section-3.8.1.2 */
309 if ((icalproperty_isa(value->parent) == ICAL_CATEGORIES_PROPERTY) ||
310 (icalproperty_isa(value->parent) == ICAL_RESOURCES_PROPERTY) ||
311 (icalproperty_isa(value->parent) == ICAL_POLLPROPERTIES_PROPERTY) ||
312 (icalproperty_isa(value->parent) == ICAL_LOCATIONTYPE_PROPERTY) ||
313 ((icalproperty_isa(value->parent) == ICAL_X_PROPERTY ||
314 icalproperty_isa(value->parent) == ICAL_IANA_PROPERTY) &&
315 icalvalue_isa(value) != ICAL_TEXT_VALUE)) {
316 icalmemory_append_char(&str, &str_p, &buf_sz, *p);
317 break;
318 }
319 _fallthrough();
320 /*issue74, we don't escape double quotes
321 case '"':
322*/
323 case '\\': {
324 icalmemory_append_char(&str, &str_p, &buf_sz, '\\');
325 icalmemory_append_char(&str, &str_p, &buf_sz, *p);
326 break;
327 }
328
329 default: {
330 icalmemory_append_char(&str, &str_p, &buf_sz, *p);
331 }
332 }
333 }
334
335 /* Assume the last character is not a '\0' and add one. We could
336 check *str_p != 0, but that would be an uninitialized memory
337 read. */
338
339 icalmemory_append_char(&str, &str_p, &buf_sz, '\0');
340 return str;
341}
342
343/*
344 * FIXME
345 *
346 * This is a bad API, as it forces callers to specify their own X type.
347 * This function should take care of this by itself.
348 */
349static icalvalue *icalvalue_new_enum(icalvalue_kind kind, int x_type, const char *str)
350{
351 int e = icalproperty_kind_and_string_to_enum((int)kind, str);
352 struct icalvalue_impl *value;
353
355 value = icalvalue_new_impl(kind);
356 value->data.v_enum = e;
357 } else {
358 /* Make it an X value */
359 value = icalvalue_new_impl(kind);
360 value->data.v_enum = x_type;
361 icalvalue_set_x(value, str);
362 }
363
364 return value;
365}
366
373static bool simple_str_to_doublestr(const char *from, char *result, int result_len, char **to)
374{
375 const char *start = NULL;
376 char *end = NULL, *cur = (char *)from;
377
378 struct lconv *loc_data = localeconv();
379 int i = 0, len;
380 double dtest;
381
382 /*sanity checks */
383 if (!from || !result) {
384 return true;
385 }
386
387 /*skip the white spaces at the beginning */
388 while (*cur && isspace((int)*cur)) {
389 cur++;
390 }
391
392 start = cur;
393 /* copy the part that looks like a double into result.
394 * during the copy, we give ourselves a chance to convert the '.'
395 * into the decimal separator of the current locale.
396 */
397 while (*cur && (isdigit((int)*cur) || *cur == '.' || *cur == '+' || *cur == '-')) {
398 ++cur;
399 }
400 end = cur;
401 len = (int)(ptrdiff_t)(end - start);
402 if (len + 1 >= result_len) {
403 /* huh hoh, number is too big. truncate it */
404 len = result_len - 1;
405 }
406
407 /* copy the float number string into result, and take
408 * care to have the (optional) decimal separator be the one
409 * of the current locale.
410 */
411 for (i = 0; i < len; ++i) {
412 if (start[i] == '.' &&
413 loc_data && loc_data->decimal_point && loc_data->decimal_point[0] && loc_data->decimal_point[0] != '.') {
414 /*replace '.' by the digit separator of the current locale */
415 result[i] = loc_data->decimal_point[0];
416 } else {
417 result[i] = start[i];
418 }
419 }
420 if (to) {
421 *to = end;
422 }
423
424 /* now try to convert to a floating point number, to check for validity only */
425 if (sscanf(result, "%lf", &dtest) != 1) {
426 return true;
427 }
428 return false;
429}
430
431static void free_icalvalue_attach_data(char *data, void *user_data)
432{
433 _unused(user_data);
434 free(data);
435}
436
437static icalvalue *icalvalue_new_from_string_with_error(icalvalue_kind kind,
438 const char *str, icalproperty **error)
439{
440 char temp[TMP_BUF_SIZE] = {};
441 icalparameter *errParam;
442
443 struct icalvalue_impl *value = 0;
444
445 icalerror_check_arg_rz(str != 0, "str");
446
447 if (error != 0) {
448 *error = 0;
449 }
450
451 switch (kind) {
452 case ICAL_ATTACH_VALUE: {
453 icalattach *attach;
454
455 attach = icalattach_new_from_url(str);
456 if (!attach) {
457 break;
458 }
459
460 value = icalvalue_new_attach(attach);
461 icalattach_unref(attach);
462 break;
463 }
464
465#if defined(__GNUC__) && !defined(__clang__)
466#pragma GCC diagnostic push
467#pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak"
468#endif
469 case ICAL_BINARY_VALUE: {
470 char *dupStr = strdup(str); // will be freed later on during unref
471 if (dupStr) {
472 icalattach *attach = icalattach_new_from_data(dupStr, free_icalvalue_attach_data, 0);
473 if (!attach) {
474 free(dupStr);
475 break;
476 }
477
478 value = icalvalue_new_attach(attach);
479 icalattach_unref(attach);
480 }
481 break;
482 }
483#if defined(__GNUC__) && !defined(__clang__)
484#pragma GCC diagnostic pop
485#endif
486
487 case ICAL_BOOLEAN_VALUE: {
488 if (!strcmp(str, "TRUE")) {
489 value = icalvalue_new_boolean(1);
490 } else if (!strcmp(str, "FALSE")) {
491 value = icalvalue_new_boolean(0);
492 } else {
493 if (error != 0) {
494 snprintf(temp, sizeof(temp),
495 "Could not parse %s as a %s property",
496 str, icalvalue_kind_to_string(kind));
497 errParam = icalparameter_new_xlicerrortype(ICAL_XLICERRORTYPE_VALUEPARSEERROR);
498 *error = icalproperty_vanew_xlicerror(temp, errParam, (void *)0);
499 }
500 snprintf(temp, TMP_BUF_SIZE,
501 "icalvalue_new_from_string cannot parse value string (%s) for \'%s\'",
502 icalvalue_kind_to_string(kind), str);
503 icalerror_warn(temp);
505 }
506 break;
507 }
508
509 case ICAL_TRANSP_VALUE:
510 value = icalvalue_new_enum(kind, (int)ICAL_TRANSP_X, str);
511 break;
512 case ICAL_METHOD_VALUE:
513 value = icalvalue_new_enum(kind, (int)ICAL_METHOD_X, str);
514 break;
515 case ICAL_STATUS_VALUE:
516 value = icalvalue_new_enum(kind, (int)ICAL_STATUS_X, str);
517 break;
518 case ICAL_ACTION_VALUE:
519 value = icalvalue_new_enum(kind, (int)ICAL_ACTION_X, str);
520 break;
521
522 case ICAL_QUERY_VALUE:
523 value = icalvalue_new_query(str);
524 break;
525
526 case ICAL_CLASS_VALUE:
527 value = icalvalue_new_enum(kind, (int)ICAL_CLASS_X, str);
528 break;
529 case ICAL_CMD_VALUE:
530 value = icalvalue_new_enum(kind, ICAL_CMD_X, str);
531 break;
532 case ICAL_QUERYLEVEL_VALUE:
533 value = icalvalue_new_enum(kind, ICAL_QUERYLEVEL_X, str);
534 break;
535 case ICAL_CARLEVEL_VALUE:
536 value = icalvalue_new_enum(kind, ICAL_CARLEVEL_X, str);
537 break;
538 case ICAL_BUSYTYPE_VALUE:
539 value = icalvalue_new_enum(kind, ICAL_BUSYTYPE_X, str);
540 break;
541 case ICAL_PROXIMITY_VALUE:
542 value = icalvalue_new_enum(kind, ICAL_PROXIMITY_X, str);
543 break;
544 case ICAL_POLLMODE_VALUE:
545 value = icalvalue_new_enum(kind, ICAL_POLLMODE_X, str);
546 break;
547 case ICAL_POLLCOMPLETION_VALUE:
548 value = icalvalue_new_enum(kind, ICAL_POLLCOMPLETION_X, str);
549 break;
550
551 case ICAL_PARTICIPANTTYPE_VALUE:
552 value = icalvalue_new_enum(kind, ICAL_PARTICIPANTTYPE_X, str);
553 break;
554
555 case ICAL_RESOURCETYPE_VALUE:
556 value = icalvalue_new_enum(kind, ICAL_RESOURCETYPE_X, str);
557 break;
558
559 case ICAL_INTEGER_VALUE:
560 value = icalvalue_new_integer(atoi(str));
561 break;
562
563 case ICAL_FLOAT_VALUE:
564 value = icalvalue_new_float((float)atof(str));
565 break;
566
567 case ICAL_UTCOFFSET_VALUE: {
568 int t, utcoffset, hours, minutes, seconds;
569
570 /* treat the UTCOFSET string as a decimal number, disassemble its digits
571 and reconstruct it as sections */
572 t = strtol(str, 0, 10);
573 /* add phantom seconds field */
574 if (strlen(str) < 7) {
575 t *= 100;
576 }
577 hours = (t / 10000);
578 minutes = (t - hours * 10000) / 100;
579 seconds = (t - hours * 10000 - minutes * 100);
580 utcoffset = hours * 3600 + minutes * 60 + seconds;
581
582 value = icalvalue_new_utcoffset(utcoffset);
583
584 break;
585 }
586
587 case ICAL_TEXT_VALUE: {
588 char *dequoted_str = icalmemory_strdup_and_dequote(str);
589
590 value = icalvalue_new_text(dequoted_str);
591 icalmemory_free_buffer(dequoted_str);
592 break;
593 }
594
595 case ICAL_STRING_VALUE:
596 value = icalvalue_new_string(str);
597 break;
598
599 case ICAL_COLOR_VALUE:
600 value = icalvalue_new_color(str);
601 break;
602
603 case ICAL_CALADDRESS_VALUE:
604 value = icalvalue_new_caladdress(str);
605 break;
606
607 case ICAL_URI_VALUE:
608 value = icalvalue_new_uri(str);
609 break;
610
611 case ICAL_GEO_VALUE: {
612 char *cur = NULL;
613 struct icalgeotype geo = {0};
614 memset(geo.lat, 0, ICAL_GEO_LEN);
615 memset(geo.lon, 0, ICAL_GEO_LEN);
616
617 if (simple_str_to_doublestr(str, geo.lat, ICAL_GEO_LEN, &cur)) {
618 goto geo_parsing_error;
619 }
620 /* skip white spaces */
621 while (cur && isspace((int)*cur)) {
622 ++cur;
623 }
624
625 /*there is a ';' between the latitude and longitude parts */
626 if (!cur || *cur != ';') {
627 goto geo_parsing_error;
628 }
629
630 ++cur;
631
632 /* skip white spaces */
633 while (cur && isspace((int)*cur)) {
634 ++cur;
635 }
636
637 if (simple_str_to_doublestr(cur, geo.lon, ICAL_GEO_LEN, &cur)) {
638 goto geo_parsing_error;
639 }
640 value = icalvalue_new_geo(geo);
641 break;
642
643 geo_parsing_error:
644 if (error != 0) {
645 snprintf(temp, sizeof(temp),
646 "Could not parse %s as a %s property",
647 str, icalvalue_kind_to_string(kind));
648 errParam = icalparameter_new_xlicerrortype(ICAL_XLICERRORTYPE_VALUEPARSEERROR);
649 *error = icalproperty_vanew_xlicerror(temp, errParam, (void *)0);
650 }
651 snprintf(temp, TMP_BUF_SIZE,
652 "icalvalue_new_from_string cannot parse value string (%s) for \'%s\'",
653 icalvalue_kind_to_string(kind), str);
654 icalerror_warn(temp);
656 } break;
657
658 case ICAL_RECUR_VALUE: {
659 struct icalrecurrencetype *rt;
660
662 if (rt) {
663 value = icalvalue_new_recur(rt);
665 }
666 break;
667 }
668
669 case ICAL_DATE_VALUE:
670 case ICAL_DATETIME_VALUE: {
671 struct icaltimetype tt;
672
673 tt = icaltime_from_string(str);
674 if (!icaltime_is_null_time(tt)) {
675 value = icalvalue_new_impl(kind);
676 value->data.v_time = tt;
677
679 }
680 break;
681 }
682
683 case ICAL_DATETIMEPERIOD_VALUE: {
684 struct icaltimetype tt;
685 struct icalperiodtype p;
686
687 tt = icaltime_from_string(str);
688
689 if (!icaltime_is_null_time(tt)) {
690 value = icalvalue_new_datetime(tt);
691 break;
692 }
693
696 value = icalvalue_new_period(p);
697 }
698
699 break;
700 }
701
702 case ICAL_DURATION_VALUE: {
704
705 if (!icaldurationtype_is_bad_duration(dur)) { /* failed to parse */
706 value = icalvalue_new_duration(dur);
707 }
708
709 break;
710 }
711
712 case ICAL_PERIOD_VALUE: {
713 struct icalperiodtype p;
714
716
718 value = icalvalue_new_period(p);
719 }
720 break;
721 }
722
723 case ICAL_TRIGGER_VALUE: {
725
727 value = icalvalue_new_trigger(tr);
728 }
729 break;
730 }
731
732 case ICAL_REQUESTSTATUS_VALUE: {
734
735 if (rst.code != ICAL_UNKNOWN_STATUS) {
736 value = icalvalue_new_requeststatus(rst);
737 }
738 break;
739 }
740
741 case ICAL_UID_VALUE: {
742 char *dequoted_str = icalmemory_strdup_and_dequote(str);
743
744 value = icalvalue_new_uid(dequoted_str);
745 icalmemory_free_buffer(dequoted_str);
746 break;
747 }
748
749 case ICAL_XMLREFERENCE_VALUE:
750 value = icalvalue_new_xmlreference(str);
751 break;
752
753 case ICAL_X_VALUE: {
754 char *dequoted_str = icalmemory_strdup_and_dequote(str);
755
756 value = icalvalue_new_x(dequoted_str);
757 icalmemory_free_buffer(dequoted_str);
758 } break;
759
760 default: {
761 if (error != 0) {
762 snprintf(temp, TMP_BUF_SIZE, "Unknown type for \'%s\'", str);
763
764 errParam = icalparameter_new_xlicerrortype(ICAL_XLICERRORTYPE_VALUEPARSEERROR);
765 *error = icalproperty_vanew_xlicerror(temp, errParam, (void *)0);
766 }
767
768 snprintf(temp, TMP_BUF_SIZE,
769 "icalvalue_new_from_string got an unknown value type (%s) for \'%s\'",
770 icalvalue_kind_to_string(kind), str);
771 icalerror_warn(temp);
773 }
774 }
775
776#if defined(__GNUC__) && !defined(__clang__)
777#pragma GCC diagnostic push
778#pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak"
779#endif
780 if (error != 0 && *error == 0 && value == 0) {
781 snprintf(temp, TMP_BUF_SIZE, "Failed to parse value: \'%s\'", str);
782
783 /* coverity[resource_leak] */
784 errParam = icalparameter_new_xlicerrortype(ICAL_XLICERRORTYPE_VALUEPARSEERROR);
785 *error = icalproperty_vanew_xlicerror(temp, errParam, (void *)0);
786 }
787#if defined(__GNUC__) && !defined(__clang__)
788#pragma GCC diagnostic pop
789#endif
790 return value;
791}
792
793icalvalue *icalvalue_new_from_string(icalvalue_kind kind, const char *str)
794{
795 return icalvalue_new_from_string_with_error(kind, str, (icalproperty **)0);
796}
797
798void icalvalue_free(icalvalue *v)
799{
800 icalerror_check_arg_rv((v != 0), "value");
801
802 if (v->parent != 0) {
803 return;
804 }
805
806 if (v->x_value != 0) {
807 icalmemory_free_buffer(v->x_value);
808 }
809
810 switch (v->kind) {
811 case ICAL_BINARY_VALUE:
812 case ICAL_ATTACH_VALUE: {
813 if (v->data.v_attach) {
814 icalattach_unref(v->data.v_attach);
815 v->data.v_attach = NULL;
816 }
817
818 break;
819 }
820 case ICAL_TEXT_VALUE:
821 _fallthrough();
822
823 case ICAL_CALADDRESS_VALUE:
824 _fallthrough();
825
826 case ICAL_URI_VALUE:
827 _fallthrough();
828
829 case ICAL_STRING_VALUE:
830 _fallthrough();
831
832 case ICAL_COLOR_VALUE:
833 _fallthrough();
834
835 case ICAL_QUERY_VALUE: {
836 _fallthrough();
837 case ICAL_UID_VALUE:
838 _fallthrough();
839 case ICAL_XMLREFERENCE_VALUE:
840 if (v->data.v_string != 0) {
841 icalmemory_free_buffer((void *)v->data.v_string);
842 v->data.v_string = 0;
843 }
844 break;
845 }
846 case ICAL_RECUR_VALUE: {
847 if (v->data.v_recur != 0) {
848 icalrecurrencetype_unref(v->data.v_recur);
849 v->data.v_recur = NULL;
850 }
851 break;
852 }
853
854 case ICAL_REQUESTSTATUS_VALUE: {
855 if (v->data.v_requeststatus.debug != 0) {
856 icalmemory_free_buffer((void *)v->data.v_requeststatus.debug);
857 v->data.v_requeststatus.debug = 0;
858 }
859 break;
860 }
861
862 default: {
863 /* Nothing to do */
864 }
865 }
866
867 v->kind = ICAL_NO_VALUE;
868 v->size = 0;
869 v->parent = 0;
870 memset(&(v->data), 0, sizeof(v->data));
871 v->id[0] = 'X';
873}
874
875bool icalvalue_is_valid(const icalvalue *value)
876{
877 if (value == 0) {
878 return false;
879 }
880
881 return true;
882}
883
884static char *icalvalue_binary_as_ical_string_r(const icalvalue *value)
885{
886 char *str;
887
888 icalerror_check_arg_rz((value != 0), "value");
889
890 str = (char *)icalmemory_new_buffer(60);
891 snprintf(str, 60, "icalvalue_binary_as_ical_string is not implemented yet");
892
893 return str;
894}
895
896static char *icalvalue_boolean_as_ical_string_r(const icalvalue *value)
897{
898 int data;
899 char *str;
900
901 icalerror_check_arg_rz((value != 0), "value");
902 str = (char *)icalmemory_new_buffer(6);
903
904 data = icalvalue_get_integer(value);
905
906 strncpy(str, data ? "TRUE" : "FALSE", 6);
907
908 return str;
909}
910
912#define MAX_INT_DIGITS 12 /* Enough for 2^32 + sign */
914
915static char *icalvalue_int_as_ical_string_r(const icalvalue *value)
916{
917 int data;
918 char *str;
919
920 icalerror_check_arg_rz((value != 0), "value");
921 str = (char *)icalmemory_new_buffer(MAX_INT_DIGITS);
922
923 data = icalvalue_get_integer(value);
924
925 snprintf(str, MAX_INT_DIGITS, "%d", data);
926
927 return str;
928}
929
930static char *icalvalue_utcoffset_as_ical_string_r(const icalvalue *value)
931{
932 int data, h, m, s;
933 char sign;
934 char *str;
935
936 icalerror_check_arg_rz((value != 0), "value");
937
938 str = (char *)icalmemory_new_buffer(9);
939 data = icalvalue_get_utcoffset(value);
940
941 if (abs(data) == data) {
942 sign = '+';
943 } else {
944 sign = '-';
945 }
946
947 h = data / 3600;
948 m = (data - (h * 3600)) / 60;
949 s = (data - (h * 3600) - (m * 60));
950
951 h = MIN(abs(h), 23);
952 m = MIN(abs(m), 59);
953 s = MIN(abs(s), 59);
954 if (s != 0) {
955 snprintf(str, 9, "%c%02d%02d%02d", sign, h, m, s);
956 } else {
957 snprintf(str, 9, "%c%02d%02d", sign, h, m);
958 }
959
960 return str;
961}
962
963static char *icalvalue_string_as_ical_string_r(const icalvalue *value)
964{
965 const char *data;
966 char *str = 0;
967
968 icalerror_check_arg_rz((value != 0), "value");
969 data = value->data.v_string;
970
971 const size_t str_len = strlen(data) + 1;
972 str = (char *)icalmemory_new_buffer(str_len);
973
974 strncpy(str, data, str_len);
975 str[str_len - 1] = '\0';
976
977 return str;
978}
979
980static char *icalvalue_recur_as_ical_string_r(const icalvalue *value)
981{
982 struct icalrecurrencetype *recur = value->data.v_recur;
983
984 return icalrecurrencetype_as_string_r(recur);
985}
986
987static char *icalvalue_text_as_ical_string_r(const icalvalue *value)
988{
989 return icalmemory_strdup_and_quote(value, value->data.v_string);
990}
991
992static char *icalvalue_attach_as_ical_string_r(const icalvalue *value)
993{
994 icalattach *a;
995 char *str;
996
997 icalerror_check_arg_rz((value != 0), "value");
998
999 a = icalvalue_get_attach(value);
1000
1001 if (icalattach_get_is_url(a)) {
1002 const char *url;
1003
1004 url = icalattach_get_url(a);
1005 const size_t len_url = strlen(url) + 1;
1006 str = icalmemory_new_buffer(len_url);
1007 strncpy(str, url, len_url);
1008 str[len_url - 1] = '\0';
1009 return str;
1010 } else {
1011 const char *data = 0;
1012
1013 data = (const char *)icalattach_get_data(a);
1014 const size_t len_data = strlen(data) + 1;
1015 str = icalmemory_new_buffer(len_data);
1016 strncpy(str, data, len_data);
1017 str[len_data - 1] = '\0';
1018 return str;
1019 }
1020}
1021
1022static char *icalvalue_duration_as_ical_string_r(const icalvalue *value)
1023{
1024 struct icaldurationtype data;
1025
1026 icalerror_check_arg_rz((value != 0), "value");
1027 data = icalvalue_get_duration(value);
1028
1030}
1031
1032static void print_time_to_string(char *str, const struct icaltimetype *data)
1033{ /* this function is a candidate for a library-wide external function
1034 except it isn't used any place outside of icalvalue.c.
1035 see print_date_to_string() and print_datetime_to_string in icalvalue.h */
1036#if defined(__GNUC__) && !defined(__clang__)
1037#pragma GCC diagnostic push
1038#pragma GCC diagnostic ignored "-Wstringop-truncation"
1039#endif
1040 char temp[8];
1041
1042 str[0] = '\0';
1043 if (data != 0) {
1044 if (icaltime_is_utc(*data)) {
1045 snprintf(temp, sizeof(temp), "%02d%02d%02dZ", data->hour, data->minute, data->second);
1046 strncat(str, temp, 7);
1047 } else {
1048 snprintf(temp, sizeof(temp), "%02d%02d%02d", data->hour, data->minute, data->second);
1049 strncat(str, temp, 6);
1050 }
1051 }
1052#if defined(__GNUC__) && !defined(__clang__)
1053#pragma GCC diagnostic pop
1054#endif
1055}
1056
1058void print_date_to_string(char *str, const struct icaltimetype *data)
1059{
1060#if defined(__GNUC__) && !defined(__clang__)
1061#pragma GCC diagnostic push
1062#pragma GCC diagnostic ignored "-Wstringop-truncation"
1063#endif
1064 char temp[9];
1065
1066 str[0] = '\0';
1067
1068 if (data != 0) {
1069 snprintf(temp, sizeof(temp), "%04d%02d%02d", data->year, data->month, data->day);
1070 strncat(str, temp, 8);
1071 }
1072#if defined(__GNUC__) && !defined(__clang__)
1073#pragma GCC diagnostic pop
1074#endif
1075}
1077
1078static char *icalvalue_date_as_ical_string_r(const icalvalue *value)
1079{
1080 struct icaltimetype data;
1081 char *str;
1082
1083 icalerror_check_arg_rz((value != 0), "value");
1084 data = icalvalue_get_date(value);
1085
1086 str = (char *)icalmemory_new_buffer(9);
1087
1088 str[0] = '\0';
1089 print_date_to_string(str, &data);
1090
1091 return str;
1092}
1093
1095void print_datetime_to_string(char *str, const struct icaltimetype *data)
1096{
1097#if defined(__GNUC__) && !defined(__clang__)
1098#pragma GCC diagnostic push
1099#pragma GCC diagnostic ignored "-Wstringop-truncation"
1100#endif
1101 char temp[20] = {0};
1102
1103 str[0] = '\0';
1104 if (data != 0) {
1105 print_date_to_string(str, data);
1106 if (!data->is_date) {
1107 strncat(str, "T", 19);
1108 temp[0] = '\0';
1109 print_time_to_string(temp, data);
1110 strncat(str, temp, 19);
1111 }
1112 }
1113#if defined(__GNUC__) && !defined(__clang__)
1114#pragma GCC diagnostic pop
1115#endif
1116}
1118
1119static char *icalvalue_datetime_as_ical_string_r(const icalvalue *value)
1120{
1121 struct icaltimetype data;
1122 char *str;
1123 icalvalue_kind kind = icalvalue_isa(value);
1124
1125 icalerror_check_arg_rz((value != 0), "value");
1126
1127 if (!(kind == ICAL_DATE_VALUE || kind == ICAL_DATETIME_VALUE)) {
1129 return 0;
1130 }
1131
1132 data = icalvalue_get_datetime(value);
1133
1134 str = (char *)icalmemory_new_buffer(20);
1135
1136 str[0] = 0;
1137 print_datetime_to_string(str, &data);
1138
1139 return str;
1140}
1141
1142static char *icalvalue_float_as_ical_string_r(const icalvalue *value)
1143{
1144 float data;
1145 char *str;
1146 char *old_locale;
1147
1148 icalerror_check_arg_rz((value != 0), "value");
1149 data = icalvalue_get_float(value);
1150
1151 /* bypass current locale in order to make
1152 sure snprintf uses a '.' as a separator
1153 set locate to 'C' and keep old locale */
1154 old_locale = icalmemory_strdup(setlocale(LC_NUMERIC, NULL));
1155 (void)setlocale(LC_NUMERIC, "C");
1156
1157 str = (char *)icalmemory_new_buffer(40);
1158
1159 snprintf(str, 40, "%f", data);
1160
1161 /* restore saved locale */
1162 (void)setlocale(LC_NUMERIC, old_locale);
1163 icalmemory_free_buffer(old_locale);
1164
1165 return str;
1166}
1167
1168static char *icalvalue_geo_as_ical_string_r(const icalvalue *value)
1169{
1170 struct icalgeotype data;
1171 char *str;
1172
1173 icalerror_check_arg_rz((value != 0), "value");
1174
1175 data = icalvalue_get_geo(value);
1176 str = (char *)icalmemory_new_buffer(80);
1177 snprintf(str, 80, "%s;%s", data.lat, data.lon);
1178
1179 return str;
1180}
1181
1182static char *icalvalue_datetimeperiod_as_ical_string_r(const icalvalue *value)
1183{
1184 struct icaldatetimeperiodtype dtp = icalvalue_get_datetimeperiod(value);
1185
1186 icalerror_check_arg_rz((value != 0), "value");
1187
1188 if (!icaltime_is_null_time(dtp.time)) {
1189 return icaltime_as_ical_string_r(dtp.time);
1190 } else {
1192 }
1193}
1194
1195static char *icalvalue_period_as_ical_string_r(const icalvalue *value)
1196{
1197 struct icalperiodtype data;
1198
1199 icalerror_check_arg_rz((value != 0), "value");
1200 data = icalvalue_get_period(value);
1201
1203}
1204
1205static char *icalvalue_trigger_as_ical_string_r(const icalvalue *value)
1206{
1207 struct icaltriggertype data;
1208
1209 icalerror_check_arg_rz((value != 0), "value");
1210 data = icalvalue_get_trigger(value);
1211
1212 if (!icaltime_is_null_time(data.time)) {
1213 return icaltime_as_ical_string_r(data.time);
1214 } else {
1215 return icaldurationtype_as_ical_string_r(data.duration);
1216 }
1217}
1218
1219const char *icalvalue_as_ical_string(const icalvalue *value)
1220{
1221 char *buf;
1222
1223 buf = icalvalue_as_ical_string_r(value);
1225 return buf;
1226}
1227
1228char *icalvalue_as_ical_string_r(const icalvalue *value)
1229{
1230 if (value == 0) {
1231 return 0;
1232 }
1233
1234 switch (value->kind) {
1235 case ICAL_ATTACH_VALUE:
1236 return icalvalue_attach_as_ical_string_r(value);
1237
1238 case ICAL_BINARY_VALUE:
1239 return icalvalue_binary_as_ical_string_r(value);
1240
1241 case ICAL_BOOLEAN_VALUE:
1242 return icalvalue_boolean_as_ical_string_r(value);
1243
1244 case ICAL_INTEGER_VALUE:
1245 return icalvalue_int_as_ical_string_r(value);
1246
1247 case ICAL_UTCOFFSET_VALUE:
1248 return icalvalue_utcoffset_as_ical_string_r(value);
1249
1250 case ICAL_TEXT_VALUE:
1251 case ICAL_UID_VALUE:
1252 return icalvalue_text_as_ical_string_r(value);
1253
1254 case ICAL_QUERY_VALUE:
1255 return icalvalue_string_as_ical_string_r(value);
1256
1257 case ICAL_STRING_VALUE:
1258 case ICAL_COLOR_VALUE:
1259 case ICAL_URI_VALUE:
1260 case ICAL_CALADDRESS_VALUE:
1261 case ICAL_XMLREFERENCE_VALUE:
1262 return icalvalue_string_as_ical_string_r(value);
1263
1264 case ICAL_DATE_VALUE:
1265 return icalvalue_date_as_ical_string_r(value);
1266 case ICAL_DATETIME_VALUE:
1267 return icalvalue_datetime_as_ical_string_r(value);
1268 case ICAL_DURATION_VALUE:
1269 return icalvalue_duration_as_ical_string_r(value);
1270
1271 case ICAL_PERIOD_VALUE:
1272 return icalvalue_period_as_ical_string_r(value);
1273 case ICAL_DATETIMEPERIOD_VALUE:
1274 return icalvalue_datetimeperiod_as_ical_string_r(value);
1275
1276 case ICAL_FLOAT_VALUE:
1277 return icalvalue_float_as_ical_string_r(value);
1278
1279 case ICAL_GEO_VALUE:
1280 return icalvalue_geo_as_ical_string_r(value);
1281
1282 case ICAL_RECUR_VALUE:
1283 return icalvalue_recur_as_ical_string_r(value);
1284
1285 case ICAL_TRIGGER_VALUE:
1286 return icalvalue_trigger_as_ical_string_r(value);
1287
1288 case ICAL_REQUESTSTATUS_VALUE:
1289 return icalreqstattype_as_string_r(value->data.v_requeststatus);
1290
1291 case ICAL_ACTION_VALUE:
1292 case ICAL_CMD_VALUE:
1293 case ICAL_QUERYLEVEL_VALUE:
1294 case ICAL_CARLEVEL_VALUE:
1295 case ICAL_METHOD_VALUE:
1296 case ICAL_STATUS_VALUE:
1297 case ICAL_TRANSP_VALUE:
1298 case ICAL_CLASS_VALUE:
1299 case ICAL_BUSYTYPE_VALUE:
1300 case ICAL_PROXIMITY_VALUE:
1301 case ICAL_POLLMODE_VALUE:
1302 case ICAL_POLLCOMPLETION_VALUE:
1303 case ICAL_PARTICIPANTTYPE_VALUE:
1304 case ICAL_RESOURCETYPE_VALUE:
1305 if (value->x_value != 0) {
1306 return icalmemory_strdup(value->x_value);
1307 }
1308
1309 return icalproperty_enum_to_string_r(value->data.v_enum);
1310
1311 case ICAL_X_VALUE:
1312 if (value->x_value != 0) {
1313 return icalmemory_strdup_and_quote(value, value->x_value);
1314 }
1315 _fallthrough();
1316
1317 case ICAL_NO_VALUE:
1318 _fallthrough();
1319
1320 default: {
1322 return icalmemory_strdup("");
1323 }
1324 return 0;
1325 }
1326 }
1327}
1328
1329icalvalue_kind icalvalue_isa(const icalvalue *value)
1330{
1331 if (value == 0) {
1332 return ICAL_NO_VALUE;
1333 }
1334
1335 return value->kind;
1336}
1337
1338bool icalvalue_isa_value(void *value)
1339{
1340 const struct icalvalue_impl *impl = (struct icalvalue_impl *)value;
1341
1342 icalerror_check_arg_rz((value != 0), "value");
1343
1344 if (strcmp(impl->id, "val") == 0) {
1345 return true;
1346 } else {
1347 return false;
1348 }
1349}
1350
1351static bool icalvalue_is_time(const icalvalue *a)
1352{
1353 icalvalue_kind kind = icalvalue_isa(a);
1354
1355 if (kind == ICAL_DATETIME_VALUE || kind == ICAL_DATE_VALUE) {
1356 return true;
1357 }
1358
1359 return false;
1360}
1361
1362icalparameter_xliccomparetype icalvalue_compare(const icalvalue *a, const icalvalue *b)
1363{
1364 icalerror_check_arg_rx((a != 0), "a", ICAL_XLICCOMPARETYPE_NONE);
1365 icalerror_check_arg_rx((b != 0), "b", ICAL_XLICCOMPARETYPE_NONE);
1366
1367 /* Not the same type; they can only be unequal */
1368 if (!(icalvalue_is_time(a) && icalvalue_is_time(b)) && icalvalue_isa(a) != icalvalue_isa(b)) {
1369 return ICAL_XLICCOMPARETYPE_NOTEQUAL;
1370 }
1371
1372 switch (icalvalue_isa(a)) {
1373 case ICAL_ATTACH_VALUE: {
1374 if (icalattach_get_is_url(a->data.v_attach) &&
1375 icalattach_get_is_url(b->data.v_attach)) {
1376 if (strcasecmp(icalattach_get_url(a->data.v_attach),
1377 icalattach_get_url(b->data.v_attach)) == 0) {
1378 return ICAL_XLICCOMPARETYPE_EQUAL;
1379 } else {
1380 return ICAL_XLICCOMPARETYPE_NOTEQUAL;
1381 }
1382 } else {
1383 if (a->data.v_attach == b->data.v_attach) {
1384 return ICAL_XLICCOMPARETYPE_EQUAL;
1385 } else {
1386 return ICAL_XLICCOMPARETYPE_NOTEQUAL;
1387 }
1388 }
1389 }
1390 case ICAL_BINARY_VALUE: {
1391 if (a->data.v_attach == b->data.v_attach) {
1392 return ICAL_XLICCOMPARETYPE_EQUAL;
1393 } else {
1394 return ICAL_XLICCOMPARETYPE_NOTEQUAL;
1395 }
1396 }
1397
1398 case ICAL_BOOLEAN_VALUE: {
1399 if (icalvalue_get_boolean(a) == icalvalue_get_boolean(b)) {
1400 return ICAL_XLICCOMPARETYPE_EQUAL;
1401 } else {
1402 return ICAL_XLICCOMPARETYPE_NOTEQUAL;
1403 }
1404 }
1405
1406 case ICAL_FLOAT_VALUE: {
1407 if (a->data.v_float > b->data.v_float) {
1408 return ICAL_XLICCOMPARETYPE_GREATER;
1409 } else if (a->data.v_float < b->data.v_float) {
1410 return ICAL_XLICCOMPARETYPE_LESS;
1411 } else {
1412 return ICAL_XLICCOMPARETYPE_EQUAL;
1413 }
1414 }
1415
1416 case ICAL_INTEGER_VALUE:
1417 case ICAL_UTCOFFSET_VALUE: {
1418 if (a->data.v_int > b->data.v_int) {
1419 return ICAL_XLICCOMPARETYPE_GREATER;
1420 } else if (a->data.v_int < b->data.v_int) {
1421 return ICAL_XLICCOMPARETYPE_LESS;
1422 } else {
1423 return ICAL_XLICCOMPARETYPE_EQUAL;
1424 }
1425 }
1426
1427 case ICAL_DURATION_VALUE: {
1428 struct icaldurationtype dur_a = a->data.v_duration,
1429 dur_b = b->data.v_duration;
1430 int a_days = (int)(7 * dur_a.weeks + dur_a.days) * (dur_a.is_neg == 1 ? -1 : 1),
1431 b_days = (int)(7 * dur_b.weeks + dur_b.days) * (dur_a.is_neg == 1 ? -1 : 1);
1432 int a_secs = (int)(dur_a.seconds + 60 * (dur_a.minutes + 60 * dur_a.hours)) *
1433 (dur_a.is_neg == 1 ? -1 : 1),
1434 b_secs = (int)(dur_b.seconds + 60 * (dur_b.minutes + 60 * dur_b.hours)) *
1435 (dur_b.is_neg == 1 ? -1 : 1);
1436
1437 if (a_secs == b_secs) {
1438 if (a_days > b_days) {
1439 return ICAL_XLICCOMPARETYPE_GREATER;
1440 } else if (a_days < b_days) {
1441 return ICAL_XLICCOMPARETYPE_LESS;
1442 } else {
1443 return ICAL_XLICCOMPARETYPE_EQUAL;
1444 }
1445 } else if (a_days == b_days) {
1446 if (a_secs > b_secs) {
1447 return ICAL_XLICCOMPARETYPE_GREATER;
1448 } else {
1449 return ICAL_XLICCOMPARETYPE_LESS;
1450 }
1451 } else {
1452 /* We can't compare a mix of nominal and accurate durations */
1453 return ICAL_XLICCOMPARETYPE_NOTEQUAL;
1454 }
1455 }
1456
1457 case ICAL_TEXT_VALUE:
1458 case ICAL_URI_VALUE:
1459 case ICAL_CALADDRESS_VALUE:
1460 case ICAL_TRIGGER_VALUE:
1461 case ICAL_DATE_VALUE:
1462 case ICAL_DATETIME_VALUE:
1463 case ICAL_DATETIMEPERIOD_VALUE:
1464 case ICAL_QUERY_VALUE:
1465 case ICAL_UID_VALUE:
1466 case ICAL_XMLREFERENCE_VALUE:
1467 case ICAL_RECUR_VALUE: {
1468 int r;
1469 char *temp1, *temp2;
1470
1471 temp1 = icalvalue_as_ical_string_r(a);
1472 if (temp1) {
1473 temp2 = icalvalue_as_ical_string_r(b);
1474 if (temp2) {
1475 r = strcmp(temp1, temp2);
1476 } else {
1478 return ICAL_XLICCOMPARETYPE_GREATER;
1479 }
1480 } else {
1481 return ICAL_XLICCOMPARETYPE_LESS;
1482 }
1485
1486 if (r > 0) {
1487 return ICAL_XLICCOMPARETYPE_GREATER;
1488 } else if (r < 0) {
1489 return ICAL_XLICCOMPARETYPE_LESS;
1490 } else {
1491 return ICAL_XLICCOMPARETYPE_EQUAL;
1492 }
1493 }
1494
1495 case ICAL_METHOD_VALUE: {
1496 if (icalvalue_get_method(a) == icalvalue_get_method(b)) {
1497 return ICAL_XLICCOMPARETYPE_EQUAL;
1498 } else {
1499 return ICAL_XLICCOMPARETYPE_NOTEQUAL;
1500 }
1501 }
1502
1503 case ICAL_STATUS_VALUE: {
1504 if (icalvalue_get_status(a) == icalvalue_get_status(b)) {
1505 return ICAL_XLICCOMPARETYPE_EQUAL;
1506 } else {
1507 return ICAL_XLICCOMPARETYPE_NOTEQUAL;
1508 }
1509 }
1510
1511 case ICAL_TRANSP_VALUE: {
1512 if (icalvalue_get_transp(a) == icalvalue_get_transp(b)) {
1513 return ICAL_XLICCOMPARETYPE_EQUAL;
1514 } else {
1515 return ICAL_XLICCOMPARETYPE_NOTEQUAL;
1516 }
1517 }
1518
1519 case ICAL_ACTION_VALUE: {
1520 if (icalvalue_get_action(a) == icalvalue_get_action(b)) {
1521 return ICAL_XLICCOMPARETYPE_EQUAL;
1522 } else {
1523 return ICAL_XLICCOMPARETYPE_NOTEQUAL;
1524 }
1525 }
1526
1527 case ICAL_PERIOD_VALUE:
1528 case ICAL_GEO_VALUE:
1529 case ICAL_NO_VALUE:
1530 default: {
1531 icalerror_warn("Comparison not implemented for value type");
1532 return ICAL_XLICCOMPARETYPE_NONE;
1533 }
1534 }
1535}
1536
1537void icalvalue_reset_kind(icalvalue *value)
1538{
1539 if (value &&
1540 (value->kind == ICAL_DATETIME_VALUE || value->kind == ICAL_DATE_VALUE) &&
1541 !icaltime_is_null_time(value->data.v_time)) {
1542 if (icaltime_is_date(value->data.v_time)) {
1543 value->kind = ICAL_DATE_VALUE;
1544 } else {
1545 value->kind = ICAL_DATETIME_VALUE;
1546 }
1547 }
1548}
1549
1550void icalvalue_set_parent(icalvalue *value, icalproperty *property)
1551{
1552 icalerror_check_arg_rv((value != 0), "value");
1553
1554 value->parent = property;
1555}
1556
1557icalproperty *icalvalue_get_parent(const icalvalue *value)
1558{
1559 return value->parent;
1560}
1561
1562bool icalvalue_encode_ical_string(const char *szText, char *szEncText, int maxBufferLen)
1563{
1564 char *ptr;
1565 icalvalue *value = 0;
1566
1567 if ((szText == 0) || (szEncText == 0)) {
1568 return false;
1569 }
1570
1571 value = icalvalue_new_from_string(ICAL_STRING_VALUE, szText);
1572
1573 if (value == 0) {
1574 return false;
1575 }
1576
1577 ptr = icalvalue_text_as_ical_string_r(value);
1578 if (ptr == 0) {
1579 return false;
1580 }
1581
1582 if ((int)strlen(ptr) >= maxBufferLen) {
1583 icalvalue_free(value);
1585 return false;
1586 }
1587
1588 strcpy(szEncText, ptr); //NOLINT(clang-analyzer-security.insecureAPI.strcp
1590
1591 icalvalue_free((icalvalue *)value);
1592
1593 return true;
1594}
1595
1596bool icalvalue_decode_ical_string(const char *szText, char *szDecText, int maxBufferLen)
1597{
1598 char *str, *str_p;
1599 const char *p;
1600 size_t buf_sz;
1601
1602 if ((szText == 0) || (szDecText == 0) || (maxBufferLen <= 0)) {
1603 return false;
1604 }
1605
1606 buf_sz = strlen(szText) + 1;
1607 str_p = str = (char *)icalmemory_new_buffer(buf_sz);
1608
1609 if (str_p == 0) {
1610 return false;
1611 }
1612
1613 for (p = szText; *p != 0; p++) {
1614 if (*p == '\\') {
1615 icalmemory_append_char(&str, &str_p, &buf_sz, *(p + 1));
1616 p++;
1617 } else {
1618 icalmemory_append_char(&str, &str_p, &buf_sz, *p);
1619 }
1620
1621 if (str_p - str > maxBufferLen) {
1622 break;
1623 }
1624 }
1625
1626 icalmemory_append_char(&str, &str_p, &buf_sz, '\0');
1627
1628 if ((int)strlen(str) >= maxBufferLen) {
1630 return false;
1631 }
1632
1633 strcpy(szDecText, str); //NOLINT(clang-analyzer-security.insecureAPI.strcpy)
1634
1636 return true;
1637}
1638
1639/* The remaining interfaces are 'new', 'set' and 'get' for each of the value
1640 types */
icalattach * icalattach_new_from_data(const char *data, icalattach_free_fn_t free_fn, void *free_fn_data)
Creates new icalattach object from data.
Definition icalattach.c:56
void icalattach_unref(icalattach *attach)
Decrements reference count of the icalattach.
Definition icalattach.c:95
void icalattach_ref(icalattach *attach)
Increments reference count of the icalattach.
Definition icalattach.c:87
unsigned char * icalattach_get_data(icalattach *attach)
Returns the data of the icalattach object.
Definition icalattach.c:130
const char * icalattach_get_url(icalattach *attach)
Returns the URL of the icalattach object.
Definition icalattach.c:122
icalattach * icalattach_new_from_url(const char *url)
Creates new icalattach object from a URL.
Definition icalattach.c:25
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
bool icaldurationtype_is_bad_duration(struct icaldurationtype d)
Checks if a duration is a bad duration.
char * icaldurationtype_as_ical_string_r(struct icaldurationtype d)
struct icaldurationtype icaldurationtype_from_string(const char *str)
Creates a new icaldurationtype from a duration given as a string.
@ ICAL_UNKNOWN_STATUS
Definition icalenums.h:80
void icalerror_set_errno(icalerrorenum x)
Sets the icalerrno to a given error.
Definition icalerror.c:90
@ ICAL_NEWFAILED_ERROR
Definition icalerror.h:50
@ ICAL_BADARG_ERROR
Definition icalerror.h:47
@ ICAL_PARSE_ERROR
Definition icalerror.h:62
size_t icallimit_get(icallimits_kind kind)
Definition icallimits.c:29
Defines the interface for getting/setting internal library limits.
@ ICAL_LIMIT_VALUE_CHARS
Definition icallimits.h:34
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_append_char(char **buf, char **pos, size_t *buf_size, char ch)
Appends a character to a buffer.
Definition icalmemory.c:406
void icalmemory_add_tmp_buffer(void *buf)
Adds an externally allocated buffer to the ring.
Definition icalmemory.c:158
Common memory management routines.
char * icalperiodtype_as_ical_string_r(struct icalperiodtype p)
Converts an icalperiodtype into an iCal-formatted string.
Definition icalperiod.c:97
bool icalperiodtype_is_null_period(struct icalperiodtype p)
Definition icalperiod.c:138
struct icalperiodtype icalperiodtype_from_string(const char *str)
Constructs a new icalperiodtype from str.
Definition icalperiod.c:25
icalproperty_kind icalproperty_isa(const icalproperty *p)
bool icalproperty_get_allow_empty_properties(void)
char * icalproperty_enum_to_string_r(int e)
bool icalproperty_enum_belongs_to_property(icalproperty_kind kind, int e)
icalproperty_kind icalproperty_value_kind_to_kind(icalvalue_kind kind)
int icalproperty_kind_and_string_to_enum(const int kind, const char *str)
struct icalrecurrencetype * icalrecurrencetype_new_from_string(const char *str)
Definition icalrecur.c:869
struct icalrecurrencetype * icalrecurrencetype_clone(struct icalrecurrencetype *recur)
Definition icalrecur.c:832
void icalrecurrencetype_unref(struct icalrecurrencetype *recur)
Definition icalrecur.c:790
char * icalrecurrencetype_as_string_r(struct icalrecurrencetype *recur)
Definition icalrecur.c:1061
bool icaltime_is_date(const struct icaltimetype t)
Definition icaltime.c:616
struct icaltimetype icaltime_from_string(const char *str)
Definition icaltime.c:374
bool icaltime_is_utc(const struct icaltimetype t)
Definition icaltime.c:621
bool icaltime_is_null_time(const struct icaltimetype t)
Definition icaltime.c:626
char * icaltime_as_ical_string_r(const struct icaltimetype tt)
Definition icaltime.c:341
Defines the data structure for representing date-times.
struct icaltriggertype icaltriggertype_from_string(const char *str)
Definition icaltypes.c:61
bool icaltriggertype_is_bad_trigger(struct icaltriggertype tr)
Definition icaltypes.c:42
struct icalreqstattype icalreqstattype_from_string(const char *str)
Definition icaltypes.c:99
char * icalreqstattype_as_string_r(struct icalreqstattype stat)
Definition icaltypes.c:165
#define ICAL_GEO_LEN
Definition icaltypes.h:35
icalproperty * icalvalue_get_parent(const icalvalue *value)
Definition icalvalue.c:1557
icalvalue_kind icalvalue_isa(const icalvalue *value)
Definition icalvalue.c:1329
bool icalvalue_is_valid(const icalvalue *value)
Definition icalvalue.c:875
bool icalvalue_isa_value(void *value)
Definition icalvalue.c:1338
icalvalue * icalvalue_clone(const icalvalue *old)
Definition icalvalue.c:65
icalvalue * icalvalue_new_from_string(icalvalue_kind kind, const char *str)
Definition icalvalue.c:793
void icalvalue_set_parent(icalvalue *value, icalproperty *property)
Definition icalvalue.c:1550
icalparameter_xliccomparetype icalvalue_compare(const icalvalue *a, const icalvalue *b)
Definition icalvalue.c:1362
icalvalue * icalvalue_new(icalvalue_kind kind)
Definition icalvalue.c:60
bool icalvalue_decode_ical_string(const char *szText, char *szDecText, int maxBufferLen)
Definition icalvalue.c:1596
void icalvalue_reset_kind(icalvalue *value)
Definition icalvalue.c:1537
void icalvalue_free(icalvalue *v)
Definition icalvalue.c:798
char * icalvalue_as_ical_string_r(const icalvalue *value)
Definition icalvalue.c:1228
bool icalvalue_encode_ical_string(const char *szText, char *szEncText, int maxBufferLen)
Definition icalvalue.c:1562
const char * icalvalue_as_ical_string(const icalvalue *value)
Definition icalvalue.c:1219
Defines the data structure representing iCalendar parameter values.
bool icalvalue_kind_is_valid(const icalvalue_kind kind)
const char * icalvalue_kind_to_string(const icalvalue_kind kind)
struct icaltimetype time
Definition icaltypes.h:30
struct icalperiodtype period
Definition icaltypes.h:31
unsigned int weeks
unsigned int hours
unsigned int seconds
unsigned int days
unsigned int minutes
char lat[16]
Definition icaltypes.h:40
char lon[16]
Definition icaltypes.h:41
icalrequeststatus code
Definition icaltypes.h:111