3 * @author fnguyen (12/10/01)
4 * @brief Implemenation of C++ Wrapper for icalcomponent.c
6 * (C) COPYRIGHT 2001, Critical Path
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of either:
11 The LGPL as published by the Free Software Foundation, version
12 2.1, available at: http://www.fsf.org/copyleft/lesser.html
16 The Mozilla Public License Version 1.0. You may obtain a copy of
17 the License at http://www.mozilla.org/MPL/
21 #include "vcomponent.h"
24 #ifndef ICALVALUE_CXX_H
25 #include "icalvalue_cxx.h"
28 #ifndef ICALPROPERTY_CXX_H
29 #include "icalproperty_cxx.h"
32 #ifndef ICALPARAMETER_CXX_H
33 #include "icalparameter_cxx.h"
40 VComponent::VComponent() throw(icalerrorenum) : imp(icalcomponent_new(ICAL_ANY_COMPONENT)) {
42 VComponent::VComponent(const VComponent& v) throw(icalerrorenum) {
43 imp = icalcomponent_new_clone(v.imp);
44 if (!imp) throw icalerrno;
47 VComponent& VComponent::operator=(const VComponent& v) throw(icalerrorenum) {
48 if (this == &v) return *this;
52 icalcomponent_free(imp);
53 imp = icalcomponent_new_clone(v.imp);
54 if (!imp) throw icalerrno;
60 VComponent::~VComponent(){
62 icalcomponent_free(imp);
65 VComponent::VComponent(icalcomponent* v) throw (icalerrorenum) : imp(v){
68 /* char* returned is in the ring buffer. caller doesn't have to free it */
69 char* VComponent::quote_ical_string(char *str){
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 */
82 for (p = str; *p!=0; p++){
98 * Create a new VComponent from a string.
100 * @exception ICAL_MALFORMEDDATA_ERROR
101 * Catch this error if you
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);
110 if (!imp) throw icalerrno;
113 VComponent::VComponent(icalcomponent_kind kind) throw(icalerrorenum) {
114 imp = icalcomponent_new(kind);
116 if (!imp) throw icalerrno;
120 string VComponent::as_ical_string() throw(icalerrorenum) {
121 char *str = icalcomponent_as_ical_string(imp);
123 if (!str) throw icalerrno;
129 bool VComponent::is_valid(){
130 if (imp == NULL) return false;
131 return (icalcomponent_is_valid(imp) ? true : false);
134 icalcomponent_kind VComponent::isa(){
135 return icalcomponent_isa(imp);
138 int VComponent::isa_component(void* component){
139 return icalcomponent_isa_component(component);
142 void VComponent::new_from_string(string str){
143 if (imp != NULL) icalcomponent_free(imp);
144 imp = icalcomponent_new_from_string(str);
147 /* Working with properties */
148 void VComponent::add_property(ICalProperty* property){
149 icalcomponent_add_property(imp, *property);
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.
156 int VComponent::count_properties(icalproperty_kind kind){
157 return icalcomponent_count_properties(imp, kind);
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);
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);
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);
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));
182 void VComponent::add_component(VComponent* child){
183 icalcomponent_add_component(imp, *child);
185 void VComponent::remove_component(VComponent* child){
186 icalcomponent_remove_component(imp, *child);
188 int VComponent::count_components(icalcomponent_kind kind){
189 return icalcomponent_count_components(imp, kind);
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.
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);
203 VComponent* VComponent::get_first_component(icalcomponent_kind kind){
204 VComponent* result = NULL;
205 icalcomponent* t = icalcomponent_get_first_component(imp, kind);
208 case ICAL_VALARM_COMPONENT:
209 result = new VAlarm(t);
211 case ICAL_VCALENDAR_COMPONENT:
212 result = new VCalendar(t);
214 case ICAL_VEVENT_COMPONENT:
215 result = new VEvent(t);
217 case ICAL_VQUERY_COMPONENT:
218 result = new VQuery(t);
220 case ICAL_VTODO_COMPONENT:
221 result = new VToDo(t);
223 case ICAL_VAGENDA_COMPONENT:
224 result = new VAgenda(t);
227 result = new VComponent(t);
233 VComponent* VComponent::get_next_component(icalcomponent_kind kind){
234 VComponent* result = NULL;
235 icalcomponent* t = icalcomponent_get_next_component(imp, kind);
238 case ICAL_VALARM_COMPONENT:
239 result = new VAlarm(t);
241 case ICAL_VCALENDAR_COMPONENT:
242 result = new VCalendar(t);
244 case ICAL_VEVENT_COMPONENT:
245 result = new VEvent(t);
247 case ICAL_VQUERY_COMPONENT:
248 result = new VQuery(t);
250 case ICAL_VTODO_COMPONENT:
251 result = new VToDo(t);
253 case ICAL_VAGENDA_COMPONENT:
254 result = new VAgenda(t);
257 result = new VComponent(t);
264 /* Using external iterators */
265 icalcompiter VComponent::begin_component(icalcomponent_kind kind){
266 return icalcomponent_begin_component(imp, kind);
268 icalcompiter VComponent::end_component(icalcomponent_kind kind){
269 return icalcomponent_end_component(imp, kind);
271 VComponent* VComponent::next(icalcompiter* i){
272 return (VComponent*)icalcompiter_next(i);
274 VComponent* VComponent::prev(icalcompiter* i){
275 return (VComponent*)icalcompiter_prior(i);
277 VComponent* VComponent::current(icalcompiter* i){
278 return (VComponent*)icalcompiter_deref(i);
281 /* Working with embedded error properties */
282 int VComponent::count_errors(){
283 return icalcomponent_count_errors(imp);
286 /* Remove all X-LIC-ERROR properties*/
287 void VComponent::strip_errors(){
288 icalcomponent_strip_errors(imp);
291 /* Convert some X-LIC-ERROR properties into RETURN-STATUS properties*/
292 void VComponent::convert_errors(){
293 icalcomponent_convert_errors(imp);
296 /* Kind conversion routines */
297 icalcomponent_kind VComponent::string_to_kind(string str){
298 return icalcomponent_string_to_kind(str);
300 string VComponent::kind_to_string(icalcomponent_kind kind){
301 return (string)icalcomponent_kind_to_string(kind);
304 struct icaltimetype VComponent::get_dtstart(){
305 return icalcomponent_get_dtstart(imp);
307 void VComponent::set_dtstart(struct icaltimetype v){
308 icalcomponent_set_dtstart(imp, v);
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.
321 struct icaltimetype VComponent::get_dtend(){
322 return icalcomponent_get_dtend(imp);
325 void VComponent::set_dtend(struct icaltimetype v){
326 icalcomponent_set_dtend(imp, v);
329 struct icaltimetype VComponent::get_due(){
330 return icalcomponent_get_due(imp);
332 void VComponent::set_due(struct icaltimetype v){
333 icalcomponent_set_due(imp, v);
336 struct icaldurationtype VComponent::get_duration(){
337 return icalcomponent_get_duration(imp);
339 void VComponent::set_duration(struct icaldurationtype v){
340 icalcomponent_set_duration(imp, v);
343 icalproperty_method VComponent::get_method(){
344 return icalcomponent_get_method(imp);
346 void VComponent::set_method(icalproperty_method method){
347 icalcomponent_set_method(imp, method);
350 struct icaltimetype VComponent::get_dtstamp(){
351 return icalcomponent_get_dtstamp(imp);
353 void VComponent::set_dtstamp(struct icaltimetype v){
354 icalcomponent_set_dtstamp(imp, v);
357 string VComponent::get_summary(){
358 return (string)icalcomponent_get_summary(imp);
360 void VComponent::set_summary(string v){
361 icalcomponent_set_summary(imp, v);
364 string VComponent::get_location(){
365 return (string)icalcomponent_get_location(imp);
367 void VComponent::set_location(string v){
368 icalcomponent_set_location(imp, v);
372 string VComponent::get_description(){
373 return (string)icalcomponent_get_description(imp);
375 void VComponent::set_description(string v){
376 icalcomponent_set_description(imp, v);
378 string VComponent::get_comment(){
379 return (string)icalcomponent_get_comment(imp);
381 void VComponent::set_comment(string v){
382 icalcomponent_set_comment(imp, v);
385 string VComponent::get_uid(){
386 return (string)icalcomponent_get_uid(imp);
388 void VComponent::set_uid(string v){
389 icalcomponent_set_uid(imp, v);
392 string VComponent::get_relcalid(){
393 return (string)icalcomponent_get_relcalid(imp);
395 void VComponent::set_relcalid(string v){
396 icalcomponent_set_relcalid(imp, v);
399 struct icaltimetype VComponent::get_recurrenceid(){
400 return icalcomponent_get_recurrenceid(imp);
402 void VComponent::set_recurrenceid(struct icaltimetype v){
403 icalcomponent_set_recurrenceid(imp, v);
406 int VComponent::get_sequence(){
407 return (int)icalcomponent_get_sequence(imp);
409 void VComponent::set_sequence(int v){
410 icalcomponent_set_sequence(imp, v);
413 int VComponent::get_status(){
414 return (int)icalcomponent_get_status(imp);
416 void VComponent::set_status(enum icalproperty_status v){
417 icalcomponent_set_status(imp, v);
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);
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);
431 int VComponent::recurrence_is_excluded( struct icaltimetype *dtstart,
432 struct icaltimetype *recurtime){
433 return icalproperty_recurrence_is_excluded(imp, dtstart, recurtime);
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));
441 void VComponent::set_parent(VComponent *parent){
442 icalcomponent_set_parent(imp, *parent);
445 /* ignoreValue means remove properties even if the data doesn't match */
446 bool VComponent::remove(VComponent& fromVC, bool ignoreValue){
448 /* the two components must be the same kind */
449 if (this->isa() != fromVC.isa()) return false;
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)) {
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());
462 this->remove_property(p);
464 if (*p == *propToBeRemoved) {
465 this->remove_property(p);
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();
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);
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){
502 /* make sure they are the same kind */
503 if (this->isa() != fromC.isa()) return false;
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);
515 ICalValue *value = new ICalValue(*(prop->get_value())); // clone the value
516 thisProp->set_value(*value);
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);
529 bool err = thisComp->update(*comp, removeMissing);
530 if (!err) return false;
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;
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);
548 /* sub-components next */
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());
561 VCalendar::VCalendar() : VComponent(icalcomponent_new_vcalendar()){
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);
570 VCalendar::~VCalendar(){}
572 VCalendar::VCalendar(icalcomponent* v) : VComponent(v){}
573 VCalendar::VCalendar(string str) : VComponent(str){}
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);
588 VEvent::VEvent(icalcomponent* v) : VComponent(v){}
589 VEvent::VEvent(string str) : VComponent(str){}
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);
604 VToDo::VToDo(icalcomponent* v) : VComponent(v){}
605 VToDo::VToDo(string str) : VComponent(str){}
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);
618 VAgenda::~VAgenda(){}
620 VAgenda::VAgenda(icalcomponent* v) : VComponent(v){}
621 VAgenda::VAgenda(string str) : VComponent(str){}
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);
636 VQuery::VQuery(icalcomponent* v) : VComponent(v){}
637 VQuery::VQuery(string str) : VComponent(str){}
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);
650 VJournal::~VJournal(){}
652 VJournal::VJournal(icalcomponent* v) : VComponent(v){}
653 VJournal::VJournal(string str) : VComponent(str){}
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);
668 VAlarm::VAlarm(icalcomponent* v) : VComponent(v){}
669 VAlarm::VAlarm(string str) : VComponent(str){}
672 VAlarm::getTriggerTime(VComponent &c, struct icaltriggertype *tr)
674 struct icaltimetype tt;
675 ICalParameter *related_param;
677 ICalPropertyTmpPtr trigger_prop = this->get_first_property(ICAL_TRIGGER_PROPERTY);
679 // all VALARMs must have a TRIGGER
680 if (trigger_prop == NULL)
681 return ICAL_3_1_INVPROPVAL_STATUS;
683 *tr = trigger_prop->get_trigger();
685 tt = icaltime_null_time();
687 if (icaltime_is_null_time(tr->time)) {
689 // relative time trigger
691 // TRIGGER;RELATED=END:P5M 5 minutes after END
692 // TRIGGER;RELATED=START:-P15M 15 minutes before START
693 // get RELATED parameter
695 related_param = trigger_prop->get_first_parameter(ICAL_RELATED_PARAMETER);
697 if (related_param && related_param->is_valid()) {
699 // get RELATED parameter value
700 icalparameter_related related = related_param->get_related();
704 case ICAL_RELATED_END:
705 if (c.isa() == ICAL_VEVENT_COMPONENT) {
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);
716 else if (c.isa() == ICAL_VTODO_COMPONENT) {
718 struct icaltimetype recur_time = c.get_recurrenceid();
719 if (!(icaltime_is_null_time(recur_time))) {
723 // @@@ TODO: if not DTEND or DUE, then DTSTART and DURATION must be present
725 case ICAL_RELATED_START:
727 case ICAL_RELATED_NONE:
729 tt = c.get_dtstart();
730 struct icaltimetype recur_time = c.get_recurrenceid();
731 if (!(icaltime_is_null_time(recur_time))) {
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))) {
748 else if (c.isa() == ICAL_VEVENT_COMPONENT)
749 tt = c.get_dtstart();
750 else if (c.isa() == ICAL_VTODO_COMPONENT)
754 // malformed? encapsulating VEVENT or VTODO MUST have DTSTART/DTEND
755 if(icaltime_is_null_time(tt))
756 return ICAL_3_1_INVPROPVAL_STATUS;;
758 // now offset using tr.duration
759 tr->time = icaltime_add(tt, tr->duration);
761 // else absolute time trigger
763 return ICAL_2_0_SUCCESS_STATUS;
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);
777 VFreeBusy::~VFreeBusy(){}
779 VFreeBusy::VFreeBusy(icalcomponent* v) : VComponent(v){}
780 VFreeBusy::VFreeBusy(string str) : VComponent(str){}
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);
793 VTimezone::~VTimezone(){}
795 VTimezone::VTimezone(icalcomponent* v) : VComponent(v){}
796 VTimezone::VTimezone(string str) : VComponent(str){}
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);
809 XStandard::~XStandard(){}
811 XStandard::XStandard(icalcomponent* v) : VComponent(v){}
812 XStandard::XStandard(string str) : VComponent(str){}
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);
825 XDaylight::~XDaylight(){}
827 XDaylight::XDaylight(icalcomponent* v) : VComponent(v){}
828 XDaylight::XDaylight(string str) : VComponent(str){}