$darkmode
Libical API Documentation 4.0 STABLE VERSION Visit the v3.0 documentation
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 
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 
35 LIBICAL_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 
60 icalvalue *icalvalue_new(icalvalue_kind kind)
61 {
62  return (icalvalue *)icalvalue_new_impl(kind);
63 }
64 
65 icalvalue *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 
177 static 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  */
258 static 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  */
347 static 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 
371 static 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 
429 static void free_icalvalue_attach_data(char *data, void *user_data)
430 {
431  _unused(user_data);
432  free(data);
433 }
434 
435 static 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 
676  icalvalue_reset_kind(value);
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 
791 icalvalue *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 
796 void 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 
873 bool icalvalue_is_valid(const icalvalue *value)
874 {
875  if (value == 0) {
876  return false;
877  }
878 
879  return true;
880 }
881 
882 static 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 
894 static 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 */
911 
913 static 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 
928 static 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 
961 static 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 
978 static 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 
985 static char *icalvalue_text_as_ical_string_r(const icalvalue *value)
986 {
987  return icalmemory_strdup_and_quote(value, value->data.v_string);
988 }
989 
990 static 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 
1020 static 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 
1027  return icaldurationtype_as_ical_string_r(data);
1028 }
1029 
1030 static 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 
1056 void 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 
1076 static 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 
1093 void 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 
1117 static 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 
1140 static 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 
1166 static 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 
1180 static 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 
1193 static 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 
1200  return icalperiodtype_as_ical_string_r(data);
1201 }
1202 
1203 static 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 
1217 const 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 
1226 char *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 
1327 icalvalue_kind icalvalue_isa(const icalvalue *value)
1328 {
1329  if (value == 0) {
1330  return ICAL_NO_VALUE;
1331  }
1332 
1333  return value->kind;
1334 }
1335 
1336 bool 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 
1345 static 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 
1356 icalparameter_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 {
1471  icalmemory_free_buffer(temp1);
1472  return ICAL_XLICCOMPARETYPE_GREATER;
1473  }
1474  } else {
1475  return ICAL_XLICCOMPARETYPE_LESS;
1476  }
1477  icalmemory_free_buffer(temp1);
1478  icalmemory_free_buffer(temp2);
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 
1531 void 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 
1544 void icalvalue_set_parent(icalvalue *value, icalproperty *property)
1545 {
1546  icalerror_check_arg_rv((value != 0), "value");
1547 
1548  value->parent = property;
1549 }
1550 
1551 icalproperty *icalvalue_get_parent(const icalvalue *value)
1552 {
1553  return value->parent;
1554 }
1555 
1556 bool 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 
1590 bool 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 */
void icalvalue_reset_kind(icalvalue *value)
Definition: icalvalue.c:1531
int is_date
Definition: icaltime.h:98
bool icalattach_get_is_url(const icalattach *attach)
Determines if attach is an URL.
Definition: icalattach.c:115
bool icalvalue_kind_is_valid(const icalvalue_kind kind)
char * icalvalue_as_ical_string_r(const icalvalue *value)
Definition: icalvalue.c:1226
icalparameter_xliccomparetype icalvalue_compare(const icalvalue *a, const icalvalue *b)
Definition: icalvalue.c:1356
icalproperty * icalvalue_get_parent(const icalvalue *value)
Definition: icalvalue.c:1551
icalproperty_kind icalproperty_value_kind_to_kind(icalvalue_kind kind)
char * icalreqstattype_as_string_r(struct icalreqstattype stat)
Definition: icaltypes.c:165
Common memory management routines.
icalproperty_kind icalproperty_isa(const icalproperty *p)
Definition: icalproperty.c:466
Defines the data structure representing iCalendar parameter values.
unsigned int seconds
Definition: icalduration.h:36
int second
Definition: icaltime.h:96
unsigned int days
Definition: icalduration.h:32
char * icalmemory_strdup(const char *s)
Creates a duplicate of a string.
Definition: icalmemory.c:242
void icalmemory_free_buffer(void *buf)
Releases a buffer.
Definition: icalmemory.c:355
bool icaltime_is_utc(const struct icaltimetype t)
Definition: icaltime.c:625
Defines the data structure for representing date-times.
struct icalrecurrencetype * icalrecurrencetype_new_from_string(const char *str)
Definition: icalrecur.c:869
bool icaltriggertype_is_bad_trigger(struct icaltriggertype tr)
Definition: icaltypes.c:42
char * icalrecurrencetype_as_string_r(struct icalrecurrencetype *recur)
Definition: icalrecur.c:1061
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
#define ICAL_GEO_LEN
Definition: icaltypes.h:35
size_t icallimit_get(icallimits_kind kind)
Definition: icallimits.c:29
void icalerror_set_errno(icalerrorenum x)
Sets the icalerrno to a given error.
Definition: icalerror.c:90
bool icalvalue_is_valid(const icalvalue *value)
Definition: icalvalue.c:873
char * icalproperty_enum_to_string_r(int e)
bool icalproperty_enum_belongs_to_property(icalproperty_kind kind, int e)
unsigned char * icalattach_get_data(icalattach *attach)
Returns the data of the icalattach object.
Definition: icalattach.c:130
bool icalvalue_decode_ical_string(const char *szText, char *szDecText, int maxBufferLen)
Definition: icalvalue.c:1590
struct icalreqstattype icalreqstattype_from_string(const char *str)
Definition: icaltypes.c:99
bool icalperiodtype_is_null_period(struct icalperiodtype p)
Definition: icalperiod.c:138
void icalattach_unref(icalattach *attach)
Decrements reference count of the icalattach.
Definition: icalattach.c:95
void icalmemory_append_char(char **buf, char **pos, size_t *buf_size, char ch)
Appends a character to a buffer.
Definition: icalmemory.c:406
int minute
Definition: icaltime.h:95
unsigned int minutes
Definition: icalduration.h:35
bool icalvalue_encode_ical_string(const char *szText, char *szEncText, int maxBufferLen)
Definition: icalvalue.c:1556
void icalattach_ref(icalattach *attach)
Increments reference count of the icalattach.
Definition: icalattach.c:87
void icalvalue_free(icalvalue *v)
Definition: icalvalue.c:796
const char * icalattach_get_url(icalattach *attach)
Returns the URL of the icalattach object.
Definition: icalattach.c:122
char * icaldurationtype_as_ical_string_r(struct icaldurationtype d)
Definition: icalduration.c:190
struct icaltimetype time
Definition: icaltypes.h:30
icalrequeststatus code
Definition: icaltypes.h:111
bool icalvalue_isa_value(void *value)
Definition: icalvalue.c:1336
void * icalmemory_new_buffer(size_t size)
Creates new buffer with the specified size.
Definition: icalmemory.c:315
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
struct icaltimetype icaltime_from_string(const char *str)
Definition: icaltime.c:374
Defines the interface for getting/setting internal library limits.
char lon[16]
Definition: icaltypes.h:41
bool icaltime_is_date(const struct icaltimetype t)
Definition: icaltime.c:620
icalvalue * icalvalue_clone(const icalvalue *old)
Definition: icalvalue.c:65
icalattach * icalattach_new_from_url(const char *url)
Creates new icalattach object from a URL.
Definition: icalattach.c:25
char * icalperiodtype_as_ical_string_r(struct icalperiodtype p)
Converts an icalperiodtype into an iCal-formatted string.
Definition: icalperiod.c:97
icalvalue_kind icalvalue_isa(const icalvalue *value)
Definition: icalvalue.c:1327
unsigned int hours
Definition: icalduration.h:34
const char * icalvalue_kind_to_string(const icalvalue_kind kind)
struct icaltriggertype icaltriggertype_from_string(const char *str)
Definition: icaltypes.c:61
void icalvalue_set_parent(icalvalue *value, icalproperty *property)
Definition: icalvalue.c:1544
struct icalattach_impl icalattach
An iCal attach object representing a link to a document object.
Definition: icalattach.h:36
void icalrecurrencetype_unref(struct icalrecurrencetype *recur)
Definition: icalrecur.c:790
icalvalue * icalvalue_new(icalvalue_kind kind)
Definition: icalvalue.c:60
struct icalperiodtype icalperiodtype_from_string(const char *str)
Constructs a new icalperiodtype from str.
Definition: icalperiod.c:25
int icalproperty_kind_and_string_to_enum(const int kind, const char *str)
unsigned int weeks
Definition: icalduration.h:33
bool icalproperty_get_allow_empty_properties(void)
Definition: icalproperty.c:72
char lat[16]
Definition: icaltypes.h:40
bool icaltime_is_null_time(const struct icaltimetype t)
Definition: icaltime.c:630
const char * icalvalue_as_ical_string(const icalvalue *value)
Definition: icalvalue.c:1217
struct icaldurationtype icaldurationtype_from_string(const char *str)
Creates a new icaldurationtype from a duration given as a string.
Definition: icalduration.c:43
bool icaldurationtype_is_bad_duration(struct icaldurationtype d)
Checks if a duration is a bad duration.
Definition: icalduration.c:292
struct icalrecurrencetype * icalrecurrencetype_clone(struct icalrecurrencetype *recur)
Definition: icalrecur.c:832
void icalmemory_add_tmp_buffer(void *buf)
Adds an externally allocated buffer to the ring.
Definition: icalmemory.c:158
icalvalue * icalvalue_new_from_string(icalvalue_kind kind, const char *str)
Definition: icalvalue.c:791
struct icalperiodtype period
Definition: icaltypes.h:31
char * icaltime_as_ical_string_r(const struct icaltimetype tt)
Definition: icaltime.c:341