Libical API Documentation 4.0 UNRELEASED Go to the stable 3.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
27#include <stdlib.h>
28
29struct vcardproperty_impl {
30 char id[5];
31 vcardproperty_kind kind;
32 char *x_name;
33 char *group;
34 icalpvl_list parameters;
35 icalpvl_elem parameter_iterator;
36 vcardvalue *value;
37 vcardcomponent *parent;
38};
39
40LIBICAL_VCARD_EXPORT struct vcardproperty_impl *vcardproperty_new_impl(vcardproperty_kind kind)
41{
42 vcardproperty *prop;
43
44 if (!vcardproperty_kind_is_valid(kind)) {
45 return NULL;
46 }
47
48 if ((prop = (vcardproperty *)icalmemory_new_buffer(sizeof(vcardproperty))) == 0) {
50 return 0;
51 }
52
53 memset(prop, 0, sizeof(vcardproperty));
54
55 strcpy(prop->id, "prop");
56
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[0] = 'X';
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 return buf;
311}
312
313/* Determine what VALUE parameter to include. The VALUE parameters
314 are ignored in the normal parameter printing ( the block after
315 this one, so we need to do it here */
316static const char *vcardproperty_get_value_kind(vcardproperty *prop,
317 const vcardvalue *value)
318{
319 const char *kind_string = NULL;
320 if (!prop) {
321 return kind_string;
322 }
323 vcardvalue_kind kind = VCARD_NO_VALUE;
324 vcardparameter *val_param =
325 vcardproperty_get_first_parameter(prop, VCARD_VALUE_PARAMETER);
326 vcardproperty_version version = vcardcomponent_get_version(prop->parent);
327
328 if (version == VCARD_VERSION_NONE) {
329 version = VCARD_VERSION_30;
330 }
331
332 if (val_param) {
333 kind = vcardparameter_value_to_value_kind(vcardparameter_get_value(val_param));
334 }
335
336 if (kind == VCARD_NO_VALUE && vcardproperty_isa(prop) != VCARD_X_PROPERTY) {
337 kind = vcardvalue_isa(value);
338 }
339
340 /* Try to omit VERSION-dependent default VALUE kinds */
341 switch (vcardproperty_isa(prop)) {
342 case VCARD_GEO_PROPERTY:
343 /* v3 default: VALUE=STRUCTURED
344 * v4 default: VALUE=URL
345 */
346 if (kind != VCARD_X_VALUE) {
347 kind = VCARD_NO_VALUE;
348 }
349 break;
350
351 case VCARD_KEY_PROPERTY:
352 case VCARD_LOGO_PROPERTY:
353 case VCARD_PHOTO_PROPERTY:
354 case VCARD_SOUND_PROPERTY:
355 /* v3 default: VALUE=BINARY (ENCODING=b parameter)
356 * v4 default: VALUE=URL
357 */
358 if (version == VCARD_VERSION_40 ||
359 vcardproperty_get_first_parameter(prop, VCARD_ENCODING_PARAMETER)) {
360 kind = VCARD_NO_VALUE;
361 }
362 break;
363
364 case VCARD_ANNIVERSARY_PROPERTY:
365 case VCARD_BDAY_PROPERTY:
366 case VCARD_DEATHDATE_PROPERTY:
367 /* TIME is v4 specific.
368 * All other types are self-evident.
369 */
370 if (version == VCARD_VERSION_40 &&
371 (kind == VCARD_TIME_VALUE || kind == VCARD_DATEANDORTIME_VALUE)) {
372 kind = VCARD_NO_VALUE;
373 } else if (kind == VCARD_DATE_VALUE || kind == VCARD_DATETIME_VALUE) {
374 kind = VCARD_NO_VALUE;
375 }
376 break;
377
378 case VCARD_TZ_PROPERTY:
379 /* v3 default: VALUE=UTCOFFSET
380 * v4 default: VALUE=TEXT
381 */
382 if (version == VCARD_VERSION_40) {
383 if (kind == VCARD_TEXT_VALUE) {
384 kind = VCARD_NO_VALUE;
385 }
386 } else if (kind == VCARD_UTCOFFSET_VALUE) {
387 kind = VCARD_NO_VALUE;
388 }
389 break;
390
391 case VCARD_UID_PROPERTY:
392 /* v3 default: VALUE=TEXT
393 * v4 default: VALUE=URI
394 */
395 if (version == VCARD_VERSION_40) {
396 if (kind == VCARD_URI_VALUE) {
397 kind = VCARD_NO_VALUE;
398 }
399 } else {
400 kind = VCARD_NO_VALUE;
401 }
402 break;
403
404 default:
405 break;
406 }
407
408 if (kind != VCARD_NO_VALUE &&
409 !vcardproperty_value_kind_is_default(prop->kind, kind)) {
410 /* Not the default, so it must be specified */
411 kind_string = vcardvalue_kind_to_string(kind);
412 } else {
413 /* Don't include the VALUE parameter at all */
414 }
415
416 return kind_string;
417}
418
419const char *vcardproperty_as_vcard_string(vcardproperty *prop)
420{
421 char *buf;
422
423 buf = vcardproperty_as_vcard_string_r(prop);
425 return buf;
426}
427
428char *vcardproperty_as_vcard_string_r(vcardproperty *prop)
429{
430 vcardparameter *param;
431
432 /* Create new buffer that we can append names, parameters and a
433 * value to, and reallocate as needed.
434 */
435
436 const char *property_name = 0;
437 size_t buf_size = 1024;
438 char *buf;
439 char *buf_ptr;
440 const vcardvalue *value;
441 char *out_buf;
442 const char *kind_string = 0;
443 const char newline[] = "\r\n";
444
445 icalerror_check_arg_rz((prop != 0), "prop");
446
447 buf = icalmemory_new_buffer(buf_size);
448 buf_ptr = buf;
449
450 /* Append property name */
451
452 if (prop->kind == VCARD_X_PROPERTY && prop->x_name != 0) {
453 property_name = prop->x_name;
454 } else {
455 property_name = vcardproperty_kind_to_string(prop->kind);
456 }
457
458 if (property_name == 0) {
459 icalerror_warn("Got a property of an unknown kind.");
461 return 0;
462 }
463
464 if (prop->group != 0) {
465 icalmemory_append_string(&buf, &buf_ptr, &buf_size, prop->group);
466 icalmemory_append_string(&buf, &buf_ptr, &buf_size, ".");
467 }
468
469 icalmemory_append_string(&buf, &buf_ptr, &buf_size, property_name);
470
471 value = vcardproperty_get_value(prop);
472 kind_string = vcardproperty_get_value_kind(prop, value);
473 if (kind_string != 0) {
474 icalmemory_append_string(&buf, &buf_ptr, &buf_size, ";VALUE=");
475 icalmemory_append_string(&buf, &buf_ptr, &buf_size, kind_string);
476 }
477
478 /* Append parameters */
479 for (param = vcardproperty_get_first_parameter(prop, VCARD_ANY_PARAMETER);
480 param != 0; param = vcardproperty_get_next_parameter(prop, VCARD_ANY_PARAMETER)) {
481 vcardparameter_kind kind = vcardparameter_isa(param);
482
483 kind_string = vcardparameter_as_vcard_string_r(param);
484
485 if (kind_string == 0) {
486 icalerror_warn("Got a parameter of unknown kind for the following property");
487
488 icalerror_warn((property_name) ? property_name : "(NULL)");
489 continue;
490 }
491
492 if (kind == VCARD_VALUE_PARAMETER) {
493 icalmemory_free_buffer((char *)kind_string);
494 continue;
495 }
496
497 icalmemory_append_string(&buf, &buf_ptr, &buf_size, ";");
498 icalmemory_append_string(&buf, &buf_ptr, &buf_size, kind_string);
499 icalmemory_free_buffer((char *)kind_string);
500 }
501
502 /* Append value */
503
504 icalmemory_append_string(&buf, &buf_ptr, &buf_size, ":");
505
506 if (value != 0) {
507 char *str = vcardvalue_as_vcard_string_r(value);
508
509 if (str != 0) {
510 icalmemory_append_string(&buf, &buf_ptr, &buf_size, str);
512 icalmemory_append_string(&buf, &buf_ptr, &buf_size, "ERROR: No Value");
513 }
516 icalmemory_append_string(&buf, &buf_ptr, &buf_size, "ERROR: No Value");
517 }
518
519 icalmemory_append_string(&buf, &buf_ptr, &buf_size, newline);
520
521 /* We now use a function to fold the line properly every 75 characters.
522 That function also adds the newline for us. */
523 out_buf = fold_property_line(buf);
524
526
527 return out_buf;
528}
529
530vcardproperty_kind vcardproperty_isa(const vcardproperty *p)
531{
532 if (p != 0) {
533 return p->kind;
534 }
535
536 return VCARD_NO_PROPERTY;
537}
538
539bool vcardproperty_isa_property(void *property)
540{
541 const vcardproperty *impl = (vcardproperty *)property;
542
543 icalerror_check_arg_rz((property != 0), "property");
544 if (strcmp(impl->id, "prop") == 0) {
545 return true;
546 } else {
547 return false;
548 }
549}
550
551void vcardproperty_add_parameter(vcardproperty *p, vcardparameter *parameter)
552{
553 icalerror_check_arg_rv((p != 0), "prop");
554 icalerror_check_arg_rv((parameter != 0), "parameter");
555
556 icalpvl_push(p->parameters, parameter);
557}
558
559void vcardproperty_set_parameter(vcardproperty *prop, vcardparameter *parameter)
560{
561 vcardparameter_kind kind;
562
563 icalerror_check_arg_rv((prop != 0), "prop");
564 icalerror_check_arg_rv((parameter != 0), "parameter");
565
566 kind = vcardparameter_isa(parameter);
567 if (kind == VCARD_X_PARAMETER) {
569 } else if (kind == VCARD_IANA_PARAMETER) {
571 } else {
573 }
574
575 vcardproperty_add_parameter(prop, parameter);
576}
577
578void vcardproperty_set_parameter_from_string(vcardproperty *prop,
579 const char *name, const char *value)
580{
581 vcardparameter_kind kind;
582 vcardparameter *param;
583
584 icalerror_check_arg_rv((prop != 0), "prop");
585 icalerror_check_arg_rv((name != 0), "name");
586 icalerror_check_arg_rv((value != 0), "value");
587
589
590 if (kind == VCARD_NO_PARAMETER) {
592 return;
593 }
594
595 param = vcardparameter_new_from_value_string(kind, value);
596
597 if (param == 0) {
599 return;
600 }
601
602 if (kind == VCARD_X_PARAMETER) {
603 vcardparameter_set_xname(param, name);
604 } else if (kind == VCARD_IANA_PARAMETER) {
605 vcardparameter_set_iana_name(param, name);
606 }
607
608 vcardproperty_set_parameter(prop, param);
609}
610
611const char *vcardproperty_get_parameter_as_string(vcardproperty *prop, const char *name)
612{
613 char *buf;
614
615 buf = vcardproperty_get_parameter_as_string_r(prop, name);
617 return buf;
618}
619
620char *vcardproperty_get_parameter_as_string_r(vcardproperty *prop, const char *name)
621{
622 vcardparameter_kind kind;
623 vcardparameter *param;
624 char *str;
625 char *pv, *t;
626 char *pvql;
627 char *pvqr;
628
629 icalerror_check_arg_rz((prop != 0), "prop");
630 icalerror_check_arg_rz((name != 0), "name");
631
633
634 if (kind == VCARD_NO_PARAMETER) {
635 /* icalenum_string_to_parameter_kind will set icalerrno */
636 return 0;
637 }
638
639 for (param = vcardproperty_get_first_parameter(prop, kind);
640 param != 0; param = vcardproperty_get_next_parameter(prop, kind)) {
641 if (kind == VCARD_X_PARAMETER) {
642 if (strcmp(vcardparameter_get_xname(param), name) == 0) {
643 break;
644 }
645 } else if (kind == VCARD_IANA_PARAMETER) {
646 if (strcmp(vcardparameter_get_iana_name(param), name) == 0) {
647 break;
648 }
649 } else {
650 break;
651 }
652 }
653
654 if (param == 0) {
655 return 0;
656 }
657
659
660 t = strchr(str, '=');
661
662 if (t == 0) {
665 return 0;
666 }
667
668 /* Strip the property name and the equal sign */
669 pv = icalmemory_strdup(t + 1);
671
672 /* Is the string quoted? */
673 pvql = strchr(pv, '"');
674 if (pvql == 0) {
675 return (pv); /* No quotes? Return it immediately. */
676 }
677
678 /* Strip everything up to the first quote */
679 str = icalmemory_strdup(pvql + 1);
681
682 /* Search for the end quote */
683 pvqr = strrchr(str, '"');
684 if (pvqr == 0) {
687 return 0;
688 }
689
690 *pvqr = '\0';
691 return str;
692}
693
694void vcardproperty_remove_parameter_by_kind(vcardproperty *prop, vcardparameter_kind kind)
695{
696 icalpvl_elem p;
697
698 icalerror_check_arg_rv((prop != 0), "prop");
699
700 for (p = icalpvl_head(prop->parameters); p != 0; p = icalpvl_next(p)) {
701 vcardparameter *param = (vcardparameter *)icalpvl_data(p);
702
703 if (vcardparameter_isa(param) == kind) {
704 (void)icalpvl_remove(prop->parameters, p);
705 vcardparameter_free(param);
706 break;
707 }
708 }
709}
710
711void vcardproperty_remove_parameter_by_name(vcardproperty *prop, const char *name)
712{
713 icalpvl_elem p;
714
715 icalerror_check_arg_rv((prop != 0), "prop");
716
717 for (p = icalpvl_head(prop->parameters); p != 0; p = icalpvl_next(p)) {
718 vcardparameter *param = (vcardparameter *)icalpvl_data(p);
719 const char *kind_string;
720
721 if (vcardparameter_isa(param) == VCARD_X_PARAMETER) {
722 kind_string = vcardparameter_get_xname(param);
723 } else if (vcardparameter_isa(param) == VCARD_IANA_PARAMETER) {
724 kind_string = vcardparameter_get_iana_name(param);
725 } else {
727 }
728
729 if (!kind_string) {
730 continue;
731 }
732
733 if (0 == strcmp(kind_string, name)) {
734 (void)icalpvl_remove(prop->parameters, p);
735 vcardparameter_free(param);
736 break;
737 }
738 }
739}
740
741void vcardproperty_remove_parameter_by_ref(vcardproperty *prop, vcardparameter *parameter)
742{
743 icalpvl_elem p;
744
745 icalerror_check_arg_rv((prop != 0), "prop");
746 icalerror_check_arg_rv((parameter != 0), "parameter");
747
748 for (p = icalpvl_head(prop->parameters); p != 0; p = icalpvl_next(p)) {
749 vcardparameter *p_param = (vcardparameter *)icalpvl_data(p);
750
751 if (parameter == p_param) {
752 (void)icalpvl_remove(prop->parameters, p);
753 vcardparameter_free(p_param);
754 break;
755 }
756 }
757}
758
759int vcardproperty_count_parameters(const vcardproperty *prop)
760{
761 if (prop != 0) {
762 return icalpvl_count(prop->parameters);
763 }
764
766 return -1;
767}
768
769vcardparameter *vcardproperty_get_first_parameter(vcardproperty *p, vcardparameter_kind kind)
770{
771 icalerror_check_arg_rz((p != 0), "prop");
772
773 p->parameter_iterator = icalpvl_head(p->parameters);
774
775 if (p->parameter_iterator == 0) {
776 return 0;
777 }
778
779 for (p->parameter_iterator = icalpvl_head(p->parameters);
780 p->parameter_iterator != 0; p->parameter_iterator = icalpvl_next(p->parameter_iterator)) {
781 vcardparameter *param = (vcardparameter *)icalpvl_data(p->parameter_iterator);
782
783 if (vcardparameter_isa(param) == kind || kind == VCARD_ANY_PARAMETER) {
784 return param;
785 }
786 }
787
788 return 0;
789}
790
791vcardparameter *vcardproperty_get_next_parameter(vcardproperty *p, vcardparameter_kind kind)
792{
793 icalerror_check_arg_rz((p != 0), "prop");
794
795 if (p->parameter_iterator == 0) {
796 return 0;
797 }
798
799 for (p->parameter_iterator = icalpvl_next(p->parameter_iterator);
800 p->parameter_iterator != 0; p->parameter_iterator = icalpvl_next(p->parameter_iterator)) {
801 vcardparameter *param = (vcardparameter *)icalpvl_data(p->parameter_iterator);
802
803 if (vcardparameter_isa(param) == kind || kind == VCARD_ANY_PARAMETER) {
804 return param;
805 }
806 }
807
808 return 0;
809}
810
811void vcardproperty_set_value(vcardproperty *p, vcardvalue *value)
812{
813 vcardvalue_kind kind;
814
815 icalerror_check_arg_rv((p != 0), "prop");
816 icalerror_check_arg_rv((value != 0), "value");
817
818 if (p->value != 0) {
819 vcardvalue_set_parent(p->value, 0);
820 vcardvalue_free(p->value);
821 p->value = 0;
822 }
823
824 p->value = value;
825
826 vcardvalue_set_parent(value, p);
827
828 kind = vcardvalue_isa(value);
829
830 if (kind == VCARD_DATE_VALUE || kind == VCARD_DATETIME_VALUE) {
831 vcardparameter *val_param;
832
833 val_param = vcardproperty_get_first_parameter(p, VCARD_VALUE_PARAMETER);
834
835 if (val_param &&
836 vcardparameter_value_to_value_kind(vcardparameter_get_value(val_param)) != kind) {
837 vcardproperty_remove_parameter_by_kind(p, VCARD_VALUE_PARAMETER);
838 }
839 }
840}
841
842void vcardproperty_set_value_from_string(vcardproperty *prop, const char *str, const char *type)
843{
844 vcardvalue *nval;
845 vcardvalue_kind kind = VCARD_NO_VALUE;
846
847 icalerror_check_arg_rv((prop != 0), "prop");
848 icalerror_check_arg_rv((str != 0), "str");
849 icalerror_check_arg_rv((type != 0), "type");
850
851 if (strcmp(type, "NO") == 0) {
852 /* Get the type from the value the property already has, if it exists */
853 const vcardvalue *oval = vcardproperty_get_value(prop);
854 if (oval != 0) {
855 /* Use the existing value kind */
856 kind = vcardvalue_isa(oval);
857 } else {
858 /* Use the default kind for the property */
859 kind = vcardproperty_kind_to_value_kind(vcardproperty_isa(prop));
860 }
861 } else {
862 /* Use the given kind string */
863 kind = vcardvalue_string_to_kind(type);
864 }
865
866 if (kind == VCARD_NO_VALUE) {
868 return;
869 }
870
872 nval = vcardvalue_new_from_string(kind, str);
873
874 if (nval == 0) {
875 /* vcardvalue_new_from_string sets errno */
876 icalassert(icalerrno != ICAL_NO_ERROR);
877 return;
878 }
879
880 vcardproperty_set_value(prop, nval);
881}
882
883vcardvalue *vcardproperty_get_value(const vcardproperty *prop)
884{
885 icalerror_check_arg_rz((prop != 0), "prop");
886
887 return prop->value;
888}
889
890const char *vcardproperty_get_value_as_string(const vcardproperty *prop)
891{
892 char *buf;
893
894 buf = vcardproperty_get_value_as_string_r(prop);
896 return buf;
897}
898
899char *vcardproperty_get_value_as_string_r(const vcardproperty *prop)
900{
901 const vcardvalue *value;
902
903 icalerror_check_arg_rz((prop != 0), "prop");
904
905 value = prop->value;
906
907 return vcardvalue_as_vcard_string_r(value);
908}
909
910void vcardproperty_set_x_name(vcardproperty *prop, const char *name)
911{
912 icalerror_check_arg_rv((name != 0), "name");
913 icalerror_check_arg_rv((prop != 0), "prop");
914
915 if (prop->x_name != 0) {
916 icalmemory_free_buffer(prop->x_name);
917 }
918
919 prop->x_name = icalmemory_strdup(name);
920
921 if (prop->x_name == 0) {
923 }
924}
925
926const char *vcardproperty_get_x_name(const vcardproperty *prop)
927{
928 icalerror_check_arg_rz((prop != 0), "prop");
929
930 return prop->x_name;
931}
932
933void vcardproperty_set_group(vcardproperty *prop, const char *group)
934{
935 icalerror_check_arg_rv((group != 0), "group");
936 icalerror_check_arg_rv((prop != 0), "prop");
937
938 if (prop->group != 0) {
939 icalmemory_free_buffer(prop->group);
940 }
941
942 prop->group = icalmemory_strdup(group);
943
944 if (prop->group == 0) {
946 }
947}
948
949const char *vcardproperty_get_group(const vcardproperty *prop)
950{
951 icalerror_check_arg_rz((prop != 0), "prop");
952
953 return prop->group;
954}
955
956const char *vcardproperty_get_property_name(const vcardproperty *prop)
957{
958 char *buf;
959
960 buf = vcardproperty_get_property_name_r(prop);
962 return buf;
963}
964
965char *vcardproperty_get_property_name_r(const vcardproperty *prop)
966{
967 const char *property_name = 0;
968 size_t buf_size = 256;
969 char *buf;
970 char *buf_ptr;
971
972 icalerror_check_arg_rz((prop != 0), "prop");
973
974 buf = icalmemory_new_buffer(buf_size);
975 buf_ptr = buf;
976
977 if (prop->kind == VCARD_X_PROPERTY && prop->x_name != 0) {
978 property_name = prop->x_name;
979 } else {
980 property_name = vcardproperty_kind_to_string(prop->kind);
981 }
982
983 if (property_name == 0) {
986 return 0;
987
988 } else {
989 /* _append_string will automatically grow the buffer if
990 property_name is longer than the initial buffer size */
991 icalmemory_append_string(&buf, &buf_ptr, &buf_size, property_name);
992 }
993
994 return buf;
995}
996
997void vcardproperty_set_parent(vcardproperty *property, vcardcomponent *comp)
998{
999 icalerror_check_arg_rv((property != 0), "property");
1000
1001 property->parent = comp;
1002}
1003
1004vcardcomponent *vcardproperty_get_parent(const vcardproperty *property)
1005{
1006 icalerror_check_arg_rz((property != 0), "property");
1007
1008 return property->parent;
1009}
1010
1011static int param_compare(void *a, void *b)
1012{
1013 return strcmp(vcardparameter_as_vcard_string((vcardparameter *)a),
1014 vcardparameter_as_vcard_string((vcardparameter *)b));
1015}
1016
1017void vcardproperty_normalize(vcardproperty *prop)
1018{
1019 vcardproperty_kind prop_kind = vcardproperty_isa(prop);
1020 icalpvl_list sorted_params = icalpvl_newlist();
1021 vcardparameter *param;
1022
1023 /* Normalize parameters into sorted list */
1024 while ((param = icalpvl_pop(prop->parameters)) != 0) {
1025 int remove = 0;
1026
1027 /* Remove parameters having default values */
1028 switch (vcardparameter_isa(param)) {
1029 case VCARD_VALUE_PARAMETER:
1030 /* Skip VALUE parameters for default property value types */
1031 switch (prop_kind) {
1032 case VCARD_TEL_PROPERTY:
1033 case VCARD_TZ_PROPERTY:
1034 case VCARD_BIRTHPLACE_PROPERTY:
1035 case VCARD_DEATHPLACE_PROPERTY:
1036 if (vcardparameter_get_value(param) == VCARD_VALUE_TEXT) {
1037 remove = 1;
1038 }
1039 break;
1040
1041 case VCARD_RELATED_PROPERTY:
1042 case VCARD_UID_PROPERTY:
1043 case VCARD_KEY_PROPERTY:
1044 if (vcardparameter_get_value(param) == VCARD_VALUE_URI) {
1045 remove = 1;
1046 }
1047 break;
1048
1049 case VCARD_BDAY_PROPERTY:
1050 case VCARD_ANNIVERSARY_PROPERTY:
1051 case VCARD_DEATHDATE_PROPERTY:
1052 if (vcardparameter_get_value(param) == VCARD_VALUE_DATEANDORTIME) {
1053 remove = 1;
1054 }
1055 break;
1056
1057 default:
1058 break;
1059 }
1060 break;
1061
1062 case VCARD_CALSCALE_PARAMETER:
1063 if (vcardparameter_get_calscale(param) == VCARD_CALSCALE_GREGORIAN) {
1064 remove = 1;
1065 }
1066 break;
1067
1068 case VCARD_PREF_PARAMETER:
1069 if (vcardparameter_get_pref(param) >= 100) {
1070 remove = 1;
1071 }
1072 break;
1073
1074 case VCARD_TYPE_PARAMETER:
1075 if (prop_kind == VCARD_TEL_PROPERTY) {
1076 /* Is it just TYPE=VOICE ? */
1077 vcardenumarray_element voice = {VCARD_TYPE_VOICE, NULL};
1078
1079 if (vcardenumarray_find(vcardparameter_get_type(param),
1080 &voice) == 0) {
1081 remove = 1;
1082 }
1083 }
1084
1085 if (!remove) {
1086 vcardenumarray_sort(vcardparameter_get_type(param));
1087 }
1088 break;
1089
1090 case VCARD_PID_PARAMETER:
1091 vcardstrarray_sort(vcardparameter_get_pid(param));
1092 break;
1093
1094 case VCARD_SORTAS_PARAMETER:
1095 vcardstrarray_sort(vcardparameter_get_sortas(param));
1096 break;
1097
1098 default:
1099 break;
1100 }
1101
1102 if (remove) {
1103 vcardparameter_set_parent(param, 0); // MUST NOT have a parent to free
1104 vcardparameter_free(param);
1105 } else {
1106 icalpvl_insert_ordered(sorted_params, param_compare, param);
1107 }
1108 }
1109
1110 icalpvl_free(prop->parameters);
1111 prop->parameters = sorted_params;
1112
1113 switch (prop_kind) {
1114 case VCARD_CATEGORIES_PROPERTY:
1115 vcardstrarray_sort(vcardproperty_get_categories(prop));
1116 break;
1117
1118 case VCARD_NICKNAME_PROPERTY:
1119 vcardstrarray_sort(vcardproperty_get_nickname(prop));
1120 break;
1121
1122 default:
1123 break;
1124 }
1125}
1126
1127void vcardproperty_add_type_parameter(vcardproperty *prop,
1128 vcardenumarray_element *type)
1129{
1130 vcardenumarray *types;
1131 vcardparameter *param =
1132 vcardproperty_get_first_parameter(prop, VCARD_TYPE_PARAMETER);
1133
1134 if (param) {
1135 types = vcardparameter_get_type(param);
1136 vcardenumarray_add(types, type);
1137 } else {
1138 param = vcardparameter_new(VCARD_TYPE_PARAMETER);
1139 types = vcardenumarray_new(0);
1140 vcardenumarray_add(types, type);
1141 vcardparameter_set_type(param, types);
1142 vcardproperty_add_parameter(prop, param);
1143 }
1144}
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:62
@ ICAL_NO_ERROR
Definition icalerror.h:44
@ ICAL_MALFORMEDDATA_ERROR
Definition icalerror.h:56
@ ICAL_PARSE_ERROR
Definition icalerror.h:59
@ ICAL_USAGE_ERROR
Definition icalerror.h:68
#define icalerrno
Access the current icalerrno value.
Definition icalerror.h:130
void icalmemory_free_buffer(void *buf)
Releases a buffer.
Definition icalmemory.c:353
char * icalmemory_strdup(const char *s)
Creates a duplicate of a string.
Definition icalmemory.c:240
void icalmemory_append_string(char **buf, char **pos, size_t *buf_size, const char *string)
Appends a string to a buffer.
Definition icalmemory.c:363
void * icalmemory_new_buffer(size_t size)
Creates new buffer with the specified size.
Definition icalmemory.c:313
void icalmemory_add_tmp_buffer(void *buf)
Adds an externally allocated buffer to the ring.
Definition icalmemory.c:156
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.