1 /* -*- Mode: C -*- */
2 
3 /*======================================================================
4   FILE: icalproperty.c
5   CREATOR: eric 28 April 1999
6 
7   $Id: icalproperty.c,v 1.44 2008-01-30 20:28:42 dothebart Exp $
8 
9 
10  (C) COPYRIGHT 2000, Eric Busboom <eric@softwarestudio.org>
11      http://www.softwarestudio.org
12 
13  This program is free software; you can redistribute it and/or modify
14  it under the terms of either:
15 
16     The LGPL as published by the Free Software Foundation, version
17     2.1, available at: http://www.fsf.org/copyleft/lesser.html
18 
19   Or:
20 
21     The Mozilla Public License Version 1.0. You may obtain a copy of
22     the License at http://www.mozilla.org/MPL/
23 
24   The original code is icalproperty.c
25 
26 ======================================================================*/
27 
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31 
32 #include "icalproperty.h"
33 #include "icalparameter.h"
34 #include "icalcomponent.h"
35 #include "pvl.h"
36 #include "icalenums.h"
37 #include "icalerror.h"
38 #include "icalmemory.h"
39 #include "icalparser.h"
40 
41 #include <string.h> /* For icalmemory_strdup, rindex */
42 #include <assert.h>
43 #include <stdlib.h>
44 #include <errno.h>
45 #include <stdio.h> /* for printf */
46 #include <stdarg.h> /* for va_list, va_start, etc. */
47 
48 #ifdef WIN32
49 #if defined(_MSC_VER) && (_MSC_VER < 1900)
50 #define snprintf _snprintf
51 #endif
52 #define strcasecmp    stricmp
53 #endif
54 
55 /* Private routines for icalproperty */
56 void icalvalue_set_parent(icalvalue* value,
57 			     icalproperty* property);
58 icalproperty* icalvalue_get_parent(icalvalue* value);
59 
60 void icalparameter_set_parent(icalparameter* param,
61 			     icalproperty* property);
62 icalproperty* icalparameter_get_parent(icalparameter* value);
63 
64 
65 void icalproperty_set_x_name(icalproperty* prop, const char* name);
66 
67 struct icalproperty_impl
68 {
69 	char id[5];
70 	icalproperty_kind kind;
71 	char* x_name;
72 	pvl_list parameters;
73 	pvl_elem parameter_iterator;
74 	icalvalue* value;
75 	icalcomponent *parent;
76 };
77 
icalproperty_add_parameters(icalproperty * prop,va_list args)78 void icalproperty_add_parameters(icalproperty* prop, va_list args)
79 {
80     void* vp;
81 
82     while((vp = va_arg(args, void*)) != 0) {
83 
84 	if (icalvalue_isa_value(vp) != 0 ){
85 	} else if (icalparameter_isa_parameter(vp) != 0 ){
86 
87 	    icalproperty_add_parameter((icalproperty*)prop,
88 				       (icalparameter*)vp);
89 	} else {
90 	    icalerror_set_errno(ICAL_BADARG_ERROR);
91 	}
92 
93     }
94 }
95 
96 
97 icalproperty*
icalproperty_new_impl(icalproperty_kind kind)98 icalproperty_new_impl(icalproperty_kind kind)
99 {
100     icalproperty* prop;
101 
102     if (!icalproperty_kind_is_valid(kind))
103       return NULL;
104 
105     if ( ( prop = (icalproperty*) malloc(sizeof(icalproperty))) == 0) {
106 	icalerror_set_errno(ICAL_NEWFAILED_ERROR);
107 	return 0;
108     }
109 
110     strcpy(prop->id,"prop");
111 
112     prop->kind = kind;
113     prop->parameters = pvl_newlist();
114     prop->parameter_iterator = 0;
115     prop->value = 0;
116     prop->x_name = 0;
117     prop->parent = 0;
118 
119     return prop;
120 }
121 
122 
123 icalproperty*
icalproperty_new(icalproperty_kind kind)124 icalproperty_new (icalproperty_kind kind)
125 {
126     if (kind == ICAL_NO_PROPERTY){
127         return 0;
128     }
129 
130     return (icalproperty*)icalproperty_new_impl(kind);
131 }
132 
133 
134 icalproperty*
icalproperty_new_clone(icalproperty * old)135 icalproperty_new_clone(icalproperty* old)
136 {
137     icalproperty *new;
138     pvl_elem p;
139 
140     icalerror_check_arg_rz((old!=0),"old");
141 
142     new = icalproperty_new_impl(old->kind);
143     icalerror_check_arg_rz((new!=0),"new");
144 
145     if (old->value !=0) {
146 	new->value = icalvalue_new_clone(old->value);
147     }
148 
149     if (old->x_name != 0) {
150 
151 	new->x_name = icalmemory_strdup(old->x_name);
152 
153 	if (new->x_name == 0) {
154 	    icalproperty_free(new);
155 	    icalerror_set_errno(ICAL_NEWFAILED_ERROR);
156 	    return 0;
157 	}
158     }
159 
160     for(p=pvl_head(old->parameters);p != 0; p = pvl_next(p)){
161 	icalparameter *param = icalparameter_new_clone(pvl_data(p));
162 
163 	if (param == 0){
164 	    icalproperty_free(new);
165 	    icalerror_set_errno(ICAL_NEWFAILED_ERROR);
166 	    return 0;
167 	}
168 
169 	pvl_push(new->parameters,param);
170 
171     }
172 
173     return new;
174 
175 }
176 
icalproperty_new_from_string(const char * str)177 icalproperty* icalproperty_new_from_string(const char* str)
178 {
179 
180     size_t buf_size = 1024;
181     char* buf;
182     char* buf_ptr;
183     icalproperty *prop;
184     icalcomponent *comp;
185     int errors  = 0;
186 
187     icalerror_check_arg_rz( (str!=0),"str");
188 
189     buf = icalmemory_new_buffer(buf_size);
190     buf_ptr = buf;
191 
192     /* Is this a HACK or a crafty reuse of code? */
193 
194     icalmemory_append_string(&buf, &buf_ptr, &buf_size, "BEGIN:VCALENDAR\r\n");
195     icalmemory_append_string(&buf, &buf_ptr, &buf_size, str);
196     icalmemory_append_string(&buf, &buf_ptr, &buf_size, "\r\n");
197     icalmemory_append_string(&buf, &buf_ptr, &buf_size, "END:VCALENDAR\r\n");
198 
199     comp = icalparser_parse_string(buf);
200 
201     if(comp == 0){
202         icalerror_set_errno(ICAL_PARSE_ERROR);
203         free(buf);
204         return 0;
205     }
206 
207     errors = icalcomponent_count_errors(comp);
208 
209     prop = icalcomponent_get_first_property(comp,ICAL_ANY_PROPERTY);
210 
211     icalcomponent_remove_property(comp,prop);
212 
213     icalcomponent_free(comp);
214     free(buf);
215 
216     if(errors > 0){
217         icalproperty_free(prop);
218         return 0;
219     } else {
220         return prop;
221     }
222 
223 }
224 
225 void
icalproperty_free(icalproperty * p)226 icalproperty_free (icalproperty* p)
227 {
228     icalparameter* param;
229 
230     icalerror_check_arg_rv((p!=0),"prop");
231 
232 #ifdef ICAL_FREE_ON_LIST_IS_ERROR
233     icalerror_assert( (p->parent ==0),"Tried to free a property that is still attached to a component. ");
234 
235 #else
236     if(p->parent !=0){
237 	return;
238     }
239 #endif
240 
241     if (p->value != 0){
242         icalvalue_set_parent(p->value,0);
243 	icalvalue_free(p->value);
244     }
245 
246     while( (param = pvl_pop(p->parameters)) != 0){
247 	icalparameter_free(param);
248     }
249 
250     pvl_free(p->parameters);
251 
252     if (p->x_name != 0) {
253 	free(p->x_name);
254     }
255 
256     p->kind = ICAL_NO_PROPERTY;
257     p->parameters = 0;
258     p->parameter_iterator = 0;
259     p->value = 0;
260     p->x_name = 0;
261     p->id[0] = 'X';
262 
263     free(p);
264 
265 }
266 
267 
268 /* This returns where the start of the next line should be. chars_left does
269    not include the trailing '\0'. */
270 #define MAX_LINE_LEN 75
271 /*#define MAX_LINE_LEN 120*/
272 
273 static char*
get_next_line_start(char * line_start,int chars_left)274 get_next_line_start (char *line_start, int chars_left)
275 {
276     char *pos;
277 
278     /* If we have 74 chars or less left, we can output all of them.
279        we return a pointer to the '\0' at the end of the string. */
280     if (chars_left < MAX_LINE_LEN) {
281         return line_start + chars_left;
282     }
283 
284     /* Now try to split on a UTF-8 boundary defined as a 7-bit
285        value or as a byte with the two high-most bits set:
286        11xxxxxx.  See http://czyborra.com/utf/ */
287 
288     pos = line_start + MAX_LINE_LEN - 1;
289     while (pos > line_start) {
290         /* plain ascii */
291         if ((*pos & 128) == 0)
292             return pos;
293 
294         /* utf8 escape byte */
295         if ((*pos & 192) == 192)
296             return pos;
297 
298         pos--;
299     }
300 
301     /* Give up, just break at 74 chars (the 75th char is the space at
302        the start of the line).  */
303 
304     return line_start + MAX_LINE_LEN - 1;
305 }
306 
307 
308 /** This splits the property into lines less than 75 octects long (as
309  *  specified in RFC2445). It tries to split after a ';' if it can.
310  *  It returns a tmp buffer.  NOTE: I'm not sure if it matters if we
311  *  split a line in the middle of a UTF-8 character. It probably won't
312  *  look nice in a text editor.
313  */
314 static char*
fold_property_line(char * text)315 fold_property_line (char *text)
316 {
317     size_t buf_size;
318     char *buf, *buf_ptr, *line_start, *next_line_start;
319     int len, chars_left, first_line;
320     char ch;
321 
322     /* Start with a buffer twice the size of our property line, so we almost
323        certainly won't overflow it. */
324     len = strlen (text);
325     buf_size = len * 2;
326     buf = icalmemory_new_buffer (buf_size);
327     buf_ptr = buf;
328 
329     /* Step through the text, finding each line to add to the output. */
330     line_start = text;
331     chars_left = len;
332     first_line = 1;
333     for (;;) {
334         if (chars_left <= 0)
335 	    break;
336 
337         /* This returns the first character for the next line. */
338         next_line_start = get_next_line_start (line_start, chars_left);
339 
340 	/* If this isn't the first line, we need to output a newline and space
341 	   first. */
342 	if (!first_line) {
343 	    icalmemory_append_string (&buf, &buf_ptr, &buf_size, "\r\n ");
344 	}
345 	first_line = 0;
346 
347 	/* This adds the line to our tmp buffer. We temporarily place a '\0'
348 	   in text, so we can copy the line in one go. */
349 	ch = *next_line_start;
350 	*next_line_start = '\0';
351 	icalmemory_append_string (&buf, &buf_ptr, &buf_size, line_start);
352 	*next_line_start = ch;
353 
354 	/* Now we move on to the next line. */
355 	chars_left -= (next_line_start - line_start);
356 	line_start = next_line_start;
357     }
358 
359     return buf;
360 }
361 
362 
363 /* Determine what VALUE parameter to include. The VALUE parameters
364    are ignored in the normal parameter printing ( the block after
365    this one, so we need to do it here */
366 static const char *
icalproperty_get_value_kind(icalproperty * prop)367 icalproperty_get_value_kind(icalproperty *prop)
368 {
369 	const char* kind_string = 0;
370 
371 	icalparameter *orig_val_param
372 	    = icalproperty_get_first_parameter(prop,ICAL_VALUE_PARAMETER);
373 
374 	icalvalue *value = icalproperty_get_value(prop);
375 
376 	icalvalue_kind orig_kind = ICAL_NO_VALUE;
377 
378 	icalvalue_kind this_kind = ICAL_NO_VALUE;
379 
380 	icalvalue_kind default_kind
381 	    =  icalproperty_kind_to_value_kind(prop->kind);
382 
383 	if(orig_val_param){
384 	    orig_kind = icalparameter_value_to_value_kind( icalparameter_get_value(orig_val_param) );
385 	}
386 
387 	if(value != 0){
388 	    this_kind = icalvalue_isa(value);
389 	}
390 
391     if ( orig_kind != ICAL_NO_VALUE ) {
392       kind_string = icalvalue_kind_to_string( orig_kind );
393     } else if(this_kind == default_kind &&
394 	   orig_kind != ICAL_NO_VALUE){
395 	    /* The kind is the default, so it does not need to be
396                included, but do it anyway, since it was explicit in
397                the property. But, use the default, not the one
398                specified in the property */
399 
400 	    kind_string = icalvalue_kind_to_string(default_kind);
401 
402 	} else if (this_kind != default_kind && this_kind !=  ICAL_NO_VALUE){
403 	    /* Not the default, so it must be specified */
404 	    kind_string = icalvalue_kind_to_string(this_kind);
405 	} else {
406 	    /* Don'tinclude the VALUE parameter at all */
407 	}
408 
409 	return kind_string;
410 }
411 
412 const char*
icalproperty_as_ical_string(icalproperty * prop)413 icalproperty_as_ical_string (icalproperty* prop)
414 {
415 	char *buf;
416 	buf = icalproperty_as_ical_string_r(prop);
417 	icalmemory_add_tmp_buffer(buf);
418 	return buf;
419 }
420 
421 
422 char*
icalproperty_as_ical_string_r(icalproperty * prop)423 icalproperty_as_ical_string_r(icalproperty* prop)
424 {
425     icalparameter *param;
426 
427     /* Create new buffer that we can append names, parameters and a
428      * value to, and reallocate as needed.
429      */
430 
431     const char* property_name = 0;
432     size_t buf_size = 1024;
433     char* buf;
434     char* buf_ptr;
435     icalvalue* value;
436     char *out_buf;
437     const char* kind_string = 0;
438     const char newline[] = "\r\n";
439 
440 
441     icalerror_check_arg_rz( (prop!=0),"prop");
442 
443     buf = icalmemory_new_buffer(buf_size);
444     buf_ptr = buf;
445 
446     /* Append property name */
447 
448     if (prop->kind == ICAL_X_PROPERTY && prop->x_name != 0){
449 	property_name = prop->x_name;
450     } else {
451 	property_name = icalproperty_kind_to_string(prop->kind);
452     }
453 
454     if (property_name == 0 ) {
455 	icalerror_warn("Got a property of an unknown kind.");
456 	icalmemory_free_buffer(buf);
457 	return 0;
458 
459     }
460 
461     icalmemory_append_string(&buf, &buf_ptr, &buf_size, property_name);
462 
463     kind_string = icalproperty_get_value_kind(prop);
464     if(kind_string!=0){
465 	icalmemory_append_string(&buf, &buf_ptr, &buf_size, ";VALUE=");
466 	icalmemory_append_string(&buf, &buf_ptr, &buf_size, kind_string);
467     }
468 
469     /* Append parameters */
470     for(param = icalproperty_get_first_parameter(prop,ICAL_ANY_PARAMETER);
471 	param != 0;
472 	param = icalproperty_get_next_parameter(prop,ICAL_ANY_PARAMETER)) {
473 
474 	icalparameter_kind kind = icalparameter_isa(param);
475 	kind_string = icalparameter_as_ical_string_r(param);
476 
477 	if (kind_string == 0 ) {
478 	  icalerror_warn("Got a parameter of unknown kind for the following property");
479 
480 	  icalerror_warn((property_name) ? property_name : "(NULL)");
481 	    continue;
482 	}
483 
484 	if (kind==ICAL_VALUE_PARAMETER) {
485 		free ((char *) kind_string);
486 		continue;
487 	}
488 
489 	icalmemory_append_string(&buf, &buf_ptr, &buf_size, ";");
490     	icalmemory_append_string(&buf, &buf_ptr, &buf_size, kind_string);
491 	free((char *)kind_string);
492     }
493 
494     /* Append value */
495 
496     icalmemory_append_string(&buf, &buf_ptr, &buf_size, ":");
497 
498     value = icalproperty_get_value(prop);
499 
500     if (value != 0){
501 	char *str = icalvalue_as_ical_string_r(value);
502 	if (str != 0)
503 	    icalmemory_append_string(&buf, &buf_ptr, &buf_size, str);
504 	else
505 	    icalmemory_append_string(&buf, &buf_ptr, &buf_size,"ERROR: No Value");
506 	free(str);
507     } else {
508 	icalmemory_append_string(&buf, &buf_ptr, &buf_size,"ERROR: No Value");
509 
510     }
511 
512     icalmemory_append_string(&buf, &buf_ptr, &buf_size, newline);
513 
514     /* We now use a function to fold the line properly every 75 characters.
515        That function also adds the newline for us. */
516     out_buf = fold_property_line (buf);
517 
518     icalmemory_free_buffer(buf);
519 
520     return out_buf;
521 }
522 
523 
524 
525 icalproperty_kind
icalproperty_isa(icalproperty * p)526 icalproperty_isa (icalproperty* p)
527 {
528    if(p != 0){
529        return p->kind;
530    }
531 
532    return ICAL_NO_PROPERTY;
533 }
534 
535 int
icalproperty_isa_property(void * property)536 icalproperty_isa_property (void* property)
537 {
538     icalproperty *impl = (icalproperty *) property;
539 
540     icalerror_check_arg_rz( (property!=0), "property");
541     if (strcmp(impl->id,"prop") == 0) {
542 	return 1;
543     } else {
544 	return 0;
545     }
546 }
547 
548 
549 void
icalproperty_add_parameter(icalproperty * p,icalparameter * parameter)550 icalproperty_add_parameter (icalproperty* p,icalparameter* parameter)
551 {
552    icalerror_check_arg_rv( (p!=0),"prop");
553    icalerror_check_arg_rv( (parameter!=0),"parameter");
554 
555    pvl_push(p->parameters, parameter);
556 
557 }
558 
559 void
icalproperty_set_parameter(icalproperty * prop,icalparameter * parameter)560 icalproperty_set_parameter (icalproperty* prop,icalparameter* parameter)
561 {
562     icalparameter_kind kind;
563 
564     icalerror_check_arg_rv( (prop!=0),"prop");
565     icalerror_check_arg_rv( (parameter!=0),"parameter");
566 
567     kind = icalparameter_isa(parameter);
568     if (kind == ICAL_X_PARAMETER) {
569       icalproperty_remove_parameter_by_name(prop,
570 					    icalparameter_get_xname(parameter));
571     } else if (kind == ICAL_IANA_PARAMETER) {
572       icalproperty_remove_parameter_by_name(prop,
573 					    icalparameter_get_iana_name(parameter));
574     }
575     else
576       icalproperty_remove_parameter_by_kind(prop,kind);
577 
578     icalproperty_add_parameter(prop,parameter);
579 }
580 
icalproperty_set_parameter_from_string(icalproperty * prop,const char * name,const char * value)581 void icalproperty_set_parameter_from_string(icalproperty* prop,
582                                             const char* name, const char* value)
583 {
584 
585     icalparameter_kind kind;
586     icalparameter *param;
587 
588     icalerror_check_arg_rv( (prop!=0),"prop");
589     icalerror_check_arg_rv( (name!=0),"name");
590     icalerror_check_arg_rv( (value!=0),"value");
591 
592     kind = icalparameter_string_to_kind(name);
593 
594     if(kind == ICAL_NO_PARAMETER){
595         icalerror_set_errno(ICAL_BADARG_ERROR);
596         return;
597     }
598 
599     param  = icalparameter_new_from_value_string(kind,value);
600 
601     if (param == 0){
602         icalerror_set_errno(ICAL_BADARG_ERROR);
603         return;
604     }
605 
606     if (kind == ICAL_X_PARAMETER) {
607         icalparameter_set_xname(param, name);
608     } else if (kind == ICAL_IANA_PARAMETER) {
609         icalparameter_set_iana_name(param, name);
610     }
611 
612     icalproperty_set_parameter(prop,param);
613 
614 }
615 
icalproperty_get_parameter_as_string(icalproperty * prop,const char * name)616 const char* icalproperty_get_parameter_as_string(icalproperty* prop,
617                                                  const char* name)
618 {
619 	char *buf;
620 	buf = icalproperty_get_parameter_as_string_r(prop, name);
621 	icalmemory_add_tmp_buffer(buf);
622 	return buf;
623 }
624 
625 
icalproperty_get_parameter_as_string_r(icalproperty * prop,const char * name)626 char* icalproperty_get_parameter_as_string_r(icalproperty* prop,
627                                                  const char* name)
628 {
629     icalparameter_kind kind;
630     icalparameter *param;
631     char* str;
632     char *pv, *t;
633     char* pvql;
634     char* pvqr;
635 
636     icalerror_check_arg_rz( (prop!=0),"prop");
637     icalerror_check_arg_rz( (name!=0),"name");
638 
639     kind = icalparameter_string_to_kind(name);
640 
641     if(kind == ICAL_NO_PARAMETER){
642         /* icalenum_string_to_parameter_kind will set icalerrno */
643         return 0;
644     }
645 
646     for(param = icalproperty_get_first_parameter(prop,kind);
647 	    param != 0;
648 	    param = icalproperty_get_next_parameter(prop,kind)) {
649 
650 	    if (kind == ICAL_X_PARAMETER) {
651             if (strcmp(icalparameter_get_xname(param),name)==0) {
652                 break;
653             }
654         } else if (kind == ICAL_IANA_PARAMETER) {
655             if (strcmp(icalparameter_get_iana_name(param),name)==0) {
656                 break;
657             }
658 	    } else {
659 		    break;
660         }
661 
662     }
663 
664     if (param == 0){
665         return 0;
666     }
667 
668 
669     str = icalparameter_as_ical_string_r(param);
670 
671     t = strchr(str,'=');
672 
673     if (t == 0) {
674         icalerror_set_errno(ICAL_INTERNAL_ERROR);
675 	free(str);
676         return 0;
677     }
678 
679     /* Strip the property name and the equal sign */
680     pv = icalmemory_strdup(t+1);
681     free(str);
682 
683     /* Is the string quoted? */
684     pvql = strchr(pv, '"');
685     if (pvql == 0) {
686 	return(pv);		/* No quotes?  Return it immediately. */
687     }
688 
689     /* Strip everything up to the first quote */
690     str = icalmemory_strdup(pvql+1);
691     free(pv);
692 
693     /* Search for the end quote */
694     pvqr = strrchr(str, '"');
695     if (pvqr == 0) {
696         icalerror_set_errno(ICAL_INTERNAL_ERROR);
697 	free(str);
698         return 0;
699     }
700 
701     *pvqr = '\0';
702     return str;
703 }
704 
705 /** @see icalproperty_remove_parameter_by_kind()
706  *
707  *  @deprecated Please use icalproperty_remove_parameter_by_kind()
708  *              instead.
709  */
710 
711 void
icalproperty_remove_parameter(icalproperty * prop,icalparameter_kind kind)712 icalproperty_remove_parameter(icalproperty* prop, icalparameter_kind kind)
713 {
714   icalproperty_remove_parameter_by_kind(prop, kind);
715 }
716 
717 
718 /** @brief Remove all parameters with the specified kind.
719  *
720  *  @param prop   A valid icalproperty.
721  *  @param kind   The kind to remove (ex. ICAL_TZID_PARAMETER)
722  *
723  *  See icalproperty_remove_parameter_by_name() and
724  *  icalproperty_remove_parameter_by_ref() for alternate ways of
725  *  removing parameters
726  */
727 
728 void
icalproperty_remove_parameter_by_kind(icalproperty * prop,icalparameter_kind kind)729 icalproperty_remove_parameter_by_kind(icalproperty* prop, icalparameter_kind kind)
730 {
731     pvl_elem p;
732 
733     icalerror_check_arg_rv((prop!=0),"prop");
734 
735     for(p=pvl_head(prop->parameters);p != 0; p = pvl_next(p)){
736 	icalparameter* param = (icalparameter *)pvl_data (p);
737         if (icalparameter_isa(param) == kind) {
738             pvl_remove (prop->parameters, p);
739 	    icalparameter_free(param);
740             break;
741         }
742     }
743 }
744 
745 
746 /** @brief Remove all parameters with the specified name.
747  *
748  *  @param prop   A valid icalproperty.
749  *  @param name   The name of the parameter to remove
750  *
751  *  This function removes parameters with the given name.  The name
752  *  corresponds to either a built-in name (TZID, etc.) or the name of
753  *  an extended parameter (X-FOO)
754  *
755  *  See icalproperty_remove_parameter_by_kind() and
756  *  icalproperty_remove_parameter_by_ref() for alternate ways of removing
757  *  parameters
758  */
759 
760 
761 void
icalproperty_remove_parameter_by_name(icalproperty * prop,const char * name)762 icalproperty_remove_parameter_by_name(icalproperty* prop, const char *name)
763 {
764     pvl_elem p;
765 
766     icalerror_check_arg_rv((prop!=0),"prop");
767 
768     for(p=pvl_head(prop->parameters);p != 0; p = pvl_next(p)){
769 	icalparameter* param = (icalparameter *)pvl_data (p);
770 	const char * kind_string;
771 
772 	if (icalparameter_isa(param) == ICAL_X_PARAMETER)
773 	  kind_string = icalparameter_get_xname(param);
774     else if (icalparameter_isa(param) == ICAL_IANA_PARAMETER)
775 	  kind_string = icalparameter_get_iana_name(param);
776 	else
777 	  kind_string = icalparameter_kind_to_string(icalparameter_isa(param));
778 
779 	if (!kind_string)
780 	  continue;
781 
782         if (0 == strcmp(kind_string, name)) {
783             pvl_remove (prop->parameters, p);
784             icalparameter_free(param);
785             break;
786         }
787     }
788 }
789 
790 
791 /** @brief Remove the specified parameter reference from the property.
792  *
793  *  @param prop   A valid icalproperty.
794  *  @param parameter   A reference to a specific icalparameter.
795  *
796  *  This function removes the specified parameter reference from the
797  *  property.
798  */
799 
800 void
icalproperty_remove_parameter_by_ref(icalproperty * prop,icalparameter * parameter)801 icalproperty_remove_parameter_by_ref(icalproperty* prop, icalparameter* parameter)
802 {
803     pvl_elem p;
804 
805     icalerror_check_arg_rv((prop!=0),"prop");
806     icalerror_check_arg_rv((parameter!=0),"parameter");
807 
808     for (p=pvl_head(prop->parameters);p != 0; p = pvl_next(p)) {
809         icalparameter* p_param = (icalparameter *)pvl_data (p);
810 
811         if (icalparameter_has_same_name(parameter, p_param)) {
812             pvl_remove (prop->parameters, p);
813             icalparameter_free(p_param);
814             break;
815         }
816     }
817 }
818 
819 
820 int
icalproperty_count_parameters(const icalproperty * prop)821 icalproperty_count_parameters (const icalproperty* prop)
822 {
823     if(prop != 0){
824 	return pvl_count(prop->parameters);
825     }
826 
827     icalerror_set_errno(ICAL_USAGE_ERROR);
828     return -1;
829 }
830 
831 
832 icalparameter*
icalproperty_get_first_parameter(icalproperty * p,icalparameter_kind kind)833 icalproperty_get_first_parameter(icalproperty* p, icalparameter_kind kind)
834 {
835    icalerror_check_arg_rz( (p!=0),"prop");
836 
837    p->parameter_iterator = pvl_head(p->parameters);
838 
839    if (p->parameter_iterator == 0) {
840        return 0;
841    }
842 
843    for( p->parameter_iterator = pvl_head(p->parameters);
844 	p->parameter_iterator !=0;
845 	p->parameter_iterator = pvl_next(p->parameter_iterator)){
846 
847        icalparameter *param = (icalparameter*)pvl_data(p->parameter_iterator);
848 
849        if(icalparameter_isa(param) == kind || kind == ICAL_ANY_PARAMETER){
850 	   return param;
851        }
852    }
853 
854    return 0;
855 }
856 
857 
858 icalparameter*
icalproperty_get_next_parameter(icalproperty * p,icalparameter_kind kind)859 icalproperty_get_next_parameter (icalproperty* p, icalparameter_kind kind)
860 {
861     icalerror_check_arg_rz( (p!=0),"prop");
862 
863     if (p->parameter_iterator == 0) {
864 	return 0;
865     }
866 
867     for( p->parameter_iterator = pvl_next(p->parameter_iterator);
868 	 p->parameter_iterator !=0;
869 	 p->parameter_iterator = pvl_next(p->parameter_iterator)){
870 
871 	icalparameter *param = (icalparameter*)pvl_data(p->parameter_iterator);
872 
873 	if(icalparameter_isa(param) == kind || kind == ICAL_ANY_PARAMETER){
874 	    return param;
875 	}
876     }
877 
878     return 0;
879 
880 }
881 
882 void
icalproperty_set_value(icalproperty * p,icalvalue * value)883 icalproperty_set_value (icalproperty* p, icalvalue* value)
884 {
885     icalerror_check_arg_rv((p !=0),"prop");
886     icalerror_check_arg_rv((value !=0),"value");
887 
888     if (p->value != 0){
889 	icalvalue_set_parent(p->value,0);
890 	icalvalue_free(p->value);
891 	p->value = 0;
892     }
893 
894     p->value = value;
895 
896     icalvalue_set_parent(value,p);
897 }
898 
899 
icalproperty_set_value_from_string(icalproperty * prop,const char * str,const char * type)900 void icalproperty_set_value_from_string(icalproperty* prop,const char* str,
901                                         const char* type)
902 {
903     icalvalue *oval,*nval;
904     icalvalue_kind kind = ICAL_NO_VALUE;
905 
906     icalerror_check_arg_rv( (prop!=0),"prop");
907     icalerror_check_arg_rv( (str!=0),"str");
908     icalerror_check_arg_rv( (type!=0),"type");
909 
910     if(strcmp(type,"NO")==0){
911         /* Get the type from the value the property already has, if it exists */
912         oval = icalproperty_get_value(prop);
913         if(oval != 0){
914             /* Use the existing value kind */
915             kind  = icalvalue_isa(oval);
916         } else {
917             /* Use the default kind for the property */
918             kind = icalproperty_kind_to_value_kind(icalproperty_isa(prop));
919         }
920     } else {
921         /* Use the given kind string */
922         kind = icalvalue_string_to_kind(type);
923     }
924 
925     if(kind == ICAL_NO_VALUE){
926         icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
927         return;
928     }
929 
930     icalerror_clear_errno();
931     nval = icalvalue_new_from_string(kind, str);
932 
933     if(nval == 0){
934         /* icalvalue_new_from_string sets errno */
935         assert(icalerrno != ICAL_NO_ERROR);
936         return;
937     }
938 
939     icalproperty_set_value(prop,nval);
940 
941 
942 }
943 
944 icalvalue*
icalproperty_get_value(const icalproperty * prop)945 icalproperty_get_value(const icalproperty* prop)
946 {
947     icalerror_check_arg_rz( (prop!=0),"prop");
948 
949     return prop->value;
950 }
951 
icalproperty_get_value_as_string(const icalproperty * prop)952 const char* icalproperty_get_value_as_string(const icalproperty* prop)
953 {
954 	char *buf;
955 	buf = icalproperty_get_value_as_string_r(prop);
956 	icalmemory_add_tmp_buffer(buf);
957 	return buf;
958 }
959 
960 
icalproperty_get_value_as_string_r(const icalproperty * prop)961 char* icalproperty_get_value_as_string_r(const icalproperty* prop)
962 {
963     icalvalue *value;
964 
965     icalerror_check_arg_rz( (prop!=0),"prop");
966 
967     value = prop->value;
968 
969     return icalvalue_as_ical_string_r(value);
970 }
971 
972 
icalproperty_set_x_name(icalproperty * prop,const char * name)973 void icalproperty_set_x_name(icalproperty* prop, const char* name)
974 {
975     icalerror_check_arg_rv( (name!=0),"name");
976     icalerror_check_arg_rv( (prop!=0),"prop");
977 
978     if (prop->x_name != 0) {
979         free(prop->x_name);
980     }
981 
982     prop->x_name = icalmemory_strdup(name);
983 
984     if(prop->x_name == 0){
985 	icalerror_set_errno(ICAL_NEWFAILED_ERROR);
986     }
987 
988 }
989 
icalproperty_get_x_name(icalproperty * prop)990 const char* icalproperty_get_x_name(icalproperty* prop){
991     icalerror_check_arg_rz( (prop!=0),"prop");
992 
993     return prop->x_name;
994 }
995 
icalproperty_get_property_name(const icalproperty * prop)996 const char* icalproperty_get_property_name(const icalproperty* prop)
997 {
998 	char *buf;
999 	buf = icalproperty_get_property_name_r(prop);
1000 	icalmemory_add_tmp_buffer(buf);
1001 	return buf;
1002 }
1003 
1004 
icalproperty_get_property_name_r(const icalproperty * prop)1005 char* icalproperty_get_property_name_r(const icalproperty* prop)
1006 {
1007 
1008     const char* property_name = 0;
1009     size_t buf_size = 256;
1010     char* buf;
1011     char* buf_ptr;
1012 
1013     icalerror_check_arg_rz( (prop!=0),"prop");
1014 
1015     buf = icalmemory_new_buffer(buf_size);
1016     buf_ptr = buf;
1017 
1018     if (prop->kind == ICAL_X_PROPERTY && prop->x_name != 0){
1019         property_name = prop->x_name;
1020     } else {
1021         property_name = icalproperty_kind_to_string(prop->kind);
1022     }
1023 
1024     if (property_name == 0 ) {
1025         icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
1026 	icalmemory_free_buffer(buf);
1027         return 0;
1028 
1029     } else {
1030         /* _append_string will automatically grow the buffer if
1031            property_name is longer than the initial buffer size */
1032         icalmemory_append_string(&buf, &buf_ptr, &buf_size, property_name);
1033     }
1034 
1035     return buf;
1036 }
1037 
1038 
1039 
1040 
icalproperty_set_parent(icalproperty * property,icalcomponent * component)1041 void icalproperty_set_parent(icalproperty* property,
1042 			     icalcomponent* component)
1043 {
1044     icalerror_check_arg_rv( (property!=0),"property");
1045 
1046     property->parent = component;
1047 }
1048 
icalproperty_get_parent(const icalproperty * property)1049 icalcomponent* icalproperty_get_parent(const icalproperty* property)
1050 {
1051     icalerror_check_arg_rz( (property!=0),"property");
1052 
1053     return property->parent;
1054 }
1055