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