diff options
-rw-r--r-- | libical/ChangeLog | 8 | ||||
-rw-r--r-- | libical/src/libical/icalcomponent.c | 410 | ||||
-rw-r--r-- | libical/src/libical/icalcomponent.h | 24 | ||||
-rw-r--r-- | libical/src/libical/icaltime.c | 222 | ||||
-rw-r--r-- | libical/src/libical/icaltime.h | 28 | ||||
-rw-r--r-- | libical/src/libical/icaltimezone.c | 439 | ||||
-rw-r--r-- | libical/src/libical/icaltimezone.h | 41 |
7 files changed, 863 insertions, 309 deletions
diff --git a/libical/ChangeLog b/libical/ChangeLog index b6c275ff2d..a86513c7ab 100644 --- a/libical/ChangeLog +++ b/libical/ChangeLog @@ -1,3 +1,9 @@ +2001-07-03 Damon Chaplin <damon@ximian.com> + + * src/libical/icaltimezone.c (icaltimezone_get_builtin_timezone_from_tzid): + * src/libical/icaltime.c: + * src/libical/icalcomponent.c: more timezone stuff. + 2001-06-28 Peter Williams <peterw@ximian.com> * zoneinfo/Makefile.am (dist-hook): Add $(srcdir) as in install-data-local @@ -7,7 +13,7 @@ * configure.in: commented out AC_DEFINE(ICAL_ERRORS_ARE_FATAL,1). We only want it to abort when there is no possibility of carrying on. - + 2001-06-26 Damon Chaplin <damon@ximian.com> * zoneinfo/*: stripped all blank lines from iCalendar files. diff --git a/libical/src/libical/icalcomponent.c b/libical/src/libical/icalcomponent.c index ee4ec54f30..8c5295b79f 100644 --- a/libical/src/libical/icalcomponent.c +++ b/libical/src/libical/icalcomponent.c @@ -44,6 +44,7 @@ #include <errno.h> #include <assert.h> #include <stdio.h> /* for fprintf */ +#include <string.h> /* for strdup */ #define MAX_TMP 1024 @@ -68,8 +69,22 @@ 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); +static void icalcomponent_merge_vtimezone (icalcomponent *comp, + icalcomponent *vtimezone, + icalarray *tzids_to_rename); +static void icalcomponent_handle_conflicting_vtimezones (icalcomponent *comp, + icalcomponent *vtimezone, + icalproperty *tzid_prop, + const char *tzid, + icalarray *tzids_to_rename); +static 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, void *data); +static int icalcomponent_compare_vtimezones (icalcomponent *vtimezone1, + icalcomponent *vtimezone2); + void icalcomponent_add_children(struct icalcomponent_impl *impl,va_list args) { @@ -704,58 +719,6 @@ icalcomponent* icalcomponent_get_first_real_component(icalcomponent *c) return 0; } -time_t icalcomponent_convert_time(icalproperty *p) -{ - struct icaltimetype sict; - time_t convt; - icalproperty *tzp; - - - /* Though it says _dtstart, it will work for dtend too */ - sict = icalproperty_get_dtstart(p); - - tzp = icalproperty_get_first_parameter(p,ICAL_TZID_PARAMETER); - - if (sict.is_utc == 1 && tzp != 0){ - icalerror_warn("icalcomponent_get_span: component has a UTC DTSTART with a timezone specified "); - icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); - return 0; - } - - if(sict.is_utc == 1){ - /* _as_timet will use gmtime() to do the conversion */ - convt = icaltime_as_timet(sict); - -#ifdef TEST_CONVERT_TIME - printf("convert time: use as_timet:\n %s\n %s", - icalproperty_as_ical_string(p), ctime(&convt)); -#endif - - } else if (sict.is_utc == 0 && tzp == 0 ) { - time_t offset; - - /* _as_timet will use localtime() to do the conversion */ - convt = icaltime_as_timet(sict); - offset = icaltime_utc_offset(sict,0); - convt += offset; - -#ifdef TEST_CONVERT_TIME - printf("convert time: use as_timet and adjust:\n %s\n %s", - icalproperty_as_ical_string(p), ctime(&convt)); -#endif - } else { - /* Convert the time to UTC for the named timezone*/ - const char* timezone = icalparameter_get_tzid(tzp); - convt = icaltime_as_timet(icaltime_as_utc(sict,timezone)); - -#ifdef TEST_CONVERT_TIME - printf("convert time: use _as_utc:\n %s\n %s", - icalproperty_as_ical_string(p), ctime(&convt)); -#endif - } - - return convt; -} struct icaltime_span icalcomponent_get_span(icalcomponent* comp) { icalcomponent *inner; @@ -822,7 +785,10 @@ struct icaltime_span icalcomponent_get_span(icalcomponent* comp) icalerror_clear_errno(); + /* FIXME: Needs updating to new icaltimezone functions. */ +#if 0 span.start = icalcomponent_convert_time(p); +#endif #ifdef TEST_CONVERT_TIME printf("convert time:\n %s %s", @@ -846,7 +812,10 @@ struct icaltime_span icalcomponent_get_span(icalcomponent* comp) } 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; @@ -1514,47 +1483,220 @@ icalcomponent* icalcomponent_new_xdaylight() return icalcomponent_new(ICAL_XDAYLIGHT_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) -{ - icalproperty *prop; - icalproperty_kind kind; - icalparameter *param; - icalcomponent *child; - /* First rename any TZID parameters used in this component. */ - prop = icalcomponent_get_first_property (comp, ICAL_ANY_PROPERTY); - while (prop) { - kind = icalproperty_isa (prop); - - /* These are the only properties that can have a TZID. Note that - COMPLETED, CREATED, DTSTAMP & LASTMODIFIED must be in UTC. */ - if (kind == ICAL_DTSTART_PROPERTY || kind == ICAL_DTEND_PROPERTY - || kind == ICAL_DUE_PROPERTY || kind == ICAL_EXDATE_PROPERTY - || kind == ICAL_RDATE_PROPERTY) { - param = icalproperty_get_first_parameter (prop, ICAL_TZID_PARAMETER); - if (param) - (*callback) (param, callback_data); +/* + * 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. */ +void icalcomponent_merge_component(icalcomponent* comp, + icalcomponent* comp_to_merge) +{ + icalcomponent *subcomp, *next_subcomp; + icalarray *tzids_to_rename; + int i; + + /* Check that both components are VCALENDAR components. */ + assert (icalcomponent_isa(comp) == ICAL_VCALENDAR_COMPONENT); + assert (icalcomponent_isa(comp_to_merge) != ICAL_VCALENDAR_COMPONENT); + + /* Step through each subcomponent of comp_to_merge, looking for VTIMEZONEs. + For each VTIMEZONE found, check if we need to add it to comp and if we + need to rename it and all TZID references to it. */ + tzids_to_rename = icalarray_new (sizeof (char*), 16); + subcomp = icalcomponent_get_first_component (comp_to_merge, + ICAL_VTIMEZONE_COMPONENT); + while (subcomp) { + next_subcomp = icalcomponent_get_next_component (comp_to_merge, + ICAL_VTIMEZONE_COMPONENT); + /* This will add the VTIMEZONE to comp, if necessary, and also update + the array of TZIDs we need to rename. */ + icalcomponent_merge_vtimezone (comp, subcomp, tzids_to_rename); + /* FIXME: Handle possible NEWFAILED error. */ + + subcomp = next_subcomp; + } + + /* If we need to do any renaming of TZIDs, do it now. */ + if (tzids_to_rename->num_elements != 0) { + icalcomponent_rename_tzids (comp_to_merge, tzids_to_rename); + + /* Now free the tzids_to_rename array. */ + for (i = 0; i < tzids_to_rename->num_elements; i++) { + free (icalarray_element_at (tzids_to_rename, i)); + } + icalarray_free (tzids_to_rename); + } + + /* Now move all the components from comp_to_merge to comp, excluding + VTIMEZONE components. */ + subcomp = icalcomponent_get_first_component (comp_to_merge, + ICAL_ANY_COMPONENT); + while (subcomp) { + next_subcomp = icalcomponent_get_next_component (comp_to_merge, + ICAL_ANY_COMPONENT); + if (icalcomponent_isa(subcomp) != ICAL_VTIMEZONE_COMPONENT) { + icalcomponent_remove_component (comp_to_merge, subcomp); + icalcomponent_add_component (comp, subcomp); + } + subcomp = next_subcomp; + } + + /* Free comp_to_merge. We have moved most of the subcomponents over to + comp now. */ + icalcomponent_free (comp_to_merge); +} + + +static void icalcomponent_merge_vtimezone (icalcomponent *comp, + icalcomponent *vtimezone, + icalarray *tzids_to_rename) +{ + icalproperty *tzid_prop; + const char *tzid; + icaltimezone *existing_vtimezone; + + /* Get the TZID of the VTIMEZONE. */ + tzid_prop = icalcomponent_get_first_property (comp, ICAL_TZID_PROPERTY); + if (!tzid_prop) + return; + + tzid = icalproperty_get_tzid (tzid_prop); + if (!tzid) + return; + + /* See if there is already a VTIMEZONE in comp with the same 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_vtimezone) { + icalcomponent_remove_component (icalcomponent_get_parent (vtimezone), + vtimezone); + icalcomponent_add_component (comp, vtimezone); + return; + } + + /* If the TZID has a '/' prefix, then we don't have to worry about the + clashing TZIDs, as they are supposed to be exactly the same VTIMEZONE. */ + if (tzid[0] == '/') + return; + + /* Now we have two VTIMEZONEs with the same TZID (which isn't a globally + unique one), so we compare the VTIMEZONE components to see if they are + the same. If they are, we don't need to do anything. */ + if (icalcomponent_compare_vtimezones (existing_vtimezone, vtimezone)) + return; + /* FIXME: Handle possible NEWFAILED error. */ + + /* Now we have two different VTIMEZONEs with the same TZID. */ + icalcomponent_handle_conflicting_vtimezones (comp, vtimezone, tzid_prop, + tzid, tzids_to_rename); +} + + +static void +icalcomponent_handle_conflicting_vtimezones (icalcomponent *comp, + icalcomponent *vtimezone, + icalproperty *tzid_prop, + const char *tzid, + icalarray *tzids_to_rename) +{ + struct icalcomponent_impl *impl = (struct icalcomponent_impl*)comp; + int tzid_len, i, suffix, max_suffix = 0; + char *tzid_copy, *new_tzid, suffix_buf[32]; + + /* Find the length of the TZID without any trailing digits. */ + tzid_len = icalcomponent_get_tzid_prefix_len (tzid); + + /* Step through each of the VTIMEZONEs in comp. We may already have the + clashing VTIMEZONE in the calendar, but it may have been renamed + (i.e. a unique number added on the end of the TZID, e.g. 'London2'). + So we compare the new VTIMEZONE with any VTIMEZONEs that have the + 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. */ + for (i = 0; i < impl->timezones->num_elements; i++) { + icaltimezone *zone; + char *existing_tzid, *existing_tzid_copy; + int existing_tzid_len; + + zone = icalarray_element_at (impl->timezones, i); + existing_tzid = icaltimezone_get_tzid (zone); + + /* Find the length of the TZID without any trailing digits. */ + existing_tzid_len = icalcomponent_get_tzid_prefix_len (existing_tzid); + + /* Check if we have the same prefix. */ + if (tzid_len == existing_tzid_len + && !strncmp (tzid, existing_tzid, tzid_len)) { + /* Compare the VTIMEZONEs. */ + if (icalcomponent_compare_vtimezones (icaltimezone_get_component (zone), + vtimezone)) { + /* The VTIMEZONEs match, so we can use the existing VTIMEZONE. But + we have to rename TZIDs to this TZID. */ + tzid_copy = strdup (tzid); + existing_tzid_copy = strdup (existing_tzid); + if (!tzid_copy || !existing_tzid_copy) { + icalerror_set_errno(ICAL_NEWFAILED_ERROR); + } else { + icalarray_append (tzids_to_rename, tzid_copy); + icalarray_append (tzids_to_rename, existing_tzid_copy); + } + return; + } else { + /* FIXME: Handle possible NEWFAILED error. */ + + /* Convert the suffix to an integer and remember the maximum numeric + suffix found. */ + suffix = atoi (existing_tzid + existing_tzid_len); + if (max_suffix < suffix) + max_suffix = suffix; } - - prop = icalcomponent_get_next_property (comp, ICAL_ANY_PROPERTY); } + } - /* Now recursively rename child components. */ - child = icalcomponent_get_first_component (comp, ICAL_ANY_COMPONENT); - while (child) { - icalcomponent_foreach_tzid (child, callback, callback_data); - child = icalcomponent_get_next_component (comp, ICAL_ANY_COMPONENT); - } + /* We didn't find a VTIMEZONE that matched, so we have to rename the TZID, + using the maximum numerical suffix found + 1. */ + tzid_copy = strdup (tzid); + sprintf (suffix_buf, "%i", max_suffix + 1); + new_tzid = malloc (tzid_len + strlen (suffix_buf) + 1); + if (!new_tzid || !tzid_copy) { + icalerror_set_errno(ICAL_NEWFAILED_ERROR); + return; + } + + strncpy (new_tzid, tzid, tzid_len); + strcpy (new_tzid + tzid_len, suffix_buf); + icalarray_append (tzids_to_rename, tzid_copy); + icalarray_append (tzids_to_rename, new_tzid); +} + + +/* Returns the length of the TZID, without any trailing digits. */ +static int icalcomponent_get_tzid_prefix_len (const char *tzid) +{ + int len; + const char *p; + + len = strlen (tzid); + p = tzid + len - 1; + while (len > 0 && *p >= '0' && *p <= '9') { + p--; + len--; + } + + return len; } /* 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. */ -void icalcomponent_rename_tzids(icalcomponent* comp, icalarray* rename_table) +static void icalcomponent_rename_tzids(icalcomponent* comp, + icalarray* rename_table) { icalcomponent_foreach_tzid (comp, icalcomponent_rename_tzids_callback, rename_table); @@ -1580,6 +1722,44 @@ static void icalcomponent_rename_tzids_callback(icalparameter *param, void *data } +/* 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) +{ + icalproperty *prop; + icalproperty_kind kind; + icalparameter *param; + icalcomponent *subcomp; + + /* First look for any TZID parameters used in this component itself. */ + prop = icalcomponent_get_first_property (comp, ICAL_ANY_PROPERTY); + while (prop) { + kind = icalproperty_isa (prop); + + /* These are the only properties that can have a TZID. Note that + COMPLETED, CREATED, DTSTAMP & LASTMODIFIED must be in UTC. */ + if (kind == ICAL_DTSTART_PROPERTY || kind == ICAL_DTEND_PROPERTY + || kind == ICAL_DUE_PROPERTY || kind == ICAL_EXDATE_PROPERTY + || kind == ICAL_RDATE_PROPERTY) { + param = icalproperty_get_first_parameter (prop, ICAL_TZID_PARAMETER); + if (param) + (*callback) (param, callback_data); + } + + prop = icalcomponent_get_next_property (comp, ICAL_ANY_PROPERTY); + } + + /* Now recursively check child components. */ + subcomp = icalcomponent_get_first_component (comp, ICAL_ANY_COMPONENT); + while (subcomp) { + icalcomponent_foreach_tzid (subcomp, callback, callback_data); + subcomp = icalcomponent_get_next_component (comp, ICAL_ANY_COMPONENT); + } +} + + + /* 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) @@ -1609,3 +1789,67 @@ icaltimezone* icalcomponent_get_timezone(icalcomponent* comp, const char *tzid) return NULL; } + +/* 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; + int cmp; + + /* Get the TZID property of the first VTIMEZONE. */ + prop1 = icalcomponent_get_first_property (vtimezone1, ICAL_TZID_PROPERTY); + if (!prop1) + return -1; + + tzid1 = icalproperty_get_tzid (prop1); + if (!tzid1) + return -1; + + /* Get the TZID property of the second VTIMEZONE. */ + prop2 = icalcomponent_get_first_property (vtimezone1, ICAL_TZID_PROPERTY); + if (!prop2) + return -1; + + tzid2 = icalproperty_get_tzid (prop2); + if (!tzid2) + return -1; + + /* Copy the second TZID, and set the property to the same as the first + TZID, since we don't care if these match of not. */ + tzid2_copy = strdup (tzid2); + if (!tzid2_copy) { + icalerror_set_errno (ICAL_NEWFAILED_ERROR); + return 0; + } + + icalproperty_set_tzid (prop2, tzid1); + + /* Now convert both VTIMEZONEs to strings and compare them. */ + string1 = icalcomponent_as_ical_string (vtimezone1); + if (!string1) { + free (tzid2_copy); + return -1; + } + + string2 = icalcomponent_as_ical_string (vtimezone2); + if (!string2) { + free (string1); + free (tzid2_copy); + return -1; + } + + cmp = strcmp (string1, string2); + + free (string1); + free (string2); + + /* Now reset the second TZID. */ + icalproperty_set_tzid (prop2, tzid2_copy); + free (tzid2_copy); + + return (cmp == 0) ? 1 : 0; +} diff --git a/libical/src/libical/icalcomponent.h b/libical/src/libical/icalcomponent.h index 6046bbee1e..55c0592bb2 100644 --- a/libical/src/libical/icalcomponent.h +++ b/libical/src/libical/icalcomponent.h @@ -32,6 +32,14 @@ typedef void icalcomponent; +/* An opaque struct representing a timezone. We declare this here to avoid + a circular dependancy. */ +#ifndef ICALTIMEONE_DEFINED +#define ICALTIMEONE_DEFINED +typedef struct _icaltimezone icaltimezone; +#endif + + /* This is exposed so that callers will not have to allocate and deallocate iterators. Pretend that you can't see it. */ typedef struct icalcompiter @@ -97,6 +105,13 @@ void icalcomponent_remove_component(icalcomponent* parent, int icalcomponent_count_components(icalcomponent* component, icalcomponent_kind kind); +/* 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); + + /* Iteration Routines. There are two forms of iterators, internal and external. The internal ones came first, and are almost completely sufficient, but they fail badly when you want to construct a loop that @@ -217,7 +232,16 @@ int icalcomponent_remove_attendee(icalcomponent *comp, char* cuid); struct icalattendeetype icalcomponent_get_attendee(icalcomponent *comp, int index); +/* Calls the given function for each TZID parameter found in the component, + and any subcomponents. */ +void icalcomponent_foreach_tzid(icalcomponent* comp, + void (*callback)(icalparameter *param, void *data), + void *callback_data); +/* Returns the icaltimezone in the component corresponding to the TZID, or NULL + if it can't be found. */ +icaltimezone* icalcomponent_get_timezone(icalcomponent* comp, + const char *tzid); /*************** Type Specific routines ***************/ diff --git a/libical/src/libical/icaltime.c b/libical/src/libical/icaltime.c index 6a3859c094..6f6ed5748f 100644 --- a/libical/src/libical/icaltime.c +++ b/libical/src/libical/icaltime.c @@ -44,6 +44,7 @@ #include "icalmemory.h" #endif +#include "icaltimezone.h" @@ -73,6 +74,41 @@ icaltime_from_timet(time_t tm, int is_date) return tt; } +struct icaltimetype +icaltime_from_timet_with_zone(time_t tm, int is_date, icaltimezone *zone) +{ + struct icaltimetype tt = icaltime_null_time(); + struct tm t; + icaltimezone *utc_zone; + + utc_zone = icaltimezone_get_utc_timezone (); + + /* Convert the time_t to a struct tm in UTC time. We can trust gmtime + for this. */ + t = *(gmtime(&tm)); + + tt.year = t.tm_year + 1900; + tt.month = t.tm_mon + 1; + tt.day = t.tm_mday; + tt.hour = t.tm_hour; + tt.minute = t.tm_min; + tt.second = t.tm_sec; + + tt.is_utc = (zone == utc_zone) ? 1 : 0; + tt.is_date = is_date; + tt.is_daylight = 0; + + /* Use our timezone functions to convert to the required timezone. */ + icaltimezone_convert_time (&tt, utc_zone, zone); + + if (is_date) { + /* FIXME: is_daylight may need to be changed. */ + tt.second = tt.minute = tt.hour = 0; + } + + return tt; +} + /* Structure used by set_tz to hold an old value of TZ, and the new value, which is in memory we will have to free in unset_tz */ /* This will hold the last "TZ=XXX" string we used with putenv(). After we @@ -177,6 +213,42 @@ time_t icaltime_as_timet(struct icaltimetype tt) } +time_t icaltime_as_timet_with_zone(struct icaltimetype tt, icaltimezone *zone) +{ + icaltimezone *utc_zone; + struct tm stm; + time_t t; + char *old_tz; + + utc_zone = icaltimezone_get_utc_timezone (); + + /* If the time is the special null time, return 0. */ + if (icaltime_is_null_time(tt)) { + return 0; + } + + /* Use our timezone functions to convert to UTC. */ + icaltimezone_convert_time (&tt, zone, utc_zone); + + /* Copy the icaltimetype to a struct tm. */ + memset (&stm, 0, sizeof (struct tm)); + + stm.tm_sec = tt.second; + stm.tm_min = tt.minute; + stm.tm_hour = tt.hour; + stm.tm_mday = tt.day; + stm.tm_mon = tt.month-1; + stm.tm_year = tt.year-1900; + stm.tm_isdst = -1; + + /* Set TZ to UTC and use mktime to convert to a time_t. */ + old_tz = set_tz ("UTC"); + t = mktime (&stm); + unset_tz (old_tz); + + return t; +} + char* icaltime_as_ical_string(struct icaltimetype tt) { size_t size = 17; @@ -202,101 +274,12 @@ char* icaltime_as_ical_string(struct icaltimetype tt) } -/* convert tt, of timezone tzid, into a utc time */ -struct icaltimetype icaltime_as_utc(struct icaltimetype tt,const char* tzid) -{ - int tzid_offset; - - if(tt.is_utc == 1 || tt.is_date == 1){ - return tt; - } - - tzid_offset = icaltime_utc_offset(tt,tzid); - - tt.second -= tzid_offset; - - tt.is_utc = 1; - - return icaltime_normalize(tt); -} - -/* convert tt, a time in UTC, into a time in timezone tzid */ -struct icaltimetype icaltime_as_zone(struct icaltimetype tt,const char* tzid) -{ - int tzid_offset; - - tzid_offset = icaltime_utc_offset(tt,tzid); - - tt.second += tzid_offset; - - tt.is_utc = 0; - - return icaltime_normalize(tt); - -} - - -/* Return the offset of the named zone as seconds. tt is a time - indicating the date for which you want the offset */ -int icaltime_utc_offset(struct icaltimetype ictt, const char* tzid) -{ - - time_t tt = icaltime_as_timet(ictt); - time_t offset_tt; - struct tm gtm; - - char *tz_str = 0; - - if(tzid != 0){ - tz_str = set_tz(tzid); - } - - /* Mis-interpret a UTC broken out time as local time */ - gtm = *(gmtime(&tt)); - gtm.tm_isdst = localtime(&tt)->tm_isdst; - offset_tt = mktime(>m); - - if(tzid != 0){ - unset_tz(tz_str); - } - - return tt-offset_tt; -} - - - -/* Normalize by converting from localtime to utc and back to local - time. This uses localtime because localtime and mktime are inverses - of each other */ +/* Normalize the icaltime, so that all fields are within the normal range. */ struct icaltimetype icaltime_normalize(struct icaltimetype tt) { - struct tm stm; - time_t tut; - - memset(&stm,0,sizeof( struct tm)); - - stm.tm_sec = tt.second; - stm.tm_min = tt.minute; - stm.tm_hour = tt.hour; - stm.tm_mday = tt.day; - stm.tm_mon = tt.month-1; - stm.tm_year = tt.year-1900; - stm.tm_isdst = -1; /* prevents mktime from changing hour based on - daylight savings */ - - tut = mktime(&stm); - - stm = *(localtime(&tut)); - - tt.second = stm.tm_sec; - tt.minute = stm.tm_min; - tt.hour = stm.tm_hour; - tt.day = stm.tm_mday; - tt.month = stm.tm_mon +1; - tt.year = stm.tm_year+1900; - - return tt; + icaltime_adjust (&tt, 0, 0, 0, 0); + return tt; } @@ -404,50 +387,69 @@ short icaltime_day_of_week(struct icaltimetype t){ return stm.tm_wday + 1; } -/* Day of the year that the first day of the week (Sunday) is on */ +/* Day of the year that the first day of the week (Sunday) is on. + FIXME: Doesn't take into account different week start days. */ short icaltime_start_doy_of_week(struct icaltimetype t){ - time_t tt = icaltime_as_timet(t); - time_t start_tt; - struct tm *stm; - int syear; + struct tm stm; - stm = gmtime(&tt); - syear = stm->tm_year; + stm.tm_year = t.year - 1900; + stm.tm_mon = t.month - 1; + stm.tm_mday = t.day; + stm.tm_hour = 0; + stm.tm_min = 0; + stm.tm_sec = 0; + stm.tm_isdst = -1; - start_tt = tt - stm->tm_wday*(60*60*24); + mktime (&stm); - stm = gmtime(&start_tt); - - if(syear == stm->tm_year){ - return stm->tm_yday+1; + /* Move back to the start of the week. */ + stm.tm_mday -= stm.tm_wday; + + mktime (&stm); + + /* If we are still in the same year as the original date, we just return + the day of the year. */ + if (t.year - 1900 == stm.tm_year){ + return stm.tm_yday+1; } else { /* return negative to indicate that start of week is in previous year. */ int is_leap = 0; - int year = stm->tm_year; + int year = stm.tm_year; if( (year % 4 == 0 && year % 100 != 0) || year % 400 == 0){ is_leap =1; } - return (stm->tm_yday+1)-(365+is_leap); + return (stm.tm_yday+1)-(365+is_leap); } } +/* FIXME: Doesn't take into account the start day of the week. strftime assumes + that weeks start on Monday. */ short icaltime_week_number(struct icaltimetype ictt) { - char str[5]; - time_t t = icaltime_as_timet(ictt); + struct tm stm; int week_no; + char str[8]; - strftime(str,5,"%V", gmtime(&t)); + stm.tm_year = ictt.year - 1900; + stm.tm_mon = ictt.month - 1; + stm.tm_mday = ictt.day; + stm.tm_hour = 0; + stm.tm_min = 0; + stm.tm_sec = 0; + stm.tm_isdst = -1; + + mktime (&stm); + + strftime(str,5,"%V", &stm); week_no = atoi(str); return week_no; - } diff --git a/libical/src/libical/icaltime.h b/libical/src/libical/icaltime.h index afe8fd4df2..ef3d65d030 100644 --- a/libical/src/libical/icaltime.h +++ b/libical/src/libical/icaltime.h @@ -31,6 +31,13 @@ #include <time.h> +/* An opaque struct representing a timezone. We declare this here to avoid + a circular dependancy. */ +#ifndef ICALTIMEONE_DEFINED +#define ICALTIMEONE_DEFINED +typedef struct _icaltimezone icaltimezone; +#endif + /* icaltime_span is returned by icalcomponent_get_span() */ struct icaltime_span { time_t start; /* in UTC */ @@ -60,9 +67,16 @@ struct icaltimetype /* Convert seconds past UNIX epoch to a timetype*/ struct icaltimetype icaltime_from_timet(time_t v, int is_date); +/* Newer version of above, using timezones. */ +struct icaltimetype icaltime_from_timet_with_zone(time_t tm, int is_date, + icaltimezone *zone); + /* Return the time as seconds past the UNIX epoch */ time_t icaltime_as_timet(struct icaltimetype); +/* Newer version of above, using timezones. */ +time_t icaltime_as_timet_with_zone(struct icaltimetype tt, icaltimezone *zone); + /* Return a string represention of the time, in RFC2445 format. The string is owned by libical */ char* icaltime_as_ical_string(struct icaltimetype tt); @@ -77,20 +91,6 @@ int icaltime_as_int(struct icaltimetype); /* create a time from an ISO format string */ struct icaltimetype icaltime_from_string(const char* str); -/* Routines for handling timezones */ -/* Return the offset of the named zone as seconds. tt is a time - indicating the date for which you want the offset */ -int icaltime_utc_offset(struct icaltimetype tt, const char* tzid); - -/* convert tt, of timezone tzid, into a utc time. Does nothing if the - time is already UTC. */ -struct icaltimetype icaltime_as_utc(struct icaltimetype tt, - const char* tzid); - -/* convert tt, a time in UTC, into a time in timezone tzid */ -struct icaltimetype icaltime_as_zone(struct icaltimetype tt, - const char* tzid); - /* Return a null time, which indicates no time has been set. This time represent the beginning of the epoch */ struct icaltimetype icaltime_null_time(void); diff --git a/libical/src/libical/icaltimezone.c b/libical/src/libical/icaltimezone.c index 796e01a3ea..def5c1a6fc 100644 --- a/libical/src/libical/icaltimezone.c +++ b/libical/src/libical/icaltimezone.c @@ -30,15 +30,19 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include "icalproperty.h" #include "icalarray.h" #include "icalerror.h" #include "icalparser.h" #include "icaltimezone.h" - /* This is the toplevel directory where the timezone data is installed in. */ #define ZONEINFO_DIRECTORY PACKAGE_DATA_DIR "/zoneinfo" +/* The prefix we use to uniquely identify TZIDs. */ +#define TZID_PREFIX "/softwarestudio.org/" +#define TZID_PREFIX_LEN 20 + /* This is the filename of the file containing the city names and coordinates of all the builtin timezones. */ #define ZONES_TAB_FILENAME "zones.tab" @@ -49,7 +53,7 @@ /* This is the maximum year we will expand to. time_t values only go up to somewhere around 2037. */ -#define ICALTIMEZONE_MAX_YEAR 2032 +#define ICALTIMEZONE_MAX_YEAR 2035 struct _icaltimezone { @@ -130,6 +134,9 @@ icaltimezone utc_timezone = { 0 }; +static void icaltimezone_reset (icaltimezone *zone); +static char* icaltimezone_get_location_from_vtimezone (icalcomponent *component); +static char* icaltimezone_get_tznames_from_vtimezone (icalcomponent *component); static void icaltimezone_expand_changes (icaltimezone *zone, int end_year); static void icaltimezone_expand_vtimezone (icalcomponent *comp, @@ -149,14 +156,14 @@ static void icaltimezone_adjust_change (icaltimezonechange *tt, static void icaltimezone_init (icaltimezone *zone); -/* Initializes an icaltimezone from the given VTIMEZONE component. It gets - the TZID from the VTIMEZONE component. It returns 1 on success, or 0 if - the TZID can't be found. */ -static int icaltimezone_init_from_vtimezone (icaltimezone *zone, - icalcomponent *component); +/* Gets the TZID, LOCATION/X-LIC-LOCATION, and TZNAME properties from the + VTIMEZONE component and places them in the icaltimezone. It returns 1 on + success, or 0 if the TZID can't be found. */ +static int icaltimezone_get_vtimezone_properties (icaltimezone *zone, + icalcomponent *component); -static void icaltimezone_load (icaltimezone *zone); +static void icaltimezone_load_builtin_timezone (icaltimezone *zone); static void icaltimezone_ensure_coverage (icaltimezone *zone, int end_year); @@ -174,8 +181,53 @@ static void format_utc_offset (int utc_offset, char *buffer); +/* Creates a new icaltimezone. */ +icaltimezone* +icaltimezone_new (void) +{ + icaltimezone *zone; + + zone = (icaltimezone*) malloc (sizeof (icaltimezone)); + if (!zone) { + icalerror_set_errno (ICAL_NEWFAILED_ERROR); + return; + } + + icaltimezone_init (zone); -/* Initializes an icaltimezone with the given TZID. */ + return zone; +} + + +/* Frees all memory used for the icaltimezone. */ +void +icaltimezone_free (icaltimezone *zone) +{ + icaltimezone_reset (zone); + free (zone); +} + + +/* Resets the icaltimezone to the initial state, freeing most of the fields. */ +static void +icaltimezone_reset (icaltimezone *zone) +{ + if (zone->tzid) + free (zone->tzid); + if (zone->location) + free (zone->location); + if (zone->tznames) + free (zone->tznames); + if (zone->component) + icalcomponent_free (zone->component); + if (zone->changes) + icalarray_free (zone->changes); + + icaltimezone_init (zone); +} + + +/* Initializes an icaltimezone. */ static void icaltimezone_init (icaltimezone *zone) { @@ -191,31 +243,171 @@ icaltimezone_init (icaltimezone *zone) } -/* Initializes an icaltimezone from the given VTIMEZONE component. It gets - the TZID from the VTIMEZONE component. It returns 1 on success, or 0 if - the TZID can't be found. */ +/* Gets the TZID, LOCATION/X-LIC-LOCATION and TZNAME properties of the + VTIMEZONE component and stores them in the icaltimezone. + It returns 1 on success, or 0 if the TZID can't be found. + Note that it expects the zone to be initialized or reset - it doesn't free + any old values. */ static int -icaltimezone_init_from_vtimezone (icaltimezone *zone, +icaltimezone_get_vtimezone_properties (icaltimezone *zone, icalcomponent *component) { icalproperty *prop; - const char *tzid; - + const char *tzid, *location; + prop = icalcomponent_get_first_property (component, ICAL_TZID_PROPERTY); if (!prop) return 0; + /* A VTIMEZONE MUST have a TZID, or a lot of our code won't work. */ tzid = icalproperty_get_tzid (prop); if (!tzid) return 0; - icaltimezone_init (zone); zone->tzid = strdup (tzid); zone->component = component; + zone->location = icaltimezone_get_location_from_vtimezone (component); + zone->tznames = icaltimezone_get_tznames_from_vtimezone (component); return 1; } +/* Gets the LOCATION or X-LIC-LOCATION property from a VTIMEZONE. */ +static char* +icaltimezone_get_location_from_vtimezone (icalcomponent *component) +{ + icalproperty *prop; + const char *location; + char *name; + int found_location = 0; + + prop = icalcomponent_get_first_property (component, + ICAL_LOCATION_PROPERTY); + if (prop) { + location = icalproperty_get_location (prop); + if (location) + return strdup (location); + } + + prop = icalcomponent_get_first_property (component, ICAL_X_PROPERTY); + while (prop) { + name = icalproperty_get_x_name (prop); + if (name && !strcmp (name, "X-LIC-LOCATION")) { + location = icalproperty_get_x (prop); + if (location) + return strdup (location); + } + prop = icalcomponent_get_next_property (component, + ICAL_X_PROPERTY); + } +} + + +/* Gets the TZNAMEs used for the last STANDARD & DAYLIGHT components in a + VTIMEZONE. If both STANDARD and DAYLIGHT components use the same TZNAME, + it returns that. If they use different TZNAMEs, it formats them like + "EST/EDT". The returned string should be freed by the caller. */ +static char* +icaltimezone_get_tznames_from_vtimezone (icalcomponent *component) +{ + icalcomponent *comp; + icalcomponent_kind type; + icalproperty *prop; + struct icaltimetype dtstart; + struct icaldatetimeperiodtype rdate; + const char *current_tzname; + const char *standard_tzname = NULL, *daylight_tzname = NULL; + struct icaltimetype standard_max_date, daylight_max_date; + struct icaltimetype current_max_date; + + /* Step through the STANDARD & DAYLIGHT subcomponents. */ + comp = icalcomponent_get_first_component (component, ICAL_ANY_COMPONENT); + while (comp) { + type = icalcomponent_isa (comp); + if (type == ICAL_XSTANDARD_COMPONENT + || type == ICAL_XDAYLIGHT_COMPONENT) { + current_max_date = icaltime_null_time (); + current_tzname = NULL; + + /* Step through the properties. We want to find the TZNAME, and + the largest DTSTART or RDATE. */ + prop = icalcomponent_get_first_property (comp, ICAL_ANY_PROPERTY); + while (prop) { + switch (icalproperty_isa (prop)) { + case ICAL_TZNAME_PROPERTY: + current_tzname = icalproperty_get_tzname (prop); + break; + + case ICAL_DTSTART_PROPERTY: + dtstart = icalproperty_get_dtstart (prop); + if (icaltime_compare (dtstart, current_max_date) > 0) + current_max_date = dtstart; + + break; + + case ICAL_RDATE_PROPERTY: + rdate = icalproperty_get_rdate (prop); + if (icaltime_compare (rdate.time, current_max_date) > 0) + current_max_date = rdate.time; + + break; + + default: + break; + } + + prop = icalcomponent_get_next_property (comp, + ICAL_ANY_PROPERTY); + } + + if (current_tzname) { + if (type == ICAL_XSTANDARD_COMPONENT) { + if (!standard_tzname + || icaltime_compare (current_max_date, + standard_max_date) > 0) { + standard_max_date = current_max_date; + standard_tzname = current_tzname; + } + } else { + if (!daylight_tzname + || icaltime_compare (current_max_date, + daylight_max_date) > 0) { + daylight_max_date = current_max_date; + daylight_tzname = current_tzname; + } + } + } + } + + comp = icalcomponent_get_next_component (component, + ICAL_ANY_COMPONENT); + } + + /* If both standard and daylight TZNAMEs were found, if they are the same + we return just one, else we format them like "EST/EDT". */ + if (standard_tzname && daylight_tzname) { + int standard_len, daylight_len; + char *tznames; + + if (!strcmp (standard_tzname, daylight_tzname)) + return strdup (standard_tzname); + + standard_len = strlen (standard_tzname); + daylight_len = strlen (daylight_tzname); + tznames = malloc (standard_len + daylight_len + 2); + strcpy (tznames, standard_tzname); + tznames[standard_len] = '/'; + strcpy (tznames + standard_len + 1, daylight_tzname); + return tznames; + } else { + const char *tznames; + + /* If either of the TZNAMEs was found just return that, else NULL. */ + tznames = standard_tzname ? standard_tzname : daylight_tzname; + return strdup (tznames); + } +} + static void icaltimezone_ensure_coverage (icaltimezone *zone, @@ -228,7 +420,7 @@ icaltimezone_ensure_coverage (icaltimezone *zone, int changes_end_year; if (!zone->component) - icaltimezone_load (zone); + icaltimezone_load_builtin_timezone (zone); if (icaltimezone_minimum_expansion_year == -1) { struct tm *tmp_tm; @@ -922,80 +1114,37 @@ icaltimezone_adjust_change (icaltimezonechange *tt, } - -/* 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. */ -int -icaltimezone_compare_vtimezone (icalcomponent *vtimezone1, - icalcomponent *vtimezone2) +char* +icaltimezone_get_tzid (icaltimezone *zone) { - icalproperty *prop1, *prop2; - const char *tzid1, *tzid2; - char *tzid2_copy, *string1, *string2; - int cmp; - - /* Get the TZID property of the first VTIMEZONE. */ - prop1 = icalcomponent_get_first_property (vtimezone1, ICAL_TZID_PROPERTY); - if (!prop1) - return -1; - - tzid1 = icalproperty_get_tzid (prop1); - if (!tzid1) - return -1; - - /* Get the TZID property of the second VTIMEZONE. */ - prop2 = icalcomponent_get_first_property (vtimezone1, ICAL_TZID_PROPERTY); - if (!prop2) - return -1; - - tzid2 = icalproperty_get_tzid (prop2); - if (!tzid2) - return -1; - - /* Copy the second TZID, and set the property to the same as the first - TZID, since we don't care if these match of not. */ - tzid2_copy = strdup (tzid2); - icalproperty_set_tzid (prop2, tzid1); - - /* Now convert both VTIMEZONEs to strings and compare them. */ - string1 = icalcomponent_as_ical_string (vtimezone1); - if (!string1) { - free (tzid2_copy); - return -1; - } - - string2 = icalcomponent_as_ical_string (vtimezone2); - if (!string2) { - free (string1); - free (tzid2_copy); - return -1; - } + /* If this is a local time, without a timezone, return NULL. */ + if (!zone) + return NULL; - cmp = strcmp (string1, string2); - - free (string1); - free (string2); - - /* Now reset the second TZID. */ - icalproperty_set_tzid (prop2, tzid2_copy); - free (tzid2_copy); + if (!zone->component) + icaltimezone_load_builtin_timezone (zone); - return (cmp == 0) ? 1 : 0; + return zone->tzid; } - char* -icaltimezone_get_tzid (icaltimezone *zone) +icaltimezone_get_location (icaltimezone *zone) { - return zone->tzid; + if (!zone->component) + icaltimezone_load_builtin_timezone (zone); + + return zone->location; } char* -icaltimezone_get_location (icaltimezone *zone) +icaltimezone_get_tznames (icaltimezone *zone) { - return zone->location; + if (!zone->component) + icaltimezone_load_builtin_timezone (zone); + + return zone->tznames; } @@ -1003,6 +1152,9 @@ icaltimezone_get_location (icaltimezone *zone) double icaltimezone_get_latitude (icaltimezone *zone) { + if (!zone->component) + icaltimezone_load_builtin_timezone (zone); + return zone->latitude; } @@ -1011,6 +1163,9 @@ icaltimezone_get_latitude (icaltimezone *zone) double icaltimezone_get_longitude (icaltimezone *zone) { + if (!zone->component) + icaltimezone_load_builtin_timezone (zone); + return zone->longitude; } @@ -1019,8 +1174,22 @@ icaltimezone_get_longitude (icaltimezone *zone) icalcomponent* icaltimezone_get_component (icaltimezone *zone) { + if (!zone->component) + icaltimezone_load_builtin_timezone (zone); + return zone->component; +} + +/* Sets the VTIMEZONE component of an icaltimezone, initializing the tzid, + location & tzname fields. It returns 1 on success or 0 on failure, i.e. + no TZID was found. */ +int +icaltimezone_set_component (icaltimezone *zone, + icalcomponent *comp) +{ + icaltimezone_reset (zone); + return icaltimezone_get_vtimezone_properties (zone, comp); } @@ -1037,7 +1206,8 @@ icaltimezone_array_append_from_vtimezone (icalarray *timezones, { icaltimezone zone; - if (icaltimezone_init_from_vtimezone (&zone, child)) + icaltimezone_init (&zone); + if (icaltimezone_get_vtimezone_properties (&zone, child)) icalarray_append (timezones, &zone); } @@ -1061,7 +1231,95 @@ icaltimezone_get_builtin_timezones (void) } -/* Returns an icaltimezone corresponding to the given location. */ +/* Returns a single builtin timezone, given its Olson city name. */ +icaltimezone* +icaltimezone_get_builtin_timezone (const char *location) +{ + icaltimezone *zone; + int lower, upper, middle, cmp; + char *zone_location; + + fprintf (stderr, "Getting builtin timezone: %s\n", location); + + if (!location || !location[0]) + return NULL; + + if (!strcmp (location, "UTC")) + return &utc_timezone; + + if (!builtin_timezones) + icaltimezone_init_builtin_timezones (); + + /* Do a simple binary search. */ + lower = middle = 0; + upper = builtin_timezones->num_elements; + + while (lower < upper) { + middle = (lower + upper) >> 1; + zone = icalarray_element_at (builtin_timezones, middle); + zone_location = icaltimezone_get_location (zone); + fprintf (stderr, " comparing with: %s\n", zone_location); + cmp = strcmp (location, zone_location); + if (cmp == 0) + return zone; + else if (cmp < 0) + upper = middle; + else + lower = middle + 1; + } + + fprintf (stderr, " not found\n"); + + return NULL; +} + + +/* Returns a single builtin timezone, given its TZID. */ +icaltimezone* +icaltimezone_get_builtin_timezone_from_tzid (const char *tzid) +{ + int num_slashes = 0; + const char *p, *zone_tzid; + icaltimezone *zone; + + fprintf (stderr, "Getting builtin timezone from TZID: %s\n", tzid); + + /* Check that the TZID starts with our unique prefix. */ + if (strncmp (tzid, TZID_PREFIX, TZID_PREFIX_LEN)) + return NULL; + + /* Get the location, which is after the 3rd '/' character. */ + p = tzid; + for (p = tzid; *p; p++) { + if (*p == '/') { + num_slashes++; + if (num_slashes == 3) + break; + } + } + + if (num_slashes != 3) + return NULL; + + p++; + + /* Now we can use the function to get the builtin timezone from the + location string. */ + zone = icaltimezone_get_builtin_timezone (p); + if (!zone) + return NULL; + + /* Check that the builtin TZID matches exactly. We don't want to return + a different version of the VTIMEZONE. */ + zone_tzid = icaltimezone_get_tzid (zone); + if (!strcmp (zone_tzid, tzid)) + return zone; + else + return NULL; +} + + +/* Returns the special UTC timezone. */ icaltimezone* icaltimezone_get_utc_timezone (void) { @@ -1104,6 +1362,8 @@ icaltimezone_parse_zone_tab (void) icalerror_assert (builtin_timezones == NULL, "Parsing zones.tab file multiple times"); + builtin_timezones = icalarray_new (sizeof (icaltimezone), 32); + filename_len = strlen (ZONEINFO_DIRECTORY) + strlen (ZONES_TAB_FILENAME) + 2; @@ -1123,8 +1383,6 @@ icaltimezone_parse_zone_tab (void) return; } - builtin_timezones = icalarray_new (sizeof (icaltimezone), 32); - while (fgets (buf, sizeof(buf), fp)) { if (*buf == '#') continue; @@ -1174,13 +1432,17 @@ icaltimezone_parse_zone_tab (void) /* Loads the builtin VTIMEZONE data for the given timezone. */ static void -icaltimezone_load (icaltimezone *zone) +icaltimezone_load_builtin_timezone (icaltimezone *zone) { char *filename; int filename_len; FILE *fp; icalparser *parser; - icalcomponent *comp; + icalcomponent *comp, *subcomp; + + /* If the location isn't set, it isn't a builtin timezone. */ + if (!zone->location || !zone->location[0]) + return; filename_len = strlen (ZONEINFO_DIRECTORY) + strlen (zone->location) + 6; @@ -1207,7 +1469,14 @@ icaltimezone_load (icaltimezone *zone) fclose (fp); /* Find the VTIMEZONE component inside the VCALENDAR. There should be 1. */ - zone->component = icalcomponent_get_first_component (comp, ICAL_VTIMEZONE_COMPONENT); + subcomp = icalcomponent_get_first_component (comp, + ICAL_VTIMEZONE_COMPONENT); + if (!subcomp) { + icalerror_set_errno(ICAL_PARSE_ERROR); + return; + } + + icaltimezone_get_vtimezone_properties (zone, subcomp); } diff --git a/libical/src/libical/icaltimezone.h b/libical/src/libical/icaltimezone.h index 2f6487e1e9..693d6bbb80 100644 --- a/libical/src/libical/icaltimezone.h +++ b/libical/src/libical/icaltimezone.h @@ -29,11 +29,19 @@ #include <stdio.h> /* For FILE* */ #include "icaltime.h" +#include "icalarray.h" +#include "icalcomponent.h" -/* An opaque struct representing a timezone. */ -typedef struct _icaltimezone icaltimezone; +/* + * Creating/Destroying individual icaltimezones. + */ +/* Creates a new icaltimezone. */ +icaltimezone *icaltimezone_new (void); + +/* Frees all memory used for the icaltimezone. */ +void icaltimezone_free (icaltimezone *zone); /* @@ -46,6 +54,9 @@ icalarray* icaltimezone_get_builtin_timezones (void); /* Returns a single builtin timezone, given its Olson city name. */ icaltimezone* icaltimezone_get_builtin_timezone (const char *location); +/* Returns a single builtin timezone, given its TZID. */ +icaltimezone* icaltimezone_get_builtin_timezone_from_tzid (const char *tzid); + /* Returns the UTC timezone. */ icaltimezone* icaltimezone_get_utc_timezone (void); @@ -55,6 +66,12 @@ char* icaltimezone_get_tzid (icaltimezone *zone); /* Returns the city name of a timezone. */ char* icaltimezone_get_location (icaltimezone *zone); +/* Returns the TZNAME properties used in the latest STANDARD and DAYLIGHT + components. If they are the same it will return just one, e.g. "LMT". + If they are different it will format them like "EST/EDT". Note that this + may also return NULL. */ +char* icaltimezone_get_tznames (icaltimezone *zone); + /* Returns the latitude of a builtin timezone. */ double icaltimezone_get_latitude (icaltimezone *zone); @@ -64,6 +81,11 @@ double icaltimezone_get_longitude (icaltimezone *zone); /* Returns the VTIMEZONE component of a timezone. */ icalcomponent* icaltimezone_get_component (icaltimezone *zone); +/* Sets the VTIMEZONE component of an icaltimezone, initializing the tzid, + location & tzname fields. It returns 1 on success or 0 on failure, i.e. + no TZID was found. */ +int icaltimezone_set_component (icaltimezone *zone, + icalcomponent *comp); /* * Converting times between timezones. @@ -94,21 +116,8 @@ int icaltimezone_get_utc_offset_of_utc_time (icaltimezone *zone, - -/* - * Comparing VTIMEZONE components. - */ - -/* 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. */ -int icaltimezone_compare_vtimezone (icalcomponent *vtimezone1, - icalcomponent *vtimezone2); - - - - /* - * Handling arrays of timezones. + * Handling arrays of timezones. Mainly for internal use. */ icalarray* icaltimezone_array_new (void); |