diff options
Diffstat (limited to 'libical/src/libical/icalcomponent.c')
-rw-r--r-- | libical/src/libical/icalcomponent.c | 1501 |
1 files changed, 1078 insertions, 423 deletions
diff --git a/libical/src/libical/icalcomponent.c b/libical/src/libical/icalcomponent.c index 6c222f01a9..a892128a0e 100644 --- a/libical/src/libical/icalcomponent.c +++ b/libical/src/libical/icalcomponent.c @@ -4,7 +4,6 @@ $Id$ - (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org This program is free software; you can redistribute it and/or modify @@ -38,6 +37,7 @@ #include "icalduration.h" #include "icalperiod.h" #include "icalparser.h" +#include "icalrestriction.h" #include <stdlib.h> /* for malloc */ #include <stdarg.h> /* for va_list, etc */ @@ -45,8 +45,7 @@ #include <assert.h> #include <stdio.h> /* for fprintf */ #include <string.h> /* for strdup */ - -#define MAX_TMP 1024 +#include <limits.h> /* for INT_MAX */ struct icalcomponent_impl { @@ -59,7 +58,7 @@ struct icalcomponent_impl pvl_elem component_iterator; icalcomponent* parent; - /* An array of icaltimezone structs. We use this so we can do fast + /** An array of icaltimezone structs. We use this so we can do fast lookup of timezones using binary searches. timezones_sorted is set to 0 whenever we add a timezone, so we remember to sort the array before doing a binary search. */ @@ -71,9 +70,8 @@ struct icalcomponent_impl void icalproperty_set_parent(icalproperty* property, icalcomponent* component); icalcomponent* icalproperty_get_parent(icalproperty* property); -void icalcomponent_add_children(struct icalcomponent_impl *impl,va_list args); -icalcomponent* icalcomponent_new_impl (icalcomponent_kind kind); -int icalcomponent_property_sorter(void *a, void *b); +void icalcomponent_add_children(icalcomponent *impl,va_list args); +static icalcomponent* icalcomponent_new_impl (icalcomponent_kind kind); static void icalcomponent_merge_vtimezone (icalcomponent *comp, icalcomponent *vtimezone, @@ -83,7 +81,7 @@ static void icalcomponent_handle_conflicting_vtimezones (icalcomponent *comp, icalproperty *tzid_prop, const char *tzid, icalarray *tzids_to_rename); -static int icalcomponent_get_tzid_prefix_len (const char *tzid); +static unsigned int icalcomponent_get_tzid_prefix_len (const char *tzid); static void icalcomponent_rename_tzids(icalcomponent* comp, icalarray* rename_table); static void icalcomponent_rename_tzids_callback(icalparameter *param, @@ -94,7 +92,7 @@ static int icalcomponent_compare_timezone_fn (const void *elem1, const void *elem2); -void icalcomponent_add_children(struct icalcomponent_impl *impl,va_list args) +void icalcomponent_add_children(icalcomponent *impl, va_list args) { void* vp; @@ -104,25 +102,23 @@ void icalcomponent_add_children(struct icalcomponent_impl *impl,va_list args) icalproperty_isa_property(vp) != 0 ) ; if (icalcomponent_isa_component(vp) != 0 ){ - - icalcomponent_add_component((icalcomponent*)impl, - (icalcomponent*)vp); + icalcomponent_add_component(impl, (icalcomponent*)vp); } else if (icalproperty_isa_property(vp) != 0 ){ - - icalcomponent_add_property((icalcomponent*)impl, - (icalproperty*)vp); + icalcomponent_add_property(impl, (icalproperty*)vp); } } } -icalcomponent* +static icalcomponent* icalcomponent_new_impl (icalcomponent_kind kind) { - struct icalcomponent_impl* comp; + icalcomponent* comp; + + if (!icalcomponent_kind_is_valid(kind)) + return NULL; - if ( ( comp = (struct icalcomponent_impl*) - malloc(sizeof(struct icalcomponent_impl))) == 0) { + if ( ( comp = (icalcomponent*) malloc(sizeof(icalcomponent))) == 0) { icalerror_set_errno(ICAL_NEWFAILED_ERROR); return 0; } @@ -142,18 +138,22 @@ icalcomponent_new_impl (icalcomponent_kind kind) return comp; } +/** @brief Constructor + */ icalcomponent* icalcomponent_new (icalcomponent_kind kind) { - return (icalcomponent*)icalcomponent_new_impl(kind); + return icalcomponent_new_impl(kind); } +/** @brief Constructor + */ icalcomponent* icalcomponent_vanew (icalcomponent_kind kind, ...) { va_list args; - struct icalcomponent_impl *impl = icalcomponent_new_impl(kind); + icalcomponent *impl = icalcomponent_new_impl(kind); if (impl == 0){ return 0; @@ -163,23 +163,26 @@ icalcomponent_vanew (icalcomponent_kind kind, ...) icalcomponent_add_children(impl, args); va_end(args); - return (icalcomponent*) impl; + return impl; } +/** @brief Constructor + */ icalcomponent* icalcomponent_new_from_string(char* str) { return icalparser_parse_string(str); } -icalcomponent* icalcomponent_new_clone(icalcomponent* component) +/** @brief Constructor + */ +icalcomponent* icalcomponent_new_clone(icalcomponent* old) { - struct icalcomponent_impl *old = (struct icalcomponent_impl*)component; - struct icalcomponent_impl *new; + icalcomponent *new; icalproperty *p; icalcomponent *c; pvl_elem itr; - icalerror_check_arg_rz( (component!=0), "component"); + icalerror_check_arg_rz( (old!=0), "component"); new = icalcomponent_new_impl(old->kind); @@ -193,8 +196,7 @@ icalcomponent* icalcomponent_new_clone(icalcomponent* component) itr = pvl_next(itr)) { p = (icalproperty*)pvl_data(itr); - if (p != 0) - icalcomponent_add_property(new,icalproperty_new_clone(p)); + icalcomponent_add_property(new,icalproperty_new_clone(p)); } @@ -210,15 +212,15 @@ icalcomponent* icalcomponent_new_clone(icalcomponent* component) } - +/*** @brief Destructor + */ void -icalcomponent_free (icalcomponent* component) +icalcomponent_free (icalcomponent* c) { icalproperty* prop; icalcomponent* comp; - struct icalcomponent_impl *c = (struct icalcomponent_impl*)component; - icalerror_check_arg_rv( (component!=0), "component"); + icalerror_check_arg_rv( (c!=0), "component"); #ifdef ICAL_FREE_ON_LIST_IS_ERROR icalerror_assert( (c->parent ==0),"Tried to free a component that is still attached to a parent component"); @@ -228,19 +230,22 @@ icalcomponent_free (icalcomponent* component) } #endif - if(component != 0 ){ + if(c != 0 ){ - while( (prop=pvl_pop(c->properties)) != 0){ - assert(prop != 0); - icalproperty_set_parent(prop,0); - icalproperty_free(prop); - } - - pvl_free(c->properties); + if ( c->properties != 0 ) + { + while( (prop=pvl_pop(c->properties)) != 0){ + assert(prop != 0); + icalproperty_set_parent(prop,0); + icalproperty_free(prop); + } + pvl_free(c->properties); + } + while( (comp=pvl_data(pvl_head(c->components))) != 0){ assert(comp!=0); - icalcomponent_remove_component(component,comp); + icalcomponent_remove_component(c,comp); icalcomponent_free(comp); } @@ -264,38 +269,40 @@ icalcomponent_free (icalcomponent* component) free(c); } - } char* -icalcomponent_as_ical_string (icalcomponent* component) +icalcomponent_as_ical_string (icalcomponent* impl) { char* buf, *out_buf; - char* tmp_buf; + const char* tmp_buf; size_t buf_size = 1024; char* buf_ptr = 0; pvl_elem itr; - struct icalcomponent_impl *impl = (struct icalcomponent_impl*)component; +/* WIN32 automatically adds the \r, Anybody else need it? #ifdef ICAL_UNIX_NEWLINE +*/ char newline[] = "\n"; +/* #else char newline[] = "\r\n"; #endif +*/ icalcomponent *c; icalproperty *p; - icalcomponent_kind kind = icalcomponent_isa(component); + icalcomponent_kind kind = icalcomponent_isa(impl); const char* kind_string; buf = icalmemory_new_buffer(buf_size); buf_ptr = buf; - icalerror_check_arg_rz( (component!=0), "component"); + icalerror_check_arg_rz( (impl!=0), "component"); icalerror_check_arg_rz( (kind!=ICAL_NO_COMPONENT), "component kind is ICAL_NO_COMPONENT"); - kind_string = icalenum_component_kind_to_string(kind); + kind_string = icalcomponent_kind_to_string(kind); icalerror_check_arg_rz( (kind_string!=0),"Unknown kind of component"); @@ -332,7 +339,7 @@ icalcomponent_as_ical_string (icalcomponent* component) icalmemory_append_string(&buf, &buf_ptr, &buf_size, "END:"); icalmemory_append_string(&buf, &buf_ptr, &buf_size, - icalenum_component_kind_to_string(kind)); + icalcomponent_kind_to_string(kind)); icalmemory_append_string(&buf, &buf_ptr, &buf_size, newline); out_buf = icalmemory_tmp_copy(buf); @@ -345,11 +352,8 @@ icalcomponent_as_ical_string (icalcomponent* component) int icalcomponent_is_valid (icalcomponent* component) { - struct icalcomponent_impl *impl = (struct icalcomponent_impl *)component; - - - if ( (strcmp(impl->id,"comp") == 0) && - impl->kind != ICAL_NO_COMPONENT){ + if ( (strcmp(component->id,"comp") == 0) && + component->kind != ICAL_NO_COMPONENT){ return 1; } else { return 0; @@ -359,14 +363,13 @@ icalcomponent_is_valid (icalcomponent* component) icalcomponent_kind -icalcomponent_isa (icalcomponent* component) +icalcomponent_isa (const icalcomponent* component) { - struct icalcomponent_impl *impl = (struct icalcomponent_impl *)component; - icalerror_check_arg_rz( (component!=0), "component"); + icalerror_check_arg_rx( (component!=0), "component", ICAL_NO_COMPONENT); if(component != 0) { - return impl->kind; + return component->kind; } return ICAL_NO_COMPONENT; @@ -376,7 +379,7 @@ icalcomponent_isa (icalcomponent* component) int icalcomponent_isa_component (void* component) { - struct icalcomponent_impl *impl = (struct icalcomponent_impl *)component; + icalcomponent *impl = component; icalerror_check_arg_rz( (component!=0), "component"); @@ -388,63 +391,32 @@ icalcomponent_isa_component (void* component) } -int icalcomponent_property_sorter(void *a, void *b) -{ - icalproperty_kind kinda, kindb; - const char *ksa, *ksb; - - kinda = icalproperty_isa((icalproperty*)a); - kindb = icalproperty_isa((icalproperty*)b); - - ksa = icalenum_property_kind_to_string(kinda); - ksb = icalenum_property_kind_to_string(kindb); - - return strcmp(ksa,ksb); -} - - void icalcomponent_add_property (icalcomponent* component, icalproperty* property) { - struct icalcomponent_impl *impl; - icalerror_check_arg_rv( (component!=0), "component"); icalerror_check_arg_rv( (property!=0), "property"); - impl = (struct icalcomponent_impl*)component; - 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"); icalproperty_set_parent(property,component); -#ifdef ICAL_INSERT_ORDERED - pvl_insert_ordered(impl->properties, - icalcomponent_property_sorter,property); -#else - pvl_push(impl->properties,property); -#endif - + pvl_push(component->properties,property); } void icalcomponent_remove_property (icalcomponent* component, icalproperty* property) { - struct icalcomponent_impl *impl; pvl_elem itr, next_itr; - struct icalproperty_impl *pimpl; icalerror_check_arg_rv( (component!=0), "component"); icalerror_check_arg_rv( (property!=0), "property"); - impl = (struct icalcomponent_impl*)component; - - pimpl = (struct icalproperty_impl*)property; - icalerror_assert( (icalproperty_get_parent(property)),"The property is not a member of a component"); - for( itr = pvl_head(impl->properties); + for( itr = pvl_head(component->properties); itr != 0; itr = next_itr) { @@ -452,11 +424,11 @@ icalcomponent_remove_property (icalcomponent* component, icalproperty* property) if( pvl_data(itr) == (void*)property ){ - if (impl->property_iterator == itr){ - impl->property_iterator = pvl_next(itr); + if (component->property_iterator == itr){ + component->property_iterator = pvl_next(itr); } - pvl_remove( impl->properties, itr); + pvl_remove( component->properties, itr); icalproperty_set_parent(property,0); } } @@ -468,11 +440,10 @@ icalcomponent_count_properties (icalcomponent* component, { int count=0; pvl_elem itr; - struct icalcomponent_impl *impl = (struct icalcomponent_impl*)component; icalerror_check_arg_rz( (component!=0), "component"); - for( itr = pvl_head(impl->properties); + for( itr = pvl_head(component->properties); itr != 0; itr = pvl_next(itr)) { @@ -489,23 +460,19 @@ icalcomponent_count_properties (icalcomponent* component, icalproperty* icalcomponent_get_current_property (icalcomponent* component) { - - struct icalcomponent_impl *c = (struct icalcomponent_impl*)component; icalerror_check_arg_rz( (component!=0),"component"); - if ((c->property_iterator==0)){ + if ((component->property_iterator==0)){ return 0; } - return (icalproperty*) pvl_data(c->property_iterator); - + return (icalproperty*) pvl_data(component->property_iterator); } icalproperty* -icalcomponent_get_first_property (icalcomponent* component, icalproperty_kind kind) +icalcomponent_get_first_property (icalcomponent* c, icalproperty_kind kind) { - struct icalcomponent_impl *c = (struct icalcomponent_impl*)component; - icalerror_check_arg_rz( (component!=0),"component"); + icalerror_check_arg_rz( (c!=0),"component"); for( c->property_iterator = pvl_head(c->properties); c->property_iterator != 0; @@ -522,10 +489,9 @@ icalcomponent_get_first_property (icalcomponent* component, icalproperty_kind ki } icalproperty* -icalcomponent_get_next_property (icalcomponent* component, icalproperty_kind kind) +icalcomponent_get_next_property (icalcomponent* c, icalproperty_kind kind) { - struct icalcomponent_impl *c = (struct icalcomponent_impl*)component; - icalerror_check_arg_rz( (component!=0),"component"); + icalerror_check_arg_rz( (c!=0),"component"); if (c->property_iterator == 0){ return 0; @@ -554,31 +520,28 @@ icalcomponent_get_properties (icalcomponent* component, icalproperty_kind kind); void icalcomponent_add_component (icalcomponent* parent, icalcomponent* child) { - struct icalcomponent_impl *impl, *cimpl; - icalerror_check_arg_rv( (parent!=0), "parent"); icalerror_check_arg_rv( (child!=0), "child"); - impl = (struct icalcomponent_impl*)parent; - cimpl = (struct icalcomponent_impl*)child; - - 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"); + if (child->parent !=0) { + icalerror_set_errno(ICAL_USAGE_ERROR); + } - cimpl->parent = parent; + child->parent = parent; - pvl_push(impl->components,child); + pvl_push(parent->components,child); /* If the new component is a VTIMEZONE, add it to our array. */ - if (cimpl->kind == ICAL_VTIMEZONE_COMPONENT) { + if (child->kind == ICAL_VTIMEZONE_COMPONENT) { /* FIXME: Currently we are also creating this array when loading in a builtin VTIMEZONE, when we don't need it. */ - if (!impl->timezones) - impl->timezones = icaltimezone_array_new (); + if (!parent->timezones) + parent->timezones = icaltimezone_array_new (); - icaltimezone_array_append_from_vtimezone (impl->timezones, child); + icaltimezone_array_append_from_vtimezone (parent->timezones, child); /* Flag that we need to sort it before doing any binary searches. */ - impl->timezones_sorted = 0; + parent->timezones_sorted = 0; } } @@ -586,32 +549,28 @@ icalcomponent_add_component (icalcomponent* parent, icalcomponent* child) void icalcomponent_remove_component (icalcomponent* parent, icalcomponent* child) { - struct icalcomponent_impl *impl,*cimpl; pvl_elem itr, next_itr; icalerror_check_arg_rv( (parent!=0), "parent"); icalerror_check_arg_rv( (child!=0), "child"); - impl = (struct icalcomponent_impl*)parent; - cimpl = (struct icalcomponent_impl*)child; - /* If the component is a VTIMEZONE, remove it from our array as well. */ - if (cimpl->kind == ICAL_VTIMEZONE_COMPONENT) { + if (child->kind == ICAL_VTIMEZONE_COMPONENT) { icaltimezone *zone; int i, num_elements; - num_elements = impl->timezones ? impl->timezones->num_elements : 0; + num_elements = parent->timezones ? parent->timezones->num_elements : 0; for (i = 0; i < num_elements; i++) { - zone = icalarray_element_at (impl->timezones, i); + zone = icalarray_element_at (parent->timezones, i); if (icaltimezone_get_component (zone) == child) { icaltimezone_free (zone, 0); - icalarray_remove_element_at (impl->timezones, i); + icalarray_remove_element_at (parent->timezones, i); break; } } } - for( itr = pvl_head(impl->components); + for( itr = pvl_head(parent->components); itr != 0; itr = next_itr) { @@ -619,16 +578,16 @@ icalcomponent_remove_component (icalcomponent* parent, icalcomponent* child) if( pvl_data(itr) == (void*)child ){ - if (impl->component_iterator == itr){ + if (parent->component_iterator == itr){ /* Don't let the current iterator become invalid */ /* HACK. The semantics for this are troubling. */ - impl->component_iterator = - pvl_next(impl->component_iterator); + parent->component_iterator = + pvl_next(parent->component_iterator); } - pvl_remove( impl->components, itr); - cimpl->parent = 0; + pvl_remove( parent->components, itr); + child->parent = 0; break; } } @@ -641,11 +600,10 @@ icalcomponent_count_components (icalcomponent* component, { int count=0; pvl_elem itr; - struct icalcomponent_impl *impl = (struct icalcomponent_impl*)component; icalerror_check_arg_rz( (component!=0), "component"); - for( itr = pvl_head(impl->components); + for( itr = pvl_head(component->components); itr != 0; itr = pvl_next(itr)) { @@ -661,24 +619,20 @@ icalcomponent_count_components (icalcomponent* component, icalcomponent* icalcomponent_get_current_component(icalcomponent* component) { - struct icalcomponent_impl *c = (struct icalcomponent_impl*)component; - icalerror_check_arg_rz( (component!=0),"component"); - if (c->component_iterator == 0){ + if (component->component_iterator == 0){ return 0; } - return (icalcomponent*) pvl_data(c->component_iterator); + return (icalcomponent*) pvl_data(component->component_iterator); } icalcomponent* -icalcomponent_get_first_component (icalcomponent* component, +icalcomponent_get_first_component (icalcomponent* c, icalcomponent_kind kind) { - struct icalcomponent_impl *c = (struct icalcomponent_impl*)component; - - icalerror_check_arg_rz( (component!=0),"component"); + icalerror_check_arg_rz( (c!=0),"component"); for( c->component_iterator = pvl_head(c->components); c->component_iterator != 0; @@ -697,11 +651,9 @@ icalcomponent_get_first_component (icalcomponent* component, icalcomponent* -icalcomponent_get_next_component (icalcomponent* component, icalcomponent_kind kind) +icalcomponent_get_next_component (icalcomponent* c, icalcomponent_kind kind) { - struct icalcomponent_impl *c = (struct icalcomponent_impl*)component; - - icalerror_check_arg_rz( (component!=0),"component"); + icalerror_check_arg_rz( (c!=0),"component"); if (c->component_iterator == 0){ return 0; @@ -734,31 +686,54 @@ icalcomponent* icalcomponent_get_first_real_component(icalcomponent *c) if(kind == ICAL_VEVENT_COMPONENT || kind == ICAL_VTODO_COMPONENT || - kind == ICAL_VJOURNAL_COMPONENT ){ + kind == ICAL_VJOURNAL_COMPONENT || + kind == ICAL_VFREEBUSY_COMPONENT || + kind == ICAL_VQUERY_COMPONENT || + kind == ICAL_VREPLY_COMPONENT || + kind == ICAL_VAGENDA_COMPONENT){ return comp; } } return 0; } -struct icaltime_span icalcomponent_get_span(icalcomponent* comp) + +/** @brief Get the timespan covered by this component, in UTC + * (deprecated) + * + * see icalcomponent_foreach_recurrence() for a better way to + * extract spans from an component. + * + * This method can be called on either a VCALENDAR or any real + * component. If the VCALENDAR contains no real component, but + * contains a VTIMEZONE, we return that span instead. + * This might not be a desirable behavior; we keep it for now + * for backward compatibility, but it might be deprecated at a + * future time. + * + * FIXME this API needs to be clarified. DTEND is defined as the + * first available time after the end of this event, so the span + * should actually end 1 second before DTEND. + */ + +icaltime_span icalcomponent_get_span(icalcomponent* comp) { icalcomponent *inner; - icalproperty *p, *duration; icalcomponent_kind kind; - struct icaltime_span span; - struct icaltimetype start; + icaltime_span span; + struct icaltimetype start, end; span.start = 0; span.end = 0; span.is_busy= 1; /* initial Error checking */ + if (comp == NULL) { + return span; + } -/* icalerror_check_arg_rz( (comp!=0),"comp");*/ - + /* FIXME this might go away */ kind = icalcomponent_isa(comp); - if(kind == ICAL_VCALENDAR_COMPONENT){ inner = icalcomponent_get_first_real_component(comp); @@ -790,73 +765,330 @@ struct icaltime_span icalcomponent_get_span(icalcomponent* comp) } + /* Get to work. starting with DTSTART */ + start = icalcomponent_get_dtstart(comp); + if (icaltime_is_null_time(start)) { + return span; + } + span.start = icaltime_as_timet_with_zone(start, + icaltimezone_get_utc_timezone()); + /* The end time could be specified as either a DTEND or a DURATION */ + /* icalcomponent_get_dtend takes care of these cases. */ + end = icalcomponent_get_dtend(comp); + if (icaltime_is_null_time(end)) { + if (!icaltime_is_date(start)) { + /* If dtstart is a DATE-TIME and there is no DTEND nor DURATION + it takes no time */ + span.start = 0; + return span; + } else { + end = start; + } + } - /* Get to work. starting with DTSTART */ + span.end = icaltime_as_timet_with_zone(end, + icaltimezone_get_utc_timezone()); + if (icaltime_is_date(start)) { + /* Until the end of the day*/ + span.end += 60*60*24 - 1; + } - p = icalcomponent_get_first_property(inner, ICAL_DTSTART_PROPERTY); + return span; - if (p ==0 ) { - icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); - /*icalerror_warn("icalcomponent_get_span: component has no DTSTART time");*/ - return span; +} + +/** + * Decide if this recurrance is acceptable + * + * @param comp A valid icalcomponent. + * @param dtstart The base dtstart value for this component. + * @param recurtime The time to test against. + * + * @return true if the recurrence value is excluded, false otherwise. + * + * This function decides if a specific recurrence value is + * excluded by EXRULE or EXDATE properties. + * + * It's not the most efficient code. You might get better performance + * if you assume that recurtime is always increasing for each + * call. Then you could: + * + * - sort the EXDATE values + * - save the state of each EXRULE iterator for the next call. + * + * In this case though you don't need to worry how you call this + * function. It will always return the correct result. + */ + +int icalproperty_recurrence_is_excluded(icalcomponent *comp, + struct icaltimetype *dtstart, + struct icaltimetype *recurtime) { + icalproperty *exdate, *exrule; + + if (comp == NULL || + dtstart == NULL || + recurtime == NULL || + icaltime_is_null_time(*recurtime)) + /* BAD DATA */ + return 1; + + /** first test against the exdate values **/ + for (exdate = icalcomponent_get_first_property(comp,ICAL_EXDATE_PROPERTY); + exdate != NULL; + exdate = icalcomponent_get_next_property(comp,ICAL_EXDATE_PROPERTY)) { + + struct icaltimetype exdatetime = icalproperty_get_exdate(exdate); + + if (icaltime_compare(*recurtime, exdatetime) == 0) { + /** MATCHED **/ + return 1; } + } + /** Now test against the EXRULEs **/ + for (exrule = icalcomponent_get_first_property(comp,ICAL_EXRULE_PROPERTY); + exdate != NULL; + exdate = icalcomponent_get_next_property(comp,ICAL_EXRULE_PROPERTY)) { + + struct icalrecurrencetype recur = icalproperty_get_exrule(exrule); + icalrecur_iterator *exrule_itr = icalrecur_iterator_new(recur, *dtstart); + struct icaltimetype exrule_time; + + while (1) { + int result; + exrule_time = icalrecur_iterator_next(exrule_itr); + + if (icaltime_is_null_time(exrule_time)) + break; + + result = icaltime_compare(*recurtime, exrule_time); + if (result == 0) { + icalrecur_iterator_free(exrule_itr); + return 1; /** MATCH **/ + } + if (result == 1) + break; /** exrule_time > recurtime **/ + } - start = icalproperty_get_dtstart(p); + icalrecur_iterator_free(exrule_itr); + } - icalerror_clear_errno(); + return 0; /** no matches **/ +} - /* FIXME: Needs updating to new icaltimezone functions. */ -#if 0 - span.start = icalcomponent_convert_time(p); -#endif +/** + * @brief Return the busy status based on the TRANSP property. + * + * @param comp A valid icalcomponent. + * + * @return 1 if the event is a busy item, 0 if it is not. + */ -#ifdef TEST_CONVERT_TIME - printf("convert time:\n %s %s", - icalproperty_as_ical_string(p), ctime(&span.start)); -#endif +static int icalcomponent_is_busy(icalcomponent *comp) { + icalproperty *transp; + enum icalproperty_status status; + int ret = 1; - if(icalerrno != ICAL_NO_ERROR){ - span.start = 0; - return span; + /** @todo check access control here, converting busy->free if the + permissions do not allow access... */ + + /* Is this a busy time? Check the TRANSP property */ + transp = icalcomponent_get_first_property(comp, ICAL_TRANSP_PROPERTY); + + if (transp) { + icalvalue *transp_val = icalproperty_get_value(transp); + + switch (icalvalue_get_transp(transp_val)) { + case ICAL_TRANSP_OPAQUE: + case ICAL_TRANSP_OPAQUENOCONFLICT: + case ICAL_TRANSP_NONE: + ret = 1; + break; + case ICAL_TRANSP_TRANSPARENT: + case ICAL_TRANSP_TRANSPARENTNOCONFLICT: + ret = 0; + break; + default: + ret = 0; + break; + } + } + status = icalcomponent_get_status(comp); + if (ret && status) { + switch (status) { + case ICAL_STATUS_CANCELLED: + case ICAL_STATUS_TENTATIVE: + ret = 0; + break; + default: + break; } + } + return(ret); +} - /* The end time could be specified as either a DTEND or a DURATION */ - p = icalcomponent_get_first_property(inner, ICAL_DTEND_PROPERTY); - duration = icalcomponent_get_first_property(inner, ICAL_DURATION_PROPERTY); - if (p==0 && duration == 0 && start.is_date != 1) { - icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); - /*icalerror_warn("icalcomponent_get_span: component has neither DTEND nor DURATION time");*/ - span.start = 0; - return span; - } - if (p!=0){ - /* FIXME: Needs updating to new icaltimezone functions. */ -#if 0 - span.end = icalcomponent_convert_time(p); -#endif - } else if (start.is_date == 1) { - /* Duration is all day */ - span.end = span.start + 60*60*24; - } else { - /* Use the duration */ - struct icaldurationtype dur; - time_t durt; - - - dur = icalproperty_get_duration(duration); - durt = icaldurationtype_as_int(dur); - span.end = span.start+durt; +/** + * @brief cycle through all recurrances of an event + * + * @param comp A valid VEVENT component + * @param start Ignore timespans before this + * @param end Ignore timespans after this + * @param callback Function called for each timespan within the range + * @param callback_data Pointer passed back to the callback function + * + * This function will call the specified callback function for once + * for the base value of DTSTART, and foreach recurring date/time + * value. + * + * It will filter out events that are specified as an EXDATE or an EXRULE. + * + * @todo We do not filter out duplicate RRULES/RDATES + * @todo We do not handle RDATEs with explicit periods + */ + +void icalcomponent_foreach_recurrence(icalcomponent* comp, + struct icaltimetype start, + struct icaltimetype end, + void (*callback)(icalcomponent *comp, + struct icaltime_span *span, + void *data), + void *callback_data) +{ + struct icaltimetype dtstart, dtend; + icaltime_span recurspan, basespan, limit_span; + time_t limit_start, limit_end; + int dtduration; + icalproperty *rrule, *rdate; + struct icaldurationtype dur; + pvl_elem property_iterator; /* for saving the iterator */ + + if (comp == NULL || callback == NULL) + return; + + dtstart = icalcomponent_get_dtstart(comp); + + if (icaltime_is_null_time(dtstart)) + return; + + + /* The end time could be specified as either a DTEND or a DURATION */ + /* icalcomponent_get_dtend takes care of these cases. */ + dtend = icalcomponent_get_dtend(comp); + + /* Now set up the base span for this item, corresponding to the + base DTSTART and DTEND */ + basespan = icaltime_span_new(dtstart, dtend, 1); + + basespan.is_busy = icalcomponent_is_busy(comp); + + + /** Calculate the ceiling and floor values.. **/ + limit_start = icaltime_as_timet_with_zone(start, icaltimezone_get_utc_timezone()); + if (!icaltime_is_null_time(end)) + limit_end = icaltime_as_timet_with_zone(end, icaltimezone_get_utc_timezone()); + else + limit_end = INT_MAX; /* max 32 bit time_t */ + + limit_span.start = limit_start; + limit_span.end = limit_end; + + + /* Do the callback for the initial DTSTART entry */ + + if (!icalproperty_recurrence_is_excluded(comp, &dtstart, &dtstart)) { + /** call callback action **/ + if (icaltime_span_overlaps(&basespan, &limit_span)) + (*callback) (comp, &basespan, callback_data); + } + + recurspan = basespan; + dtduration = basespan.end - basespan.start; + + /* Now cycle through the rrule entries */ + for (rrule = icalcomponent_get_first_property(comp,ICAL_RRULE_PROPERTY); + rrule != NULL; + rrule = icalcomponent_get_next_property(comp,ICAL_RRULE_PROPERTY)) { + + struct icalrecurrencetype recur = icalproperty_get_rrule(rrule); + icalrecur_iterator *rrule_itr = icalrecur_iterator_new(recur, dtstart); + struct icaltimetype rrule_time; + + while (1) { + rrule_time = icalrecur_iterator_next(rrule_itr); + + if (icaltime_is_null_time(rrule_time)) + break; + + if (!icaltime_compare(rrule_time, dtstart)) + continue; + + dur = icaltime_subtract(rrule_time, dtstart); + + recurspan.start = basespan.start + icaldurationtype_as_int(dur); + recurspan.end = recurspan.start + dtduration; + + /** save the iterator ICK! **/ + property_iterator = comp->property_iterator; + + if (!icalproperty_recurrence_is_excluded(comp, &dtstart, &rrule_time)) { + /** call callback action **/ + if (icaltime_span_overlaps(&recurspan, &limit_span)) + (*callback) (comp, &recurspan, callback_data); + } + comp->property_iterator = property_iterator; + } /* end of iteration over a specific RRULE */ + + icalrecur_iterator_free(rrule_itr); + } /* end of RRULE loop */ + + + /** Now process RDATE entries **/ + for (rdate = icalcomponent_get_first_property(comp,ICAL_RDATE_PROPERTY); + rdate != NULL; + rdate = icalcomponent_get_next_property(comp,ICAL_RDATE_PROPERTY)) { + + struct icaldatetimeperiodtype rdate_period = icalproperty_get_rdate(rdate); + + /** RDATES can specify raw datetimes, periods, or dates. + we only support raw datetimes for now.. + + @todo Add support for other types **/ + + if (icaltime_is_null_time(rdate_period.time)) + continue; + + dur = icaltime_subtract(rdate_period.time, dtstart); + + recurspan.start = basespan.start + icaldurationtype_as_int(dur); + recurspan.end = recurspan.start + dtduration; + + /** save the iterator ICK! **/ + property_iterator = comp->property_iterator; + + if (!icalproperty_recurrence_is_excluded(comp, &dtstart, &rdate_period.time)) { + /** call callback action **/ + (*callback) (comp, &recurspan, callback_data); } + comp->property_iterator = property_iterator; + } +} + - return span; +int icalcomponent_check_restrictions(icalcomponent* comp){ + icalerror_check_arg_rz(comp!=0,"comp"); + return icalrestriction_check(comp); } +/** @brief returns the number of errors encountered parsing the data + * + * This function counts the number times the X-LIC-ERROR occurs + * in the data structure. + */ int icalcomponent_count_errors(icalcomponent* component) { @@ -864,9 +1096,8 @@ int icalcomponent_count_errors(icalcomponent* component) icalproperty *p; icalcomponent *c; pvl_elem itr; - struct icalcomponent_impl *impl = (struct icalcomponent_impl*)component; - for( itr = pvl_head(impl->properties); + for( itr = pvl_head(component->properties); itr != 0; itr = pvl_next(itr)) { @@ -879,7 +1110,7 @@ int icalcomponent_count_errors(icalcomponent* component) } - for( itr = pvl_head(impl->components); + for( itr = pvl_head(component->components); itr != 0; itr = pvl_next(itr)) { @@ -898,9 +1129,8 @@ void icalcomponent_strip_errors(icalcomponent* component) icalproperty *p; icalcomponent *c; pvl_elem itr, next_itr; - struct icalcomponent_impl *impl = (struct icalcomponent_impl*)component; - for( itr = pvl_head(impl->properties); + for( itr = pvl_head(component->properties); itr != 0; itr = next_itr) { @@ -913,7 +1143,7 @@ void icalcomponent_strip_errors(icalcomponent* component) } } - for( itr = pvl_head(impl->components); + for( itr = pvl_head(component->components); itr != 0; itr = pvl_next(itr)) { @@ -967,16 +1197,14 @@ void icalcomponent_convert_errors(icalcomponent* component) } default: { + break; } } if (rst.code != ICAL_UNKNOWN_STATUS){ rst.debug = icalproperty_get_xlicerror(p); icalcomponent_add_property(component, - icalproperty_new_requeststatus( - icalreqstattype_as_string(rst) - ) - ); + icalproperty_new_requeststatus(rst)); icalcomponent_remove_property(component,p); } @@ -994,16 +1222,12 @@ void icalcomponent_convert_errors(icalcomponent* component) icalcomponent* icalcomponent_get_parent(icalcomponent* component) { - struct icalcomponent_impl *c = (struct icalcomponent_impl*)component; - - return c->parent; + return component->parent; } void icalcomponent_set_parent(icalcomponent* component, icalcomponent* parent) { - struct icalcomponent_impl *c = (struct icalcomponent_impl*)component; - - c->parent = parent; + component->parent = parent; } icalcompiter icalcompiter_null = {ICAL_NO_COMPONENT,0}; @@ -1022,6 +1246,7 @@ static struct icalcomponent_kind_map component_map[] = { ICAL_VTODO_COMPONENT, "VTODO" }, { ICAL_VJOURNAL_COMPONENT, "VJOURNAL" }, { ICAL_VCALENDAR_COMPONENT, "VCALENDAR" }, + { ICAL_VAGENDA_COMPONENT, "VAGENDA" }, { ICAL_VFREEBUSY_COMPONENT, "VFREEBUSY" }, { ICAL_VTIMEZONE_COMPONENT, "VTIMEZONE" }, { ICAL_VALARM_COMPONENT, "VALARM" }, @@ -1031,9 +1256,10 @@ static struct icalcomponent_kind_map component_map[] = { ICAL_VSCHEDULE_COMPONENT, "SCHEDULE" }, /* CAP components */ - { ICAL_VQUERY_COMPONENT, "VQUERY" }, { ICAL_VCAR_COMPONENT, "VCAR" }, { ICAL_VCOMMAND_COMPONENT, "VCOMMAND" }, + { ICAL_VQUERY_COMPONENT, "VQUERY" }, + { ICAL_VREPLY_COMPONENT, "VREPLY" }, /* libical private components */ { ICAL_XLICINVALID_COMPONENT, "X-LIC-UNKNOWN" }, @@ -1046,6 +1272,16 @@ static struct icalcomponent_kind_map component_map[] = }; +int icalcomponent_kind_is_valid(const icalcomponent_kind kind) +{ + int i = 0; + do { + if (component_map[i].kind == kind) + return 1; + } while (component_map[i++].kind != ICAL_NO_COMPONENT); + + return 0; +} const char* icalcomponent_kind_to_string(icalcomponent_kind kind) { @@ -1083,15 +1319,15 @@ icalcomponent_kind icalcomponent_string_to_kind(const char* string) icalcompiter icalcomponent_begin_component(icalcomponent* component,icalcomponent_kind kind) { - struct icalcomponent_impl *impl = (struct icalcomponent_impl*)component; icalcompiter itr; pvl_elem i; itr.kind = kind; + itr.iter = NULL; - icalerror_check_arg_re( (component!=0),"component",icalcompiter_null); + icalerror_check_arg_re(component!=0,"component",icalcompiter_null); - for( i = pvl_head(impl->components); i != 0; i = pvl_next(i)) { + for( i = pvl_head(component->components); i != 0; i = pvl_next(i)) { icalcomponent *c = (icalcomponent*) pvl_data(i); @@ -1109,15 +1345,14 @@ icalcomponent_begin_component(icalcomponent* component,icalcomponent_kind kind) icalcompiter icalcomponent_end_component(icalcomponent* component,icalcomponent_kind kind) { - struct icalcomponent_impl *impl = (struct icalcomponent_impl*)component; icalcompiter itr; pvl_elem i; itr.kind = kind; - icalerror_check_arg_re( (component!=0),"component",icalcompiter_null); + icalerror_check_arg_re(component!=0,"component",icalcompiter_null); - for( i = pvl_tail(impl->components); i != 0; i = pvl_prior(i)) { + for( i = pvl_tail(component->components); i != 0; i = pvl_prior(i)) { icalcomponent *c = (icalcomponent*) pvl_data(i); @@ -1198,140 +1433,240 @@ icalcomponent* icalcomponent_get_inner(icalcomponent* comp) } } +/** @brief sets the METHOD property to the given method + */ -void icalcomponent_set_dtstart(icalcomponent* comp, struct icaltimetype v) +void icalcomponent_set_method(icalcomponent* comp, icalproperty_method method) { + icalproperty *prop + = icalcomponent_get_first_property(comp, ICAL_METHOD_PROPERTY); - icalcomponent *inner = icalcomponent_get_inner(comp); + + if (prop == 0){ + prop = icalproperty_new_method(method); + icalcomponent_add_property(comp, prop); + } + + icalproperty_set_method(prop,method); + +} + +/** @brief returns the METHOD property + */ + +icalproperty_method icalcomponent_get_method(icalcomponent* comp) +{ icalproperty *prop - = icalcomponent_get_first_property(inner, ICAL_DTSTART_PROPERTY); + = icalcomponent_get_first_property(comp,ICAL_METHOD_PROPERTY); + if (prop == 0){ + return ICAL_METHOD_NONE; + } + + return icalproperty_get_method(prop); +} + +#define ICALSETUPSET(p_kind) \ + icalcomponent *inner; \ + icalproperty *prop; \ + icalerror_check_arg_rv(comp!=0,"comp");\ + inner = icalcomponent_get_inner(comp); \ + if(inner == 0){\ + icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);\ + return;\ + }\ + prop = icalcomponent_get_first_property(inner, p_kind); + + +/** @brief Set DTSTART property to given icaltime + * + * This method respects the icaltime type (DATE vs DATE-TIME) and + * timezone (or lack thereof). + */ +void icalcomponent_set_dtstart(icalcomponent* comp, struct icaltimetype v) +{ + char *tzid; + ICALSETUPSET(ICAL_DTSTART_PROPERTY); if (prop == 0){ prop = icalproperty_new_dtstart(v); icalcomponent_add_property(inner, prop); + } else { + icalproperty_remove_parameter_by_kind(prop, ICAL_TZID_PARAMETER); } icalproperty_set_dtstart(prop,v); + if ((tzid = icaltime_get_tzid(v)) != NULL && !icaltime_is_utc(v)) { + icalproperty_add_parameter(prop, icalparameter_new_tzid(tzid)); + } } +/** @brief Get a DATE or DATE-TIME property as an icaltime + * + * If the property is a DATE-TIME with a timezone parameter and a + * corresponding VTIMEZONE is present in the component, the + * returned component will already be in the correct timezone; + * otherwise the caller is responsible for converting it. + * + * FIXME this is useless until we can flag the failure + */ +static struct icaltimetype +icalcomponent_get_datetime(icalcomponent *comp, icalproperty *prop) { + + icalcomponent *c; + icalparameter *param; + struct icaltimetype ret; + + ret = icalvalue_get_datetime(icalproperty_get_value(prop)); + + if ((param = icalproperty_get_first_parameter(prop, ICAL_TZID_PARAMETER)) + != NULL) { + const char *tzid = icalparameter_get_tzid(param); + icaltimezone *tz = NULL; + + for (c = comp; c != NULL; c = icalcomponent_get_parent(c)) { + tz = icalcomponent_get_timezone(c, tzid); + if (tz != NULL) + break; + } + + if (tz == NULL) + tz = icaltimezone_get_builtin_timezone(tzid); + if (tz != NULL) + ret = icaltime_set_timezone(&ret, tz); + } + + return ret; +} + +/** @brief Get DTSTART property as an icaltime + * + * If DTSTART is a DATE-TIME with a timezone parameter and a + * corresponding VTIMEZONE is present in the component, the + * returned component will already be in the correct timezone; + * otherwise the caller is responsible for converting it. + * + * FIXME this is useless until we can flag the failure + */ struct icaltimetype icalcomponent_get_dtstart(icalcomponent* comp) { icalcomponent *inner = icalcomponent_get_inner(comp); - icalproperty *prop - = icalcomponent_get_first_property(inner,ICAL_DTSTART_PROPERTY); + icalproperty *prop; + prop = icalcomponent_get_first_property(inner,ICAL_DTSTART_PROPERTY); if (prop == 0){ return icaltime_null_time(); } - - return icalproperty_get_dtstart(prop); -} + return icalcomponent_get_datetime(comp, prop); +} +/** @brief Get DTEND property as an icaltime + * + * If a DTEND property is not present but a DURATION is, we use + * that to determine the proper end. + * + * If DTSTART is a DATE-TIME with a timezone parameter and a + * corresponding VTIMEZONE is present in the component, the + * returned component will already be in the correct timezone; + * otherwise the caller is responsible for converting it. + * + * FIXME this is useless until we can flag the failure + */ struct icaltimetype icalcomponent_get_dtend(icalcomponent* comp) { icalcomponent *inner = icalcomponent_get_inner(comp); - icalproperty *end_prop = icalcomponent_get_first_property(inner,ICAL_DTEND_PROPERTY); - icalproperty *dur_prop = icalcomponent_get_first_property(inner, ICAL_DURATION_PROPERTY); + struct icaltimetype ret = icaltime_null_time(); - - if( end_prop == 0 && dur_prop == 0){ - return icaltime_null_time(); - } else if ( end_prop != 0) { - return icalproperty_get_dtend(end_prop); + if ( end_prop != 0) { + ret = icalcomponent_get_datetime(comp, end_prop); } else if ( dur_prop != 0) { - + struct icaltimetype start = icalcomponent_get_dtstart(inner); struct icaldurationtype duration = icalproperty_get_duration(dur_prop); - - struct icaltimetype end = icaltime_add(start,duration); - return end; - - } else { - /* Error, both duration and dtend have been specified */ - icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); - return icaltime_null_time(); + struct icaltimetype end = icaltime_add(start,duration); + ret = end; } - -} + return ret; +} +/** @brief Set DTEND property to given icaltime + * + * This method respects the icaltime type (DATE vs DATE-TIME) and + * timezone (or lack thereof). + * + * This also checks that a DURATION property isn't already there, + * and returns an error if it is. It's the caller's responsibility + * to remove it. + */ void icalcomponent_set_dtend(icalcomponent* comp, struct icaltimetype v) { - icalcomponent *inner = icalcomponent_get_inner(comp); - - icalproperty *end_prop - = icalcomponent_get_first_property(inner,ICAL_DTEND_PROPERTY); + char *tzid; + ICALSETUPSET(ICAL_DTEND_PROPERTY); - icalproperty *dur_prop - = icalcomponent_get_first_property(inner,ICAL_DURATION_PROPERTY); - - - if( end_prop == 0 && dur_prop == 0){ - end_prop = icalproperty_new_dtend(v); - icalcomponent_add_property(inner,end_prop); - } else if ( end_prop != 0) { - icalproperty_set_dtend(end_prop,v); - } else if ( dur_prop != 0) { - struct icaltimetype start = - icalcomponent_get_dtstart(inner); - - struct icaltimetype end = - icalcomponent_get_dtend(inner); + if (icalcomponent_get_first_property(inner,ICAL_DURATION_PROPERTY) + != NULL) { + icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); + return; + } - struct icaldurationtype dur - = icaltime_subtract(end,start); + if (prop == 0) { + prop = icalproperty_new_dtend(v); + icalcomponent_add_property(inner, prop); + } else { + icalproperty_remove_parameter_by_kind(prop, ICAL_TZID_PARAMETER); + } - icalproperty_set_duration(dur_prop,dur); + icalproperty_set_dtend(prop,v); - } else { - /* Error, both duration and dtend have been specified */ - icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); + if ((tzid = icaltime_get_tzid(v)) != NULL && !icaltime_is_utc(v)) { + icalproperty_add_parameter(prop, icalparameter_new_tzid(tzid)); } } +/** @brief Set DURATION property to given icalduration + * + * This method respects the icaltime type (DATE vs DATE-TIME) and + * timezone (or lack thereof). + * + * This also checks that a DTEND property isn't already there, + * and returns an error if it is. It's the caller's responsibility + * to remove it. + */ void icalcomponent_set_duration(icalcomponent* comp, struct icaldurationtype v) { - icalcomponent *inner = icalcomponent_get_inner(comp); - - icalproperty *end_prop - = icalcomponent_get_first_property(inner,ICAL_DTEND_PROPERTY); - - icalproperty *dur_prop - = icalcomponent_get_first_property(inner,ICAL_DURATION_PROPERTY); - - - if( end_prop == 0 && dur_prop == 0){ - dur_prop = icalproperty_new_duration(v); - icalcomponent_add_property(inner, dur_prop); - } else if ( end_prop != 0) { - struct icaltimetype start = - icalcomponent_get_dtstart(inner); - - struct icaltimetype new_end = icaltime_add(start,v); + ICALSETUPSET(ICAL_DURATION_PROPERTY); - icalproperty_set_dtend(end_prop,new_end); + if (icalcomponent_get_first_property(inner,ICAL_DTEND_PROPERTY) != NULL) { + icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); + return; + } - } else if ( dur_prop != 0) { - icalproperty_set_duration(dur_prop,v); + if (prop == 0) { + prop = icalproperty_new_duration(v); + icalcomponent_add_property(inner, prop); } else { - /* Error, both duration and dtend have been specified */ - icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); + icalproperty_set_duration(prop,v); } } +/** @brief Get DURATION property as an icalduration + * + * If a DURATION property is not present but a DTEND is, we use + * that to determine the proper end. + */ struct icaldurationtype icalcomponent_get_duration(icalcomponent* comp) { icalcomponent *inner = icalcomponent_get_inner(comp); @@ -1342,65 +1677,34 @@ struct icaldurationtype icalcomponent_get_duration(icalcomponent* comp) icalproperty *dur_prop = icalcomponent_get_first_property(inner,ICAL_DURATION_PROPERTY); - struct icaldurationtype null_duration; - memset(&null_duration,0,sizeof(struct icaldurationtype)); + struct icaldurationtype ret = icaldurationtype_null_duration(); + if ( dur_prop != 0 && end_prop == 0) { + ret = icalproperty_get_duration(dur_prop); - if( end_prop == 0 && dur_prop == 0){ - return null_duration; - } else if ( end_prop != 0) { + } else if ( end_prop != 0 && dur_prop == 0) { + /** + * FIXME + * We assume DTSTART and DTEND are not in different time zones. + * Does the standard actually guarantee this? + */ struct icaltimetype start = icalcomponent_get_dtstart(inner); - time_t startt = icaltime_as_timet(start); - struct icaltimetype end = icalcomponent_get_dtend(inner); - time_t endt = icaltime_as_timet(end); - - return icaldurationtype_from_int(endt-startt); - } else if ( dur_prop != 0) { - return icalproperty_get_duration(dur_prop); + + ret = icaltime_subtract(end, start); } else { /* Error, both duration and dtend have been specified */ icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); - return null_duration; - } -} - -void icalcomponent_set_method(icalcomponent* comp, icalproperty_method method) -{ - icalproperty *prop - = icalcomponent_get_first_property(comp, ICAL_METHOD_PROPERTY); - - - if (prop == 0){ - prop = icalproperty_new_method(method); - icalcomponent_add_property(comp, prop); - } - - icalproperty_set_method(prop,method); - -} - -icalproperty_method icalcomponent_get_method(icalcomponent* comp) -{ - icalproperty *prop - = icalcomponent_get_first_property(comp,ICAL_METHOD_PROPERTY); - - if (prop == 0){ - return ICAL_METHOD_NONE; } - - return icalproperty_get_method(prop); + return ret; } void icalcomponent_set_dtstamp(icalcomponent* comp, struct icaltimetype v) { - icalcomponent *inner = icalcomponent_get_inner(comp); - icalproperty *prop - = icalcomponent_get_first_property(inner, ICAL_DTSTAMP_PROPERTY); - + ICALSETUPSET(ICAL_DTSTAMP_PROPERTY); if (prop == 0){ prop = icalproperty_new_dtstamp(v); @@ -1428,10 +1732,8 @@ struct icaltimetype icalcomponent_get_dtstamp(icalcomponent* comp) void icalcomponent_set_summary(icalcomponent* comp, const char* v) { - icalcomponent *inner = icalcomponent_get_inner(comp); - icalproperty *prop - = icalcomponent_get_first_property(inner, ICAL_SUMMARY_PROPERTY); - + ICALSETUPSET(ICAL_SUMMARY_PROPERTY) + if (prop == 0){ prop = icalproperty_new_summary(v); icalcomponent_add_property(inner, prop); @@ -1443,9 +1745,18 @@ void icalcomponent_set_summary(icalcomponent* comp, const char* v) const char* icalcomponent_get_summary(icalcomponent* comp) { - icalcomponent *inner = icalcomponent_get_inner(comp); - icalproperty *prop - = icalcomponent_get_first_property(inner,ICAL_SUMMARY_PROPERTY); + icalcomponent *inner; + icalproperty *prop; + icalerror_check_arg_rz(comp!=0,"comp"); + + inner = icalcomponent_get_inner(comp); + + if(inner == 0){ + icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); + return 0; + } + + prop= icalcomponent_get_first_property(inner,ICAL_SUMMARY_PROPERTY); if (prop == 0){ return 0; @@ -1455,41 +1766,240 @@ const char* icalcomponent_get_summary(icalcomponent* comp) } -void icalcomponent_set_comment(icalcomponent* comp, const char* v); -const char* icalcomponent_get_comment(icalcomponent* comp); +void icalcomponent_set_comment(icalcomponent* comp, const char* v) +{ + ICALSETUPSET(ICAL_COMMENT_PROPERTY); + + if (prop == 0){ + prop = icalproperty_new_comment(v); + icalcomponent_add_property(inner, prop); + } + + icalproperty_set_summary(prop,v); + +} +const char* icalcomponent_get_comment(icalcomponent* comp){ + icalcomponent *inner; + icalproperty *prop; + icalerror_check_arg_rz(comp!=0,"comp"); + + inner = icalcomponent_get_inner(comp); + + if(inner == 0){ + icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); + return 0; + } + + prop= icalcomponent_get_first_property(inner,ICAL_COMMENT_PROPERTY); + + if (prop == 0){ + return 0; + } + + return icalproperty_get_comment(prop); +} void icalcomponent_set_uid(icalcomponent* comp, const char* v) { - icalcomponent *inner = icalcomponent_get_inner (comp); - icalproperty *prop - = icalcomponent_get_first_property (inner, ICAL_UID_PROPERTY); + ICALSETUPSET(ICAL_UID_PROPERTY); - if (prop == 0) { - prop = icalproperty_new_uid (v); - icalcomponent_add_property (inner, prop); - } + if (prop == 0){ + prop = icalproperty_new_uid(v); + icalcomponent_add_property(inner, prop); + } + + icalproperty_set_summary(prop,v); - icalproperty_set_uid (prop, v); } +const char* icalcomponent_get_uid(icalcomponent* comp){ + icalcomponent *inner; + icalproperty *prop; + icalerror_check_arg_rz(comp!=0,"comp"); + + inner = icalcomponent_get_inner(comp); -const char* icalcomponent_get_uid(icalcomponent* comp) + if(inner == 0){ + icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); + return 0; + } + + prop= icalcomponent_get_first_property(inner,ICAL_UID_PROPERTY); + + if (prop == 0){ + return 0; + } + + return icalproperty_get_uid(prop); +} + +void icalcomponent_set_recurrenceid(icalcomponent* comp, struct icaltimetype v) { - icalcomponent *inner = icalcomponent_get_inner (comp); - icalproperty *prop = icalcomponent_get_first_property (inner, ICAL_UID_PROPERTY); + ICALSETUPSET(ICAL_RECURRENCEID_PROPERTY); - if (prop == 0) { - return 0; - } + if (prop == 0){ + prop = icalproperty_new_recurrenceid(v); + icalcomponent_add_property(inner, prop); + } - return icalproperty_get_uid (prop); + icalproperty_set_recurrenceid(prop,v); } +struct icaltimetype icalcomponent_get_recurrenceid(icalcomponent* comp) +{ + icalcomponent *inner; + icalproperty *prop; + if (comp == 0) { + icalerror_set_errno(ICAL_BADARG_ERROR); + return icaltime_null_time(); + } -void icalcomponent_set_recurrenceid(icalcomponent* comp, - struct icaltimetype v); -struct icaltimetype icalcomponent_get_recurrenceid(icalcomponent* comp); + inner = icalcomponent_get_inner(comp); + if(inner == 0){ + icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); + return icaltime_null_time(); + } + + prop= icalcomponent_get_first_property(inner, ICAL_RECURRENCEID_PROPERTY); + + if (prop == 0){ + return icaltime_null_time(); + } + + return icalproperty_get_recurrenceid(prop); +} + +void icalcomponent_set_description(icalcomponent* comp, const char* v) +{ + ICALSETUPSET(ICAL_DESCRIPTION_PROPERTY); + + if (prop == 0){ + prop = icalproperty_new_description(v); + icalcomponent_add_property(inner, prop); + } + + icalproperty_set_description(prop,v); +} +const char* icalcomponent_get_description(icalcomponent* comp) +{ + icalcomponent *inner; + icalproperty *prop; + icalerror_check_arg_rz(comp!=0,"comp"); + + inner = icalcomponent_get_inner(comp); + + if(inner == 0){ + icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); + return 0; + } + + prop= icalcomponent_get_first_property(inner,ICAL_DESCRIPTION_PROPERTY); + + if (prop == 0){ + return 0; + } + return icalproperty_get_description(prop); +} + +void icalcomponent_set_location(icalcomponent* comp, const char* v) +{ + ICALSETUPSET(ICAL_LOCATION_PROPERTY) + if (prop == 0){ + prop = icalproperty_new_location(v); + icalcomponent_add_property(inner, prop); + } + + icalproperty_set_location(prop,v); +} +const char* icalcomponent_get_location(icalcomponent* comp) +{ + icalcomponent *inner; + icalproperty *prop; + icalerror_check_arg_rz(comp!=0,"comp"); + + inner = icalcomponent_get_inner(comp); + + if(inner == 0){ + icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); + return 0; + } + + prop= icalcomponent_get_first_property(inner,ICAL_LOCATION_PROPERTY); + + if (prop == 0){ + return 0; + } + + return icalproperty_get_location(prop); +} + +void icalcomponent_set_sequence(icalcomponent* comp, int v) +{ + ICALSETUPSET(ICAL_SEQUENCE_PROPERTY); + + if (prop == 0){ + prop = icalproperty_new_sequence(v); + icalcomponent_add_property(inner, prop); + } + + icalproperty_set_sequence(prop,v); + +} +int icalcomponent_get_sequence(icalcomponent* comp){ + icalcomponent *inner; + icalproperty *prop; + icalerror_check_arg_rz(comp!=0,"comp"); + + inner = icalcomponent_get_inner(comp); + + if(inner == 0){ + icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); + return 0; + } + + prop= icalcomponent_get_first_property(inner,ICAL_SEQUENCE_PROPERTY); + + if (prop == 0){ + return 0; + } + + return icalproperty_get_sequence(prop); +} + + +void icalcomponent_set_status(icalcomponent* comp, enum icalproperty_status v) +{ + ICALSETUPSET(ICAL_STATUS_PROPERTY); + + if (prop == 0){ + prop = icalproperty_new_status(v); + icalcomponent_add_property(inner, prop); + } + + icalproperty_set_status(prop,v); + +} +enum icalproperty_status icalcomponent_get_status(icalcomponent* comp){ + icalcomponent *inner; + icalproperty *prop; + icalerror_check_arg_rz(comp!=0,"comp"); + + inner = icalcomponent_get_inner(comp); + + if(inner == 0){ + icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); + return 0; + } + + prop= icalcomponent_get_first_property(inner,ICAL_STATUS_PROPERTY); + + if (prop == 0){ + return 0; + } + + return icalproperty_get_status(prop); +} icalcomponent* icalcomponent_new_vcalendar() { @@ -1527,15 +2037,29 @@ icalcomponent* icalcomponent_new_xdaylight() { return icalcomponent_new(ICAL_XDAYLIGHT_COMPONENT); } - +icalcomponent* icalcomponent_new_vagenda() +{ + return icalcomponent_new(ICAL_VAGENDA_COMPONENT); +} +icalcomponent* icalcomponent_new_vquery() +{ + return icalcomponent_new(ICAL_VQUERY_COMPONENT); +} +icalcomponent* icalcomponent_new_vreply() +{ + return icalcomponent_new(ICAL_VREPLY_COMPONENT); +} /* * Timezone stuff. */ -/* This takes 2 VCALENDAR components and merges the second one into the first, - resolving any problems with conflicting TZIDs. comp_to_merge will no - longer exist after calling this function. */ + +/** + * This takes 2 VCALENDAR components and merges the second one into the first, + * resolving any problems with conflicting TZIDs. comp_to_merge will no + * longer exist after calling this function. + */ void icalcomponent_merge_component(icalcomponent* comp, icalcomponent* comp_to_merge) { @@ -1602,8 +2126,7 @@ static void icalcomponent_merge_vtimezone (icalcomponent *comp, icalproperty *tzid_prop; const char *tzid; char *tzid_copy; - icaltimezone *existing_zone; - icalcomponent *existing_vtimezone; + icaltimezone *existing_vtimezone; /* Get the TZID of the VTIMEZONE. */ tzid_prop = icalcomponent_get_first_property (vtimezone, ICAL_TZID_PROPERTY); @@ -1615,11 +2138,11 @@ static void icalcomponent_merge_vtimezone (icalcomponent *comp, return; /* See if there is already a VTIMEZONE in comp with the same TZID. */ - existing_zone = icalcomponent_get_timezone (comp, tzid); + existing_vtimezone = icalcomponent_get_timezone (comp, tzid); /* If there is no existing VTIMEZONE with the same TZID, we can just move the VTIMEZONE to comp and return. */ - if (!existing_zone) { + if (!existing_vtimezone) { icalcomponent_remove_component (icalcomponent_get_parent (vtimezone), vtimezone); icalcomponent_add_component (comp, vtimezone); @@ -1641,8 +2164,7 @@ static void icalcomponent_merge_vtimezone (icalcomponent *comp, return; } - existing_vtimezone = icaltimezone_get_component (existing_zone); - if (!icalcomponent_compare_vtimezones (existing_vtimezone, vtimezone)) { + if (!icalcomponent_compare_vtimezones (comp, vtimezone)) { /* FIXME: Handle possible NEWFAILED error. */ /* Now we have two different VTIMEZONEs with the same TZID. */ @@ -1660,8 +2182,8 @@ icalcomponent_handle_conflicting_vtimezones (icalcomponent *comp, const char *tzid, icalarray *tzids_to_rename) { - struct icalcomponent_impl *impl = (struct icalcomponent_impl*)comp; - int tzid_len, i, suffix, max_suffix = 1, num_elements; + int i, suffix, max_suffix = 0, num_elements; + unsigned int tzid_len; char *tzid_copy, *new_tzid, suffix_buf[32]; /* Find the length of the TZID without any trailing digits. */ @@ -1674,13 +2196,13 @@ icalcomponent_handle_conflicting_vtimezones (icalcomponent *comp, same prefix (e.g. 'London'). If it matches any of those, we have to rename the TZIDs to that TZID, else we rename to a new TZID, using the biggest numeric suffix found + 1. */ - num_elements = impl->timezones ? impl->timezones->num_elements : 0; + num_elements = comp->timezones ? comp->timezones->num_elements : 0; for (i = 0; i < num_elements; i++) { icaltimezone *zone; char *existing_tzid, *existing_tzid_copy; - int existing_tzid_len; + unsigned int existing_tzid_len; - zone = icalarray_element_at (impl->timezones, i); + zone = icalarray_element_at (comp->timezones, i); existing_tzid = icaltimezone_get_tzid (zone); /* Find the length of the TZID without any trailing digits. */ @@ -1733,7 +2255,7 @@ icalcomponent_handle_conflicting_vtimezones (icalcomponent *comp, /* Returns the length of the TZID, without any trailing digits. */ -static int icalcomponent_get_tzid_prefix_len (const char *tzid) +static unsigned int icalcomponent_get_tzid_prefix_len (const char *tzid) { int len; const char *p; @@ -1749,9 +2271,11 @@ static int icalcomponent_get_tzid_prefix_len (const char *tzid) } -/* Renames all references to the given TZIDs to a new name. rename_table - contains pairs of strings - a current TZID, and the new TZID to rename it - to. */ +/** + * Renames all references to the given TZIDs to a new name. rename_table + * contains pairs of strings - a current TZID, and the new TZID to rename it + * to. + */ static void icalcomponent_rename_tzids(icalcomponent* comp, icalarray* rename_table) { @@ -1781,7 +2305,9 @@ static void icalcomponent_rename_tzids_callback(icalparameter *param, void *data } -/* Calls the given function for each TZID parameter found in the component. */ +/** + * Calls the given function for each TZID parameter found in the component. + */ void icalcomponent_foreach_tzid(icalcomponent* comp, void (*callback)(icalparameter *param, void *data), void *callback_data) @@ -1819,33 +2345,32 @@ void icalcomponent_foreach_tzid(icalcomponent* comp, -/* Returns the icaltimezone from the component corresponding to the given - TZID, or NULL if the component does not have a corresponding VTIMEZONE. */ +/** + * Returns the icaltimezone from the component corresponding to the given + * TZID, or NULL if the component does not have a corresponding VTIMEZONE. + */ icaltimezone* icalcomponent_get_timezone(icalcomponent* comp, const char *tzid) { - struct icalcomponent_impl *impl; icaltimezone *zone; int lower, upper, middle, cmp; char *zone_tzid; - impl = (struct icalcomponent_impl*)comp; - - if (!impl->timezones) + if (!comp->timezones) return NULL; /* Sort the array if necessary (by the TZID string). */ - if (!impl->timezones_sorted) { - icalarray_sort (impl->timezones, icalcomponent_compare_timezone_fn); - impl->timezones_sorted = 1; + if (!comp->timezones_sorted) { + icalarray_sort (comp->timezones, icalcomponent_compare_timezone_fn); + comp->timezones_sorted = 1; } /* Do a simple binary search. */ lower = middle = 0; - upper = impl->timezones->num_elements; + upper = comp->timezones->num_elements; while (lower < upper) { middle = (lower + upper) >> 1; - zone = icalarray_element_at (impl->timezones, middle); + zone = icalarray_element_at (comp->timezones, middle); zone_tzid = icaltimezone_get_tzid (zone); cmp = strcmp (tzid, zone_tzid); if (cmp == 0) @@ -1860,13 +2385,14 @@ icaltimezone* icalcomponent_get_timezone(icalcomponent* comp, const char *tzid) } -/* A function to compare 2 icaltimezone elements, used for qsort(). */ +/** + * A function to compare 2 icaltimezone elements, used for qsort(). + */ static int icalcomponent_compare_timezone_fn (const void *elem1, const void *elem2) { icaltimezone *zone1, *zone2; const char *zone1_tzid, *zone2_tzid; - int retval; zone1 = (icaltimezone*) elem1; zone2 = (icaltimezone*) elem2; @@ -1878,14 +2404,16 @@ static int icalcomponent_compare_timezone_fn (const void *elem1, } -/* Compares 2 VTIMEZONE components to see if they match, ignoring their TZIDs. - It returns 1 if they match, 0 if they don't, or -1 on error. */ +/** + * Compares 2 VTIMEZONE components to see if they match, ignoring their TZIDs. + * It returns 1 if they match, 0 if they don't, or -1 on error. + */ static int icalcomponent_compare_vtimezones (icalcomponent *vtimezone1, icalcomponent *vtimezone2) { icalproperty *prop1, *prop2; const char *tzid1, *tzid2; - char *tzid2_copy, *string1, *string2, *string1_copy; + char *tzid2_copy, *string1, *string2; int cmp; /* Get the TZID property of the first VTIMEZONE. */ @@ -1893,7 +2421,6 @@ static int icalcomponent_compare_vtimezones (icalcomponent *vtimezone1, if (!prop1) return -1; - /* This returns the pointer to the actual string in the property. */ tzid1 = icalproperty_get_tzid (prop1); if (!tzid1) return -1; @@ -1903,7 +2430,6 @@ static int icalcomponent_compare_vtimezones (icalcomponent *vtimezone1, if (!prop2) return -1; - /* This returns the pointer to the actual string in the property. */ tzid2 = icalproperty_get_tzid (prop2); if (!tzid2) return -1; @@ -1921,32 +2447,21 @@ static int icalcomponent_compare_vtimezones (icalcomponent *vtimezone1, /* Now convert both VTIMEZONEs to strings and compare them. */ string1 = icalcomponent_as_ical_string (vtimezone1); if (!string1) { - /* Try to reset the property. Though this may not work if we are low - on memory. */ - icalproperty_set_tzid (prop2, tzid2_copy); - free (tzid2_copy); - return -1; - } - - /* Copy the string, since it is in a temporary buffer which may get freed - during the next call. */ - string1_copy = strdup (string1); - if (!string1_copy) { - icalproperty_set_tzid (prop2, tzid2_copy); free (tzid2_copy); return -1; } string2 = icalcomponent_as_ical_string (vtimezone2); if (!string2) { - icalproperty_set_tzid (prop2, tzid2_copy); + free (string1); free (tzid2_copy); return -1; } - cmp = strcmp (string1_copy, string2); + cmp = strcmp (string1, string2); - free (string1_copy); + free (string1); + free (string2); /* Now reset the second TZID. */ icalproperty_set_tzid (prop2, tzid2_copy); @@ -1954,3 +2469,143 @@ static int icalcomponent_compare_vtimezones (icalcomponent *vtimezone1, return (cmp == 0) ? 1 : 0; } + + + + + + +/** + * @brief set the RELCALID property of a component. + * + * @param comp Valid calendar component. + * @param v Relcalid URL value + */ + +void icalcomponent_set_relcalid(icalcomponent* comp, const char* v) +{ + ICALSETUPSET(ICAL_RELCALID_PROPERTY); + + if (prop == 0){ + prop = icalproperty_new_relcalid(v); + icalcomponent_add_property(inner, prop); + } + + icalproperty_set_relcalid(prop,v); + +} + + +/** + * @brief get the RELCALID property of a component. + * + * @param comp Valid calendar component. + */ + +const char* icalcomponent_get_relcalid(icalcomponent* comp){ + icalcomponent *inner; + icalproperty *prop; + icalerror_check_arg_rz(comp!=0,"comp"); + + inner = icalcomponent_get_inner(comp); + + if(inner == 0){ + return 0; + } + + prop= icalcomponent_get_first_property(inner,ICAL_RELCALID_PROPERTY); + + if (prop == 0){ + return 0; + } + + return icalproperty_get_relcalid(prop); +} + + +/** @brief Return the time a TODO task is DUE. + * + * @param comp Valid calendar component. + * + * Uses the DUE: property if it exists, otherwise we calculate the DUE + * value by adding the task's duration to the DTSTART time + */ + +struct icaltimetype icalcomponent_get_due(icalcomponent* comp) +{ + icalcomponent *inner = icalcomponent_get_inner(comp); + + icalproperty *due_prop + = icalcomponent_get_first_property(inner,ICAL_DUE_PROPERTY); + + icalproperty *dur_prop + = icalcomponent_get_first_property(inner, ICAL_DURATION_PROPERTY); + + if( due_prop == 0 && dur_prop == 0){ + return icaltime_null_time(); + } else if ( due_prop != 0) { + return icalproperty_get_due(due_prop); + } else if ( dur_prop != 0) { + + struct icaltimetype start = + icalcomponent_get_dtstart(inner); + struct icaldurationtype duration = + icalproperty_get_duration(dur_prop); + + struct icaltimetype due = icaltime_add(start,duration); + + return due; + + } else { + /* Error, both duration and due have been specified */ + icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); + return icaltime_null_time(); + + } + +} + +/** @brief Set the due date of a VTODO task. + * + * @param comp Valid VTODO component. + * @param v Valid due date time. + * + * - If no duration or due properties then set the DUE property. + * - If a DUE property is already set, then reset it to the value v. + * - If a DURATION property is already set, then calculate the new + * duration based on the supplied value of v. + */ + +void icalcomponent_set_due(icalcomponent* comp, struct icaltimetype v) +{ + icalcomponent *inner = icalcomponent_get_inner(comp); + + icalproperty *due_prop + = icalcomponent_get_first_property(inner,ICAL_DUE_PROPERTY); + + icalproperty *dur_prop + = icalcomponent_get_first_property(inner,ICAL_DURATION_PROPERTY); + + + if( due_prop == 0 && dur_prop == 0){ + due_prop = icalproperty_new_due(v); + icalcomponent_add_property(inner,due_prop); + } else if ( due_prop != 0) { + icalproperty_set_due(due_prop,v); + } else if ( dur_prop != 0) { + struct icaltimetype start = + icalcomponent_get_dtstart(inner); + + struct icaltimetype due = + icalcomponent_get_due(inner); + + struct icaldurationtype dur + = icaltime_subtract(due,start); + + icalproperty_set_duration(dur_prop,dur); + + } else { + /* Error, both duration and due have been specified */ + icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); + } +} |