b723086f9c909b3dc18d2bfe7d1875a15658dcfa
[claws.git] / src / plugins / vcalendar / libical / libical / icalcomponent.c
1 /*======================================================================
2   FILE: icalcomponent.c
3   CREATOR: eric 28 April 1999
4   
5   $Id$
6
7
8  (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
9
10  This program is free software; you can redistribute it and/or modify
11  it under the terms of either: 
12
13     The LGPL as published by the Free Software Foundation, version
14     2.1, available at: http://www.fsf.org/copyleft/lesser.html
15
16   Or:
17
18     The Mozilla Public License Version 1.0. You may obtain a copy of
19     the License at http://www.mozilla.org/MPL/
20
21   The original code is icalcomponent.c
22
23 ======================================================================*/
24
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #include "icalcomponent.h"
31 #include "pvl.h" /* "Pointer-to-void list" */
32 #include "icalerror.h"
33 #include "icalmemory.h"
34 #include "icalenums.h"
35 #include "icaltime.h"
36 #include "icalduration.h"
37 #include "icalperiod.h"
38 #include "icalparser.h"
39
40 #include <string.h>  /* for strcpy & memset */
41 #include <stdlib.h>  /* for malloc */
42 #include <stdarg.h> /* for va_list, etc */
43 #include <errno.h>
44 #include <assert.h>
45 #include <stdio.h> /* for fprintf */
46
47 #define MAX_TMP 1024
48
49 struct icalcomponent_impl 
50 {
51         char id[5];
52         icalcomponent_kind kind;
53         char* x_name;
54         pvl_list properties;
55         pvl_elem property_iterator;
56         pvl_list components;
57         pvl_elem component_iterator;
58         icalcomponent* parent;
59 };
60
61 /* icalproperty functions that only components get to use */
62 void icalproperty_set_parent(icalproperty* property,
63                              icalcomponent* component);
64 icalcomponent* icalproperty_get_parent(icalproperty* property);
65 void icalcomponent_add_children(struct icalcomponent_impl *impl,va_list args);
66 icalcomponent* icalcomponent_new_impl (icalcomponent_kind kind);
67 int icalcomponent_property_sorter(void *a, void *b);
68
69
70 void icalcomponent_add_children(struct icalcomponent_impl *impl,va_list args)
71 {
72     void* vp;
73     
74     while((vp = va_arg(args, void*)) != 0) {
75
76         assert (icalcomponent_isa_component(vp) != 0 ||
77                 icalproperty_isa_property(vp) != 0 ) ;
78
79         if (icalcomponent_isa_component(vp) != 0 ){
80
81             icalcomponent_add_component((icalcomponent*)impl,
82                                        (icalcomponent*)vp);
83
84         } else if (icalproperty_isa_property(vp) != 0 ){
85
86             icalcomponent_add_property((icalcomponent*)impl,
87                                        (icalproperty*)vp);
88         }
89     }    
90 }
91
92 icalcomponent*
93 icalcomponent_new_impl (icalcomponent_kind kind)
94 {
95     struct icalcomponent_impl* comp;
96
97     if ( ( comp = (struct icalcomponent_impl*)
98            malloc(sizeof(struct icalcomponent_impl))) == 0) {
99         icalerror_set_errno(ICAL_NEWFAILED_ERROR);
100         return 0;
101     }
102     
103     strcpy(comp->id,"comp");
104
105     comp->kind = kind;
106     comp->properties = pvl_newlist();
107     comp->property_iterator = 0;
108     comp->components = pvl_newlist();
109     comp->component_iterator = 0;
110     comp->x_name = 0;
111     comp->parent = 0;
112
113     return comp;
114 }
115
116 icalcomponent*
117 icalcomponent_new (icalcomponent_kind kind)
118 {
119    return (icalcomponent*)icalcomponent_new_impl(kind);
120 }
121
122 icalcomponent*
123 icalcomponent_vanew (icalcomponent_kind kind, ...)
124 {
125    va_list args;
126
127    struct icalcomponent_impl *impl = icalcomponent_new_impl(kind);
128
129     if (impl == 0){
130         return 0;
131     }
132
133    va_start(args,kind);
134    icalcomponent_add_children(impl, args);
135    va_end(args);
136
137    return (icalcomponent*) impl;
138 }
139
140 icalcomponent* icalcomponent_new_from_string(char* str)
141 {
142     return icalparser_parse_string(str);
143 }
144
145 icalcomponent* icalcomponent_new_clone(icalcomponent* component)
146 {
147     struct icalcomponent_impl *old = (struct icalcomponent_impl*)component;
148     struct icalcomponent_impl *new;
149     icalproperty *p;
150     icalcomponent *c;
151     pvl_elem itr;
152
153     icalerror_check_arg_rz( (component!=0), "component");
154
155     new = icalcomponent_new_impl(old->kind);
156
157     if (new == 0){
158         return 0;
159     }
160
161     
162     for( itr = pvl_head(old->properties);
163          itr != 0;
164          itr = pvl_next(itr))
165     {   
166         p = (icalproperty*)pvl_data(itr);
167         icalcomponent_add_property(new,icalproperty_new_clone(p));
168     }
169    
170    
171     for( itr = pvl_head(old->components);
172          itr != 0;
173          itr = pvl_next(itr))
174     {   
175         c = (icalcomponent*)pvl_data(itr);
176         icalcomponent_add_component(new,icalcomponent_new_clone(c));
177     }
178
179    return new;
180
181 }
182
183
184 void
185 icalcomponent_free (icalcomponent* component)
186 {
187     icalproperty* prop;
188     icalcomponent* comp;
189     struct icalcomponent_impl *c = (struct icalcomponent_impl*)component;
190
191     icalerror_check_arg_rv( (component!=0), "component");
192
193 #ifdef ICAL_FREE_ON_LIST_IS_ERROR
194     icalerror_assert( (c->parent ==0),"Tried to free a component that is still attached to a parent component");
195 #else
196     if(c->parent != 0){
197         return;
198     }
199 #endif
200
201     if(component != 0 ){
202        
203        while( (prop=pvl_pop(c->properties)) != 0){
204            assert(prop != 0);
205            icalproperty_set_parent(prop,0);
206            icalproperty_free(prop);
207        }
208        
209        pvl_free(c->properties);
210
211        while( (comp=pvl_data(pvl_head(c->components))) != 0){
212            assert(comp!=0);
213            icalcomponent_remove_component(component,comp);
214            icalcomponent_free(comp);
215        }
216        
217        pvl_free(c->components);
218
219         if (c->x_name != 0) {
220             free(c->x_name);
221         }
222
223         c->kind = ICAL_NO_COMPONENT;
224         c->properties = 0;
225         c->property_iterator = 0;
226         c->components = 0;
227         c->component_iterator = 0;
228         c->x_name = 0;  
229         c->id[0] = 'X';
230
231         free(c);
232     }
233 }
234
235 char*
236 icalcomponent_as_ical_string (icalcomponent* component)
237 {
238    char* buf, *out_buf;
239    char* tmp_buf;
240    size_t buf_size = 1024;
241    char* buf_ptr = 0;
242     pvl_elem itr;
243     struct icalcomponent_impl *impl = (struct icalcomponent_impl*)component;
244
245 #ifdef ICAL_UNIX_NEWLINE    
246     char newline[] = "\n";
247 #else
248     char newline[] = "\r\n";
249 #endif
250    
251    icalcomponent *c;
252    icalproperty *p;
253    icalcomponent_kind kind = icalcomponent_isa(component);
254
255    const char* kind_string;
256
257    buf = icalmemory_new_buffer(buf_size);
258    buf_ptr = buf; 
259
260    icalerror_check_arg_rz( (component!=0), "component");
261    icalerror_check_arg_rz( (kind!=ICAL_NO_COMPONENT), "component kind is ICAL_NO_COMPONENT");
262    
263    kind_string  = icalenum_component_kind_to_string(kind);
264
265    icalerror_check_arg_rz( (kind_string!=0),"Unknown kind of component");
266
267    icalmemory_append_string(&buf, &buf_ptr, &buf_size, "BEGIN:");
268    icalmemory_append_string(&buf, &buf_ptr, &buf_size, kind_string);
269    icalmemory_append_string(&buf, &buf_ptr, &buf_size, newline);
270    
271
272
273    for( itr = pvl_head(impl->properties);
274          itr != 0;
275          itr = pvl_next(itr))
276     {   
277         p = (icalproperty*)pvl_data(itr);
278         
279         icalerror_assert((p!=0),"Got a null property");
280         tmp_buf = icalproperty_as_ical_string(p);
281         
282         icalmemory_append_string(&buf, &buf_ptr, &buf_size, tmp_buf);
283     }
284    
285    
286    for( itr = pvl_head(impl->components);
287         itr != 0;
288         itr = pvl_next(itr))
289    {    
290        c = (icalcomponent*)pvl_data(itr);
291        
292        tmp_buf = icalcomponent_as_ical_string(c);
293        
294        icalmemory_append_string(&buf, &buf_ptr, &buf_size, tmp_buf);
295        
296    }
297    
298    icalmemory_append_string(&buf, &buf_ptr, &buf_size, "END:");
299    icalmemory_append_string(&buf, &buf_ptr, &buf_size, 
300                             icalenum_component_kind_to_string(kind));
301    icalmemory_append_string(&buf, &buf_ptr, &buf_size, newline);
302
303    out_buf = icalmemory_tmp_copy(buf);
304    free(buf);
305
306    return out_buf;
307 }
308
309
310 int
311 icalcomponent_is_valid (icalcomponent* component)
312 {
313     struct icalcomponent_impl *impl = (struct icalcomponent_impl *)component;
314
315         
316     if ( (strcmp(impl->id,"comp") == 0) &&
317          impl->kind != ICAL_NO_COMPONENT){
318         return 1;
319     } else {
320         return 0;
321     }
322
323 }
324
325
326 icalcomponent_kind
327 icalcomponent_isa (icalcomponent* component)
328 {
329     struct icalcomponent_impl *impl = (struct icalcomponent_impl *)component;
330     icalerror_check_arg_rz( (component!=0), "component");
331
332    if(component != 0)
333    {
334        return impl->kind;
335    }
336
337    return ICAL_NO_COMPONENT;
338 }
339
340
341 int
342 icalcomponent_isa_component (void* component)
343 {
344     struct icalcomponent_impl *impl = (struct icalcomponent_impl *)component;
345
346     icalerror_check_arg_rz( (component!=0), "component");
347
348     if (strcmp(impl->id,"comp") == 0) {
349         return 1;
350     } else {
351         return 0;
352     }
353
354 }
355
356 int icalcomponent_property_sorter(void *a, void *b)
357 {
358     icalproperty_kind kinda, kindb;
359     const char *ksa, *ksb;
360
361     kinda = icalproperty_isa((icalproperty*)a);
362     kindb = icalproperty_isa((icalproperty*)b);
363
364     ksa = icalenum_property_kind_to_string(kinda);
365     ksb = icalenum_property_kind_to_string(kindb);
366
367     return strcmp(ksa,ksb);
368 }
369
370
371 void
372 icalcomponent_add_property (icalcomponent* component, icalproperty* property)
373 {
374     struct icalcomponent_impl *impl;
375
376     icalerror_check_arg_rv( (component!=0), "component");
377     icalerror_check_arg_rv( (property!=0), "property");
378
379      impl = (struct icalcomponent_impl*)component;
380
381     icalerror_assert( (!icalproperty_get_parent(property)),"The property has already been added to a component. Remove the property with icalcomponent_remove_property before calling icalcomponent_add_property");
382
383     icalproperty_set_parent(property,component);
384
385 #ifdef ICAL_INSERT_ORDERED
386     pvl_insert_ordered(impl->properties,
387                        icalcomponent_property_sorter,property);
388 #else
389     pvl_push(impl->properties,property);
390 #endif
391
392 }
393
394
395 void
396 icalcomponent_remove_property (icalcomponent* component, icalproperty* property)
397 {
398     struct icalcomponent_impl *impl;
399     pvl_elem itr, next_itr;
400
401     icalerror_check_arg_rv( (component!=0), "component");
402     icalerror_check_arg_rv( (property!=0), "property");
403     
404     impl = (struct icalcomponent_impl*)component;
405
406     icalerror_assert( (icalproperty_get_parent(property)),"The property is not a member of a component");
407
408     
409     for( itr = pvl_head(impl->properties);
410          itr != 0;
411          itr = next_itr)
412     {
413         next_itr = pvl_next(itr);
414         
415         if( pvl_data(itr) == (void*)property ){
416
417            if (impl->property_iterator == itr){
418                impl->property_iterator = pvl_next(itr);
419            }
420
421            pvl_remove( impl->properties, itr); 
422           icalproperty_set_parent(property,0);
423         }
424     }   
425 }
426
427 int
428 icalcomponent_count_properties (icalcomponent* component, 
429                                 icalproperty_kind kind)
430 {
431     int count=0;
432     pvl_elem itr;
433     struct icalcomponent_impl *impl = (struct icalcomponent_impl*)component;
434
435     icalerror_check_arg_rz( (component!=0), "component");
436
437     for( itr = pvl_head(impl->properties);
438          itr != 0;
439          itr = pvl_next(itr))
440     {   
441         if(kind == icalproperty_isa((icalproperty*)pvl_data(itr)) ||
442             kind == ICAL_ANY_PROPERTY){
443             count++;
444         }
445     }
446
447
448     return count;
449
450 }
451
452 icalproperty* icalcomponent_get_current_property (icalcomponent* component)
453 {
454
455    struct icalcomponent_impl *c = (struct icalcomponent_impl*)component;
456    icalerror_check_arg_rz( (component!=0),"component");
457
458    if ((c->property_iterator==0)){
459        return 0;
460    }
461
462    return (icalproperty*) pvl_data(c->property_iterator);
463
464 }
465
466 icalproperty*
467 icalcomponent_get_first_property (icalcomponent* component, icalproperty_kind kind)
468 {
469    struct icalcomponent_impl *c = (struct icalcomponent_impl*)component;
470    icalerror_check_arg_rz( (component!=0),"component");
471   
472    for( c->property_iterator = pvl_head(c->properties);
473         c->property_iterator != 0;
474         c->property_iterator = pvl_next(c->property_iterator)) {
475             
476        icalproperty *p =  (icalproperty*) pvl_data(c->property_iterator);
477         
478            if (icalproperty_isa(p) == kind || kind == ICAL_ANY_PROPERTY) {
479                
480                return p;
481            }
482    }
483    return 0;
484 }
485
486 icalproperty*
487 icalcomponent_get_next_property (icalcomponent* component, icalproperty_kind kind)
488 {
489    struct icalcomponent_impl *c = (struct icalcomponent_impl*)component;
490    icalerror_check_arg_rz( (component!=0),"component");
491
492    if (c->property_iterator == 0){
493        return 0;
494    }
495
496    for( c->property_iterator = pvl_next(c->property_iterator);
497         c->property_iterator != 0;
498         c->property_iterator = pvl_next(c->property_iterator)) {
499             
500        icalproperty *p =  (icalproperty*) pvl_data(c->property_iterator);
501            
502        if (icalproperty_isa(p) == kind || kind == ICAL_ANY_PROPERTY) {
503            
504            return p;
505        }
506    }
507
508    return 0;
509 }
510
511
512 icalproperty**
513 icalcomponent_get_properties (icalcomponent* component, icalproperty_kind kind);
514
515
516 void
517 icalcomponent_add_component (icalcomponent* parent, icalcomponent* child)
518 {
519     struct icalcomponent_impl *impl, *cimpl;
520
521     icalerror_check_arg_rv( (parent!=0), "parent");
522     icalerror_check_arg_rv( (child!=0), "child");
523     
524     impl = (struct icalcomponent_impl*)parent;
525     cimpl = (struct icalcomponent_impl*)child;
526
527     icalerror_assert( (cimpl->parent ==0),"The child component has already been added to a parent component. Remove the component with icalcomponent_remove_component before calling icalcomponent_add_component");
528
529     cimpl->parent = parent;
530
531     pvl_push(impl->components,child);
532 }
533
534
535 void
536 icalcomponent_remove_component (icalcomponent* parent, icalcomponent* child)
537 {
538    struct icalcomponent_impl *impl,*cimpl;
539    pvl_elem itr, next_itr;
540
541    icalerror_check_arg_rv( (parent!=0), "parent");
542    icalerror_check_arg_rv( (child!=0), "child");
543    
544    impl = (struct icalcomponent_impl*)parent;
545    cimpl = (struct icalcomponent_impl*)child;
546    
547    for( itr = pvl_head(impl->components);
548         itr != 0;
549         itr = next_itr)
550    {
551        next_itr = pvl_next(itr);
552        
553        if( pvl_data(itr) == (void*)child ){
554
555            if (impl->component_iterator == itr){
556                /* Don't let the current iterator become invalid */
557
558                /* HACK. The semantics for this are troubling. */
559                impl->component_iterator = 
560                    pvl_next(impl->component_iterator);
561                   
562            }
563            pvl_remove( impl->components, itr); 
564            cimpl->parent = 0;
565            break;
566        }
567    }    
568 }
569
570
571 int
572 icalcomponent_count_components (icalcomponent* component, 
573                                 icalcomponent_kind kind)
574 {
575     int count=0;
576     pvl_elem itr;
577     struct icalcomponent_impl *impl = (struct icalcomponent_impl*)component;
578
579     icalerror_check_arg_rz( (component!=0), "component");
580
581     for( itr = pvl_head(impl->components);
582          itr != 0;
583          itr = pvl_next(itr))
584     {
585         if(kind == icalcomponent_isa((icalcomponent*)pvl_data(itr)) ||
586             kind == ICAL_ANY_COMPONENT){
587             count++;
588         }
589     }
590
591     return count;
592 }
593
594 icalcomponent*
595 icalcomponent_get_current_component(icalcomponent* component)
596 {
597    struct icalcomponent_impl *c = (struct icalcomponent_impl*)component;
598
599    icalerror_check_arg_rz( (component!=0),"component");
600
601    if (c->component_iterator == 0){
602        return 0;
603    }
604
605    return (icalcomponent*) pvl_data(c->component_iterator);
606 }
607
608 icalcomponent*
609 icalcomponent_get_first_component (icalcomponent* component, 
610                                    icalcomponent_kind kind)
611 {
612    struct icalcomponent_impl *c = (struct icalcomponent_impl*)component;
613
614    icalerror_check_arg_rz( (component!=0),"component");
615   
616    for( c->component_iterator = pvl_head(c->components);
617         c->component_iterator != 0;
618         c->component_iterator = pvl_next(c->component_iterator)) {
619             
620        icalcomponent *p =  (icalcomponent*) pvl_data(c->component_iterator);
621         
622            if (icalcomponent_isa(p) == kind || kind == ICAL_ANY_COMPONENT) {
623                
624                return p;
625            }
626    }
627
628    return 0;
629 }
630
631
632 icalcomponent*
633 icalcomponent_get_next_component (icalcomponent* component, icalcomponent_kind kind)
634 {
635    struct icalcomponent_impl *c = (struct icalcomponent_impl*)component;
636
637    icalerror_check_arg_rz( (component!=0),"component");
638   
639    if (c->component_iterator == 0){
640        return 0;
641    }
642
643    for( c->component_iterator = pvl_next(c->component_iterator);
644         c->component_iterator != 0;
645         c->component_iterator = pvl_next(c->component_iterator)) {
646             
647        icalcomponent *p =  (icalcomponent*) pvl_data(c->component_iterator);
648         
649            if (icalcomponent_isa(p) == kind || kind == ICAL_ANY_COMPONENT) {
650                
651                return p;
652            }
653    }
654
655    return 0;
656 }
657
658 icalcomponent* icalcomponent_get_first_real_component(icalcomponent *c)
659 {
660     icalcomponent *comp;
661
662     for(comp = icalcomponent_get_first_component(c,ICAL_ANY_COMPONENT);
663         comp != 0;
664         comp = icalcomponent_get_next_component(c,ICAL_ANY_COMPONENT)){
665
666         icalcomponent_kind kind = icalcomponent_isa(comp);
667
668         if(kind == ICAL_VEVENT_COMPONENT ||
669            kind == ICAL_VTODO_COMPONENT ||
670            kind == ICAL_VJOURNAL_COMPONENT ){
671             return comp;
672         }
673     }
674     return 0;
675 }
676
677 time_t icalcomponent_convert_time(icalproperty *p)
678 {
679     struct icaltimetype sict;
680     time_t convt;
681     icalproperty *tzp;
682         
683
684     /* Though it says _dtstart, it will work for dtend too */
685     sict = icalproperty_get_dtstart(p);
686
687     tzp = icalproperty_get_first_parameter(p,ICAL_TZID_PARAMETER);
688
689     if (sict.is_utc == 1 && tzp != 0){
690         icalerror_warn("icalcomponent_get_span: component has a UTC DTSTART with a timezone specified ");
691         icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
692         return 0; 
693     }
694
695     if(sict.is_utc == 1){
696 #ifdef TEST_CONVERT_TIME
697         gchar buft[512];
698 #endif
699         /* _as_timet will use gmtime() to do the conversion */
700         convt = icaltime_as_timet(sict);
701
702 #ifdef TEST_CONVERT_TIME
703         printf("convert time: use as_timet:\n %s\n %s",
704                icalproperty_as_ical_string(p), ctime_r(&convt,buft));
705 #endif
706
707     } else if (sict.is_utc == 0 && tzp == 0 ) {
708         time_t offset;
709 #ifdef TEST_CONVERT_TIME
710         gchar buft[512];
711 #endif
712
713         /* _as_timet will use localtime() to do the conversion */
714         convt = icaltime_as_timet(sict);
715         offset = icaltime_utc_offset(sict,0);
716         convt += offset;
717
718 #ifdef TEST_CONVERT_TIME
719         printf("convert time: use as_timet and adjust:\n %s\n %s",
720                icalproperty_as_ical_string(p), ctime_r(&convt,buft));
721 #endif
722     } else {
723 #ifdef TEST_CONVERT_TIME
724         gchar buft[512];
725 #endif
726         /* Convert the time to UTC for the named timezone*/
727         const char* timezone = icalparameter_get_tzid(tzp);
728         convt = icaltime_as_timet(icaltime_as_utc(sict,timezone));
729
730 #ifdef TEST_CONVERT_TIME
731         printf("convert time: use _as_utc:\n %s\n %s",
732                icalproperty_as_ical_string(p), ctime_r(&convt,buft));
733 #endif
734     }       
735
736     return convt;
737 }
738 struct icaltime_span icalcomponent_get_span(icalcomponent* comp)
739 {
740     icalcomponent *inner;
741     icalproperty *p, *duration;
742     icalcomponent_kind kind;
743     struct icaltime_span span;
744     struct icaltimetype start;
745 #ifdef TEST_CONVERT_TIME
746     gchar buft[512];
747 #endif
748
749     span.start = 0;
750     span.end = 0;
751     span.is_busy= 1;
752
753     /* initial Error checking */
754
755 /*    icalerror_check_arg_rz( (comp!=0),"comp");*/
756
757     kind  = icalcomponent_isa(comp);
758
759     if(kind == ICAL_VCALENDAR_COMPONENT){
760         inner = icalcomponent_get_first_real_component(comp);
761
762         /* Maybe there is a VTIMEZONE in there */
763         if (inner == 0){
764             inner = icalcomponent_get_first_component(comp,
765                                ICAL_VTIMEZONE_COMPONENT);
766         }
767
768     } else {
769         inner = comp;
770     }
771
772     if (inner == 0){
773         icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
774         /*icalerror_warn("icalcomponent_get_span: no component specified, or empty VCALENDAR component");*/
775         return span; 
776     }
777     
778     kind  = icalcomponent_isa(inner);
779
780     if( !( kind == ICAL_VEVENT_COMPONENT ||
781            kind == ICAL_VJOURNAL_COMPONENT ||
782            kind == ICAL_VTODO_COMPONENT ||         
783            kind == ICAL_VFREEBUSY_COMPONENT )) {
784         icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
785         /*icalerror_warn("icalcomponent_get_span: no component specified, or empty VCALENDAR component");*/
786         return span; 
787         
788     }
789
790
791
792     /* Get to work. starting with DTSTART */
793
794     p = icalcomponent_get_first_property(inner, ICAL_DTSTART_PROPERTY);
795
796     if (p ==0 ) {
797         icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
798         /*icalerror_warn("icalcomponent_get_span: component has no DTSTART time");*/
799         return span; 
800     }
801
802
803     start = icalproperty_get_dtstart(p);
804
805     icalerror_clear_errno();
806
807     span.start = icalcomponent_convert_time(p);
808
809 #ifdef TEST_CONVERT_TIME
810     printf("convert time:\n %s %s",
811            icalproperty_as_ical_string(p), ctime_r(&span.start, buft));
812 #endif
813
814     if(icalerrno != ICAL_NO_ERROR){
815         span.start = 0;
816         return span;
817     }
818
819     /* The end time could be specified as either a DTEND or a DURATION */
820     p = icalcomponent_get_first_property(inner, ICAL_DTEND_PROPERTY);
821     duration = icalcomponent_get_first_property(inner, ICAL_DURATION_PROPERTY);
822
823     if (p==0 && duration == 0 && start.is_date != 1) {
824         icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
825         /*icalerror_warn("icalcomponent_get_span: component has neither DTEND nor DURATION time");*/
826         span.start = 0;
827         return span; 
828     } 
829
830     if (p!=0){
831         span.end = icalcomponent_convert_time(p);
832     } else if (start.is_date == 1) {
833         /* Duration is all day */
834         span.end = span.start + 60*60*24;
835     } else {
836         /* Use the duration */
837         struct icaldurationtype dur;
838         time_t durt;
839         
840         
841         dur = icalproperty_get_duration(duration);
842
843         durt = icaldurationtype_as_int(dur);
844         span.end = span.start+durt;
845     }
846
847     return span;
848
849 }
850
851
852 int icalcomponent_count_errors(icalcomponent* component)
853 {
854     int errors = 0;
855     icalproperty *p;
856     icalcomponent *c;
857     pvl_elem itr;
858     struct icalcomponent_impl *impl = (struct icalcomponent_impl*)component;
859
860     for( itr = pvl_head(impl->properties);
861          itr != 0;
862          itr = pvl_next(itr))
863     {   
864         p = (icalproperty*)pvl_data(itr);
865         
866         if(icalproperty_isa(p) == ICAL_XLICERROR_PROPERTY)
867         {
868             errors++;
869         }
870     }
871
872
873     for( itr = pvl_head(impl->components);
874          itr != 0;
875          itr = pvl_next(itr))
876     {   
877         c = (icalcomponent*)pvl_data(itr);
878         
879         errors += icalcomponent_count_errors(c);
880         
881     }
882
883     return errors;
884 }
885
886
887 void icalcomponent_strip_errors(icalcomponent* component)
888 {
889     icalproperty *p;
890     icalcomponent *c;
891     pvl_elem itr, next_itr;
892     struct icalcomponent_impl *impl = (struct icalcomponent_impl*)component;
893
894    for( itr = pvl_head(impl->properties);
895          itr != 0;
896          itr = next_itr)
897     {   
898         p = (icalproperty*)pvl_data(itr);
899         next_itr = pvl_next(itr);
900
901         if(icalproperty_isa(p) == ICAL_XLICERROR_PROPERTY)
902         {
903             icalcomponent_remove_property(component,p);
904         }
905     }
906     
907     for( itr = pvl_head(impl->components);
908          itr != 0;
909          itr = pvl_next(itr))
910     {   
911         c = (icalcomponent*)pvl_data(itr);
912         icalcomponent_strip_errors(c);
913     }
914 }
915
916 /* Hack. This will change the state of the iterators */
917 void icalcomponent_convert_errors(icalcomponent* component)
918 {
919     icalproperty *p, *next_p;
920     icalcomponent *c;
921
922     for(p = icalcomponent_get_first_property(component,ICAL_ANY_PROPERTY);
923         p != 0;
924         p = next_p){
925         
926         next_p = icalcomponent_get_next_property(component,ICAL_ANY_PROPERTY);
927
928         if(icalproperty_isa(p) == ICAL_XLICERROR_PROPERTY)
929         {
930             struct icalreqstattype rst;
931             icalparameter *param  = icalproperty_get_first_parameter
932                 (p,ICAL_XLICERRORTYPE_PARAMETER);
933
934             rst.code = ICAL_UNKNOWN_STATUS;
935             rst.desc = 0;
936
937             switch(icalparameter_get_xlicerrortype(param)){
938
939                 case  ICAL_XLICERRORTYPE_PARAMETERNAMEPARSEERROR: {
940                     rst.code = ICAL_3_2_INVPARAM_STATUS;
941                     break;
942                 }
943                 case  ICAL_XLICERRORTYPE_PARAMETERVALUEPARSEERROR: {
944                     rst.code = ICAL_3_3_INVPARAMVAL_STATUS;
945                     break;
946                 }
947                 case  ICAL_XLICERRORTYPE_PROPERTYPARSEERROR: {              
948                     rst.code = ICAL_3_0_INVPROPNAME_STATUS;
949                     break;
950                 }
951                 case  ICAL_XLICERRORTYPE_VALUEPARSEERROR: {
952                     rst.code = ICAL_3_1_INVPROPVAL_STATUS;
953                     break;
954                 }
955                 case  ICAL_XLICERRORTYPE_COMPONENTPARSEERROR: {
956                     rst.code = ICAL_3_4_INVCOMP_STATUS;
957                     break;
958                 }
959
960                 default: {
961                 }
962             }
963             if (rst.code != ICAL_UNKNOWN_STATUS){
964                 
965                 rst.debug = icalproperty_get_xlicerror(p);
966                 icalcomponent_add_property(component,
967                                            icalproperty_new_requeststatus(
968                                                icalreqstattype_as_string(rst)
969                                                )
970                     );
971                 
972                 icalcomponent_remove_property(component,p);
973             }
974         }
975     }
976
977     for(c = icalcomponent_get_first_component(component,ICAL_ANY_COMPONENT);
978         c != 0;
979         c = icalcomponent_get_next_component(component,ICAL_ANY_COMPONENT)){
980         
981         icalcomponent_convert_errors(c);
982     }
983 }
984
985
986 icalcomponent* icalcomponent_get_parent(icalcomponent* component)
987 {
988    struct icalcomponent_impl *c = (struct icalcomponent_impl*)component;
989
990    return c->parent;
991 }
992
993 void icalcomponent_set_parent(icalcomponent* component, icalcomponent* parent)
994 {
995    struct icalcomponent_impl *c = (struct icalcomponent_impl*)component;
996
997    c->parent = parent;
998 }
999
1000 icalcompiter icalcompiter_null = {ICAL_NO_COMPONENT,0};
1001
1002
1003 struct icalcomponent_kind_map {
1004         icalcomponent_kind kind;
1005         char name[20];
1006 };
1007
1008   
1009
1010 static struct icalcomponent_kind_map component_map[] = 
1011 {
1012     { ICAL_VEVENT_COMPONENT, "VEVENT" },
1013     { ICAL_VTODO_COMPONENT, "VTODO" },
1014     { ICAL_VJOURNAL_COMPONENT, "VJOURNAL" },
1015     { ICAL_VCALENDAR_COMPONENT, "VCALENDAR" },
1016     { ICAL_VFREEBUSY_COMPONENT, "VFREEBUSY" },
1017     { ICAL_VTIMEZONE_COMPONENT, "VTIMEZONE" },
1018     { ICAL_VALARM_COMPONENT, "VALARM" },
1019     { ICAL_XSTANDARD_COMPONENT, "STANDARD" }, /*These are part of RFC2445 */
1020     { ICAL_XDAYLIGHT_COMPONENT, "DAYLIGHT" }, /*but are not really components*/
1021     { ICAL_X_COMPONENT, "X" },
1022     { ICAL_VSCHEDULE_COMPONENT, "SCHEDULE" },
1023
1024     /* CAP components */
1025     { ICAL_VQUERY_COMPONENT, "VQUERY" },  
1026     { ICAL_VCAR_COMPONENT, "VCAR" },  
1027     { ICAL_VCOMMAND_COMPONENT, "VCOMMAND" },  
1028
1029     /* libical private components */
1030     { ICAL_XLICINVALID_COMPONENT, "X-LIC-UNKNOWN" },  
1031     { ICAL_XLICMIMEPART_COMPONENT, "X-LIC-MIME-PART" },  
1032     { ICAL_ANY_COMPONENT, "ANY" },  
1033     { ICAL_XROOT_COMPONENT, "XROOT" },  
1034
1035     /* End of list */
1036     { ICAL_NO_COMPONENT, "" },
1037 };
1038
1039
1040
1041 const char* icalcomponent_kind_to_string(icalcomponent_kind kind)
1042 {
1043     int i;
1044
1045     for (i=0; component_map[i].kind != ICAL_NO_COMPONENT; i++) {
1046         if (component_map[i].kind == kind) {
1047             return component_map[i].name;
1048         }
1049     }
1050
1051     return 0;
1052
1053 }
1054
1055 icalcomponent_kind icalcomponent_string_to_kind(const char* string)
1056 {
1057     int i;
1058
1059     if (string ==0 ) { 
1060         return ICAL_NO_COMPONENT;
1061     }
1062
1063     for (i=0; component_map[i].kind  != ICAL_NO_COMPONENT; i++) {
1064         if (strcmp(component_map[i].name, string) == 0) {
1065             return component_map[i].kind;
1066         }
1067     }
1068
1069     return ICAL_NO_COMPONENT;
1070 }
1071
1072
1073
1074 icalcompiter 
1075 icalcomponent_begin_component(icalcomponent* component,icalcomponent_kind kind)
1076 {
1077     struct icalcomponent_impl *impl = (struct icalcomponent_impl*)component;
1078     icalcompiter itr;
1079     pvl_elem i;
1080
1081     itr.kind = kind;
1082
1083     icalerror_check_arg_re( (component!=0),"component",icalcompiter_null);
1084
1085     for( i = pvl_head(impl->components); i != 0; i = pvl_next(i)) {
1086         
1087         icalcomponent *c =  (icalcomponent*) pvl_data(i);
1088         
1089         if (icalcomponent_isa(c) == kind || kind == ICAL_ANY_COMPONENT) {
1090             
1091             itr.iter = i;
1092
1093             return itr;
1094         }
1095     }
1096
1097     return icalcompiter_null;
1098 }
1099
1100 icalcompiter
1101 icalcomponent_end_component(icalcomponent* component,icalcomponent_kind kind)
1102 {
1103     struct icalcomponent_impl *impl = (struct icalcomponent_impl*)component;
1104     icalcompiter itr; 
1105     pvl_elem i;
1106
1107     itr.kind = kind;
1108
1109     icalerror_check_arg_re( (component!=0),"component",icalcompiter_null);
1110
1111     for( i = pvl_tail(impl->components); i != 0; i = pvl_prior(i)) {
1112         
1113         icalcomponent *c =  (icalcomponent*) pvl_data(i);
1114         
1115         if (icalcomponent_isa(c) == kind || kind == ICAL_ANY_COMPONENT) {
1116             
1117             itr.iter = pvl_next(i);
1118
1119             return itr;
1120         }
1121     }
1122
1123     return icalcompiter_null;;
1124 }
1125
1126
1127 icalcomponent* icalcompiter_next(icalcompiter* i)
1128 {
1129    if (i->iter == 0){
1130        return 0;
1131    }
1132
1133    icalerror_check_arg_rz( (i!=0),"i");
1134
1135    for( i->iter = pvl_next(i->iter);
1136         i->iter != 0;
1137         i->iter = pvl_next(i->iter)) {
1138             
1139        icalcomponent *c =  (icalcomponent*) pvl_data(i->iter);
1140         
1141            if (icalcomponent_isa(c) == i->kind 
1142                || i->kind == ICAL_ANY_COMPONENT) {
1143                
1144                return icalcompiter_deref(i);;
1145            }
1146    }
1147
1148    return 0;
1149
1150 }
1151
1152 icalcomponent* icalcompiter_prior(icalcompiter* i)
1153 {
1154    if (i->iter == 0){
1155        return 0;
1156    }
1157
1158    for( i->iter = pvl_prior(i->iter);
1159         i->iter != 0;
1160         i->iter = pvl_prior(i->iter)) {
1161             
1162        icalcomponent *c =  (icalcomponent*) pvl_data(i->iter);
1163         
1164            if (icalcomponent_isa(c) == i->kind 
1165                || i->kind == ICAL_ANY_COMPONENT) {
1166                
1167                return icalcompiter_deref(i);;
1168            }
1169    }
1170
1171    return 0;
1172
1173 }
1174 icalcomponent* icalcompiter_deref(icalcompiter* i)
1175 {
1176     if(i->iter ==0){
1177         return 0;
1178     }
1179
1180     return pvl_data(i->iter);
1181 }
1182
1183 icalcomponent* icalcomponent_get_inner(icalcomponent* comp)
1184 {
1185     if (icalcomponent_isa(comp) == ICAL_VCALENDAR_COMPONENT){
1186         return icalcomponent_get_first_real_component(comp);
1187     } else {
1188         return comp;
1189     }
1190 }
1191
1192
1193 void icalcomponent_set_dtstart(icalcomponent* comp, struct icaltimetype v)
1194 {
1195
1196     icalcomponent *inner = icalcomponent_get_inner(comp); 
1197     icalproperty *prop 
1198         = icalcomponent_get_first_property(inner, ICAL_DTSTART_PROPERTY);
1199
1200
1201     if (prop == 0){
1202         prop = icalproperty_new_dtstart(v);
1203         icalcomponent_add_property(inner, prop);
1204     }
1205     
1206     icalproperty_set_dtstart(prop,v);
1207
1208 }
1209
1210
1211 struct icaltimetype icalcomponent_get_dtstart(icalcomponent* comp)
1212 {
1213     icalcomponent *inner = icalcomponent_get_inner(comp); 
1214     icalproperty *prop 
1215         = icalcomponent_get_first_property(inner,ICAL_DTSTART_PROPERTY);
1216
1217     if (prop == 0){
1218         return icaltime_null_time();
1219     }
1220     
1221     return icalproperty_get_dtstart(prop);
1222 }
1223
1224
1225 struct icaltimetype icalcomponent_get_dtend(icalcomponent* comp)
1226 {
1227     icalcomponent *inner = icalcomponent_get_inner(comp); 
1228
1229     icalproperty *end_prop 
1230         = icalcomponent_get_first_property(inner,ICAL_DTEND_PROPERTY);
1231
1232     icalproperty *dur_prop 
1233         = icalcomponent_get_first_property(inner, ICAL_DURATION_PROPERTY);
1234
1235
1236     if( end_prop == 0 && dur_prop == 0){
1237         return icaltime_null_time();
1238     } else if ( end_prop != 0) {
1239         return icalproperty_get_dtend(end_prop);
1240     } else if ( dur_prop != 0) { 
1241         
1242         struct icaltimetype start = 
1243             icalcomponent_get_dtstart(inner);
1244         struct icaldurationtype duration = 
1245             icalproperty_get_duration(dur_prop);
1246         
1247         struct icaltimetype end = icaltime_add(start,duration);
1248
1249         return end;
1250
1251     } else {
1252         /* Error, both duration and dtend have been specified */
1253         icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
1254         return icaltime_null_time();
1255
1256     }
1257     
1258 }
1259
1260
1261 void icalcomponent_set_dtend(icalcomponent* comp, struct icaltimetype v)
1262 {
1263     icalcomponent *inner = icalcomponent_get_inner(comp); 
1264
1265     icalproperty *end_prop 
1266         = icalcomponent_get_first_property(inner,ICAL_DTEND_PROPERTY);
1267
1268     icalproperty *dur_prop 
1269         = icalcomponent_get_first_property(inner,ICAL_DURATION_PROPERTY);
1270
1271
1272     if( end_prop == 0 && dur_prop == 0){
1273         end_prop = icalproperty_new_dtend(v);
1274         icalcomponent_add_property(inner,end_prop);
1275     } else if ( end_prop != 0) {
1276         icalproperty_set_dtend(end_prop,v);
1277     } else if ( dur_prop != 0) { 
1278         struct icaltimetype start = 
1279             icalcomponent_get_dtstart(inner);
1280
1281         struct icaltimetype end = 
1282             icalcomponent_get_dtend(inner);
1283
1284         struct icaldurationtype dur 
1285             = icaltime_subtract(end,start);
1286
1287         icalproperty_set_duration(dur_prop,dur);
1288
1289     } else {
1290         /* Error, both duration and dtend have been specified */
1291         icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
1292     }
1293 }
1294
1295 void icalcomponent_set_duration(icalcomponent* comp, 
1296                                 struct icaldurationtype v)
1297 {
1298     icalcomponent *inner = icalcomponent_get_inner(comp); 
1299
1300     icalproperty *end_prop 
1301         = icalcomponent_get_first_property(inner,ICAL_DTEND_PROPERTY);
1302
1303     icalproperty *dur_prop 
1304         = icalcomponent_get_first_property(inner,ICAL_DURATION_PROPERTY);
1305
1306
1307     if( end_prop == 0 && dur_prop == 0){
1308         dur_prop = icalproperty_new_duration(v);
1309         icalcomponent_add_property(inner, dur_prop);
1310     } else if ( end_prop != 0) {
1311         struct icaltimetype start = 
1312             icalcomponent_get_dtstart(inner);
1313         
1314         struct icaltimetype new_end = icaltime_add(start,v);
1315
1316         icalproperty_set_dtend(end_prop,new_end);
1317
1318     } else if ( dur_prop != 0) { 
1319         icalproperty_set_duration(dur_prop,v);
1320     } else {
1321         /* Error, both duration and dtend have been specified */
1322         icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
1323     }
1324 }
1325
1326 struct icaldurationtype icalcomponent_get_duration(icalcomponent* comp)
1327 {
1328     icalcomponent *inner = icalcomponent_get_inner(comp); 
1329
1330     icalproperty *end_prop 
1331         = icalcomponent_get_first_property(inner,ICAL_DTEND_PROPERTY);
1332
1333     icalproperty *dur_prop 
1334         = icalcomponent_get_first_property(inner,ICAL_DURATION_PROPERTY);
1335
1336     struct icaldurationtype null_duration;
1337     memset(&null_duration,0,sizeof(struct icaldurationtype));
1338
1339
1340     if( end_prop == 0 && dur_prop == 0){
1341         return null_duration;
1342     } else if ( end_prop != 0) {
1343         struct icaltimetype start = 
1344             icalcomponent_get_dtstart(inner);
1345         time_t startt = icaltime_as_timet(start);
1346
1347         struct icaltimetype end = 
1348             icalcomponent_get_dtend(inner);
1349         time_t endt = icaltime_as_timet(end);
1350         
1351         return icaldurationtype_from_int(endt-startt);
1352     } else if ( dur_prop != 0) { 
1353         return icalproperty_get_duration(dur_prop);
1354     } else {
1355         /* Error, both duration and dtend have been specified */
1356         icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
1357         return null_duration;
1358     }
1359 }
1360
1361 void icalcomponent_set_method(icalcomponent* comp, icalproperty_method method)
1362 {
1363     icalproperty *prop 
1364         = icalcomponent_get_first_property(comp, ICAL_METHOD_PROPERTY);
1365
1366
1367     if (prop == 0){
1368         prop = icalproperty_new_method(method);
1369         icalcomponent_add_property(comp, prop);
1370     }
1371     
1372     icalproperty_set_method(prop,method);
1373
1374 }
1375
1376 icalproperty_method icalcomponent_get_method(icalcomponent* comp)
1377 {
1378     icalproperty *prop 
1379         = icalcomponent_get_first_property(comp,ICAL_METHOD_PROPERTY);
1380
1381     if (prop == 0){
1382         return ICAL_METHOD_NONE;
1383     }
1384     
1385     return icalproperty_get_method(prop);
1386 }
1387
1388 void icalcomponent_set_dtstamp(icalcomponent* comp, struct icaltimetype v)
1389 {
1390
1391     icalcomponent *inner = icalcomponent_get_inner(comp); 
1392     icalproperty *prop 
1393         = icalcomponent_get_first_property(inner, ICAL_DTSTAMP_PROPERTY);
1394
1395
1396     if (prop == 0){
1397         prop = icalproperty_new_dtstamp(v);
1398         icalcomponent_add_property(inner, prop);
1399     }
1400     
1401     icalproperty_set_dtstamp(prop,v);
1402
1403 }
1404
1405
1406 struct icaltimetype icalcomponent_get_dtstamp(icalcomponent* comp)
1407 {
1408     icalcomponent *inner = icalcomponent_get_inner(comp); 
1409     icalproperty *prop 
1410         = icalcomponent_get_first_property(inner,ICAL_DTSTAMP_PROPERTY);
1411
1412     if (prop == 0){
1413         return icaltime_null_time();
1414     }
1415     
1416     return icalproperty_get_dtstamp(prop);
1417 }
1418
1419
1420 void icalcomponent_set_summary(icalcomponent* comp, const char* v)
1421 {
1422     icalcomponent *inner = icalcomponent_get_inner(comp); 
1423     icalproperty *prop 
1424         = icalcomponent_get_first_property(inner, ICAL_SUMMARY_PROPERTY);
1425
1426     if (prop == 0){
1427         prop = icalproperty_new_summary(v);
1428         icalcomponent_add_property(inner, prop);
1429     }
1430     
1431     icalproperty_set_summary(prop,v);
1432 }
1433
1434
1435 const char* icalcomponent_get_summary(icalcomponent* comp)
1436 {
1437     icalcomponent *inner = icalcomponent_get_inner(comp); 
1438     icalproperty *prop 
1439         = icalcomponent_get_first_property(inner,ICAL_SUMMARY_PROPERTY);
1440
1441     if (prop == 0){
1442         return 0;
1443     }
1444     
1445     return icalproperty_get_summary(prop);
1446
1447 }
1448
1449 void icalcomponent_set_comment(icalcomponent* comp, const char* v);
1450 const char* icalcomponent_get_comment(icalcomponent* comp);
1451
1452 void icalcomponent_set_uid(icalcomponent* comp, const char* v);
1453 const char* icalcomponent_get_uid(icalcomponent* comp);
1454
1455 void icalcomponent_set_recurrenceid(icalcomponent* comp, 
1456                                     struct icaltimetype v);
1457 struct icaltimetype icalcomponent_get_recurrenceid(icalcomponent* comp);
1458
1459
1460
1461
1462 icalcomponent* icalcomponent_new_vcalendar()
1463 {
1464     return icalcomponent_new(ICAL_VCALENDAR_COMPONENT);
1465 }
1466 icalcomponent* icalcomponent_new_vevent()
1467 {
1468     return icalcomponent_new(ICAL_VEVENT_COMPONENT);
1469 }
1470 icalcomponent* icalcomponent_new_vtodo()
1471 {
1472     return icalcomponent_new(ICAL_VTODO_COMPONENT);
1473 }
1474 icalcomponent* icalcomponent_new_vjournal()
1475 {
1476     return icalcomponent_new(ICAL_VJOURNAL_COMPONENT);
1477 }
1478 icalcomponent* icalcomponent_new_valarm()
1479 {
1480     return icalcomponent_new(ICAL_VALARM_COMPONENT);
1481 }
1482 icalcomponent* icalcomponent_new_vfreebusy()
1483 {
1484     return icalcomponent_new(ICAL_VFREEBUSY_COMPONENT);
1485 }
1486 icalcomponent* icalcomponent_new_vtimezone()
1487 {
1488     return icalcomponent_new(ICAL_VTIMEZONE_COMPONENT);
1489 }
1490 icalcomponent* icalcomponent_new_xstandard()
1491 {
1492     return icalcomponent_new(ICAL_XSTANDARD_COMPONENT);
1493 }
1494 icalcomponent* icalcomponent_new_xdaylight()
1495 {
1496     return icalcomponent_new(ICAL_XDAYLIGHT_COMPONENT);
1497 }