2013-02-13 [colin] 3.9.0cvs65
[claws.git] / src / plugins / vcalendar / libical / libical / icalproperty.c
1 /* -*- Mode: C -*- */
2
3 /*======================================================================
4   FILE: icalproperty.c
5   CREATOR: eric 28 April 1999
6   
7   $Id$
8
9
10  (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
11
12  This program is free software; you can redistribute it and/or modify
13  it under the terms of either: 
14
15     The LGPL as published by the Free Software Foundation, version
16     2.1, available at: http://www.fsf.org/copyleft/lesser.html
17
18   Or:
19
20     The Mozilla Public License Version 1.0. You may obtain a copy of
21     the License at http://www.mozilla.org/MPL/
22
23   The original code is icalproperty.c
24
25 ======================================================================*/
26 /*#line 27 "icalproperty.c.in"*/
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 #define TMP_BUF_SIZE 1024
49
50 /* Private routines for icalproperty */
51 void icalvalue_set_parent(icalvalue* value,
52                              icalproperty* property);
53 icalproperty* icalvalue_get_parent(icalvalue* value);
54
55 void icalparameter_set_parent(icalparameter* param,
56                              icalproperty* property);
57 icalproperty* icalparameter_get_parent(icalparameter* value);
58
59
60 void icalproperty_set_x_name(icalproperty* prop, char* name);
61
62 struct icalproperty_impl 
63 {
64         char id[5];
65         icalproperty_kind kind;
66         char* x_name;
67         pvl_list parameters;
68         pvl_elem parameter_iterator;
69         icalvalue* value;
70         icalcomponent *parent;
71 };
72
73 void icalproperty_add_parameters(struct icalproperty_impl *prop,va_list args)
74 {
75
76     void* vp;
77
78     struct icalproperty_impl *impl = (struct icalproperty_impl*)prop;
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*)impl,
86                                        (icalparameter*)vp);
87         } else {
88             assert(0);
89         }
90
91     }
92     
93     
94 }
95
96
97 struct icalproperty_impl*
98 icalproperty_new_impl (icalproperty_kind kind)
99 {
100     struct icalproperty_impl* prop;
101
102     if ( ( prop = (struct icalproperty_impl*)
103            malloc(sizeof(struct icalproperty_impl))) == 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* prop)
134 {
135     struct icalproperty_impl *old = (struct icalproperty_impl*)prop;
136     struct icalproperty_impl *new = icalproperty_new_impl(old->kind);
137     pvl_elem p;
138
139     icalerror_check_arg_rz((prop!=0),"Prop");
140     icalerror_check_arg_rz((old!=0),"old");
141     icalerror_check_arg_rz((new!=0),"new");
142
143     if (old->value !=0) {
144         new->value = icalvalue_new_clone(old->value);
145     }
146
147     if (old->x_name != 0) {
148
149         new->x_name = icalmemory_strdup(old->x_name);
150         
151         if (new->x_name == 0) {
152             icalproperty_free(new);
153             icalerror_set_errno(ICAL_NEWFAILED_ERROR);
154             return 0;
155         }
156     }
157
158     for(p=pvl_head(old->parameters);p != 0; p = pvl_next(p)){
159         icalparameter *param = icalparameter_new_clone(pvl_data(p));
160         
161         if (param == 0){
162             icalproperty_free(new);
163             icalerror_set_errno(ICAL_NEWFAILED_ERROR);
164             return 0;
165         }
166
167         pvl_push(new->parameters,param);
168     
169     } 
170
171     return new;
172
173 }
174
175 icalproperty* icalproperty_new_from_string(char* str)
176 {
177
178     size_t buf_size = 1024;
179     char* buf = icalmemory_new_buffer(buf_size);
180     char* buf_ptr = buf;  
181     icalproperty *prop;
182     icalcomponent *comp;
183     int errors  = 0;
184
185     icalerror_check_arg_rz( (str!=0),"str");
186
187     /* Is this a HACK or a crafty reuse of code? */
188
189     icalmemory_append_string(&buf, &buf_ptr, &buf_size, "BEGIN:VCALENDAR\n");
190     icalmemory_append_string(&buf, &buf_ptr, &buf_size, str);
191     icalmemory_append_string(&buf, &buf_ptr, &buf_size, "\n");    
192     icalmemory_append_string(&buf, &buf_ptr, &buf_size, "END:VCALENDAR\n");
193
194     comp = icalparser_parse_string(buf);
195
196     if(comp == 0){
197         icalerror_set_errno(ICAL_PARSE_ERROR);
198         return 0;
199     }
200
201     errors = icalcomponent_count_errors(comp);
202
203     prop = icalcomponent_get_first_property(comp,ICAL_ANY_PROPERTY);
204
205     icalcomponent_remove_property(comp,prop);
206
207     icalcomponent_free(comp);
208     free(buf);
209
210     if(errors > 0){
211         icalproperty_free(prop);
212         return 0;
213     } else {
214         return prop;
215     }
216     
217 }
218
219 void
220 icalproperty_free (icalproperty* prop)
221 {
222     struct icalproperty_impl *p;
223
224     icalparameter* param;
225     
226     icalerror_check_arg_rv((prop!=0),"prop");
227
228     p = (struct icalproperty_impl*)prop;
229
230 #ifdef ICAL_FREE_ON_LIST_IS_ERROR
231     icalerror_assert( (p->parent ==0),"Tried to free a property that is still attached to a component. ");
232     
233 #else
234     if(p->parent !=0){
235         return;
236     }
237 #endif
238
239     if (p->value != 0){
240         icalvalue_set_parent(p->value,0);
241         icalvalue_free(p->value);
242     }
243     
244     while( (param = pvl_pop(p->parameters)) != 0){
245         icalparameter_free(param);
246     }
247     
248     pvl_free(p->parameters);
249     
250     if (p->x_name != 0) {
251         free(p->x_name);
252     }
253     
254     p->kind = ICAL_NO_PROPERTY;
255     p->parameters = 0;
256     p->parameter_iterator = 0;
257     p->value = 0;
258     p->x_name = 0;
259     p->id[0] = 'X';
260     
261     free(p);
262
263 }
264
265
266 char*
267 icalproperty_as_ical_string (icalproperty* prop)
268 {   
269     icalparameter *param;
270
271     /* Create new buffer that we can append names, parameters and a
272        value to, and reallocate as needed. Later, this buffer will be
273        copied to a icalmemory_tmp_buffer, which is managed internally
274        by libical, so it can be given to the caller without fear of
275        the caller forgetting to free it */
276
277     const char* property_name = 0; 
278     size_t buf_size = 1024;
279     char* buf = icalmemory_new_buffer(buf_size);
280     char* buf_ptr = buf;
281     icalvalue* value;
282     char *out_buf;
283
284     char newline[] = "\n";
285
286     struct icalproperty_impl *impl = (struct icalproperty_impl*)prop;
287     
288     icalerror_check_arg_rz( (prop!=0),"prop");
289
290
291     /* Append property name */
292
293     if (impl->kind == ICAL_X_PROPERTY && impl->x_name != 0){
294         property_name = impl->x_name;
295     } else {
296         property_name = icalproperty_kind_to_string(impl->kind);
297     }
298
299     if (property_name == 0 ) {
300         icalerror_warn("Got a property of an unknown kind.");
301         icalmemory_free_buffer(buf);
302         return 0;
303         
304     }
305
306
307     icalmemory_append_string(&buf, &buf_ptr, &buf_size, property_name);
308     icalmemory_append_string(&buf, &buf_ptr, &buf_size, newline);
309
310
311
312     /* Determine what VALUE parameter to include. The VALUE parameters
313        are ignored in the normal parameter printing ( the block after
314        this one, so we need to do it here */
315     {
316         const char* kind_string = 0;
317
318         icalparameter *orig_val_param
319             = icalproperty_get_first_parameter(prop,ICAL_VALUE_PARAMETER);
320
321         icalvalue *value = icalproperty_get_value(impl);
322
323         icalvalue_kind orig_kind = ICAL_NO_VALUE;
324
325         icalvalue_kind this_kind = ICAL_NO_VALUE;
326
327         icalvalue_kind default_kind 
328             =  icalproperty_kind_to_value_kind(impl->kind);
329
330         if(orig_val_param){
331             orig_kind = (icalvalue_kind)icalparameter_get_value(orig_val_param);
332         }
333
334         if(value != 0){
335             this_kind = icalvalue_isa(value);
336         }
337         
338         
339         if(this_kind == default_kind &&
340            orig_kind != ICAL_NO_VALUE){
341             /* The kind is the default, so it does not need to be
342                included, but do it anyway, since it was explicit in
343                the property. But, use the default, not the one
344                specified in the property */
345             
346             kind_string = icalvalue_kind_to_string(default_kind);
347
348         } else if (this_kind != default_kind && this_kind !=  ICAL_NO_VALUE){
349             /* Not the default, so it must be specified */
350             kind_string = icalvalue_kind_to_string(this_kind);
351         } else {
352             /* Don'tinclude the VALUE parameter at all */
353         }
354
355         if(kind_string!=0){
356             icalmemory_append_string(&buf, &buf_ptr, &buf_size, " ;");
357             icalmemory_append_string(&buf, &buf_ptr, &buf_size, "VALUE=");
358             icalmemory_append_string(&buf, &buf_ptr, &buf_size, kind_string);
359             icalmemory_append_string(&buf, &buf_ptr, &buf_size, newline);
360         }
361         
362
363     }
364
365     /* Append parameters */
366     for(param = icalproperty_get_first_parameter(prop,ICAL_ANY_PARAMETER);
367         param != 0; 
368         param = icalproperty_get_next_parameter(prop,ICAL_ANY_PARAMETER)) {
369
370         char* kind_string = icalparameter_as_ical_string(param); 
371         icalparameter_kind kind = icalparameter_isa(param);
372
373         if(kind==ICAL_VALUE_PARAMETER){
374             continue;
375         }
376
377         if (kind_string == 0 ) {
378             char temp[TMP_BUF_SIZE];
379             snprintf(temp, TMP_BUF_SIZE,"Got a parameter of unknown kind in %s property",property_name);
380             icalerror_warn(temp);
381             continue;
382         }
383
384         icalmemory_append_string(&buf, &buf_ptr, &buf_size, " ;");
385         icalmemory_append_string(&buf, &buf_ptr, &buf_size, kind_string);
386         icalmemory_append_string(&buf, &buf_ptr, &buf_size, newline);
387
388     }    
389
390     /* Append value */
391
392     icalmemory_append_string(&buf, &buf_ptr, &buf_size, " :");
393
394     value = icalproperty_get_value(prop);
395
396     if (value != 0){
397         const char *str = icalvalue_as_ical_string(value);
398         icalerror_assert((str !=0),"Could not get string representation of a value");
399         icalmemory_append_string(&buf, &buf_ptr, &buf_size, str);
400     } else {
401         icalmemory_append_string(&buf, &buf_ptr, &buf_size,"ERROR: No Value"); 
402         
403     }
404     
405     icalmemory_append_string(&buf, &buf_ptr, &buf_size, newline);
406
407     /* Now, copy the buffer to a tmp_buffer, which is safe to give to
408        the caller without worring about de-allocating it. */
409
410     
411     out_buf = icalmemory_tmp_buffer(strlen(buf)+1);
412     strcpy(out_buf, buf);
413
414     icalmemory_free_buffer(buf);
415
416     return out_buf;
417 }
418
419
420
421 icalproperty_kind
422 icalproperty_isa (icalproperty* property)
423 {
424     struct icalproperty_impl *p = (struct icalproperty_impl*)property;
425
426    if(property != 0){
427        return p->kind;
428    }
429
430    return ICAL_NO_PROPERTY;
431 }
432
433 int
434 icalproperty_isa_property (void* property)
435 {
436     struct icalproperty_impl *impl = (struct icalproperty_impl*)property;
437
438     icalerror_check_arg_rz( (property!=0), "property");
439
440     if (strcmp(impl->id,"prop") == 0) {
441         return 1;
442     } else {
443         return 0;
444     }
445 }
446
447
448 void
449 icalproperty_add_parameter (icalproperty* prop,icalparameter* parameter)
450 {
451     struct icalproperty_impl *p = (struct icalproperty_impl*)prop;
452     
453    icalerror_check_arg_rv( (prop!=0),"prop");
454    icalerror_check_arg_rv( (parameter!=0),"parameter");
455     
456    pvl_push(p->parameters, parameter);
457
458 }
459
460 void
461 icalproperty_set_parameter (icalproperty* prop,icalparameter* parameter)
462 {
463     icalparameter_kind kind;
464     
465     icalerror_check_arg_rv( (prop!=0),"prop");
466     icalerror_check_arg_rv( (parameter!=0),"parameter");
467
468     kind = icalparameter_isa(parameter);
469
470     icalproperty_remove_parameter(prop,kind);
471
472     icalproperty_add_parameter(prop,parameter);
473 }
474
475 void icalproperty_set_parameter_from_string(icalproperty* prop,
476                                             const char* name, const char* value)
477 {
478
479     icalparameter_kind kind;
480     icalparameter *param;
481
482     icalerror_check_arg_rv( (prop!=0),"prop");
483     icalerror_check_arg_rv( (name!=0),"name");
484     icalerror_check_arg_rv( (value!=0),"value");
485     
486     kind = icalparameter_string_to_kind(name);
487
488     if(kind == ICAL_NO_PARAMETER){
489         icalerror_set_errno(ICAL_BADARG_ERROR);
490         return;
491     }
492
493     param  = icalparameter_new_from_value_string(kind,value);
494
495     if (param == 0){
496         icalerror_set_errno(ICAL_BADARG_ERROR);
497         return;
498     }
499
500     icalproperty_set_parameter(prop,param);
501
502 }
503
504 const char* icalproperty_get_parameter_as_string(icalproperty* prop,
505                                                  const char* name)
506 {
507     icalparameter_kind kind;
508     icalparameter *param;
509     char* str;
510     char* pv;
511
512     icalerror_check_arg_rz( (prop!=0),"prop");
513     icalerror_check_arg_rz( (name!=0),"name");
514     
515     kind = icalparameter_string_to_kind(name);
516
517     if(kind == ICAL_NO_PROPERTY){
518         /* icalenum_string_to_parameter_kind will set icalerrno */
519         return 0;
520     }
521
522     param = icalproperty_get_first_parameter(prop,kind);
523
524     if (param == 0){
525         return 0;
526     }
527
528     str = icalparameter_as_ical_string(param);
529
530     pv = strchr(str,'=');
531
532     if(pv == 0){
533         icalerror_set_errno(ICAL_INTERNAL_ERROR);
534         return 0;
535     }
536
537     return pv+1;
538
539 }
540
541 void
542 icalproperty_remove_parameter (icalproperty* prop, icalparameter_kind kind)
543 {
544     pvl_elem p;     
545     struct icalproperty_impl *impl = (struct icalproperty_impl*)prop;
546
547     icalerror_check_arg_rv((prop!=0),"prop");
548     
549     for(p=pvl_head(impl->parameters);p != 0; p = pvl_next(p)){
550         icalparameter* param = (icalparameter *)pvl_data (p);
551         if (icalparameter_isa(param) == kind) {
552             pvl_remove (impl->parameters, p);
553             icalparameter_free (param);
554             break;
555         }
556     }                       
557 }
558
559
560 int
561 icalproperty_count_parameters (icalproperty* prop)
562 {
563     struct icalproperty_impl *p = (struct icalproperty_impl*)prop;
564
565     if(prop != 0){
566         return pvl_count(p->parameters);
567     }
568
569     icalerror_set_errno(ICAL_USAGE_ERROR);
570     return -1;
571 }
572
573
574 icalparameter*
575 icalproperty_get_first_parameter (icalproperty* prop, icalparameter_kind kind)
576 {
577    struct icalproperty_impl *p = (struct icalproperty_impl*)prop;
578
579    icalerror_check_arg_rz( (prop!=0),"prop");
580    
581    p->parameter_iterator = pvl_head(p->parameters);
582
583    if (p->parameter_iterator == 0) {
584        return 0;
585    }
586
587    for( p->parameter_iterator = pvl_head(p->parameters);
588         p->parameter_iterator !=0;
589         p->parameter_iterator = pvl_next(p->parameter_iterator)){
590
591        icalparameter *param = (icalparameter*)pvl_data(p->parameter_iterator);
592
593        if(icalparameter_isa(param) == kind || kind == ICAL_ANY_PARAMETER){
594            return param;
595        }
596    }
597
598    return 0;
599 }
600
601
602 icalparameter*
603 icalproperty_get_next_parameter (icalproperty* prop, icalparameter_kind kind)
604 {
605     struct icalproperty_impl *p = (struct icalproperty_impl*)prop;
606     
607     icalerror_check_arg_rz( (prop!=0),"prop");
608     
609     if (p->parameter_iterator == 0) {
610         return 0;
611     }
612     
613     for( p->parameter_iterator = pvl_next(p->parameter_iterator);
614          p->parameter_iterator !=0;
615          p->parameter_iterator = pvl_next(p->parameter_iterator)){
616         
617         icalparameter *param = (icalparameter*)pvl_data(p->parameter_iterator);
618         
619         if(icalparameter_isa(param) == kind || kind == ICAL_ANY_PARAMETER){
620             return param;
621         }
622     }
623     
624     return 0;
625
626 }
627
628 void
629 icalproperty_set_value (icalproperty* prop, icalvalue* value)
630 {
631     struct icalproperty_impl *p = (struct icalproperty_impl*)prop;
632
633     icalerror_check_arg_rv((prop !=0),"prop");
634     icalerror_check_arg_rv((value !=0),"value");
635     
636     if (p->value != 0){
637         icalvalue_set_parent(p->value,0);
638         icalvalue_free(p->value);
639         p->value = 0;
640     }
641
642     p->value = value;
643     
644     icalvalue_set_parent(value,prop);
645 }
646
647
648 void icalproperty_set_value_from_string(icalproperty* prop,const char* str,
649                                         const char* type)
650 {
651     icalvalue *oval,*nval;
652     icalvalue_kind kind = ICAL_NO_VALUE;
653
654     icalerror_check_arg_rv( (prop!=0),"prop"); 
655     icalerror_check_arg_rv( (str!=0),"str");
656     icalerror_check_arg_rv( (type!=0),"type");
657    
658     if(strcmp(type,"NO")==0){
659         /* Get the type from the value the property already has, if it exists */
660         oval = icalproperty_get_value(prop);
661         if(oval != 0){
662             /* Use the existing value kind */
663             kind  = icalvalue_isa(oval);
664         } else {   
665             /* Use the default kind for the property */
666             kind = icalproperty_kind_to_value_kind(icalproperty_isa(prop));
667         }
668     } else {
669         /* Use the given kind string */
670         kind = icalvalue_string_to_kind(type);
671     }
672
673     if(kind == ICAL_NO_VALUE){
674         icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
675         return;
676     }
677
678     nval = icalvalue_new_from_string(kind, str);
679
680     if(nval == 0){
681         /* icalvalue_new_from_string sets errno */
682         assert(icalerrno != ICAL_NO_ERROR);
683         return;
684     }
685
686     icalproperty_set_value(prop,nval);
687
688
689 }
690
691 icalvalue*
692 icalproperty_get_value (icalproperty* prop)
693 {
694     struct icalproperty_impl *p = (struct icalproperty_impl*)prop;
695     
696     icalerror_check_arg_rz( (prop!=0),"prop");
697     
698     return p->value;
699 }
700
701 const char* icalproperty_get_value_as_string(icalproperty* prop)
702 {
703     icalvalue *value;
704     
705     struct icalproperty_impl *impl = (struct icalproperty_impl*)prop;
706     
707     icalerror_check_arg_rz( (prop!=0),"prop");
708
709     value = impl->value; 
710
711     return icalvalue_as_ical_string(value);
712 }
713
714
715 void icalproperty_set_x_name(icalproperty* prop, char* name)
716 {
717     struct icalproperty_impl *impl = (struct icalproperty_impl*)prop;
718
719     icalerror_check_arg_rv( (name!=0),"name");
720     icalerror_check_arg_rv( (prop!=0),"prop");
721
722     if (impl->x_name != 0) {
723         free(impl->x_name);
724     }
725
726     impl->x_name = icalmemory_strdup(name);
727
728     if(impl->x_name == 0){
729         icalerror_set_errno(ICAL_NEWFAILED_ERROR);
730     }
731
732 }
733                               
734 char* icalproperty_get_x_name(icalproperty* prop){
735
736     struct icalproperty_impl *impl = (struct icalproperty_impl*)prop;
737
738     icalerror_check_arg_rz( (prop!=0),"prop");
739
740     return impl->x_name;
741 }
742
743
744 /* From Jonathan Yue <jonathan.yue@cp.net>    */
745 char* icalproperty_get_name (icalproperty* prop)
746 {
747
748     const char* property_name = 0;
749     size_t buf_size = 256;
750     char* buf = icalmemory_new_buffer(buf_size);
751     char* buf_ptr = buf;  
752
753     struct icalproperty_impl *impl = (struct icalproperty_impl*)prop;
754
755     icalerror_check_arg_rz( (prop!=0),"prop");
756  
757     if (impl->kind == ICAL_X_PROPERTY && impl->x_name != 0){
758         property_name = impl->x_name;
759     } else {
760         property_name = icalproperty_kind_to_string(impl->kind);
761     }
762  
763     if (property_name == 0 ) {
764         icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
765         return 0;
766
767     } else {
768         /* _append_string will automatically grow the buffer if
769            property_name is longer than the initial buffer size */
770         icalmemory_append_string(&buf, &buf_ptr, &buf_size, property_name);
771     }
772  
773     /* Add the buffer to the temporary buffer ring -- the caller will
774        not have to free the memory. */
775     icalmemory_add_tmp_buffer(buf);
776  
777     return buf;
778 }
779                             
780
781
782
783 void icalproperty_set_parent(icalproperty* property,
784                              icalcomponent* component)
785 {
786     struct icalproperty_impl *impl = (struct icalproperty_impl*)property;
787
788     icalerror_check_arg_rv( (property!=0),"property");
789     
790     impl->parent = component;
791 }
792
793 icalcomponent* icalproperty_get_parent(icalproperty* property)
794 {
795     struct icalproperty_impl *impl = (struct icalproperty_impl*)property;
796  
797     icalerror_check_arg_rz( (property!=0),"property");
798
799     return impl->parent;
800 }
801
802
803
804
805
806
807
808 /* Everything below this line is machine generated. Do not edit. */