2013-02-13 [colin] 3.9.0cvs65
[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     struct icalproperty_impl *pimpl;
401
402     icalerror_check_arg_rv( (component!=0), "component");
403     icalerror_check_arg_rv( (property!=0), "property");
404     
405     impl = (struct icalcomponent_impl*)component;
406
407     pimpl = (struct icalproperty_impl*)property;
408
409     icalerror_assert( (icalproperty_get_parent(property)),"The property is not a member of a component");
410
411     
412     for( itr = pvl_head(impl->properties);
413          itr != 0;
414          itr = next_itr)
415     {
416         next_itr = pvl_next(itr);
417         
418         if( pvl_data(itr) == (void*)property ){
419
420            if (impl->property_iterator == itr){
421                impl->property_iterator = pvl_next(itr);
422            }
423
424            pvl_remove( impl->properties, itr); 
425           icalproperty_set_parent(property,0);
426         }
427     }   
428 }
429
430 int
431 icalcomponent_count_properties (icalcomponent* component, 
432                                 icalproperty_kind kind)
433 {
434     int count=0;
435     pvl_elem itr;
436     struct icalcomponent_impl *impl = (struct icalcomponent_impl*)component;
437
438     icalerror_check_arg_rz( (component!=0), "component");
439
440     for( itr = pvl_head(impl->properties);
441          itr != 0;
442          itr = pvl_next(itr))
443     {   
444         if(kind == icalproperty_isa((icalproperty*)pvl_data(itr)) ||
445             kind == ICAL_ANY_PROPERTY){
446             count++;
447         }
448     }
449
450
451     return count;
452
453 }
454
455 icalproperty* icalcomponent_get_current_property (icalcomponent* component)
456 {
457
458    struct icalcomponent_impl *c = (struct icalcomponent_impl*)component;
459    icalerror_check_arg_rz( (component!=0),"component");
460
461    if ((c->property_iterator==0)){
462        return 0;
463    }
464
465    return (icalproperty*) pvl_data(c->property_iterator);
466
467 }
468
469 icalproperty*
470 icalcomponent_get_first_property (icalcomponent* component, icalproperty_kind kind)
471 {
472    struct icalcomponent_impl *c = (struct icalcomponent_impl*)component;
473    icalerror_check_arg_rz( (component!=0),"component");
474   
475    for( c->property_iterator = pvl_head(c->properties);
476         c->property_iterator != 0;
477         c->property_iterator = pvl_next(c->property_iterator)) {
478             
479        icalproperty *p =  (icalproperty*) pvl_data(c->property_iterator);
480         
481            if (icalproperty_isa(p) == kind || kind == ICAL_ANY_PROPERTY) {
482                
483                return p;
484            }
485    }
486    return 0;
487 }
488
489 icalproperty*
490 icalcomponent_get_next_property (icalcomponent* component, icalproperty_kind kind)
491 {
492    struct icalcomponent_impl *c = (struct icalcomponent_impl*)component;
493    icalerror_check_arg_rz( (component!=0),"component");
494
495    if (c->property_iterator == 0){
496        return 0;
497    }
498
499    for( c->property_iterator = pvl_next(c->property_iterator);
500         c->property_iterator != 0;
501         c->property_iterator = pvl_next(c->property_iterator)) {
502             
503        icalproperty *p =  (icalproperty*) pvl_data(c->property_iterator);
504            
505        if (icalproperty_isa(p) == kind || kind == ICAL_ANY_PROPERTY) {
506            
507            return p;
508        }
509    }
510
511    return 0;
512 }
513
514
515 icalproperty**
516 icalcomponent_get_properties (icalcomponent* component, icalproperty_kind kind);
517
518
519 void
520 icalcomponent_add_component (icalcomponent* parent, icalcomponent* child)
521 {
522     struct icalcomponent_impl *impl, *cimpl;
523
524     icalerror_check_arg_rv( (parent!=0), "parent");
525     icalerror_check_arg_rv( (child!=0), "child");
526     
527     impl = (struct icalcomponent_impl*)parent;
528     cimpl = (struct icalcomponent_impl*)child;
529
530     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");
531
532     cimpl->parent = parent;
533
534     pvl_push(impl->components,child);
535 }
536
537
538 void
539 icalcomponent_remove_component (icalcomponent* parent, icalcomponent* child)
540 {
541    struct icalcomponent_impl *impl,*cimpl;
542    pvl_elem itr, next_itr;
543
544    icalerror_check_arg_rv( (parent!=0), "parent");
545    icalerror_check_arg_rv( (child!=0), "child");
546    
547    impl = (struct icalcomponent_impl*)parent;
548    cimpl = (struct icalcomponent_impl*)child;
549    
550    for( itr = pvl_head(impl->components);
551         itr != 0;
552         itr = next_itr)
553    {
554        next_itr = pvl_next(itr);
555        
556        if( pvl_data(itr) == (void*)child ){
557
558            if (impl->component_iterator == itr){
559                /* Don't let the current iterator become invalid */
560
561                /* HACK. The semantics for this are troubling. */
562                impl->component_iterator = 
563                    pvl_next(impl->component_iterator);
564                   
565            }
566            pvl_remove( impl->components, itr); 
567            cimpl->parent = 0;
568            break;
569        }
570    }    
571 }
572
573
574 int
575 icalcomponent_count_components (icalcomponent* component, 
576                                 icalcomponent_kind kind)
577 {
578     int count=0;
579     pvl_elem itr;
580     struct icalcomponent_impl *impl = (struct icalcomponent_impl*)component;
581
582     icalerror_check_arg_rz( (component!=0), "component");
583
584     for( itr = pvl_head(impl->components);
585          itr != 0;
586          itr = pvl_next(itr))
587     {
588         if(kind == icalcomponent_isa((icalcomponent*)pvl_data(itr)) ||
589             kind == ICAL_ANY_COMPONENT){
590             count++;
591         }
592     }
593
594     return count;
595 }
596
597 icalcomponent*
598 icalcomponent_get_current_component(icalcomponent* component)
599 {
600    struct icalcomponent_impl *c = (struct icalcomponent_impl*)component;
601
602    icalerror_check_arg_rz( (component!=0),"component");
603
604    if (c->component_iterator == 0){
605        return 0;
606    }
607
608    return (icalcomponent*) pvl_data(c->component_iterator);
609 }
610
611 icalcomponent*
612 icalcomponent_get_first_component (icalcomponent* component, 
613                                    icalcomponent_kind kind)
614 {
615    struct icalcomponent_impl *c = (struct icalcomponent_impl*)component;
616
617    icalerror_check_arg_rz( (component!=0),"component");
618   
619    for( c->component_iterator = pvl_head(c->components);
620         c->component_iterator != 0;
621         c->component_iterator = pvl_next(c->component_iterator)) {
622             
623        icalcomponent *p =  (icalcomponent*) pvl_data(c->component_iterator);
624         
625            if (icalcomponent_isa(p) == kind || kind == ICAL_ANY_COMPONENT) {
626                
627                return p;
628            }
629    }
630
631    return 0;
632 }
633
634
635 icalcomponent*
636 icalcomponent_get_next_component (icalcomponent* component, icalcomponent_kind kind)
637 {
638    struct icalcomponent_impl *c = (struct icalcomponent_impl*)component;
639
640    icalerror_check_arg_rz( (component!=0),"component");
641   
642    if (c->component_iterator == 0){
643        return 0;
644    }
645
646    for( c->component_iterator = pvl_next(c->component_iterator);
647         c->component_iterator != 0;
648         c->component_iterator = pvl_next(c->component_iterator)) {
649             
650        icalcomponent *p =  (icalcomponent*) pvl_data(c->component_iterator);
651         
652            if (icalcomponent_isa(p) == kind || kind == ICAL_ANY_COMPONENT) {
653                
654                return p;
655            }
656    }
657
658    return 0;
659 }
660
661 icalcomponent* icalcomponent_get_first_real_component(icalcomponent *c)
662 {
663     icalcomponent *comp;
664
665     for(comp = icalcomponent_get_first_component(c,ICAL_ANY_COMPONENT);
666         comp != 0;
667         comp = icalcomponent_get_next_component(c,ICAL_ANY_COMPONENT)){
668
669         icalcomponent_kind kind = icalcomponent_isa(comp);
670
671         if(kind == ICAL_VEVENT_COMPONENT ||
672            kind == ICAL_VTODO_COMPONENT ||
673            kind == ICAL_VJOURNAL_COMPONENT ){
674             return comp;
675         }
676     }
677     return 0;
678 }
679
680 time_t icalcomponent_convert_time(icalproperty *p)
681 {
682     struct icaltimetype sict;
683     time_t convt;
684     icalproperty *tzp;
685         
686
687     /* Though it says _dtstart, it will work for dtend too */
688     sict = icalproperty_get_dtstart(p);
689
690     tzp = icalproperty_get_first_parameter(p,ICAL_TZID_PARAMETER);
691
692     if (sict.is_utc == 1 && tzp != 0){
693         icalerror_warn("icalcomponent_get_span: component has a UTC DTSTART with a timezone specified ");
694         icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
695         return 0; 
696     }
697
698     if(sict.is_utc == 1){
699 #ifdef TEST_CONVERT_TIME
700         gchar buft[512];
701 #endif
702         /* _as_timet will use gmtime() to do the conversion */
703         convt = icaltime_as_timet(sict);
704
705 #ifdef TEST_CONVERT_TIME
706         printf("convert time: use as_timet:\n %s\n %s",
707                icalproperty_as_ical_string(p), ctime_r(&convt,buft));
708 #endif
709
710     } else if (sict.is_utc == 0 && tzp == 0 ) {
711         time_t offset;
712 #ifdef TEST_CONVERT_TIME
713         gchar buft[512];
714 #endif
715
716         /* _as_timet will use localtime() to do the conversion */
717         convt = icaltime_as_timet(sict);
718         offset = icaltime_utc_offset(sict,0);
719         convt += offset;
720
721 #ifdef TEST_CONVERT_TIME
722         printf("convert time: use as_timet and adjust:\n %s\n %s",
723                icalproperty_as_ical_string(p), ctime_r(&convt,buft));
724 #endif
725     } else {
726 #ifdef TEST_CONVERT_TIME
727         gchar buft[512];
728 #endif
729         /* Convert the time to UTC for the named timezone*/
730         const char* timezone = icalparameter_get_tzid(tzp);
731         convt = icaltime_as_timet(icaltime_as_utc(sict,timezone));
732
733 #ifdef TEST_CONVERT_TIME
734         printf("convert time: use _as_utc:\n %s\n %s",
735                icalproperty_as_ical_string(p), ctime_r(&convt,buft));
736 #endif
737     }       
738
739     return convt;
740 }
741 struct icaltime_span icalcomponent_get_span(icalcomponent* comp)
742 {
743     icalcomponent *inner;
744     icalproperty *p, *duration;
745     icalcomponent_kind kind;
746     struct icaltime_span span;
747     struct icaltimetype start;
748 #ifdef TEST_CONVERT_TIME
749     gchar buft[512];
750 #endif
751
752     span.start = 0;
753     span.end = 0;
754     span.is_busy= 1;
755
756     /* initial Error checking */
757
758 /*    icalerror_check_arg_rz( (comp!=0),"comp");*/
759
760     kind  = icalcomponent_isa(comp);
761
762     if(kind == ICAL_VCALENDAR_COMPONENT){
763         inner = icalcomponent_get_first_real_component(comp);
764
765         /* Maybe there is a VTIMEZONE in there */
766         if (inner == 0){
767             inner = icalcomponent_get_first_component(comp,
768                                ICAL_VTIMEZONE_COMPONENT);
769         }
770
771     } else {
772         inner = comp;
773     }
774
775     if (inner == 0){
776         icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
777         /*icalerror_warn("icalcomponent_get_span: no component specified, or empty VCALENDAR component");*/
778         return span; 
779     }
780     
781     kind  = icalcomponent_isa(inner);
782
783     if( !( kind == ICAL_VEVENT_COMPONENT ||
784            kind == ICAL_VJOURNAL_COMPONENT ||
785            kind == ICAL_VTODO_COMPONENT ||         
786            kind == ICAL_VFREEBUSY_COMPONENT )) {
787         icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
788         /*icalerror_warn("icalcomponent_get_span: no component specified, or empty VCALENDAR component");*/
789         return span; 
790         
791     }
792
793
794
795     /* Get to work. starting with DTSTART */
796
797     p = icalcomponent_get_first_property(inner, ICAL_DTSTART_PROPERTY);
798
799     if (p ==0 ) {
800         icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
801         /*icalerror_warn("icalcomponent_get_span: component has no DTSTART time");*/
802         return span; 
803     }
804
805
806     start = icalproperty_get_dtstart(p);
807
808     icalerror_clear_errno();
809
810     span.start = icalcomponent_convert_time(p);
811
812 #ifdef TEST_CONVERT_TIME
813     printf("convert time:\n %s %s",
814            icalproperty_as_ical_string(p), ctime_r(&span.start, buft));
815 #endif
816
817     if(icalerrno != ICAL_NO_ERROR){
818         span.start = 0;
819         return span;
820     }
821
822     /* The end time could be specified as either a DTEND or a DURATION */
823     p = icalcomponent_get_first_property(inner, ICAL_DTEND_PROPERTY);
824     duration = icalcomponent_get_first_property(inner, ICAL_DURATION_PROPERTY);
825
826     if (p==0 && duration == 0 && start.is_date != 1) {
827         icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
828         /*icalerror_warn("icalcomponent_get_span: component has neither DTEND nor DURATION time");*/
829         span.start = 0;
830         return span; 
831     } 
832
833     if (p!=0){
834         span.end = icalcomponent_convert_time(p);
835     } else if (start.is_date == 1) {
836         /* Duration is all day */
837         span.end = span.start + 60*60*24;
838     } else {
839         /* Use the duration */
840         struct icaldurationtype dur;
841         time_t durt;
842         
843         
844         dur = icalproperty_get_duration(duration);
845
846         durt = icaldurationtype_as_int(dur);
847         span.end = span.start+durt;
848     }
849
850     return span;
851
852 }
853
854
855 int icalcomponent_count_errors(icalcomponent* component)
856 {
857     int errors = 0;
858     icalproperty *p;
859     icalcomponent *c;
860     pvl_elem itr;
861     struct icalcomponent_impl *impl = (struct icalcomponent_impl*)component;
862
863     for( itr = pvl_head(impl->properties);
864          itr != 0;
865          itr = pvl_next(itr))
866     {   
867         p = (icalproperty*)pvl_data(itr);
868         
869         if(icalproperty_isa(p) == ICAL_XLICERROR_PROPERTY)
870         {
871             errors++;
872         }
873     }
874
875
876     for( itr = pvl_head(impl->components);
877          itr != 0;
878          itr = pvl_next(itr))
879     {   
880         c = (icalcomponent*)pvl_data(itr);
881         
882         errors += icalcomponent_count_errors(c);
883         
884     }
885
886     return errors;
887 }
888
889
890 void icalcomponent_strip_errors(icalcomponent* component)
891 {
892     icalproperty *p;
893     icalcomponent *c;
894     pvl_elem itr, next_itr;
895     struct icalcomponent_impl *impl = (struct icalcomponent_impl*)component;
896
897    for( itr = pvl_head(impl->properties);
898          itr != 0;
899          itr = next_itr)
900     {   
901         p = (icalproperty*)pvl_data(itr);
902         next_itr = pvl_next(itr);
903
904         if(icalproperty_isa(p) == ICAL_XLICERROR_PROPERTY)
905         {
906             icalcomponent_remove_property(component,p);
907         }
908     }
909     
910     for( itr = pvl_head(impl->components);
911          itr != 0;
912          itr = pvl_next(itr))
913     {   
914         c = (icalcomponent*)pvl_data(itr);
915         icalcomponent_strip_errors(c);
916     }
917 }
918
919 /* Hack. This will change the state of the iterators */
920 void icalcomponent_convert_errors(icalcomponent* component)
921 {
922     icalproperty *p, *next_p;
923     icalcomponent *c;
924
925     for(p = icalcomponent_get_first_property(component,ICAL_ANY_PROPERTY);
926         p != 0;
927         p = next_p){
928         
929         next_p = icalcomponent_get_next_property(component,ICAL_ANY_PROPERTY);
930
931         if(icalproperty_isa(p) == ICAL_XLICERROR_PROPERTY)
932         {
933             struct icalreqstattype rst;
934             icalparameter *param  = icalproperty_get_first_parameter
935                 (p,ICAL_XLICERRORTYPE_PARAMETER);
936
937             rst.code = ICAL_UNKNOWN_STATUS;
938             rst.desc = 0;
939
940             switch(icalparameter_get_xlicerrortype(param)){
941
942                 case  ICAL_XLICERRORTYPE_PARAMETERNAMEPARSEERROR: {
943                     rst.code = ICAL_3_2_INVPARAM_STATUS;
944                     break;
945                 }
946                 case  ICAL_XLICERRORTYPE_PARAMETERVALUEPARSEERROR: {
947                     rst.code = ICAL_3_3_INVPARAMVAL_STATUS;
948                     break;
949                 }
950                 case  ICAL_XLICERRORTYPE_PROPERTYPARSEERROR: {              
951                     rst.code = ICAL_3_0_INVPROPNAME_STATUS;
952                     break;
953                 }
954                 case  ICAL_XLICERRORTYPE_VALUEPARSEERROR: {
955                     rst.code = ICAL_3_1_INVPROPVAL_STATUS;
956                     break;
957                 }
958                 case  ICAL_XLICERRORTYPE_COMPONENTPARSEERROR: {
959                     rst.code = ICAL_3_4_INVCOMP_STATUS;
960                     break;
961                 }
962
963                 default: {
964                 }
965             }
966             if (rst.code != ICAL_UNKNOWN_STATUS){
967                 
968                 rst.debug = icalproperty_get_xlicerror(p);
969                 icalcomponent_add_property(component,
970                                            icalproperty_new_requeststatus(
971                                                icalreqstattype_as_string(rst)
972                                                )
973                     );
974                 
975                 icalcomponent_remove_property(component,p);
976             }
977         }
978     }
979
980     for(c = icalcomponent_get_first_component(component,ICAL_ANY_COMPONENT);
981         c != 0;
982         c = icalcomponent_get_next_component(component,ICAL_ANY_COMPONENT)){
983         
984         icalcomponent_convert_errors(c);
985     }
986 }
987
988
989 icalcomponent* icalcomponent_get_parent(icalcomponent* component)
990 {
991    struct icalcomponent_impl *c = (struct icalcomponent_impl*)component;
992
993    return c->parent;
994 }
995
996 void icalcomponent_set_parent(icalcomponent* component, icalcomponent* parent)
997 {
998    struct icalcomponent_impl *c = (struct icalcomponent_impl*)component;
999
1000    c->parent = parent;
1001 }
1002
1003 icalcompiter icalcompiter_null = {ICAL_NO_COMPONENT,0};
1004
1005
1006 struct icalcomponent_kind_map {
1007         icalcomponent_kind kind;
1008         char name[20];
1009 };
1010
1011   
1012
1013 static struct icalcomponent_kind_map component_map[] = 
1014 {
1015     { ICAL_VEVENT_COMPONENT, "VEVENT" },
1016     { ICAL_VTODO_COMPONENT, "VTODO" },
1017     { ICAL_VJOURNAL_COMPONENT, "VJOURNAL" },
1018     { ICAL_VCALENDAR_COMPONENT, "VCALENDAR" },
1019     { ICAL_VFREEBUSY_COMPONENT, "VFREEBUSY" },
1020     { ICAL_VTIMEZONE_COMPONENT, "VTIMEZONE" },
1021     { ICAL_VALARM_COMPONENT, "VALARM" },
1022     { ICAL_XSTANDARD_COMPONENT, "STANDARD" }, /*These are part of RFC2445 */
1023     { ICAL_XDAYLIGHT_COMPONENT, "DAYLIGHT" }, /*but are not really components*/
1024     { ICAL_X_COMPONENT, "X" },
1025     { ICAL_VSCHEDULE_COMPONENT, "SCHEDULE" },
1026
1027     /* CAP components */
1028     { ICAL_VQUERY_COMPONENT, "VQUERY" },  
1029     { ICAL_VCAR_COMPONENT, "VCAR" },  
1030     { ICAL_VCOMMAND_COMPONENT, "VCOMMAND" },  
1031
1032     /* libical private components */
1033     { ICAL_XLICINVALID_COMPONENT, "X-LIC-UNKNOWN" },  
1034     { ICAL_XLICMIMEPART_COMPONENT, "X-LIC-MIME-PART" },  
1035     { ICAL_ANY_COMPONENT, "ANY" },  
1036     { ICAL_XROOT_COMPONENT, "XROOT" },  
1037
1038     /* End of list */
1039     { ICAL_NO_COMPONENT, "" },
1040 };
1041
1042
1043
1044 const char* icalcomponent_kind_to_string(icalcomponent_kind kind)
1045 {
1046     int i;
1047
1048     for (i=0; component_map[i].kind != ICAL_NO_COMPONENT; i++) {
1049         if (component_map[i].kind == kind) {
1050             return component_map[i].name;
1051         }
1052     }
1053
1054     return 0;
1055
1056 }
1057
1058 icalcomponent_kind icalcomponent_string_to_kind(const char* string)
1059 {
1060     int i;
1061
1062     if (string ==0 ) { 
1063         return ICAL_NO_COMPONENT;
1064     }
1065
1066     for (i=0; component_map[i].kind  != ICAL_NO_COMPONENT; i++) {
1067         if (strcmp(component_map[i].name, string) == 0) {
1068             return component_map[i].kind;
1069         }
1070     }
1071
1072     return ICAL_NO_COMPONENT;
1073 }
1074
1075
1076
1077 icalcompiter 
1078 icalcomponent_begin_component(icalcomponent* component,icalcomponent_kind kind)
1079 {
1080     struct icalcomponent_impl *impl = (struct icalcomponent_impl*)component;
1081     icalcompiter itr;
1082     pvl_elem i;
1083
1084     itr.kind = kind;
1085
1086     icalerror_check_arg_re( (component!=0),"component",icalcompiter_null);
1087
1088     for( i = pvl_head(impl->components); i != 0; i = pvl_next(itr.iter)) {
1089         
1090         icalcomponent *c =  (icalcomponent*) pvl_data(i);
1091         
1092         if (icalcomponent_isa(c) == kind || kind == ICAL_ANY_COMPONENT) {
1093             
1094             itr.iter = i;
1095
1096             return itr;
1097         }
1098     }
1099
1100     return icalcompiter_null;
1101 }
1102
1103 icalcompiter
1104 icalcomponent_end_component(icalcomponent* component,icalcomponent_kind kind)
1105 {
1106     struct icalcomponent_impl *impl = (struct icalcomponent_impl*)component;
1107     icalcompiter itr; 
1108     pvl_elem i;
1109
1110     itr.kind = kind;
1111
1112     icalerror_check_arg_re( (component!=0),"component",icalcompiter_null);
1113
1114     for( i = pvl_tail(impl->components); i != 0; i = pvl_prior(i)) {
1115         
1116         icalcomponent *c =  (icalcomponent*) pvl_data(i);
1117         
1118         if (icalcomponent_isa(c) == kind || kind == ICAL_ANY_COMPONENT) {
1119             
1120             itr.iter = pvl_next(i);
1121
1122             return itr;
1123         }
1124     }
1125
1126     return icalcompiter_null;;
1127 }
1128
1129
1130 icalcomponent* icalcompiter_next(icalcompiter* i)
1131 {
1132    if (i->iter == 0){
1133        return 0;
1134    }
1135
1136    icalerror_check_arg_rz( (i!=0),"i");
1137
1138    for( i->iter = pvl_next(i->iter);
1139         i->iter != 0;
1140         i->iter = pvl_next(i->iter)) {
1141             
1142        icalcomponent *c =  (icalcomponent*) pvl_data(i->iter);
1143         
1144            if (icalcomponent_isa(c) == i->kind 
1145                || i->kind == ICAL_ANY_COMPONENT) {
1146                
1147                return icalcompiter_deref(i);;
1148            }
1149    }
1150
1151    return 0;
1152
1153 }
1154
1155 icalcomponent* icalcompiter_prior(icalcompiter* i)
1156 {
1157    if (i->iter == 0){
1158        return 0;
1159    }
1160
1161    for( i->iter = pvl_prior(i->iter);
1162         i->iter != 0;
1163         i->iter = pvl_prior(i->iter)) {
1164             
1165        icalcomponent *c =  (icalcomponent*) pvl_data(i->iter);
1166         
1167            if (icalcomponent_isa(c) == i->kind 
1168                || i->kind == ICAL_ANY_COMPONENT) {
1169                
1170                return icalcompiter_deref(i);;
1171            }
1172    }
1173
1174    return 0;
1175
1176 }
1177 icalcomponent* icalcompiter_deref(icalcompiter* i)
1178 {
1179     if(i->iter ==0){
1180         return 0;
1181     }
1182
1183     return pvl_data(i->iter);
1184 }
1185
1186 icalcomponent* icalcomponent_get_inner(icalcomponent* comp)
1187 {
1188     if (icalcomponent_isa(comp) == ICAL_VCALENDAR_COMPONENT){
1189         return icalcomponent_get_first_real_component(comp);
1190     } else {
1191         return comp;
1192     }
1193 }
1194
1195
1196 void icalcomponent_set_dtstart(icalcomponent* comp, struct icaltimetype v)
1197 {
1198
1199     icalcomponent *inner = icalcomponent_get_inner(comp); 
1200     icalproperty *prop 
1201         = icalcomponent_get_first_property(inner, ICAL_DTSTART_PROPERTY);
1202
1203
1204     if (prop == 0){
1205         prop = icalproperty_new_dtstart(v);
1206         icalcomponent_add_property(inner, prop);
1207     }
1208     
1209     icalproperty_set_dtstart(prop,v);
1210
1211 }
1212
1213
1214 struct icaltimetype icalcomponent_get_dtstart(icalcomponent* comp)
1215 {
1216     icalcomponent *inner = icalcomponent_get_inner(comp); 
1217     icalproperty *prop 
1218         = icalcomponent_get_first_property(inner,ICAL_DTSTART_PROPERTY);
1219
1220     if (prop == 0){
1221         return icaltime_null_time();
1222     }
1223     
1224     return icalproperty_get_dtstart(prop);
1225 }
1226
1227
1228 struct icaltimetype icalcomponent_get_dtend(icalcomponent* comp)
1229 {
1230     icalcomponent *inner = icalcomponent_get_inner(comp); 
1231
1232     icalproperty *end_prop 
1233         = icalcomponent_get_first_property(inner,ICAL_DTEND_PROPERTY);
1234
1235     icalproperty *dur_prop 
1236         = icalcomponent_get_first_property(inner, ICAL_DURATION_PROPERTY);
1237
1238
1239     if( end_prop == 0 && dur_prop == 0){
1240         return icaltime_null_time();
1241     } else if ( end_prop != 0) {
1242         return icalproperty_get_dtend(end_prop);
1243     } else if ( dur_prop != 0) { 
1244         
1245         struct icaltimetype start = 
1246             icalcomponent_get_dtstart(inner);
1247         struct icaldurationtype duration = 
1248             icalproperty_get_duration(dur_prop);
1249         
1250         struct icaltimetype end = icaltime_add(start,duration);
1251
1252         return end;
1253
1254     } else {
1255         /* Error, both duration and dtend have been specified */
1256         icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
1257         return icaltime_null_time();
1258
1259     }
1260     
1261 }
1262
1263
1264 void icalcomponent_set_dtend(icalcomponent* comp, struct icaltimetype v)
1265 {
1266     icalcomponent *inner = icalcomponent_get_inner(comp); 
1267
1268     icalproperty *end_prop 
1269         = icalcomponent_get_first_property(inner,ICAL_DTEND_PROPERTY);
1270
1271     icalproperty *dur_prop 
1272         = icalcomponent_get_first_property(inner,ICAL_DURATION_PROPERTY);
1273
1274
1275     if( end_prop == 0 && dur_prop == 0){
1276         end_prop = icalproperty_new_dtend(v);
1277         icalcomponent_add_property(inner,end_prop);
1278     } else if ( end_prop != 0) {
1279         icalproperty_set_dtend(end_prop,v);
1280     } else if ( dur_prop != 0) { 
1281         struct icaltimetype start = 
1282             icalcomponent_get_dtstart(inner);
1283
1284         struct icaltimetype end = 
1285             icalcomponent_get_dtend(inner);
1286
1287         struct icaldurationtype dur 
1288             = icaltime_subtract(end,start);
1289
1290         icalproperty_set_duration(dur_prop,dur);
1291
1292     } else {
1293         /* Error, both duration and dtend have been specified */
1294         icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
1295     }
1296 }
1297
1298 void icalcomponent_set_duration(icalcomponent* comp, 
1299                                 struct icaldurationtype v)
1300 {
1301     icalcomponent *inner = icalcomponent_get_inner(comp); 
1302
1303     icalproperty *end_prop 
1304         = icalcomponent_get_first_property(inner,ICAL_DTEND_PROPERTY);
1305
1306     icalproperty *dur_prop 
1307         = icalcomponent_get_first_property(inner,ICAL_DURATION_PROPERTY);
1308
1309
1310     if( end_prop == 0 && dur_prop == 0){
1311         dur_prop = icalproperty_new_duration(v);
1312         icalcomponent_add_property(inner, dur_prop);
1313     } else if ( end_prop != 0) {
1314         struct icaltimetype start = 
1315             icalcomponent_get_dtstart(inner);
1316         
1317         struct icaltimetype new_end = icaltime_add(start,v);
1318
1319         icalproperty_set_dtend(end_prop,new_end);
1320
1321     } else if ( dur_prop != 0) { 
1322         icalproperty_set_duration(dur_prop,v);
1323     } else {
1324         /* Error, both duration and dtend have been specified */
1325         icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
1326     }
1327 }
1328
1329 struct icaldurationtype icalcomponent_get_duration(icalcomponent* comp)
1330 {
1331     icalcomponent *inner = icalcomponent_get_inner(comp); 
1332
1333     icalproperty *end_prop 
1334         = icalcomponent_get_first_property(inner,ICAL_DTEND_PROPERTY);
1335
1336     icalproperty *dur_prop 
1337         = icalcomponent_get_first_property(inner,ICAL_DURATION_PROPERTY);
1338
1339     struct icaldurationtype null_duration;
1340     memset(&null_duration,0,sizeof(struct icaldurationtype));
1341
1342
1343     if( end_prop == 0 && dur_prop == 0){
1344         return null_duration;
1345     } else if ( end_prop != 0) {
1346         struct icaltimetype start = 
1347             icalcomponent_get_dtstart(inner);
1348         time_t startt = icaltime_as_timet(start);
1349
1350         struct icaltimetype end = 
1351             icalcomponent_get_dtend(inner);
1352         time_t endt = icaltime_as_timet(end);
1353         
1354         return icaldurationtype_from_int(endt-startt);
1355     } else if ( dur_prop != 0) { 
1356         return icalproperty_get_duration(dur_prop);
1357     } else {
1358         /* Error, both duration and dtend have been specified */
1359         icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
1360         return null_duration;
1361     }
1362 }
1363
1364 void icalcomponent_set_method(icalcomponent* comp, icalproperty_method method)
1365 {
1366     icalproperty *prop 
1367         = icalcomponent_get_first_property(comp, ICAL_METHOD_PROPERTY);
1368
1369
1370     if (prop == 0){
1371         prop = icalproperty_new_method(method);
1372         icalcomponent_add_property(comp, prop);
1373     }
1374     
1375     icalproperty_set_method(prop,method);
1376
1377 }
1378
1379 icalproperty_method icalcomponent_get_method(icalcomponent* comp)
1380 {
1381     icalproperty *prop 
1382         = icalcomponent_get_first_property(comp,ICAL_METHOD_PROPERTY);
1383
1384     if (prop == 0){
1385         return ICAL_METHOD_NONE;
1386     }
1387     
1388     return icalproperty_get_method(prop);
1389 }
1390
1391 void icalcomponent_set_dtstamp(icalcomponent* comp, struct icaltimetype v)
1392 {
1393
1394     icalcomponent *inner = icalcomponent_get_inner(comp); 
1395     icalproperty *prop 
1396         = icalcomponent_get_first_property(inner, ICAL_DTSTAMP_PROPERTY);
1397
1398
1399     if (prop == 0){
1400         prop = icalproperty_new_dtstamp(v);
1401         icalcomponent_add_property(inner, prop);
1402     }
1403     
1404     icalproperty_set_dtstamp(prop,v);
1405
1406 }
1407
1408
1409 struct icaltimetype icalcomponent_get_dtstamp(icalcomponent* comp)
1410 {
1411     icalcomponent *inner = icalcomponent_get_inner(comp); 
1412     icalproperty *prop 
1413         = icalcomponent_get_first_property(inner,ICAL_DTSTAMP_PROPERTY);
1414
1415     if (prop == 0){
1416         return icaltime_null_time();
1417     }
1418     
1419     return icalproperty_get_dtstamp(prop);
1420 }
1421
1422
1423 void icalcomponent_set_summary(icalcomponent* comp, const char* v)
1424 {
1425     icalcomponent *inner = icalcomponent_get_inner(comp); 
1426     icalproperty *prop 
1427         = icalcomponent_get_first_property(inner, ICAL_SUMMARY_PROPERTY);
1428
1429     if (prop == 0){
1430         prop = icalproperty_new_summary(v);
1431         icalcomponent_add_property(inner, prop);
1432     }
1433     
1434     icalproperty_set_summary(prop,v);
1435 }
1436
1437
1438 const char* icalcomponent_get_summary(icalcomponent* comp)
1439 {
1440     icalcomponent *inner = icalcomponent_get_inner(comp); 
1441     icalproperty *prop 
1442         = icalcomponent_get_first_property(inner,ICAL_SUMMARY_PROPERTY);
1443
1444     if (prop == 0){
1445         return 0;
1446     }
1447     
1448     return icalproperty_get_summary(prop);
1449
1450 }
1451
1452 void icalcomponent_set_comment(icalcomponent* comp, const char* v);
1453 const char* icalcomponent_get_comment(icalcomponent* comp);
1454
1455 void icalcomponent_set_uid(icalcomponent* comp, const char* v);
1456 const char* icalcomponent_get_uid(icalcomponent* comp);
1457
1458 void icalcomponent_set_recurrenceid(icalcomponent* comp, 
1459                                     struct icaltimetype v);
1460 struct icaltimetype icalcomponent_get_recurrenceid(icalcomponent* comp);
1461
1462
1463
1464
1465 icalcomponent* icalcomponent_new_vcalendar()
1466 {
1467     return icalcomponent_new(ICAL_VCALENDAR_COMPONENT);
1468 }
1469 icalcomponent* icalcomponent_new_vevent()
1470 {
1471     return icalcomponent_new(ICAL_VEVENT_COMPONENT);
1472 }
1473 icalcomponent* icalcomponent_new_vtodo()
1474 {
1475     return icalcomponent_new(ICAL_VTODO_COMPONENT);
1476 }
1477 icalcomponent* icalcomponent_new_vjournal()
1478 {
1479     return icalcomponent_new(ICAL_VJOURNAL_COMPONENT);
1480 }
1481 icalcomponent* icalcomponent_new_valarm()
1482 {
1483     return icalcomponent_new(ICAL_VALARM_COMPONENT);
1484 }
1485 icalcomponent* icalcomponent_new_vfreebusy()
1486 {
1487     return icalcomponent_new(ICAL_VFREEBUSY_COMPONENT);
1488 }
1489 icalcomponent* icalcomponent_new_vtimezone()
1490 {
1491     return icalcomponent_new(ICAL_VTIMEZONE_COMPONENT);
1492 }
1493 icalcomponent* icalcomponent_new_xstandard()
1494 {
1495     return icalcomponent_new(ICAL_XSTANDARD_COMPONENT);
1496 }
1497 icalcomponent* icalcomponent_new_xdaylight()
1498 {
1499     return icalcomponent_new(ICAL_XDAYLIGHT_COMPONENT);
1500 }