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