Libical API Documentation 4.0 STABLE VERSION Visit the v3.0 documentation
Loading...
Searching...
No Matches
vcardproperty.c
Go to the documentation of this file.
1/*======================================================================
2 FILE: vcardproperty.c
3 CREATOR: Ken Murchison 24 Aug 2022
4
5 SPDX-FileCopyrightText: 2022, Fastmail Pty. Ltd. (https://fastmail.com)
6 SPDX-License-Identifier: LGPL-2.1-only OR MPL-2.0
7 ======================================================================*/
8
13
14#ifdef HAVE_CONFIG_H
15#include <config.h>
16#endif
17
18#include "vcardproperty_p.h"
19#include "vcardcomponent.h"
20#include "vcardparser.h"
21#include "vcardvalue.h"
22#include "icalerror_p.h"
23#include "icalmemory.h"
24#include "icalproperty.h"
25#include "icalpvl_p.h"
26#include "icaltypes_p.h"
27
28#include <stdlib.h>
29
30struct vcardproperty_impl {
31 icalstructuretype id;
32 vcardproperty_kind kind;
33 char *x_name;
34 char *group;
35 icalpvl_list parameters;
36 icalpvl_elem parameter_iterator;
37 vcardvalue *value;
38 vcardcomponent *parent;
39};
40
41LIBICAL_VCARD_EXPORT struct vcardproperty_impl *vcardproperty_new_impl(vcardproperty_kind kind)
42{
43 vcardproperty *prop;
44
45 if (!vcardproperty_kind_is_valid(kind)) {
46 return NULL;
47 }
48
49 if ((prop = (vcardproperty *)icalmemory_new_buffer(sizeof(vcardproperty))) == 0) {
51 return 0;
52 }
53
54 memset(prop, 0, sizeof(vcardproperty));
55
56 prop->id = ICAL_STRUCTURE_TYPE_PROPERTY;
57 prop->kind = kind;
58 prop->parameters = icalpvl_newlist();
59
60 return prop;
61}
62
63void vcardproperty_add_parameters(vcardproperty *prop, va_list args)
64{
65 void *vp;
66
67 while ((vp = va_arg(args, void *)) != 0) {
68 if (vcardvalue_isa_value(vp) != 0) {
69 } else if (vcardparameter_isa_parameter(vp) != 0) {
70 vcardproperty_add_parameter((vcardproperty *)prop,
71 (vcardparameter *)vp);
72 } else {
74 }
75 }
76}
77
78vcardproperty *vcardproperty_new(vcardproperty_kind kind)
79{
80 if (kind == VCARD_NO_PROPERTY) {
81 return 0;
82 }
83
84 return (vcardproperty *)vcardproperty_new_impl(kind);
85}
86
87vcardproperty *vcardproperty_clone(const vcardproperty *old)
88{
89 vcardproperty *clone;
90 icalpvl_elem p;
91
92 icalerror_check_arg_rz((old != 0), "old");
93 clone = vcardproperty_new_impl(old->kind);
94 icalerror_check_arg_rz((clone != 0), "clone");
95
96 if (old->value != 0) {
97 clone->value = vcardvalue_clone(old->value);
98 }
99
100 if (old->x_name != 0) {
101 clone->x_name = icalmemory_strdup(old->x_name);
102
103 if (clone->x_name == 0) {
104 vcardproperty_free(clone);
106 return 0;
107 }
108 }
109
110 for (p = icalpvl_head(old->parameters); p != 0; p = icalpvl_next(p)) {
111 vcardparameter *param = vcardparameter_clone(icalpvl_data(p));
112
113 if (param == 0) {
114 vcardproperty_free(clone);
116 return 0;
117 }
118
119 icalpvl_push(clone->parameters, param);
120 }
121
122 return clone;
123}
124
125vcardproperty *vcardproperty_new_from_string(const char *str)
126{
127 size_t buf_size = 1024;
128 char *buf;
129 char *buf_ptr;
130 vcardproperty *prop;
131 vcardcomponent *comp;
132 int errors = 0;
133
134 icalerror_check_arg_rz((str != 0), "str");
135
136 buf = icalmemory_new_buffer(buf_size);
137 buf_ptr = buf;
138
139 /* Is this a HACK or a crafty reuse of code? */
140
141 icalmemory_append_string(&buf, &buf_ptr, &buf_size, "BEGIN:VCARD\r\n");
142 icalmemory_append_string(&buf, &buf_ptr, &buf_size, str);
143 icalmemory_append_string(&buf, &buf_ptr, &buf_size, "\r\n");
144 icalmemory_append_string(&buf, &buf_ptr, &buf_size, "END:VCARD\r\n");
145
146 comp = vcardparser_parse_string(buf);
147
148 if (comp == 0) {
151 return 0;
152 }
153
154 errors = vcardcomponent_count_errors(comp);
155
156 prop = vcardcomponent_get_first_property(comp, VCARD_ANY_PROPERTY);
157
158 vcardcomponent_remove_property(comp, prop);
159
160 vcardcomponent_free(comp);
162
163 if (errors > 0) {
164 vcardproperty_free(prop);
165 return 0;
166 } else {
167 return prop;
168 }
169}
170
171void vcardproperty_free(vcardproperty *p)
172{
173 vcardparameter *param;
174
175 icalerror_check_arg_rv((p != 0), "prop");
176
177 if (p->parent != 0) {
178 return;
179 }
180
181 if (p->value != 0) {
182 vcardvalue_set_parent(p->value, 0);
183 vcardvalue_free(p->value);
184 }
185
186 while ((param = icalpvl_pop(p->parameters)) != 0) {
187 vcardparameter_free(param);
188 }
189
190 icalpvl_free(p->parameters);
191
192 if (p->x_name != 0) {
193 icalmemory_free_buffer(p->x_name);
194 }
195
196 if (p->group != 0) {
197 icalmemory_free_buffer(p->group);
198 }
199
200 p->kind = VCARD_NO_PROPERTY;
201 p->parameters = 0;
202 p->parameter_iterator = 0;
203 p->value = 0;
204 p->x_name = 0;
205 p->id = ICAL_STRUCTURE_TYPE_PROPERTY_EMPTY;
206
208}
209
210/* This returns where the start of the next line should be. chars_left does
211 not include the trailing '\0'. */
212static const size_t MAX_LINE_LEN = 75;
213
214static char *get_next_line_start(char *line_start, size_t chars_left)
215{
216 char *pos;
217
218 /* If we have 74 chars or less left, we can output all of them.
219 we return a pointer to the '\0' at the end of the string. */
220 if (chars_left < MAX_LINE_LEN) {
221 return line_start + chars_left;
222 }
223
224 /* Now we jump to the last possible character of the line, and step back
225 trying to find a ';' ':' or ' '. If we find one, we return the character
226 after it. */
227 pos = line_start + MAX_LINE_LEN - 2;
228 while (pos > line_start) {
229 if (*pos == ';' || *pos == ':' || *pos == ' ') {
230 return pos + 1;
231 }
232 pos--;
233 }
234 /* Now try to split on a UTF-8 boundary defined as a 7-bit
235 value or as a byte with the two high-most bits set:
236 11xxxxxx. See https://czyborra.com/utf/ */
237
238 pos = line_start + MAX_LINE_LEN - 1;
239 while (pos > line_start) {
240 /* plain ascii */
241 if ((*pos & 128) == 0) {
242 return pos;
243 }
244
245 /* utf8 escape byte */
246 if ((*pos & 192) == 192) {
247 return pos;
248 }
249
250 pos--;
251 }
252
253 /* Give up, just break at 74 chars (the 75th char is the space at
254 the start of the line). */
255
256 return line_start + MAX_LINE_LEN - 1;
257}
258
265static char *fold_property_line(char *text)
266{
267 size_t buf_size, len;
268 ssize_t chars_left;
269 char *buf, *buf_ptr, *line_start, *next_line_start;
270 int first_line;
271
272 /* Start with a buffer twice the size of our property line, so we almost
273 certainly won't overflow it. */
274 len = strlen(text);
275 buf_size = len * 2;
276 buf = icalmemory_new_buffer(buf_size);
277 buf_ptr = buf;
278
279 /* Step through the text, finding each line to add to the output. */
280 line_start = text;
281 chars_left = (ssize_t)len;
282 first_line = 1;
283 for (;;) {
284 if (chars_left <= 0) {
285 break;
286 }
287
288 /* This returns the first character for the next line. */
289 next_line_start = get_next_line_start(line_start, (size_t)chars_left);
290
291 /* If this isn't the first line, we need to output a newline and space
292 first. */
293 if (!first_line) {
294 icalmemory_append_string(&buf, &buf_ptr, &buf_size, "\r\n ");
295 }
296 first_line = 0;
297
298 /* This adds the line to our tmp buffer. We temporarily place a '\0'
299 in text, so we can copy the line in one go. */
300 char ch = *next_line_start;
301 *next_line_start = '\0';
302 icalmemory_append_string(&buf, &buf_ptr, &buf_size, line_start);
303 *next_line_start = ch;
304
305 /* Now we move on to the next line. */
306 chars_left -= (next_line_start - line_start);
307 line_start = next_line_start;
308 }
309
310 icalmemory_append_string(&buf, &buf_ptr, &buf_size, "\r\n");
311
312 return buf;
313}
314
315/* Determine what VALUE parameter to include. The VALUE parameters
316 are ignored in the normal parameter printing ( the block after
317 this one, so we need to do it here */
318static const char *vcardproperty_get_value_kind(vcardproperty *prop,
319 const vcardvalue *value)
320{
321 const char *kind_string = NULL;
322 if (!prop) {
323 return kind_string;
324 }
325 vcardvalue_kind kind = VCARD_NO_VALUE;
326 vcardparameter *val_param =
327 vcardproperty_get_first_parameter(prop, VCARD_VALUE_PARAMETER);
328 vcardproperty_version version = vcardcomponent_get_version(prop->parent);
329
330 if (version == VCARD_VERSION_NONE) {
331 version = VCARD_VERSION_30;
332 }
333
334 if (val_param) {
335 kind = vcardparameter_value_to_value_kind(vcardparameter_get_value(val_param));
336 }
337
338 if (kind == VCARD_NO_VALUE && vcardproperty_isa(prop) != VCARD_X_PROPERTY) {
339 kind = vcardvalue_isa(value);
340 }
341
342 /* Try to omit VERSION-dependent default VALUE kinds */
343 switch (vcardproperty_isa(prop)) {
344 case VCARD_GEO_PROPERTY:
345 /* v3 default: VALUE=STRUCTURED
346 * v4 default: VALUE=URL
347 */
348 if (kind != VCARD_X_VALUE) {
349 kind = VCARD_NO_VALUE;
350 }
351 break;
352
353 case VCARD_KEY_PROPERTY:
354 case VCARD_LOGO_PROPERTY:
355 case VCARD_PHOTO_PROPERTY:
356 case VCARD_SOUND_PROPERTY:
357 /* v3 default: VALUE=BINARY (ENCODING=b parameter)
358 * v4 default: VALUE=URL
359 */
360 if (version == VCARD_VERSION_40 ||
361 vcardproperty_get_first_parameter(prop, VCARD_ENCODING_PARAMETER)) {
362 kind = VCARD_NO_VALUE;
363 }
364 break;
365
366 case VCARD_ANNIVERSARY_PROPERTY:
367 case VCARD_BDAY_PROPERTY:
368 case VCARD_DEATHDATE_PROPERTY:
369 /* TIME is v4 specific.
370 * All other types are self-evident.
371 */
372 if (version == VCARD_VERSION_40 &&
373 (kind == VCARD_TIME_VALUE || kind == VCARD_DATEANDORTIME_VALUE)) {
374 kind = VCARD_NO_VALUE;
375 } else if (kind == VCARD_DATE_VALUE || kind == VCARD_DATETIME_VALUE) {
376 kind = VCARD_NO_VALUE;
377 }
378 break;
379
380 case VCARD_TZ_PROPERTY:
381 /* v3 default: VALUE=UTCOFFSET
382 * v4 default: VALUE=TEXT
383 */
384 if (version == VCARD_VERSION_40) {
385 if (kind == VCARD_TEXT_VALUE) {
386 kind = VCARD_NO_VALUE;
387 }
388 } else if (kind == VCARD_UTCOFFSET_VALUE) {
389 kind = VCARD_NO_VALUE;
390 }
391 break;
392
393 case VCARD_UID_PROPERTY:
394 /* v3 default: VALUE=TEXT
395 * v4 default: VALUE=URI
396 */
397 if (version == VCARD_VERSION_40) {
398 if (kind == VCARD_URI_VALUE) {
399 kind = VCARD_NO_VALUE;
400 }
401 } else {
402 kind = VCARD_NO_VALUE;
403 }
404 break;
405
406 default:
407 break;
408 }
409
410 if (kind != VCARD_NO_VALUE &&
411 !vcardproperty_value_kind_is_default(prop->kind, kind)) {
412 /* Not the default, so it must be specified */
413 kind_string = vcardvalue_kind_to_string(kind);
414 } else {
415 /* Don't include the VALUE parameter at all */
416 }
417
418 return kind_string;
419}
420
421const char *vcardproperty_as_vcard_string(vcardproperty *prop)
422{
423 char *buf;
424
425 buf = vcardproperty_as_vcard_string_r(prop);
427 return buf;
428}
429
430char *vcardproperty_as_vcard_string_r(vcardproperty *prop)
431{
432 vcardparameter *param;
433
434 /* Create new buffer that we can append names, parameters and a
435 * value to, and reallocate as needed.
436 */
437
438 const char *property_name = 0;
439 size_t buf_size = 1024;
440 char *buf;
441 char *buf_ptr;
442 const vcardvalue *value;
443 char *out_buf;
444 const char *kind_string = 0;
445
446 icalerror_check_arg_rz((prop != 0), "prop");
447
448 buf = icalmemory_new_buffer(buf_size);
449 buf_ptr = buf;
450
451 /* Append property name */
452
453 if (prop->kind == VCARD_X_PROPERTY && prop->x_name != 0) {
454 property_name = prop->x_name;
455 } else {
456 property_name = vcardproperty_kind_to_string(prop->kind);
457 }
458
459 if (property_name == 0) {
460 icalerror_warn("Got a property of an unknown kind.");
462 return 0;
463 }
464
465 if (prop->group != 0) {
466 icalmemory_append_string(&buf, &buf_ptr, &buf_size, prop->group);
467 icalmemory_append_string(&buf, &buf_ptr, &buf_size, ".");
468 }
469
470 icalmemory_append_string(&buf, &buf_ptr, &buf_size, property_name);
471
472 value = vcardproperty_get_value(prop);
473 kind_string = vcardproperty_get_value_kind(prop, value);
474 if (kind_string != 0) {
475 icalmemory_append_string(&buf, &buf_ptr, &buf_size, ";VALUE=");
476 icalmemory_append_string(&buf, &buf_ptr, &buf_size, kind_string);
477 }
478
479 /* Append parameters */
480 for (param = vcardproperty_get_first_parameter(prop, VCARD_ANY_PARAMETER);
481 param != 0; param = vcardproperty_get_next_parameter(prop, VCARD_ANY_PARAMETER)) {
482 vcardparameter_kind kind = vcardparameter_isa(param);
483
484 kind_string = vcardparameter_as_vcard_string_r(param);
485
486 if (kind_string == 0) {
487 icalerror_warn("Got a parameter of unknown kind for the following property");
488
489 icalerror_warn((property_name) ? property_name : "(NULL)");
490 continue;
491 }
492
493 if (kind == VCARD_VALUE_PARAMETER) {
494 icalmemory_free_buffer((char *)kind_string);
495 continue;
496 }
497
498 icalmemory_append_string(&buf, &buf_ptr, &buf_size, ";");
499 icalmemory_append_string(&buf, &buf_ptr, &buf_size, kind_string);
500 icalmemory_free_buffer((char *)kind_string);
501 }
502
503 /* Append value */
504
505 icalmemory_append_string(&buf, &buf_ptr, &buf_size, ":");
506
507 if (value != 0) {
508 char *str = vcardvalue_as_vcard_string_r(value);
509
510 if (str != 0) {
511 icalmemory_append_string(&buf, &buf_ptr, &buf_size, str);
513 icalmemory_append_string(&buf, &buf_ptr, &buf_size, "ERROR: No Value");
514 }
517 icalmemory_append_string(&buf, &buf_ptr, &buf_size, "ERROR: No Value");
518 }
519
520 /* We now use a function to fold the line properly every 75 characters.
521 That function also adds the newline for us. */
522 out_buf = fold_property_line(buf);
523
525
526 return out_buf;
527}
528
529vcardproperty_kind vcardproperty_isa(const vcardproperty *p)
530{
531 if (p != 0) {
532 return p->kind;
533 }
534
535 return VCARD_NO_PROPERTY;
536}
537
538bool vcardproperty_isa_property(void *property)
539{
540 const vcardproperty *impl = (vcardproperty *)property;
541
542 icalerror_check_arg_rz((property != 0), "property");
543 return (impl->id == ICAL_STRUCTURE_TYPE_PROPERTY);
544}
545
546void vcardproperty_add_parameter(vcardproperty *p, vcardparameter *parameter)
547{
548 icalerror_check_arg_rv((p != 0), "prop");
549 icalerror_check_arg_rv((parameter != 0), "parameter");
550
551 icalpvl_push(p->parameters, parameter);
552}
553
554void vcardproperty_set_parameter(vcardproperty *prop, vcardparameter *parameter)
555{
556 vcardparameter_kind kind;
557
558 icalerror_check_arg_rv((prop != 0), "prop");
559 icalerror_check_arg_rv((parameter != 0), "parameter");
560
561 kind = vcardparameter_isa(parameter);
562 if (kind == VCARD_X_PARAMETER) {
564 } else if (kind == VCARD_IANA_PARAMETER) {
566 } else {
568 }
569
570 vcardproperty_add_parameter(prop, parameter);
571}
572
573void vcardproperty_set_parameter_from_string(vcardproperty *prop,
574 const char *name, const char *value)
575{
576 vcardparameter_kind kind;
577 vcardparameter *param;
578
579 icalerror_check_arg_rv((prop != 0), "prop");
580 icalerror_check_arg_rv((name != 0), "name");
581 icalerror_check_arg_rv((value != 0), "value");
582
584
585 if (kind == VCARD_NO_PARAMETER) {
587 return;
588 }
589
590 param = vcardparameter_new_from_value_string(kind, value);
591
592 if (param == 0) {
594 return;
595 }
596
597 if (kind == VCARD_X_PARAMETER) {
598 vcardparameter_set_xname(param, name);
599 } else if (kind == VCARD_IANA_PARAMETER) {
600 vcardparameter_set_iana_name(param, name);
601 }
602
603 vcardproperty_set_parameter(prop, param);
604}
605
606const char *vcardproperty_get_parameter_as_string(vcardproperty *prop, const char *name)
607{
608 char *buf;
609
610 buf = vcardproperty_get_parameter_as_string_r(prop, name);
612 return buf;
613}
614
615char *vcardproperty_get_parameter_as_string_r(vcardproperty *prop, const char *name)
616{
617 vcardparameter_kind kind;
618 vcardparameter *param;
619 char *str;
620 char *pv, *t;
621 char *pvql;
622 char *pvqr;
623
624 icalerror_check_arg_rz((prop != 0), "prop");
625 icalerror_check_arg_rz((name != 0), "name");
626
628
629 if (kind == VCARD_NO_PARAMETER) {
630 /* icalenum_string_to_parameter_kind will set icalerrno */
631 return 0;
632 }
633
634 for (param = vcardproperty_get_first_parameter(prop, kind);
635 param != 0; param = vcardproperty_get_next_parameter(prop, kind)) {
636 if (kind == VCARD_X_PARAMETER) {
637 if (strcmp(vcardparameter_get_xname(param), name) == 0) {
638 break;
639 }
640 } else if (kind == VCARD_IANA_PARAMETER) {
641 if (strcmp(vcardparameter_get_iana_name(param), name) == 0) {
642 break;
643 }
644 } else {
645 break;
646 }
647 }
648
649 if (param == 0) {
650 return 0;
651 }
652
654
655 t = strchr(str, '=');
656
657 if (t == 0) {
660 return 0;
661 }
662
663 /* Strip the property name and the equal sign */
664 pv = icalmemory_strdup(t + 1);
666
667 /* Is the string quoted? */
668 pvql = strchr(pv, '"');
669 if (pvql == 0) {
670 return (pv); /* No quotes? Return it immediately. */
671 }
672
673 /* Strip everything up to the first quote */
674 str = icalmemory_strdup(pvql + 1);
676
677 /* Search for the end quote */
678 pvqr = strrchr(str, '"');
679 if (pvqr == 0) {
682 return 0;
683 }
684
685 *pvqr = '\0';
686 return str;
687}
688
689void vcardproperty_remove_parameter_by_kind(vcardproperty *prop, vcardparameter_kind kind)
690{
691 icalpvl_elem p;
692
693 icalerror_check_arg_rv((prop != 0), "prop");
694
695 for (p = icalpvl_head(prop->parameters); p != 0; p = icalpvl_next(p)) {
696 vcardparameter *param = (vcardparameter *)icalpvl_data(p);
697
698 if (vcardparameter_isa(param) == kind) {
699 (void)icalpvl_remove(prop->parameters, p);
700 vcardparameter_free(param);
701 break;
702 }
703 }
704}
705
706void vcardproperty_remove_parameter_by_name(vcardproperty *prop, const char *name)
707{
708 icalpvl_elem p;
709
710 icalerror_check_arg_rv((prop != 0), "prop");
711
712 for (p = icalpvl_head(prop->parameters); p != 0; p = icalpvl_next(p)) {
713 vcardparameter *param = (vcardparameter *)icalpvl_data(p);
714 const char *kind_string;
715
716 if (vcardparameter_isa(param) == VCARD_X_PARAMETER) {
717 kind_string = vcardparameter_get_xname(param);
718 } else if (vcardparameter_isa(param) == VCARD_IANA_PARAMETER) {
719 kind_string = vcardparameter_get_iana_name(param);
720 } else {
722 }
723
724 if (!kind_string) {
725 continue;
726 }
727
728 if (0 == strcmp(kind_string, name)) {
729 (void)icalpvl_remove(prop->parameters, p);
730 vcardparameter_free(param);
731 break;
732 }
733 }
734}
735
736void vcardproperty_remove_parameter_by_ref(vcardproperty *prop, vcardparameter *parameter)
737{
738 icalpvl_elem p;
739
740 icalerror_check_arg_rv((prop != 0), "prop");
741 icalerror_check_arg_rv((parameter != 0), "parameter");
742
743 for (p = icalpvl_head(prop->parameters); p != 0; p = icalpvl_next(p)) {
744 vcardparameter *p_param = (vcardparameter *)icalpvl_data(p);
745
746 if (parameter == p_param) {
747 (void)icalpvl_remove(prop->parameters, p);
748 vcardparameter_free(p_param);
749 break;
750 }
751 }
752}
753
754int vcardproperty_count_parameters(const vcardproperty *prop)
755{
756 if (prop != 0) {
757 return icalpvl_count(prop->parameters);
758 }
759
761 return -1;
762}
763
764vcardparameter *vcardproperty_get_first_parameter(vcardproperty *p, vcardparameter_kind kind)
765{
766 icalerror_check_arg_rz((p != 0), "prop");
767
768 p->parameter_iterator = icalpvl_head(p->parameters);
769
770 if (p->parameter_iterator == 0) {
771 return 0;
772 }
773
774 for (p->parameter_iterator = icalpvl_head(p->parameters);
775 p->parameter_iterator != 0; p->parameter_iterator = icalpvl_next(p->parameter_iterator)) {
776 vcardparameter *param = (vcardparameter *)icalpvl_data(p->parameter_iterator);
777
778 if (vcardparameter_isa(param) == kind || kind == VCARD_ANY_PARAMETER) {
779 return param;
780 }
781 }
782
783 return 0;
784}
785
786vcardparameter *vcardproperty_get_next_parameter(vcardproperty *p, vcardparameter_kind kind)
787{
788 icalerror_check_arg_rz((p != 0), "prop");
789
790 if (p->parameter_iterator == 0) {
791 return 0;
792 }
793
794 for (p->parameter_iterator = icalpvl_next(p->parameter_iterator);
795 p->parameter_iterator != 0; p->parameter_iterator = icalpvl_next(p->parameter_iterator)) {
796 vcardparameter *param = (vcardparameter *)icalpvl_data(p->parameter_iterator);
797
798 if (vcardparameter_isa(param) == kind || kind == VCARD_ANY_PARAMETER) {
799 return param;
800 }
801 }
802
803 return 0;
804}
805
806void vcardproperty_set_value(vcardproperty *p, vcardvalue *value)
807{
808 vcardvalue_kind kind;
809
810 icalerror_check_arg_rv((p != 0), "prop");
811 icalerror_check_arg_rv((value != 0), "value");
812
813 if (p->value != 0) {
814 vcardvalue_set_parent(p->value, 0);
815 vcardvalue_free(p->value);
816 p->value = 0;
817 }
818
819 p->value = value;
820
821 vcardvalue_set_parent(value, p);
822
823 kind = vcardvalue_isa(value);
824
825 if (kind == VCARD_DATE_VALUE || kind == VCARD_DATETIME_VALUE) {
826 vcardparameter *val_param;
827
828 val_param = vcardproperty_get_first_parameter(p, VCARD_VALUE_PARAMETER);
829
830 if (val_param &&
831 vcardparameter_value_to_value_kind(vcardparameter_get_value(val_param)) != kind) {
832 vcardproperty_remove_parameter_by_kind(p, VCARD_VALUE_PARAMETER);
833 }
834 }
835}
836
837void vcardproperty_set_value_from_string(vcardproperty *prop, const char *str, const char *type)
838{
839 vcardvalue *nval;
840 vcardvalue_kind kind = VCARD_NO_VALUE;
841
842 icalerror_check_arg_rv((prop != 0), "prop");
843 icalerror_check_arg_rv((str != 0), "str");
844 icalerror_check_arg_rv((type != 0), "type");
845
846 if (strcmp(type, "NO") == 0) {
847 /* Get the type from the value the property already has, if it exists */
848 const vcardvalue *oval = vcardproperty_get_value(prop);
849 if (oval != 0) {
850 /* Use the existing value kind */
851 kind = vcardvalue_isa(oval);
852 } else {
853 /* Use the default kind for the property */
854 kind = vcardproperty_kind_to_value_kind(vcardproperty_isa(prop));
855 }
856 } else {
857 /* Use the given kind string */
858 kind = vcardvalue_string_to_kind(type);
859 }
860
861 if (kind == VCARD_NO_VALUE) {
863 return;
864 }
865
867 nval = vcardvalue_new_from_string(kind, str);
868
869 if (nval == 0) {
870 /* vcardvalue_new_from_string sets errno */
871 icalassert(icalerrno != ICAL_NO_ERROR);
872 return;
873 }
874
875 vcardproperty_set_value(prop, nval);
876}
877
878vcardvalue *vcardproperty_get_value(const vcardproperty *prop)
879{
880 icalerror_check_arg_rz((prop != 0), "prop");
881
882 return prop->value;
883}
884
885const char *vcardproperty_get_value_as_string(const vcardproperty *prop)
886{
887 char *buf;
888
889 buf = vcardproperty_get_value_as_string_r(prop);
891 return buf;
892}
893
894char *vcardproperty_get_value_as_string_r(const vcardproperty *prop)
895{
896 const vcardvalue *value;
897
898 icalerror_check_arg_rz((prop != 0), "prop");
899
900 value = prop->value;
901
902 return vcardvalue_as_vcard_string_r(value);
903}
904
905void vcardproperty_set_x_name(vcardproperty *prop, const char *name)
906{
907 icalerror_check_arg_rv((name != 0), "name");
908 icalerror_check_arg_rv((prop != 0), "prop");
909
910 if (prop->x_name != 0) {
911 icalmemory_free_buffer(prop->x_name);
912 }
913
914 prop->x_name = icalmemory_strdup(name);
915
916 if (prop->x_name == 0) {
918 }
919}
920
921const char *vcardproperty_get_x_name(const vcardproperty *prop)
922{
923 icalerror_check_arg_rz((prop != 0), "prop");
924
925 return prop->x_name;
926}
927
928void vcardproperty_set_group(vcardproperty *prop, const char *group)
929{
930 icalerror_check_arg_rv((group != 0), "group");
931 icalerror_check_arg_rv((prop != 0), "prop");
932
933 if (prop->group != 0) {
934 icalmemory_free_buffer(prop->group);
935 }
936
937 prop->group = icalmemory_strdup(group);
938
939 if (prop->group == 0) {
941 }
942}
943
944const char *vcardproperty_get_group(const vcardproperty *prop)
945{
946 icalerror_check_arg_rz((prop != 0), "prop");
947
948 return prop->group;
949}
950
951const char *vcardproperty_get_property_name(const vcardproperty *prop)
952{
953 char *buf;
954
955 buf = vcardproperty_get_property_name_r(prop);
957 return buf;
958}
959
960char *vcardproperty_get_property_name_r(const vcardproperty *prop)
961{
962 const char *property_name = 0;
963 size_t buf_size = 256;
964 char *buf;
965 char *buf_ptr;
966
967 icalerror_check_arg_rz((prop != 0), "prop");
968
969 buf = icalmemory_new_buffer(buf_size);
970 buf_ptr = buf;
971
972 if (prop->kind == VCARD_X_PROPERTY && prop->x_name != 0) {
973 property_name = prop->x_name;
974 } else {
975 property_name = vcardproperty_kind_to_string(prop->kind);
976 }
977
978 if (property_name == 0) {
981 return 0;
982
983 } else {
984 /* _append_string will automatically grow the buffer if
985 property_name is longer than the initial buffer size */
986 icalmemory_append_string(&buf, &buf_ptr, &buf_size, property_name);
987 }
988
989 return buf;
990}
991
992void vcardproperty_set_parent(vcardproperty *property, vcardcomponent *comp)
993{
994 icalerror_check_arg_rv((property != 0), "property");
995
996 property->parent = comp;
997}
998
999vcardcomponent *vcardproperty_get_parent(const vcardproperty *property)
1000{
1001 icalerror_check_arg_rz((property != 0), "property");
1002
1003 return property->parent;
1004}
1005
1006static int param_compare(void *a, void *b)
1007{
1008 return strcmp(vcardparameter_as_vcard_string((vcardparameter *)a),
1009 vcardparameter_as_vcard_string((vcardparameter *)b));
1010}
1011
1012void vcardproperty_normalize(vcardproperty *prop)
1013{
1014 vcardproperty_kind prop_kind = vcardproperty_isa(prop);
1015 icalpvl_list sorted_params = icalpvl_newlist();
1016 vcardparameter *param;
1017
1018 /* Normalize parameters into sorted list */
1019 while ((param = icalpvl_pop(prop->parameters)) != 0) {
1020 int remove = 0;
1021
1022 /* Remove parameters having default values */
1023 switch (vcardparameter_isa(param)) {
1024 case VCARD_VALUE_PARAMETER:
1025 /* Skip VALUE parameters for default property value types */
1026 switch (prop_kind) {
1027 case VCARD_TEL_PROPERTY:
1028 case VCARD_TZ_PROPERTY:
1029 case VCARD_BIRTHPLACE_PROPERTY:
1030 case VCARD_DEATHPLACE_PROPERTY:
1031 if (vcardparameter_get_value(param) == VCARD_VALUE_TEXT) {
1032 remove = 1;
1033 }
1034 break;
1035
1036 case VCARD_RELATED_PROPERTY:
1037 case VCARD_UID_PROPERTY:
1038 case VCARD_KEY_PROPERTY:
1039 if (vcardparameter_get_value(param) == VCARD_VALUE_URI) {
1040 remove = 1;
1041 }
1042 break;
1043
1044 case VCARD_BDAY_PROPERTY:
1045 case VCARD_ANNIVERSARY_PROPERTY:
1046 case VCARD_DEATHDATE_PROPERTY:
1047 if (vcardparameter_get_value(param) == VCARD_VALUE_DATEANDORTIME) {
1048 remove = 1;
1049 }
1050 break;
1051
1052 default:
1053 break;
1054 }
1055 break;
1056
1057 case VCARD_CALSCALE_PARAMETER:
1058 if (vcardparameter_get_calscale(param) == VCARD_CALSCALE_GREGORIAN) {
1059 remove = 1;
1060 }
1061 break;
1062
1063 case VCARD_PREF_PARAMETER:
1064 if (vcardparameter_get_pref(param) >= 100) {
1065 remove = 1;
1066 }
1067 break;
1068
1069 case VCARD_TYPE_PARAMETER:
1070 if (prop_kind == VCARD_TEL_PROPERTY) {
1071 /* Is it just TYPE=VOICE ? */
1072 vcardenumarray_element voice = {VCARD_TYPE_VOICE, NULL};
1073
1074 if (vcardenumarray_find(vcardparameter_get_type(param),
1075 &voice) == 0) {
1076 remove = 1;
1077 }
1078 }
1079
1080 if (!remove) {
1081 vcardenumarray_sort(vcardparameter_get_type(param));
1082 }
1083 break;
1084
1085 case VCARD_PID_PARAMETER:
1086 vcardstrarray_sort(vcardparameter_get_pid(param));
1087 break;
1088
1089 case VCARD_SORTAS_PARAMETER:
1090 vcardstrarray_sort(vcardparameter_get_sortas(param));
1091 break;
1092
1093 default:
1094 break;
1095 }
1096
1097 if (remove) {
1098 vcardparameter_set_parent(param, 0); // MUST NOT have a parent to free
1099 vcardparameter_free(param);
1100 } else {
1101 icalpvl_insert_ordered(sorted_params, param_compare, param);
1102 }
1103 }
1104
1105 icalpvl_free(prop->parameters);
1106 prop->parameters = sorted_params;
1107
1108 switch (prop_kind) {
1109 case VCARD_CATEGORIES_PROPERTY:
1110 vcardstrarray_sort(vcardproperty_get_categories(prop));
1111 break;
1112
1113 case VCARD_NICKNAME_PROPERTY:
1114 vcardstrarray_sort(vcardproperty_get_nickname(prop));
1115 break;
1116
1117 default:
1118 break;
1119 }
1120}
1121
1122void vcardproperty_add_type_parameter(vcardproperty *prop,
1123 vcardenumarray_element *type)
1124{
1125 vcardenumarray *types;
1126 vcardparameter *param =
1127 vcardproperty_get_first_parameter(prop, VCARD_TYPE_PARAMETER);
1128
1129 if (param) {
1130 types = vcardparameter_get_type(param);
1131 vcardenumarray_add(types, type);
1132 } else {
1133 param = vcardparameter_new(VCARD_TYPE_PARAMETER);
1134 types = vcardenumarray_new(0);
1135 vcardenumarray_add(types, type);
1136 vcardparameter_set_type(param, types);
1137 vcardproperty_add_parameter(prop, param);
1138 }
1139}
void icalerror_set_errno(icalerrorenum x)
Sets the icalerrno to a given error.
Definition icalerror.c:90
void icalerror_clear_errno(void)
Resets icalerrno to ICAL_NO_ERROR.
Definition icalerror.c:85
@ ICAL_NEWFAILED_ERROR
Definition icalerror.h:50
@ ICAL_BADARG_ERROR
Definition icalerror.h:47
@ ICAL_INTERNAL_ERROR
Definition icalerror.h:65
@ ICAL_NO_ERROR
Definition icalerror.h:44
@ ICAL_MALFORMEDDATA_ERROR
Definition icalerror.h:59
@ ICAL_PARSE_ERROR
Definition icalerror.h:62
@ ICAL_USAGE_ERROR
Definition icalerror.h:71
#define icalerrno
Access the current icalerrno value.
Definition icalerror.h:133
void icalmemory_free_buffer(void *buf)
Releases a buffer.
Definition icalmemory.c:355
char * icalmemory_strdup(const char *s)
Creates a duplicate of a string.
Definition icalmemory.c:242
void icalmemory_append_string(char **buf, char **pos, size_t *buf_size, const char *string)
Appends a string to a buffer.
Definition icalmemory.c:365
void * icalmemory_new_buffer(size_t size)
Creates new buffer with the specified size.
Definition icalmemory.c:315
void icalmemory_add_tmp_buffer(void *buf)
Adds an externally allocated buffer to the ring.
Definition icalmemory.c:158
Common memory management routines.
bool icalproperty_get_allow_empty_properties(void)
Defines the data structure representing iCalendar properties.
int vcardcomponent_count_errors(vcardcomponent *comp)
Returns the number of errors encountered parsing the data.
Defines the data structure representing vCard components.
char * vcardparameter_as_vcard_string(vcardparameter *param)
Converts vcardparameter into a string representation.
void vcardparameter_set_xname(vcardparameter *param, const char *v)
Sets the X-name of param to v.
void vcardparameter_free(vcardparameter *param)
Frees an vcardparameter object.
const char * vcardparameter_get_iana_name(const vcardparameter *param)
Returns the IANA name of param.
void vcardparameter_set_parent(vcardparameter *param, vcardproperty *property)
bool vcardparameter_isa_parameter(void *parameter)
vcardparameter_kind vcardparameter_isa(const vcardparameter *parameter)
void vcardparameter_set_iana_name(vcardparameter *param, const char *v)
Sets the IANA name of param to v.
vcardparameter * vcardparameter_clone(const vcardparameter *old)
Creates new vcardparameter as a clone of the given one.
const char * vcardparameter_get_xname(const vcardparameter *param)
Returns the X-name of param.
vcardparameter * vcardparameter_new(vcardparameter_kind kind)
Creates new vcardparameter object.
char * vcardparameter_as_vcard_string_r(vcardparameter *param)
Converts vcardparameter into an string representation according to RFC5445/RFC6868.
const char * vcardparameter_kind_to_string(vcardparameter_kind kind)
Returns a string representing the given vcardparameter_kind.
vcardparameter * vcardparameter_new_from_value_string(vcardparameter_kind kind, const char *value)
Creates new vcardparameter of a given kind with a given value.
vcardparameter_kind vcardparameter_string_to_kind(const char *string)
Returns the vcardparameter_kind for a given string.
Line-oriented parsing vCard format.
const char * vcardproperty_get_property_name(const vcardproperty *prop)
void vcardproperty_normalize(vcardproperty *prop)
void vcardproperty_remove_parameter_by_name(vcardproperty *prop, const char *name)
Removes all parameters with the specified name.
void vcardproperty_remove_parameter_by_ref(vcardproperty *prop, vcardparameter *parameter)
Removes the specified parameter reference from the property.
vcardcomponent * vcardproperty_get_parent(const vcardproperty *property)
Returns the parent vcard for the specified property.
void vcardproperty_set_parent(vcardproperty *property, vcardcomponent *comp)
Sets the parent vcard for the specified vcardproperty property.
vcardproperty * vcardproperty_clone(const vcardproperty *old)
Deeply clones an vcardproperty.
void vcardproperty_remove_parameter_by_kind(vcardproperty *prop, vcardparameter_kind kind)
Removes all parameters with the specified kind.
bool vcardproperty_kind_is_valid(const vcardproperty_kind kind)
void vcardvalue_set_parent(vcardvalue *value, vcardproperty *property)
Defines the data structure representing vCard values.