bump to 1.0.0 and clean up spec file
[platform/upstream/libical.git] / src / libical / vcomponent.cpp
1 /**
2  * @file    vcomponent.cpp
3  * @author  fnguyen (12/10/01)
4  * @brief   Implemenation of C++ Wrapper for icalcomponent.c
5  *
6  * (C) COPYRIGHT 2001, Critical Path
7
8  This program is free software; you can redistribute it and/or modify
9  it under the terms of either: 
10
11     The LGPL as published by the Free Software Foundation, version
12     2.1, available at: http://www.fsf.org/copyleft/lesser.html
13
14   Or:
15
16     The Mozilla Public License Version 1.0. You may obtain a copy of
17     the License at http://www.mozilla.org/MPL/
18  */
19
20 #ifndef VCOMPONENT_H
21 #include "vcomponent.h"
22 #endif
23
24 #ifndef ICALVALUE_CXX_H
25 #include "icalvalue_cxx.h"
26 #endif
27
28 #ifndef ICALPROPERTY_CXX_H
29 #include "icalproperty_cxx.h"
30 #endif
31
32 #ifndef ICALPARAMETER_CXX_H
33 #include "icalparameter_cxx.h"
34 #endif
35 #include <stdlib.h>
36 #include <string.h>
37
38 #include <exception>
39
40 VComponent::VComponent() throw(icalerrorenum) : imp(icalcomponent_new(ICAL_ANY_COMPONENT)) {
41 }
42 VComponent::VComponent(const VComponent& v) throw(icalerrorenum) {
43   imp = icalcomponent_new_clone(v.imp);
44   if (!imp) throw icalerrno;
45 }
46
47 VComponent& VComponent::operator=(const VComponent& v) throw(icalerrorenum) {
48         if (this == &v) return *this;
49
50         if (imp != NULL)
51         {
52                 icalcomponent_free(imp);
53                 imp = icalcomponent_new_clone(v.imp);
54         if (!imp) throw icalerrno;
55         }
56
57         return *this;
58 }
59
60 VComponent::~VComponent(){
61         if (imp)
62            icalcomponent_free(imp);
63 }
64
65 VComponent::VComponent(icalcomponent* v) throw (icalerrorenum) : imp(v){
66 }
67
68 /* char* returned is in the ring buffer. caller doesn't have to free it */
69 char* VComponent::quote_ical_string(char *str){
70     const char* p;
71     size_t  buf_sz;
72     buf_sz = strlen(str) * 2;   /* assume worse case scenarios. otherwise, we have to parse the string and count \ */
73     char* out = (char*)icalmemory_new_buffer(buf_sz);    /* memory is from the ring buffer */
74     char* pout;
75
76     if (out == 0){
77         return 0;
78     }
79
80     pout = out;
81
82     for (p = str; *p!=0; p++){
83
84         if( *p == '\\'){
85             *pout++ = '\\';
86         }
87         *pout++ = *p;
88
89     }
90     *pout++ = '\0';
91
92     return out;
93 }
94
95 /**
96  * @brief Constructor
97  * 
98  * Create a new VComponent from a string.
99  *
100  * @exception ICAL_MALFORMEDDATA_ERROR
101  *            Catch this error if you 
102  * 
103  */
104 VComponent::VComponent(string str)  throw (icalerrorenum) {
105         // Fix for BUG #15647, but breaks fix for BUG #15596.  Attempting a UI fix for cal-4.0.
106         //char* quoted_str = quote_ical_string((char *)str);
107         //imp = icalcomponent_new_from_string(quoted_str);
108         imp = icalcomponent_new_from_string(str);
109
110         if (!imp) throw icalerrno;
111 }
112
113 VComponent::VComponent(icalcomponent_kind kind)  throw(icalerrorenum) {
114   imp = icalcomponent_new(kind);
115
116   if (!imp) throw icalerrno;
117 }
118
119
120 string VComponent::as_ical_string()  throw(icalerrorenum) {
121   char *str = icalcomponent_as_ical_string(imp);
122
123   if (!str) throw icalerrno;
124
125   return(str);
126 }
127
128
129 bool VComponent::is_valid(){
130         if (imp == NULL) return false;
131         return (icalcomponent_is_valid(imp) ? true : false);
132 }
133
134 icalcomponent_kind VComponent::isa(){
135         return icalcomponent_isa(imp);
136 }
137
138 int VComponent::isa_component(void* component){
139         return icalcomponent_isa_component(component);
140 }
141
142 void VComponent::new_from_string(string str){
143         if (imp != NULL) icalcomponent_free(imp);
144         imp = icalcomponent_new_from_string(str);
145 }
146
147 /* Working with properties */
148 void VComponent::add_property(ICalProperty* property){
149         icalcomponent_add_property(imp, *property);
150 }
151 void VComponent::remove_property(ICalProperty* property){
152         icalcomponent_remove_property(imp, *property);
153         icalproperty_free(*property);
154         property->detach();             // set imp to null, it's free already.
155 }
156 int VComponent::count_properties(icalproperty_kind kind){
157         return icalcomponent_count_properties(imp, kind);
158 }
159
160 /* Iterate through the properties */
161 ICalProperty* VComponent::get_current_property(){
162         icalproperty* t = icalcomponent_get_current_property(imp);
163         return ((t != NULL) ? new ICalProperty(t) : NULL);
164 }
165
166 ICalProperty* VComponent::get_first_property(icalproperty_kind kind){
167         icalproperty* t = icalcomponent_get_first_property(imp, kind);
168         return ((t != NULL) ? new ICalProperty(t) : NULL);
169 }
170
171 ICalProperty* VComponent::get_next_property(icalproperty_kind kind){
172         icalproperty* t = icalcomponent_get_next_property(imp, kind);
173         return ((t != NULL) ? new ICalProperty(t) : NULL);
174 }
175
176 /* Working with components */ 
177 /* Return the first VEVENT, VTODO or VJOURNAL sub-component if it is one of those types */
178 VComponent* VComponent::get_inner(){
179         return new VComponent(icalcomponent_get_inner(imp));
180 }
181
182 void VComponent::add_component(VComponent* child){
183         icalcomponent_add_component(imp, *child);
184 }
185 void VComponent::remove_component(VComponent* child){
186         icalcomponent_remove_component(imp, *child);
187 }
188 int VComponent::count_components(icalcomponent_kind kind){
189         return  icalcomponent_count_components(imp, kind);
190 }
191
192 /* Iteration Routines. There are two forms of iterators, internal and
193    external. The internal ones came first, and are almost completely
194    sufficient, but they fail badly when you want to construct a loop that
195    removes components from the container.
196 */
197
198 /* Iterate through components */
199 VComponent* VComponent::get_current_component(){
200         icalcomponent* t = icalcomponent_get_current_component(imp);
201         return ((t != NULL) ? new VComponent(t) : NULL);
202 }
203 VComponent* VComponent::get_first_component(icalcomponent_kind kind){
204         VComponent* result = NULL;
205         icalcomponent* t = icalcomponent_get_first_component(imp, kind);
206         if (t != NULL) {
207                 switch (kind) {
208                         case ICAL_VALARM_COMPONENT:
209                                 result = new VAlarm(t);
210                                 break;
211                         case ICAL_VCALENDAR_COMPONENT:
212                                 result = new VCalendar(t);
213                                 break;
214                         case ICAL_VEVENT_COMPONENT:
215                                 result = new VEvent(t);
216                                 break;
217                         case ICAL_VQUERY_COMPONENT:
218                                 result = new VQuery(t);
219                                 break;
220                         case ICAL_VTODO_COMPONENT:
221                                 result = new VToDo(t);
222                                 break;
223                         case ICAL_VAGENDA_COMPONENT:
224                                 result = new VAgenda(t);
225                                 break;
226                         default:
227                                 result = new VComponent(t);
228                 }
229         }
230
231         return (result);
232 }
233 VComponent* VComponent::get_next_component(icalcomponent_kind kind){
234         VComponent* result = NULL;
235         icalcomponent* t = icalcomponent_get_next_component(imp, kind);
236         if (t != NULL) {
237                 switch (kind) {
238                         case ICAL_VALARM_COMPONENT:
239                                 result = new VAlarm(t);
240                                 break;
241                         case ICAL_VCALENDAR_COMPONENT:
242                                 result = new VCalendar(t);
243                                 break;
244                         case ICAL_VEVENT_COMPONENT:
245                                 result = new VEvent(t);
246                                 break;
247                         case ICAL_VQUERY_COMPONENT:
248                                 result = new VQuery(t);
249                                 break;
250                         case ICAL_VTODO_COMPONENT:
251                                 result = new VToDo(t);
252                                 break;
253                         case ICAL_VAGENDA_COMPONENT:
254                                 result = new VAgenda(t);
255                                 break;
256                         default:
257                                 result = new VComponent(t);
258                 }
259         }
260
261         return (result);
262 }
263
264 /* Using external iterators */
265 icalcompiter VComponent::begin_component(icalcomponent_kind kind){
266         return icalcomponent_begin_component(imp, kind);
267 }
268 icalcompiter VComponent::end_component(icalcomponent_kind kind){
269         return icalcomponent_end_component(imp, kind);
270 }
271 VComponent* VComponent::next(icalcompiter* i){
272         return (VComponent*)icalcompiter_next(i);
273 }
274 VComponent* VComponent::prev(icalcompiter* i){
275         return (VComponent*)icalcompiter_prior(i);
276 }
277 VComponent* VComponent::current(icalcompiter* i){
278         return (VComponent*)icalcompiter_deref(i);
279 }
280
281 /* Working with embedded error properties */
282 int VComponent::count_errors(){
283         return icalcomponent_count_errors(imp);
284 }
285
286 /* Remove all X-LIC-ERROR properties*/
287 void VComponent::strip_errors(){
288         icalcomponent_strip_errors(imp);
289 }
290
291 /* Convert some X-LIC-ERROR properties into RETURN-STATUS properties*/
292 void VComponent::convert_errors(){
293         icalcomponent_convert_errors(imp);
294 }
295
296 /* Kind conversion routines */
297 icalcomponent_kind VComponent::string_to_kind(string str){
298         return icalcomponent_string_to_kind(str);
299 }
300 string VComponent::kind_to_string(icalcomponent_kind kind){
301         return (string)icalcomponent_kind_to_string(kind);
302 }
303
304 struct icaltimetype VComponent::get_dtstart(){
305         return icalcomponent_get_dtstart(imp);
306 }
307 void VComponent::set_dtstart(struct icaltimetype v){
308         icalcomponent_set_dtstart(imp, v);
309 }
310
311 /* For the icalcomponent routines only, dtend and duration are tied
312    together. If you call the set routine for one and the other exists,
313    the routine will calculate the change to the other. That is, if
314    there is a DTEND and you call set_duration, the routine will modify
315    DTEND to be the sum of DTSTART and the duration. If you call a get
316    routine for one and the other exists, the routine will calculate
317    the return value. If you call a set routine and neither exists, the
318    routine will create the apcompriate comperty.
319 */
320
321 struct icaltimetype VComponent::get_dtend(){
322         return icalcomponent_get_dtend(imp);
323 }
324
325 void VComponent::set_dtend(struct icaltimetype v){
326         icalcomponent_set_dtend(imp, v);
327 }
328
329 struct icaltimetype VComponent::get_due(){
330         return icalcomponent_get_due(imp);
331 }
332 void VComponent::set_due(struct icaltimetype v){
333         icalcomponent_set_due(imp, v);
334 }
335
336 struct icaldurationtype VComponent::get_duration(){
337         return icalcomponent_get_duration(imp);
338 }
339 void VComponent::set_duration(struct icaldurationtype v){
340         icalcomponent_set_duration(imp, v);
341 }
342
343 icalproperty_method VComponent::get_method(){
344         return icalcomponent_get_method(imp);
345 }
346 void VComponent::set_method(icalproperty_method method){
347         icalcomponent_set_method(imp, method);
348 }
349
350 struct icaltimetype VComponent::get_dtstamp(){
351         return icalcomponent_get_dtstamp(imp);
352 }
353 void VComponent::set_dtstamp(struct icaltimetype v){
354         icalcomponent_set_dtstamp(imp, v);
355 }
356
357 string VComponent::get_summary(){
358         return (string)icalcomponent_get_summary(imp);
359 }
360 void VComponent::set_summary(string v){
361         icalcomponent_set_summary(imp, v);
362 }
363
364 string VComponent::get_location(){
365         return (string)icalcomponent_get_location(imp);
366 }
367 void VComponent::set_location(string v){
368         icalcomponent_set_location(imp, v);
369 }
370
371
372 string VComponent::get_description(){
373         return (string)icalcomponent_get_description(imp);
374 }
375 void VComponent::set_description(string v){
376         icalcomponent_set_description(imp, v);
377 }
378 string VComponent::get_comment(){
379         return (string)icalcomponent_get_comment(imp);
380 }
381 void VComponent::set_comment(string v){
382         icalcomponent_set_comment(imp, v);
383 }
384
385 string VComponent::get_uid(){
386         return (string)icalcomponent_get_uid(imp);
387 }
388 void VComponent::set_uid(string v){
389         icalcomponent_set_uid(imp, v);
390 }
391
392 string VComponent::get_relcalid(){
393         return (string)icalcomponent_get_relcalid(imp);
394 }
395 void VComponent::set_relcalid(string v){
396         icalcomponent_set_relcalid(imp, v);
397 }
398
399 struct icaltimetype VComponent::get_recurrenceid(){
400         return icalcomponent_get_recurrenceid(imp);
401 }
402 void VComponent::set_recurrenceid(struct icaltimetype v){
403         icalcomponent_set_recurrenceid(imp, v);
404 }
405
406 int VComponent::get_sequence(){
407         return (int)icalcomponent_get_sequence(imp);
408 }
409 void VComponent::set_sequence(int v){
410         icalcomponent_set_sequence(imp, v);
411 }
412
413 int VComponent::get_status(){
414         return (int)icalcomponent_get_status(imp);
415 }
416 void VComponent::set_status(enum icalproperty_status v){
417         icalcomponent_set_status(imp, v);
418 }
419
420 /* For VCOMPONENT: Return a reference to the first VEVENT, VTODO, or VJOURNAL */
421 VComponent* VComponent::get_first_real_component(){
422         return (VComponent*)icalcomponent_get_first_real_component(imp);
423 }
424
425 /* For VEVENT, VTODO, VJOURNAL and VTIMEZONE: report the start and end
426    times of an event in UTC */
427 struct icaltime_span VComponent::get_span(){
428         return icalcomponent_get_span(imp);
429 }
430
431 int VComponent::recurrence_is_excluded( struct icaltimetype *dtstart,
432                                        struct icaltimetype *recurtime){
433        return  icalproperty_recurrence_is_excluded(imp, dtstart, recurtime);
434 }
435
436
437 /* Internal operations. They are private, and you should not be using them. */
438 VComponent* VComponent::get_parent() {
439         return new VComponent(icalcomponent_get_parent(imp));
440 }
441 void VComponent::set_parent(VComponent *parent){
442         icalcomponent_set_parent(imp, *parent);
443 }
444
445 /* ignoreValue means remove properties even if the data doesn't match */
446 bool VComponent::remove(VComponent& fromVC, bool ignoreValue){
447
448     /* the two components must be the same kind */
449     if (this->isa() != fromVC.isa()) return false;
450
451     /* properties first */
452     ICalPropertyTmpPtr propToBeRemoved;
453     for (propToBeRemoved=fromVC.get_first_property(ICAL_ANY_PROPERTY); propToBeRemoved != NULL;
454          propToBeRemoved=fromVC.get_next_property(ICAL_ANY_PROPERTY)) {
455
456         /* loop through properties from this component */
457         ICalPropertyTmpPtr next;
458         ICalPropertyTmpPtr p;
459         for (p=this->get_first_property(propToBeRemoved->isa()); p != NULL; p=next) {
460             next = this->get_next_property(propToBeRemoved->isa());
461             if (ignoreValue)
462                  this->remove_property(p);
463             else {
464                  if (*p == *propToBeRemoved) {
465                      this->remove_property(p);
466                      break;
467                  }
468             }
469         }
470     }
471
472     /* components next - should remove by UID */
473     VComponentTmpPtr comp;
474     for (comp=fromVC.get_first_component(ICAL_ANY_COMPONENT); comp != NULL;
475          comp=fromVC.get_next_component(ICAL_ANY_COMPONENT)) {
476         const char* fromCompUid = comp->get_uid();
477         VComponentTmpPtr c;
478         for (c=this->get_first_component(comp->isa()); c != NULL;
479              c=this->get_next_component(comp->isa())) {
480             const char* thisCompUid = c->get_uid();
481             if (strcmp(fromCompUid, thisCompUid) == 0) {
482                 // recursively go down the components
483                 c->remove(*comp, ignoreValue);
484                     // if all properties are removed and there is no sub-components, then
485                     // remove this compoent
486                     if ((c->count_properties(ICAL_ANY_PROPERTY) == 0) &&
487                         (c->count_components(ICAL_ANY_COMPONENT) == 0)) {
488                         this->remove_component(c);
489                     }
490                 break;
491                 }
492             }
493     }
494     
495     return true;
496 }
497 /* removeMissing == true: remove properties that are missing from fromC */
498 /* todo: only change the first occurence of the property */
499 /* todo: removeMissing is not implemented */
500 bool VComponent::update(VComponent& fromC, bool removeMissing){
501
502     /* make sure they are the same kind */
503     if (this->isa() != fromC.isa()) return false;
504
505     /* property first */
506     ICalPropertyTmpPtr prop;
507     for (prop=fromC.get_first_property(ICAL_ANY_PROPERTY); prop != NULL;
508          prop=fromC.get_next_property(ICAL_ANY_PROPERTY)) {
509         ICalPropertyTmpPtr thisProp;
510         thisProp = this->get_first_property(prop->isa());
511         if (thisProp == NULL) {
512             thisProp = new ICalProperty(prop->isa());
513             this->add_property(thisProp);
514         }
515         ICalValue *value = new ICalValue(*(prop->get_value())); // clone the value
516         thisProp->set_value(*value);
517     }
518
519     /* recursively updating sub-components */
520     VComponentTmpPtr comp;
521     for (comp=fromC.get_first_component(ICAL_ANY_COMPONENT); comp != NULL;
522          comp=fromC.get_next_component(ICAL_ANY_COMPONENT)) {
523         VComponentTmpPtr thisComp;
524         thisComp = this->get_first_component(comp->isa());
525         if (thisComp == NULL) {
526             thisComp = new VComponent(comp->isa());
527             this->add_component(thisComp);
528         }
529         bool err = thisComp->update(*comp, removeMissing);
530         if (!err) return false;
531     }
532     return true;
533 }
534 /* add components and property. recursively goes down child components */
535 bool VComponent::add(VComponent& fromC){
536         /* make sure the kind are the same */
537         if (this->isa() != fromC.isa()) return false;
538
539         /* properties first */
540     ICalPropertyTmpPtr prop;
541         for (prop=fromC.get_first_property(ICAL_ANY_PROPERTY); prop != NULL;
542                  prop=fromC.get_next_property(ICAL_ANY_PROPERTY)) {
543                 /* clone another property */
544                 ICalProperty *p = new ICalProperty(*prop);
545                 add_property(p);
546         }
547
548         /* sub-components next */
549         bool err = false;
550     VComponentTmpPtr comp;
551         for (comp=fromC.get_first_component(ICAL_ANY_COMPONENT); comp != NULL;
552                  comp=fromC.get_next_component(ICAL_ANY_COMPONENT)) {
553                 VComponent *c = new VComponent(comp->isa());
554                 err = c->add(*comp);
555                 add_component(c);
556         }
557
558         return true;
559 }
560
561 VCalendar::VCalendar() : VComponent(icalcomponent_new_vcalendar()){
562 }
563 VCalendar::VCalendar(const VCalendar& v) : VComponent(v) {}
564 VCalendar& VCalendar::operator=(const VCalendar& v){
565         if (this == &v) return *this;
566         VComponent::operator=(v);
567
568         return *this;
569 }
570 VCalendar::~VCalendar(){}
571
572 VCalendar::VCalendar(icalcomponent* v) : VComponent(v){}
573 VCalendar::VCalendar(string str) : VComponent(str){}
574
575
576 /* VEvent */
577
578 VEvent::VEvent() : VComponent(icalcomponent_new_vevent()){}
579 VEvent::VEvent(const VEvent& v) : VComponent(v) {}
580 VEvent& VEvent::operator=(const VEvent& v){
581         if (this == &v) return *this;
582         VComponent::operator=(v);
583
584         return *this;
585 }
586 VEvent::~VEvent(){}
587
588 VEvent::VEvent(icalcomponent* v) : VComponent(v){}
589 VEvent::VEvent(string str) : VComponent(str){}
590
591
592 /* VTodo */
593
594 VToDo::VToDo() : VComponent(icalcomponent_new_vtodo()){}
595 VToDo::VToDo(const VToDo& v) : VComponent(v) {}
596 VToDo& VToDo::operator=(const VToDo& v){
597         if (this == &v) return *this;
598         VComponent::operator=(v);
599
600         return *this;
601 }
602 VToDo::~VToDo(){}
603
604 VToDo::VToDo(icalcomponent* v) : VComponent(v){}
605 VToDo::VToDo(string str) : VComponent(str){}
606
607
608 /* VAgenda */
609
610 VAgenda::VAgenda() : VComponent(icalcomponent_new_vagenda()){}
611 VAgenda::VAgenda(const VAgenda& v) : VComponent(v) {}
612 VAgenda& VAgenda::operator=(const VAgenda& v){
613         if (this == &v) return *this;
614         VComponent::operator=(v);
615
616         return *this;
617 }
618 VAgenda::~VAgenda(){}
619
620 VAgenda::VAgenda(icalcomponent* v) : VComponent(v){}
621 VAgenda::VAgenda(string str) : VComponent(str){}
622
623
624 /* VQuery */
625
626 VQuery::VQuery() : VComponent(icalcomponent_new_vquery()){}
627 VQuery::VQuery(const VQuery& v) : VComponent(v) {}
628 VQuery& VQuery::operator=(const VQuery& v){
629         if (this == &v) return *this;
630         VComponent::operator=(v);
631
632         return *this;
633 }
634 VQuery::~VQuery(){}
635
636 VQuery::VQuery(icalcomponent* v) : VComponent(v){}
637 VQuery::VQuery(string str) : VComponent(str){}
638
639
640 /* VJournal */
641
642 VJournal::VJournal() : VComponent(icalcomponent_new_vjournal()){}
643 VJournal::VJournal(const VJournal& v) : VComponent(v) {}
644 VJournal& VJournal::operator=(const VJournal& v){
645         if (this == &v) return *this;
646         VComponent::operator=(v);
647
648         return *this;
649 }
650 VJournal::~VJournal(){}
651
652 VJournal::VJournal(icalcomponent* v) : VComponent(v){}
653 VJournal::VJournal(string str) : VComponent(str){}
654
655
656 /* VAlarm */
657
658 VAlarm::VAlarm() : VComponent(icalcomponent_new_valarm()){}
659 VAlarm::VAlarm(const VAlarm& v) : VComponent(v) {}
660 VAlarm& VAlarm::operator=(const VAlarm& v){
661         if (this == &v) return *this;
662         VComponent::operator=(v);
663
664         return *this;
665 }
666 VAlarm::~VAlarm(){}
667
668 VAlarm::VAlarm(icalcomponent* v) : VComponent(v){}
669 VAlarm::VAlarm(string str) : VComponent(str){}
670
671 icalrequeststatus
672 VAlarm::getTriggerTime(VComponent &c, struct icaltriggertype *tr)
673 {
674   struct icaltimetype tt;
675   ICalParameter *related_param;
676
677   ICalPropertyTmpPtr trigger_prop = this->get_first_property(ICAL_TRIGGER_PROPERTY);
678
679   // all VALARMs must have a TRIGGER
680   if (trigger_prop == NULL)  
681     return ICAL_3_1_INVPROPVAL_STATUS; 
682
683   *tr = trigger_prop->get_trigger();
684
685   tt = icaltime_null_time();
686
687   if (icaltime_is_null_time(tr->time)) {
688
689     // relative time trigger
690
691     // TRIGGER;RELATED=END:P5M 5 minutes after END
692     // TRIGGER;RELATED=START:-P15M 15 minutes before START
693     // get RELATED parameter
694
695     related_param = trigger_prop->get_first_parameter(ICAL_RELATED_PARAMETER);
696
697     if (related_param && related_param->is_valid()) {
698
699         // get RELATED parameter value
700         icalparameter_related related = related_param->get_related();
701
702         if(related) {
703             switch(related) {
704                 case ICAL_RELATED_END:
705                     if (c.isa() == ICAL_VEVENT_COMPONENT) {
706                         tt = c.get_dtend();
707
708                         // If a recurrenceid exists, use that to calculate the
709                         // dtend from the dtstart.
710                         struct icaltimetype recur_time = c.get_recurrenceid();
711                         if (!(icaltime_is_null_time(recur_time))) {
712                             struct icaldurationtype dur = icaltime_subtract(c.get_dtstart(), tt);
713                             tt = icaltime_add(recur_time, dur);
714                         } 
715                     }   
716                     else if (c.isa() == ICAL_VTODO_COMPONENT) {
717                         tt = c.get_due();
718                         struct icaltimetype recur_time = c.get_recurrenceid();
719                         if (!(icaltime_is_null_time(recur_time))) {
720                             tt = recur_time;
721                         }
722                     }
723                     // @@@ TODO: if not DTEND or DUE, then DTSTART and DURATION must be present
724                 break;
725                 case ICAL_RELATED_START:
726                 case ICAL_RELATED_X:
727                 case ICAL_RELATED_NONE:
728                 default:
729                     tt = c.get_dtstart();
730                     struct icaltimetype recur_time = c.get_recurrenceid();
731                     if (!(icaltime_is_null_time(recur_time))) {
732                         tt = recur_time;
733                     }
734                 break;
735             }
736
737         }
738     }
739     else { // no RELATED explicity specified, the default is 
740            // relative to the start of an event or to-do, rfc2445
741         // if no RELATED, we are forced to use dtstart for VEVENT,
742         // due for VTODO to calculate trigger time. 
743         // If a recur time exists, use that. Recur time trumps dtstart or due.
744         struct icaltimetype recur_time = c.get_recurrenceid();
745         if (!(icaltime_is_null_time(recur_time))) {
746             tt = recur_time;
747         }
748         else if (c.isa() == ICAL_VEVENT_COMPONENT)
749             tt = c.get_dtstart();
750         else if (c.isa() == ICAL_VTODO_COMPONENT)
751             tt = c.get_due();
752     }
753
754     // malformed? encapsulating VEVENT or VTODO MUST have DTSTART/DTEND 
755     if(icaltime_is_null_time(tt))
756       return ICAL_3_1_INVPROPVAL_STATUS;;
757
758     // now offset using tr.duration
759     tr->time = icaltime_add(tt, tr->duration);
760   }
761   // else absolute time trigger
762
763   return ICAL_2_0_SUCCESS_STATUS;
764 }
765
766
767 /* VFreeBusy */
768
769 VFreeBusy::VFreeBusy() : VComponent(icalcomponent_new_vfreebusy()){}
770 VFreeBusy::VFreeBusy(const VFreeBusy& v) : VComponent(v) {}
771 VFreeBusy& VFreeBusy::operator=(const VFreeBusy& v){
772         if (this == &v) return *this;
773         VComponent::operator=(v);
774
775         return *this;
776 }
777 VFreeBusy::~VFreeBusy(){}
778
779 VFreeBusy::VFreeBusy(icalcomponent* v) : VComponent(v){}
780 VFreeBusy::VFreeBusy(string str) : VComponent(str){}
781
782
783 /* VTimezone */
784
785 VTimezone::VTimezone() : VComponent(icalcomponent_new_vtimezone()){}
786 VTimezone::VTimezone(const VTimezone& v) : VComponent(v) {}
787 VTimezone& VTimezone::operator=(const VTimezone& v){
788         if (this == &v) return *this;
789         VComponent::operator=(v);
790
791         return *this;
792 }
793 VTimezone::~VTimezone(){}
794
795 VTimezone::VTimezone(icalcomponent* v) : VComponent(v){}
796 VTimezone::VTimezone(string str) : VComponent(str){}
797
798
799 /* XStandard */
800
801 XStandard::XStandard() : VComponent(icalcomponent_new_xstandard()){}
802 XStandard::XStandard(const XStandard& v) : VComponent(v) {}
803 XStandard& XStandard::operator=(const XStandard& v){
804         if (this == &v) return *this;
805         VComponent::operator=(v);
806
807         return *this;
808 }
809 XStandard::~XStandard(){}
810
811 XStandard::XStandard(icalcomponent* v) : VComponent(v){}
812 XStandard::XStandard(string str) : VComponent(str){}
813
814
815 /* XDaylight */
816
817 XDaylight::XDaylight() : VComponent(icalcomponent_new_xdaylight()){}
818 XDaylight::XDaylight(const XDaylight& v) : VComponent(v) {}
819 XDaylight& XDaylight::operator=(const XDaylight& v){
820         if (this == &v) return *this;
821         VComponent::operator=(v);
822
823         return *this;
824 }
825 XDaylight::~XDaylight(){}
826
827 XDaylight::XDaylight(icalcomponent* v) : VComponent(v){}
828 XDaylight::XDaylight(string str) : VComponent(str){}