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