$darkmode
Libical API Documentation 4.0 STABLE VERSION Visit the v3.0 documentation
icalproperty.c
Go to the documentation of this file.
1 /*======================================================================
2  FILE: icalproperty.c
3  CREATOR: eric 28 April 1999
4 
5  SPDX-FileCopyrightText: 2000, Eric Busboom <eric@civicknowledge.com>
6  SPDX-License-Identifier: LGPL-2.1-only OR MPL-2.0
7 ======================================================================*/
8 
14 #ifdef HAVE_CONFIG_H
15 #include <config.h>
16 #endif
17 
18 #include "icalproperty_p.h"
19 #include "icalcomponent.h"
20 #include "icalerror_p.h"
21 #include "icalerror.h"
22 #include "icalmemory.h"
23 #include "icalparser.h"
24 #include "icaltimezone.h"
25 #include "icalvalue.h"
26 #include "icalpvl_p.h"
27 #include "icaltypes_p.h"
28 
29 #include <stdlib.h>
30 
31 struct icalproperty_impl {
32  icalstructuretype id;
33  icalproperty_kind kind;
34  char *x_name;
35  icalpvl_list parameters;
36  icalpvl_elem parameter_iterator;
37  icalvalue *value;
38  icalcomponent *parent;
39 };
40 
42 LIBICAL_ICAL_EXPORT struct icalproperty_impl *icalproperty_new_impl(icalproperty_kind kind)
43 {
44  icalproperty *prop;
45 
46  if (!icalproperty_kind_is_valid(kind)) {
47  return NULL;
48  }
49 
50  if ((prop = (icalproperty *)icalmemory_new_buffer(sizeof(icalproperty))) == 0) {
52  return 0;
53  }
54 
55  memset(prop, 0, sizeof(icalproperty));
56 
57  prop->id = ICAL_STRUCTURE_TYPE_PROPERTY;
58  prop->kind = kind;
59  prop->parameters = icalpvl_newlist();
60 
61  return prop;
62 }
64 
65 static ICAL_GLOBAL_VAR bool icalprop_allow_empty_properties = false;
66 
68 {
69  icalprop_allow_empty_properties = enable;
70 }
71 
73 {
74  return icalprop_allow_empty_properties;
75 }
76 
77 void icalproperty_add_parameters(icalproperty *prop, va_list args)
78 {
79  void *vp;
80 
81  while ((vp = va_arg(args, void *)) != 0) {
82  if (icalvalue_isa_value(vp)) {
83  } else if (icalparameter_isa_parameter(vp)) {
84  icalproperty_add_parameter((icalproperty *)prop, (icalparameter *)vp);
85  } else {
87  }
88  }
89 }
90 
91 icalproperty *icalproperty_new(icalproperty_kind kind)
92 {
93  if (kind == ICAL_NO_PROPERTY) {
94  return 0;
95  }
96 
97  return (icalproperty *)icalproperty_new_impl(kind);
98 }
99 
100 icalproperty *icalproperty_clone(const icalproperty *old)
101 {
102  icalproperty *clone;
103  icalpvl_elem p;
104 
105  icalerror_check_arg_rz((old != 0), "old");
106  clone = icalproperty_new_impl(old->kind);
107  icalerror_check_arg_rz((clone != 0), "clone");
108 
109  if (old->value != 0) {
110  clone->value = icalvalue_clone(old->value);
111  }
112 
113  if (old->x_name != 0) {
114  clone->x_name = icalmemory_strdup(old->x_name);
115 
116  if (clone->x_name == 0) {
117  icalproperty_free(clone);
119  return 0;
120  }
121  }
122 
123  for (p = icalpvl_head(old->parameters); p != 0; p = icalpvl_next(p)) {
124  icalparameter *param = icalparameter_clone(icalpvl_data(p));
125 
126  if (param == 0) {
127  icalproperty_free(clone);
129  return 0;
130  }
131 
132  icalpvl_push(clone->parameters, param);
133  }
134 
135  return clone;
136 }
137 
138 icalproperty *icalproperty_new_from_string(const char *str)
139 {
140  size_t buf_size = 1024;
141  char *buf;
142  char *buf_ptr;
143  icalproperty *prop;
144  icalcomponent *comp;
145  int errors = 0;
146 
147  icalerror_check_arg_rz((str != 0), "str");
148 
149  buf = icalmemory_new_buffer(buf_size);
150  buf_ptr = buf;
151 
152  /* Is this a HACK or a crafty reuse of code? */
153 
154  icalmemory_append_string(&buf, &buf_ptr, &buf_size, "BEGIN:VCALENDAR\r\n");
155  icalmemory_append_string(&buf, &buf_ptr, &buf_size, str);
156  icalmemory_append_string(&buf, &buf_ptr, &buf_size, "\r\n");
157  icalmemory_append_string(&buf, &buf_ptr, &buf_size, "END:VCALENDAR\r\n");
158 
159  comp = icalparser_parse_string(buf);
160 
161  if (comp == 0) {
164  return 0;
165  }
166 
167  errors = icalcomponent_count_errors(comp);
168 
169  prop = icalcomponent_get_first_property(comp, ICAL_ANY_PROPERTY);
170 
171  icalcomponent_remove_property(comp, prop);
172 
173  icalcomponent_free(comp);
175 
176  if (errors > 0) {
177  icalproperty_free(prop);
178  return 0;
179  } else {
180  return prop;
181  }
182 }
183 
184 void icalproperty_free(icalproperty *p)
185 {
186  icalparameter *param;
187 
188  icalerror_check_arg_rv((p != 0), "prop");
189 
190  if (p->parent != 0) {
191  return;
192  }
193 
194  if (p->value != 0) {
195  icalvalue_set_parent(p->value, 0);
196  icalvalue_free(p->value);
197  }
198 
199  while ((param = icalpvl_pop(p->parameters)) != 0) {
200  icalparameter_free(param);
201  }
202 
203  icalpvl_free(p->parameters);
204  icalmemory_free_buffer(p->x_name);
205 
206  p->kind = ICAL_NO_PROPERTY;
207  p->parameters = 0;
208  p->parameter_iterator = 0;
209  p->value = 0;
210  p->x_name = 0;
211  p->id = ICAL_STRUCTURE_TYPE_PROPERTY_EMPTY;
212 
214 }
215 
216 /* This returns where the start of the next line should be. chars_left does
217  not include the trailing '\0'. */
218 static const size_t MAX_LINE_LEN = 75;
219 
220 static char *get_next_line_start(char *line_start, size_t chars_left)
221 {
222  char *pos;
223 
224  /* If we have 74 chars or less left, we can output all of them.
225  we return a pointer to the '\0' at the end of the string. */
226  if (chars_left < MAX_LINE_LEN) {
227  return line_start + chars_left;
228  }
229 
230  /* Now we jump to the last possible character of the line, and step back
231  trying to find a ';' ':' or ' '. If we find one, we return the character
232  after it. */
233  pos = line_start + MAX_LINE_LEN - 2;
234  while (pos > line_start) {
235  if (*pos == ';' || *pos == ':' || *pos == ' ') {
236  return pos + 1;
237  }
238  pos--;
239  }
240  /* Now try to split on a UTF-8 boundary defined as a 7-bit
241  value or as a byte with the two high-most bits set:
242  11xxxxxx. See https://czyborra.com/utf/ */
243 
244  pos = line_start + MAX_LINE_LEN - 1;
245  while (pos > line_start) {
246  /* plain ascii */
247  if ((*pos & 128) == 0) {
248  return pos;
249  }
250 
251  /* utf8 escape byte */
252  if ((*pos & 192) == 192) {
253  return pos;
254  }
255 
256  pos--;
257  }
258 
259  /* Give up, just break at 74 chars (the 75th char is the space at
260  the start of the line). */
261 
262  return line_start + MAX_LINE_LEN - 1;
263 }
264 
271 static char *fold_property_line(char *text)
272 {
273  size_t buf_size, len;
274  ssize_t chars_left;
275  char *buf, *buf_ptr, *line_start, *next_line_start;
276  int first_line;
277 
278  /* Start with a buffer twice the size of our property line, so we almost
279  certainly won't overflow it. */
280  len = strlen(text);
281  buf_size = len * 2;
282  buf = icalmemory_new_buffer(buf_size);
283  buf_ptr = buf;
284 
285  /* Step through the text, finding each line to add to the output. */
286  line_start = text;
287  chars_left = (ssize_t)len;
288  first_line = 1;
289  for (;;) {
290  if (chars_left <= 0) {
291  break;
292  }
293 
294  /* This returns the first character for the next line. */
295  next_line_start = get_next_line_start(line_start, (size_t)chars_left);
296 
297  /* If this isn't the first line, we need to output a newline and space
298  first. */
299  if (!first_line) {
300  icalmemory_append_string(&buf, &buf_ptr, &buf_size, "\r\n ");
301  }
302  first_line = 0;
303 
304  /* This adds the line to our tmp buffer. We temporarily place a '\0'
305  in text, so we can copy the line in one go. */
306  char ch = *next_line_start;
307  *next_line_start = '\0';
308  icalmemory_append_string(&buf, &buf_ptr, &buf_size, line_start);
309  *next_line_start = ch;
310 
311  /* Now we move on to the next line. */
312  chars_left -= (next_line_start - line_start);
313  line_start = next_line_start;
314  }
315 
316  icalmemory_append_string(&buf, &buf_ptr, &buf_size, "\r\n");
317 
318  return buf;
319 }
320 
321 /* Determine what VALUE parameter to include. The VALUE parameters
322  are ignored in the normal parameter printing ( the block after
323  this one, so we need to do it here */
324 static const char *icalproperty_get_value_kind(icalproperty *prop)
325 {
326  const char *kind_string = NULL;
327  if (!prop) {
328  return kind_string;
329  }
330 
331  icalvalue_kind kind = ICAL_NO_VALUE;
332  icalparameter *val_param =
333  icalproperty_get_first_parameter(prop, ICAL_VALUE_PARAMETER);
334 
335  if (val_param) {
336  kind = icalparameter_value_to_value_kind(icalparameter_get_value(val_param));
337  }
338 
339  if (kind == ICAL_NO_VALUE) {
340  icalvalue *value = icalproperty_get_value(prop);
341 
342  kind = icalvalue_isa(value);
343 
344  if (kind == ICAL_ATTACH_VALUE) {
345  icalattach *a = icalvalue_get_attach(value);
346 
347  kind = icalattach_get_is_url(a) ? ICAL_URI_VALUE : ICAL_BINARY_VALUE;
348  }
349  }
350 
351  if (kind != ICAL_NO_VALUE &&
352  !icalproperty_value_kind_is_default(prop->kind, kind)) {
353  /* Not the default, so it must be specified */
354  kind_string = icalvalue_kind_to_string(kind);
355  } else {
356  /* Don't include the VALUE parameter at all */
357  }
358 
359  return kind_string;
360 }
361 
362 const char *icalproperty_as_ical_string(icalproperty *prop)
363 {
364  const char *buf;
365 
366  buf = icalproperty_as_ical_string_r(prop);
367  icalmemory_add_tmp_buffer((char *)buf);
368  return buf;
369 }
370 
371 char *icalproperty_as_ical_string_r(icalproperty *prop)
372 {
373  icalparameter *param;
374 
375  /* Create new buffer that we can append names, parameters and a
376  * value to, and reallocate as needed.
377  */
378 
379  const char *property_name = 0;
380  size_t buf_size = 1024;
381  char *buf;
382  char *buf_ptr;
383  const icalvalue *value;
384  char *out_buf;
385  const char *kind_string = 0;
386 
387  icalerror_check_arg_rz((prop != 0), "prop");
388 
389  buf = icalmemory_new_buffer(buf_size);
390  buf_ptr = buf;
391 
392  /* Append property name */
393 
394  if ((prop->kind == ICAL_X_PROPERTY || prop->kind == ICAL_IANA_PROPERTY) && prop->x_name != 0) {
395  property_name = prop->x_name;
396  } else {
397  property_name = icalproperty_kind_to_string(prop->kind);
398  }
399 
400  if (property_name == 0) {
401  icalerror_warn("Got a property of an unknown kind.");
403  return 0;
404  }
405 
406  icalmemory_append_string(&buf, &buf_ptr, &buf_size, property_name);
407 
408  kind_string = icalproperty_get_value_kind(prop);
409  if (kind_string != 0) {
410  icalmemory_append_string(&buf, &buf_ptr, &buf_size, ";VALUE=");
411  icalmemory_append_string(&buf, &buf_ptr, &buf_size, kind_string);
412  }
413 
414  /* Append parameters */
415  for (param = icalproperty_get_first_parameter(prop, ICAL_ANY_PARAMETER);
416  param != 0; param = icalproperty_get_next_parameter(prop, ICAL_ANY_PARAMETER)) {
417  icalparameter_kind kind = icalparameter_isa(param);
418 
419  kind_string = icalparameter_as_ical_string_r(param);
420 
421  if (kind_string == 0) {
422  icalerror_warn("Got a parameter of unknown kind for the following property");
423 
424  icalerror_warn((property_name) ? property_name : "(NULL)");
425  continue;
426  }
427 
428  if (kind == ICAL_VALUE_PARAMETER) {
429  icalmemory_free_buffer((char *)kind_string);
430  continue;
431  }
432 
433  icalmemory_append_string(&buf, &buf_ptr, &buf_size, ";");
434  icalmemory_append_string(&buf, &buf_ptr, &buf_size, kind_string);
435  icalmemory_free_buffer((char *)kind_string);
436  }
437 
438  /* Append value */
439 
440  icalmemory_append_string(&buf, &buf_ptr, &buf_size, ":");
441 
442  value = icalproperty_get_value(prop);
443 
444  if (value != 0) {
445  char *str = icalvalue_as_ical_string_r(value);
446 
447  if (str != 0) {
448  icalmemory_append_string(&buf, &buf_ptr, &buf_size, str);
450  icalmemory_append_string(&buf, &buf_ptr, &buf_size, "ERROR: No Value");
451  }
454  icalmemory_append_string(&buf, &buf_ptr, &buf_size, "ERROR: No Value");
455  }
456 
457  /* We now use a function to fold the line properly every 75 characters.
458  That function also adds the newline for us. */
459  out_buf = fold_property_line(buf);
460 
462 
463  return out_buf;
464 }
465 
466 icalproperty_kind icalproperty_isa(const icalproperty *p)
467 {
468  if (p != 0) {
469  return p->kind;
470  }
471 
472  return ICAL_NO_PROPERTY;
473 }
474 
475 bool icalproperty_isa_property(void *property)
476 {
477  const icalproperty *impl = (icalproperty *)property;
478 
479  icalerror_check_arg_rz((property != 0), "property");
480  return (impl->id == ICAL_STRUCTURE_TYPE_PROPERTY);
481 }
482 
483 void icalproperty_add_parameter(icalproperty *p, icalparameter *parameter)
484 {
485  icalerror_check_arg_rv((p != 0), "prop");
486  icalerror_check_arg_rv((parameter != 0), "parameter");
487 
488  icalpvl_push(p->parameters, parameter);
489 }
490 
491 void icalproperty_set_parameter(icalproperty *prop, icalparameter *parameter)
492 {
493  icalparameter_kind kind;
494 
495  icalerror_check_arg_rv((prop != 0), "prop");
496  icalerror_check_arg_rv((parameter != 0), "parameter");
497 
498  kind = icalparameter_isa(parameter);
499  if (kind == ICAL_X_PARAMETER) {
501  } else if (kind == ICAL_IANA_PARAMETER) {
503  } else {
505  }
506 
507  icalproperty_add_parameter(prop, parameter);
508 }
509 
511  const char *name, const char *value)
512 {
513  icalparameter_kind kind;
514  icalparameter *param;
515 
516  icalerror_check_arg_rv((prop != 0), "prop");
517  icalerror_check_arg_rv((name != 0), "name");
518  icalerror_check_arg_rv((value != 0), "value");
519 
520  kind = icalparameter_string_to_kind(name);
521 
522  if (kind == ICAL_NO_PARAMETER) {
524  return;
525  }
526 
527  param = icalparameter_new_from_value_string(kind, value);
528 
529  if (param == 0) {
531  return;
532  }
533 
534  if (kind == ICAL_X_PARAMETER) {
535  icalparameter_set_xname(param, name);
536  } else if (kind == ICAL_IANA_PARAMETER) {
537  icalparameter_set_iana_name(param, name);
538  }
539 
540  icalproperty_set_parameter(prop, param);
541 }
542 
543 const char *icalproperty_get_parameter_as_string(icalproperty *prop, const char *name)
544 {
545  char *buf;
546 
547  buf = icalproperty_get_parameter_as_string_r(prop, name);
549  return buf;
550 }
551 
552 char *icalproperty_get_parameter_as_string_r(icalproperty *prop, const char *name)
553 {
554  icalparameter_kind kind;
555  icalparameter *param;
556  char *str;
557  const char *t;
558  const char *pv;
559  const char *pvql;
560  char *pvqr;
561 
562  icalerror_check_arg_rz((prop != 0), "prop");
563  icalerror_check_arg_rz((name != 0), "name");
564 
565  kind = icalparameter_string_to_kind(name);
566 
567  if (kind == ICAL_NO_PARAMETER) {
568  /* icalenum_string_to_parameter_kind will set icalerrno */
569  return 0;
570  }
571 
572  for (param = icalproperty_get_first_parameter(prop, kind);
573  param != 0; param = icalproperty_get_next_parameter(prop, kind)) {
574  if (kind == ICAL_X_PARAMETER) {
575  if (strcmp(icalparameter_get_xname(param), name) == 0) {
576  break;
577  }
578  } else if (kind == ICAL_IANA_PARAMETER) {
579  if (strcmp(icalparameter_get_iana_name(param), name) == 0) {
580  break;
581  }
582  } else {
583  break;
584  }
585  }
586 
587  if (param == 0) {
588  return 0;
589  }
590 
591  str = icalparameter_as_ical_string_r(param);
592 
593  t = strchr(str, '=');
594 
595  if (t == 0) {
598  return 0;
599  }
600 
601  /* Strip the property name and the equal sign */
602  pv = icalmemory_strdup(t + 1);
604 
605  /* Is the string quoted? */
606  pvql = strchr(pv, '"');
607  if (pvql == 0) {
608  return ((char *)pv); /* No quotes? Return it immediately. */
609  }
610 
611  /* Strip everything up to the first quote */
612  str = icalmemory_strdup(pvql + 1);
613  icalmemory_free_buffer((char *)pv);
614 
615  /* Search for the end quote */
616  pvqr = strrchr(str, '"');
617  if (pvqr == 0) {
620  return 0;
621  }
622 
623  *pvqr = '\0';
624  return str;
625 }
626 
627 void icalproperty_remove_parameter_by_kind(icalproperty *prop, icalparameter_kind kind)
628 {
629  icalpvl_elem p, next;
630 
631  icalerror_check_arg_rv((prop != 0), "prop");
632 
633  for (p = icalpvl_head(prop->parameters); p != 0; p = next) {
634  next = icalpvl_next(p);
635 
636  icalparameter *param = (icalparameter *)icalpvl_data(p);
637 
638  if (icalparameter_isa(param) == kind) {
639  (void)icalpvl_remove(prop->parameters, p);
640  icalparameter_free(param);
641  }
642  }
643 }
644 
645 void icalproperty_remove_parameter_by_name(icalproperty *prop, const char *name)
646 {
647  icalpvl_elem p, next;
648 
649  icalerror_check_arg_rv((prop != 0), "prop");
650 
651  for (p = icalpvl_head(prop->parameters); p != 0; p = next) {
652  next = icalpvl_next(p);
653 
654  icalparameter *param = (icalparameter *)icalpvl_data(p);
655  const char *kind_string;
656 
657  if (icalparameter_isa(param) == ICAL_X_PARAMETER) {
658  kind_string = icalparameter_get_xname(param);
659  } else if (icalparameter_isa(param) == ICAL_IANA_PARAMETER) {
660  kind_string = icalparameter_get_iana_name(param);
661  } else {
662  kind_string = icalparameter_kind_to_string(icalparameter_isa(param));
663  }
664 
665  if (!kind_string) {
666  continue;
667  }
668 
669  if (0 == strcasecmp(kind_string, name)) {
670  (void)icalpvl_remove(prop->parameters, p);
671  icalparameter_free(param);
672  }
673  }
674 }
675 
676 void icalproperty_remove_parameter_by_ref(icalproperty *prop, icalparameter *parameter)
677 {
678  icalpvl_elem p;
679 
680  icalerror_check_arg_rv((prop != 0), "prop");
681  icalerror_check_arg_rv((parameter != 0), "parameter");
682 
683  for (p = icalpvl_head(prop->parameters); p != 0; p = icalpvl_next(p)) {
684  icalparameter *p_param = (icalparameter *)icalpvl_data(p);
685 
686  if (icalparameter_has_same_name(parameter, p_param)) {
687  (void)icalpvl_remove(prop->parameters, p);
688  icalparameter_free(p_param);
689  break;
690  }
691  }
692 }
693 
694 int icalproperty_count_parameters(const icalproperty *prop)
695 {
696  if (prop != 0) {
697  return icalpvl_count(prop->parameters);
698  }
699 
701  return -1;
702 }
703 
704 icalparameter *icalproperty_get_first_parameter(icalproperty *p, icalparameter_kind kind)
705 {
706  icalerror_check_arg_rz((p != 0), "prop");
707 
708  p->parameter_iterator = icalpvl_head(p->parameters);
709 
710  if (p->parameter_iterator == 0) {
711  return 0;
712  }
713 
714  for (p->parameter_iterator = icalpvl_head(p->parameters);
715  p->parameter_iterator != 0; p->parameter_iterator = icalpvl_next(p->parameter_iterator)) {
716  icalparameter *param = (icalparameter *)icalpvl_data(p->parameter_iterator);
717 
718  if (icalparameter_isa(param) == kind || kind == ICAL_ANY_PARAMETER) {
719  return param;
720  }
721  }
722 
723  return 0;
724 }
725 
726 icalparameter *icalproperty_get_next_parameter(icalproperty *p, icalparameter_kind kind)
727 {
728  icalerror_check_arg_rz((p != 0), "prop");
729 
730  if (p->parameter_iterator == 0) {
731  return 0;
732  }
733 
734  for (p->parameter_iterator = icalpvl_next(p->parameter_iterator);
735  p->parameter_iterator != 0; p->parameter_iterator = icalpvl_next(p->parameter_iterator)) {
736  icalparameter *param = (icalparameter *)icalpvl_data(p->parameter_iterator);
737 
738  if (icalparameter_isa(param) == kind || kind == ICAL_ANY_PARAMETER) {
739  return param;
740  }
741  }
742 
743  return 0;
744 }
745 
746 void icalproperty_set_value(icalproperty *p, icalvalue *value)
747 {
748  icalvalue_kind kind;
749 
750  icalerror_check_arg_rv((p != 0), "prop");
751  icalerror_check_arg_rv((value != 0), "value");
752 
753  if (p->value != 0) {
754  icalvalue_set_parent(p->value, 0);
755  icalvalue_free(p->value);
756  p->value = 0;
757  }
758 
759  p->value = value;
760 
761  icalvalue_set_parent(value, p);
762 
763  kind = icalvalue_isa(value);
764  if (kind == ICAL_DATE_VALUE || kind == ICAL_DATETIME_VALUE) {
765  icalparameter *val_param;
766 
767  val_param = icalproperty_get_first_parameter(p, ICAL_VALUE_PARAMETER);
768 
769  if (val_param &&
770  icalparameter_value_to_value_kind(icalparameter_get_value(val_param)) != kind) {
771  icalproperty_remove_parameter_by_kind(p, ICAL_VALUE_PARAMETER);
772  }
773  }
774 }
775 
776 void icalproperty_set_value_from_string(icalproperty *prop, const char *str, const char *type)
777 {
778  icalvalue *nval;
779  icalvalue_kind kind = ICAL_NO_VALUE;
780 
781  icalerror_check_arg_rv((prop != 0), "prop");
782  icalerror_check_arg_rv((str != 0), "str");
783  icalerror_check_arg_rv((type != 0), "type");
784 
785  if (strcmp(type, "NO") == 0) {
786  /* Get the type from the value the property already has, if it exists */
787  const icalvalue *oval = icalproperty_get_value(prop);
788  if (oval != 0) {
789  /* Use the existing value kind */
790  kind = icalvalue_isa(oval);
791  } else {
792  /* Use the default kind for the property */
794  }
795  } else {
796  /* Use the given kind string */
797  kind = icalvalue_string_to_kind(type);
798  }
799 
800  if (kind == ICAL_NO_VALUE) {
802  return;
803  }
804 
806  nval = icalvalue_new_from_string(kind, str);
807 
808  if (nval == 0) {
809  /* icalvalue_new_from_string sets errno */
810  icalassert(icalerrno != ICAL_NO_ERROR);
811  return;
812  }
813 
814  icalproperty_set_value(prop, nval);
815 }
816 
817 icalvalue *icalproperty_get_value(const icalproperty *prop)
818 {
819  icalerror_check_arg_rz((prop != 0), "prop");
820 
821  return prop->value;
822 }
823 
824 const char *icalproperty_get_value_as_string(const icalproperty *prop)
825 {
826  char *buf;
827 
830  return buf;
831 }
832 
833 char *icalproperty_get_value_as_string_r(const icalproperty *prop)
834 {
835  const icalvalue *value;
836 
837  icalerror_check_arg_rz((prop != 0), "prop");
838 
839  value = prop->value;
840 
841  return icalvalue_as_ical_string_r(value);
842 }
843 
844 void icalproperty_set_x_name(icalproperty *prop, const char *name)
845 {
846  icalerror_check_arg_rv((name != 0), "name");
847  icalerror_check_arg_rv((prop != 0), "prop");
848 
849  icalmemory_free_buffer(prop->x_name);
850  prop->x_name = icalmemory_strdup(name);
851 
852  if (prop->x_name == 0) {
854  }
855 }
856 
857 const char *icalproperty_get_x_name(const icalproperty *prop)
858 {
859  icalerror_check_arg_rz((prop != 0), "prop");
860 
861  return prop->x_name;
862 }
863 
864 void icalproperty_set_iana_name(icalproperty *prop, const char *name)
865 {
866  icalerror_check_arg_rv((name != 0), "name");
867  icalerror_check_arg_rv((prop != 0), "prop");
868  icalerror_check_arg_rv((prop->kind == ICAL_IANA_PROPERTY), "prop->kind");
869 
870  icalmemory_free_buffer(prop->x_name);
871  prop->x_name = icalmemory_strdup(name);
872 
873  if (prop->x_name == 0) {
875  }
876 }
877 
878 const char *icalproperty_get_iana_name(const icalproperty *prop)
879 {
880  icalerror_check_arg_rz((prop != 0), "prop");
881  icalerror_check_arg_rz((prop->kind == ICAL_IANA_PROPERTY), "prop->kind");
882 
883  return prop->x_name;
884 }
885 
886 const char *icalproperty_get_property_name(const icalproperty *prop)
887 {
888  char *buf;
889 
892  return buf;
893 }
894 
895 char *icalproperty_get_property_name_r(const icalproperty *prop)
896 {
897  const char *property_name = 0;
898  size_t buf_size = 256;
899  char *buf;
900  char *buf_ptr;
901 
902  icalerror_check_arg_rz((prop != 0), "prop");
903 
904  buf = icalmemory_new_buffer(buf_size);
905  buf_ptr = buf;
906 
907  if ((prop->kind == ICAL_X_PROPERTY || prop->kind == ICAL_IANA_PROPERTY) && prop->x_name != 0) {
908  property_name = prop->x_name;
909  } else {
910  property_name = icalproperty_kind_to_string(prop->kind);
911  }
912 
913  if (property_name == 0) {
916  return 0;
917 
918  } else {
919  /* _append_string will automatically grow the buffer if
920  property_name is longer than the initial buffer size */
921  icalmemory_append_string(&buf, &buf_ptr, &buf_size, property_name);
922  }
923 
924  return buf;
925 }
926 
927 void icalproperty_set_parent(icalproperty *property, icalcomponent *component)
928 {
929  icalerror_check_arg_rv((property != 0), "property");
930 
931  property->parent = component;
932 }
933 
934 icalcomponent *icalproperty_get_parent(const icalproperty *property)
935 {
936  icalerror_check_arg_rz((property != 0), "property");
937 
938  return property->parent;
939 }
940 
941 static int param_compare(void *a, void *b)
942 {
943  /* XXX Need to sort values for multi-valued parameters (e.g. MEMBER) */
944  return strcmp(icalparameter_as_ical_string((icalparameter *)a),
945  icalparameter_as_ical_string((icalparameter *)b));
946 }
947 
948 void icalproperty_normalize(icalproperty *prop)
949 {
950  icalproperty_kind prop_kind = icalproperty_isa(prop);
951  icalpvl_list sorted_params = icalpvl_newlist();
952  icalparameter *param;
953 
954  /* Normalize parameters into sorted list */
955  while ((param = icalpvl_pop(prop->parameters)) != 0) {
956  int remove = 0;
957 
958  /* Remove parameters having default values */
959  switch (icalparameter_isa(param)) {
960  case ICAL_VALUE_PARAMETER:
961  /* Skip VALUE parameters for default property value types */
962  switch (prop_kind) {
963  case ICAL_ATTACH_PROPERTY:
964  if (icalparameter_get_value(param) == ICAL_VALUE_URI) {
965  remove = 1;
966  }
967  break;
968 
969  case ICAL_DTEND_PROPERTY:
970  case ICAL_DUE_PROPERTY:
971  case ICAL_DTSTART_PROPERTY:
972  case ICAL_EXDATE_PROPERTY:
973  case ICAL_RDATE_PROPERTY:
974  case ICAL_RECURRENCEID_PROPERTY:
975  if (icalparameter_get_value(param) == ICAL_VALUE_DATETIME) {
976  remove = 1;
977  }
978  break;
979 
980  case ICAL_DURATION_PROPERTY:
981  if (icalparameter_get_value(param) == ICAL_VALUE_DURATION) {
982  remove = 1;
983  }
984  break;
985 
986  case ICAL_RELATEDTO_PROPERTY:
987  if (icalparameter_get_value(param) == ICAL_VALUE_TEXT) {
988  remove = 1;
989  }
990  break;
991 
992  default:
993  break;
994  }
995  break;
996 
997  case ICAL_CUTYPE_PARAMETER:
998  if (icalparameter_get_cutype(param) == ICAL_CUTYPE_INDIVIDUAL) {
999  remove = 1;
1000  }
1001  break;
1002 
1003  case ICAL_ENCODING_PARAMETER:
1004  if (icalparameter_get_encoding(param) == ICAL_ENCODING_8BIT) {
1005  remove = 1;
1006  }
1007  break;
1008 
1009  case ICAL_FBTYPE_PARAMETER:
1010  if (icalparameter_get_fbtype(param) == ICAL_FBTYPE_BUSY) {
1011  remove = 1;
1012  }
1013  break;
1014 
1015  case ICAL_PARTSTAT_PARAMETER:
1016  if (icalparameter_get_partstat(param) == ICAL_PARTSTAT_NEEDSACTION) {
1017  remove = 1;
1018  }
1019  break;
1020 
1021  case ICAL_RELATED_PARAMETER:
1022  if (icalparameter_get_related(param) == ICAL_RELATED_START) {
1023  remove = 1;
1024  }
1025  break;
1026 
1027  case ICAL_RELTYPE_PARAMETER:
1028  if (icalparameter_get_reltype(param) == ICAL_RELTYPE_PARENT) {
1029  remove = 1;
1030  }
1031  break;
1032 
1033  case ICAL_ROLE_PARAMETER:
1034  if (icalparameter_get_role(param) == ICAL_ROLE_REQPARTICIPANT) {
1035  remove = 1;
1036  }
1037  break;
1038 
1039  case ICAL_RSVP_PARAMETER:
1040  if (icalparameter_get_rsvp(param) == ICAL_RSVP_FALSE) {
1041  remove = 1;
1042  }
1043  break;
1044 
1045  case ICAL_SCHEDULEAGENT_PARAMETER:
1046  if (icalparameter_get_scheduleagent(param) == ICAL_SCHEDULEAGENT_SERVER) {
1047  remove = 1;
1048  }
1049  break;
1050 
1051  default:
1052  break;
1053  }
1054 
1055  if (remove) {
1056  icalparameter_set_parent(param, 0); // MUST NOT have a parent to free
1057  icalparameter_free(param);
1058  } else {
1059  icalpvl_insert_ordered(sorted_params, param_compare, param);
1060  }
1061  }
1062 
1063  icalpvl_free(prop->parameters);
1064  prop->parameters = sorted_params;
1065 }
1066 
1068  icalcomponent *comp)
1069 {
1070  icalcomponent *c;
1071  icalparameter *param;
1072  struct icaltimetype ret;
1073 
1074  ret = icalvalue_get_datetime(icalproperty_get_value(prop));
1075 
1076  if (icaltime_is_utc(ret)) {
1077  return ret;
1078  }
1079 
1080  if ((param = icalproperty_get_first_parameter(prop, ICAL_TZID_PARAMETER)) != NULL) {
1081  const char *tzid = icalparameter_get_tzid(param);
1082  icaltimezone *tz = NULL;
1083 
1084  if (!comp) {
1085  comp = icalproperty_get_parent(prop);
1086  }
1087 
1088  for (c = comp; c != NULL; c = icalcomponent_get_parent(c)) {
1089  tz = icalcomponent_get_timezone(c, tzid);
1090  if (tz != NULL) {
1091  break;
1092  }
1093  }
1094 
1095  if (tz == NULL) {
1097  }
1098 
1099  if (tz == NULL) {
1101  }
1102 
1103  if (tz != NULL) {
1104  ret = icaltime_set_timezone(&ret, tz);
1105  }
1106  }
1107 
1108  return ret;
1109 }
1110 
1111 static const icalparamiter icalparamiter_null = {ICAL_NO_PARAMETER, 0};
1112 
1114 icalparamiter icalproperty_begin_parameter(icalproperty *property, icalparameter_kind kind)
1115 {
1116  icalerror_check_arg_re(property != 0, "property", icalparamiter_null);
1117 
1118  icalpvl_elem i;
1119 
1120  for (i = icalpvl_head(property->parameters); i != 0; i = icalpvl_next(i)) {
1121  icalparameter *p = (icalparameter *)icalpvl_data(i);
1122 
1123  if (icalparameter_isa(p) == kind || kind == ICAL_ANY_PARAMETER) {
1124  icalparamiter itr = {kind, i};
1125  return itr;
1126  }
1127  }
1128 
1129  return icalparamiter_null;
1130 }
1131 
1132 icalparameter *icalparamiter_next(icalparamiter *i)
1133 {
1134  icalerror_check_arg_rz((i != 0), "i");
1135 
1136  if (i->iter == 0) {
1137  return 0;
1138  }
1139 
1140  for (i->iter = icalpvl_next(i->iter); i->iter != 0; i->iter = icalpvl_next(i->iter)) {
1141  icalparameter *p = (icalparameter *)icalpvl_data(i->iter);
1142 
1143  if (icalparameter_isa(p) == i->kind || i->kind == ICAL_ANY_PARAMETER) {
1144  return icalparamiter_deref(i);
1145  }
1146  }
1147 
1148  return 0;
1149 }
1150 
1151 icalparameter *icalparamiter_deref(icalparamiter *i)
1152 {
1153  if (i->iter == 0) {
1154  return 0;
1155  }
1156 
1157  return icalpvl_data(i->iter);
1158 }
const char * icalproperty_get_x_name(const icalproperty *prop)
Definition: icalproperty.c:857
void icalparameter_set_parent(icalparameter *param, icalproperty *property)
const char * icalproperty_kind_to_string(icalproperty_kind kind)
bool icalattach_get_is_url(const icalattach *attach)
Determines if attach is an URL.
Definition: icalattach.c:115
void icalproperty_remove_parameter_by_kind(icalproperty *prop, icalparameter_kind kind)
Removes all parameters with the specified kind.
Definition: icalproperty.c:627
icalcomponent * icalparser_parse_string(const char *str)
Parses a string and returns the parsed icalcomponent.
Definition: icalparser.c:1331
void icalproperty_normalize(icalproperty *prop)
Definition: icalproperty.c:948
icalparameter_kind icalparameter_isa(const icalparameter *parameter)
char * icalvalue_as_ical_string_r(const icalvalue *value)
Definition: icalvalue.c:1226
Line-oriented parsing.
void icalparameter_free(icalparameter *param)
Frees an icalparameter object.
Definition: icalparameter.c:58
void icalproperty_add_parameters(icalproperty *prop, va_list args)
Definition: icalproperty.c:77
icalvalue * icalproperty_get_value(const icalproperty *prop)
Definition: icalproperty.c:817
void icalcomponent_remove_property(icalcomponent *component, icalproperty *property)
const char * icalparameter_get_iana_name(const icalparameter *param)
Returns the IANA name of param.
icalparameter * icalparameter_clone(const icalparameter *old)
Creates new icalparameter as a clone of the given one.
Definition: icalparameter.c:86
void icalproperty_set_value_from_string(icalproperty *prop, const char *str, const char *type)
Definition: icalproperty.c:776
Common memory management routines.
icalproperty_kind icalproperty_isa(const icalproperty *p)
Definition: icalproperty.c:466
Timezone handling routines.
icalcomponent * icalproperty_get_parent(const icalproperty *property)
Definition: icalproperty.c:934
int icalcomponent_count_errors(icalcomponent *component)
Defines the data structure representing iCalendar parameter values.
icaltimezone * icalcomponent_get_timezone(icalcomponent *comp, const char *tzid)
void icalparameter_set_iana_name(icalparameter *param, const char *v)
Sets the IANA name of param to v.
const char * icalproperty_get_parameter_as_string(icalproperty *prop, const char *name)
Definition: icalproperty.c:543
const char * icalparameter_kind_to_string(icalparameter_kind kind)
Returns a string representing the given icalparameter_kind.
const char * icalproperty_get_value_as_string(const icalproperty *prop)
Definition: icalproperty.c:824
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
bool icalparameter_isa_parameter(void *parameter)
void icalproperty_set_parameter(icalproperty *prop, icalparameter *parameter)
Definition: icalproperty.c:491
Defines the data structure for iCalendar components.
void icalerror_set_errno(icalerrorenum x)
Sets the icalerrno to a given error.
Definition: icalerror.c:90
icalproperty * icalproperty_new(icalproperty_kind kind)
Definition: icalproperty.c:91
void icalproperty_add_parameter(icalproperty *p, icalparameter *parameter)
Definition: icalproperty.c:483
void icalerror_clear_errno(void)
Resets icalerrno to ICAL_NO_ERROR.
Definition: icalerror.c:85
bool icalparameter_has_same_name(const icalparameter *param1, const icalparameter *param2)
Determines if two parameters have the same name.
icaltimezone * icaltimezone_get_builtin_timezone_from_tzid(const char *tzid)
void icalproperty_set_x_name(icalproperty *prop, const char *name)
Definition: icalproperty.c:844
Error handling for libical.
void icalproperty_free(icalproperty *p)
Definition: icalproperty.c:184
void icalproperty_set_value(icalproperty *p, icalvalue *value)
Definition: icalproperty.c:746
char * icalproperty_get_parameter_as_string_r(icalproperty *prop, const char *name)
Definition: icalproperty.c:552
void icalvalue_free(icalvalue *v)
Definition: icalvalue.c:796
struct icaltimetype icaltime_set_timezone(struct icaltimetype *t, const icaltimezone *zone)
Definition: icaltime.c:883
void icalproperty_set_parent(icalproperty *property, icalcomponent *component)
Definition: icalproperty.c:927
icalvalue_kind icalproperty_kind_to_value_kind(icalproperty_kind kind)
icaltimezone * icaltimezone_get_builtin_timezone(const char *location)
const char * icalproperty_get_property_name(const icalproperty *prop)
Definition: icalproperty.c:886
struct _icaltimezone icaltimezone
Definition: icaltimezone.h:29
icalvalue_kind icalvalue_string_to_kind(const char *str)
bool icalvalue_isa_value(void *value)
Definition: icalvalue.c:1336
icalproperty * icalproperty_new_from_string(const char *str)
Definition: icalproperty.c:138
char * icalparameter_as_ical_string(icalparameter *param)
Converts icalparameter into a string representation.
char * icalproperty_as_ical_string_r(icalproperty *prop)
Definition: icalproperty.c:371
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
int icalproperty_count_parameters(const icalproperty *prop)
Definition: icalproperty.c:694
void icalproperty_set_parameter_from_string(icalproperty *prop, const char *name, const char *value)
Definition: icalproperty.c:510
char * icalparameter_as_ical_string_r(icalparameter *param)
Converts icalparameter into a string representation according to RFC5445/RFC6868. ...
icalvalue * icalvalue_clone(const icalvalue *old)
Definition: icalvalue.c:65
char * icalproperty_get_property_name_r(const icalproperty *prop)
Definition: icalproperty.c:895
icalvalue_kind icalvalue_isa(const icalvalue *value)
Definition: icalvalue.c:1327
bool icalproperty_isa_property(void *property)
Definition: icalproperty.c:475
const char * icalproperty_get_iana_name(const icalproperty *prop)
Definition: icalproperty.c:878
icalparameter * icalproperty_get_first_parameter(icalproperty *p, icalparameter_kind kind)
Definition: icalproperty.c:704
icalvalue_kind icalparameter_value_to_value_kind(icalparameter_value value)
void icalproperty_set_iana_name(icalproperty *prop, const char *name)
Definition: icalproperty.c:864
const char * icalvalue_kind_to_string(const icalvalue_kind kind)
icalproperty * icalproperty_clone(const icalproperty *old)
Definition: icalproperty.c:100
void icalproperty_remove_parameter_by_name(icalproperty *prop, const char *name)
Removes all parameters with the specified name.
Definition: icalproperty.c:645
void icalproperty_set_allow_empty_properties(bool enable)
Definition: icalproperty.c:67
struct icalattach_impl icalattach
An iCal attach object representing a link to a document object.
Definition: icalattach.h:36
void icalparameter_set_xname(icalparameter *param, const char *v)
Sets the X-name of param to v.
icalparameter * icalparameter_new_from_value_string(icalparameter_kind kind, const char *value)
Creates new icalparameter of a given kind with a given value.
icalparameter_kind icalparameter_string_to_kind(const char *string)
Returns the icalparameter_kind for a given string.
const char * icalparameter_get_xname(const icalparameter *param)
Returns the X-name of param.
#define icalerrno
Access the current icalerrno value.
Definition: icalerror.h:133
bool icalproperty_get_allow_empty_properties(void)
Definition: icalproperty.c:72
icalparameter * icalproperty_get_next_parameter(icalproperty *p, icalparameter_kind kind)
Definition: icalproperty.c:726
struct icaltimetype icalproperty_get_datetime_with_component(icalproperty *prop, icalcomponent *comp)
const char * icalproperty_as_ical_string(icalproperty *prop)
Definition: icalproperty.c:362
void icalmemory_add_tmp_buffer(void *buf)
Adds an externally allocated buffer to the ring.
Definition: icalmemory.c:158
void icalvalue_set_parent(icalvalue *value, icalproperty *property)
Definition: icalvalue.c:1544
void icalcomponent_free(icalcomponent *c)
icalvalue * icalvalue_new_from_string(icalvalue_kind kind, const char *str)
Definition: icalvalue.c:791
void icalproperty_remove_parameter_by_ref(icalproperty *prop, icalparameter *parameter)
Removes the specified parameter reference from the property.
Definition: icalproperty.c:676
char * icalproperty_get_value_as_string_r(const icalproperty *prop)
Definition: icalproperty.c:833
bool icalproperty_kind_is_valid(const icalproperty_kind kind)
icalproperty * icalcomponent_get_first_property(icalcomponent *c, icalproperty_kind kind)