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