From 53d3fd9cef15ec864b645958ddeeca288da3661f Mon Sep 17 00:00:00 2001 From: Milan Crha Date: Tue, 10 Nov 2020 20:59:19 +0100 Subject: [PATCH 1/2] icaltimezone.c: Correct handling of builtin timezones properties Make the built-in time zones set expected TZID and LOCATION/X-LIC-LOCATION also for internal zone data, thus when the timezone component is stored to a string and read back it preserves these values. --- src/libical/icaltimezone.c | 42 ++++++++++++++++++++++++++++++++++++++ src/test/regression.c | 18 ++++++++++++++-- 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/src/libical/icaltimezone.c b/src/libical/icaltimezone.c index b518677b..36403f96 100644 --- a/src/libical/icaltimezone.c +++ b/src/libical/icaltimezone.c @@ -1830,6 +1830,48 @@ static void icaltimezone_load_builtin_timezone(icaltimezone *zone) /* Find the VTIMEZONE component inside the VCALENDAR. There should be 1. */ subcomp = icalcomponent_get_first_component(comp, ICAL_VTIMEZONE_COMPONENT); + + if (subcomp) { + icalproperty *prop; + + /* Ensure expected TZID */ + prop = icalcomponent_get_first_property(subcomp, ICAL_TZID_PROPERTY); + if(prop) { + char *new_tzid; + size_t new_tzid_len; + const char *tzid_prefix = icaltimezone_tzid_prefix(); + + new_tzid_len = strlen(tzid_prefix) + strlen(zone->location) + 1; + new_tzid = (char *)malloc(sizeof(char)*(new_tzid_len + 1)); + if(new_tzid) { + snprintf(new_tzid, new_tzid_len, "%s%s", tzid_prefix, zone->location); + icalproperty_set_tzid(prop, new_tzid); + free(new_tzid); + } else { + icalerror_set_errno(ICAL_NEWFAILED_ERROR); + } + } + + /* Ensure expected Location - it's for cases where one VTIMEZONE is shared + between different locations (like Pacific/Midway is Pacific/Pago_Pago). + This updates the properties, thus when the component is converted to + the string and back to the component the Location will still match. */ + prop = icalcomponent_get_first_property(subcomp, ICAL_LOCATION_PROPERTY); + if (prop) + icalproperty_set_location(prop, zone->location); + + for (prop = icalcomponent_get_first_property(subcomp, ICAL_X_PROPERTY); + prop; + prop = icalcomponent_get_next_property(subcomp, ICAL_X_PROPERTY)) { + const char *name; + + name = icalproperty_get_x_name(prop); + if (name && !strcasecmp(name, "X-LIC-LOCATION")) { + icalproperty_set_x(prop, zone->location); + break; + } + } + } } else { subcomp = icaltzutil_fetch_timezone(zone->location); } diff --git a/src/test/regression.c b/src/test/regression.c index 8b802e09..922557fb 100644 --- a/src/test/regression.c +++ b/src/test/regression.c @@ -4432,11 +4432,25 @@ void test_timezone_from_builtin(void) ok("DTEND is America/New_York", (strcmp(icaltimezone_get_location((icaltimezone *) dtend.zone), "America/New_York") == 0)); ok("DUE is Europe/Berlin", (strcmp(icaltimezone_get_location((icaltimezone *) due.zone), "Europe/Berlin") == 0)); - icaltimezone_set_tzid_prefix(TESTS_TZID_PREFIX); - icalcomponent_free(comp); free(tzidprefix); free(strcomp); + + zone = icaltimezone_get_builtin_timezone("Pacific/Midway"); + ok("builtin location is Pacific/Midway", (strcmp(icaltimezone_get_location((icaltimezone *) zone), "Pacific/Midway") == 0)); + comp = icaltimezone_get_component(zone); + strcomp = icalcomponent_as_ical_string_r(comp); + comp = icalcomponent_new_from_string(strcomp); + free(strcomp); + + ok("VTIMEZONE icalcomponent_new_from_string()", (comp != NULL)); + + zone = icaltimezone_new(); + ok("set icaltimezone component", (icaltimezone_set_component(zone, comp))); + ok("read from string builtin location is still Pacific/Midway", (strcmp(icaltimezone_get_location((icaltimezone *) zone), "Pacific/Midway") == 0)); + icaltimezone_free(zone, 1); + + icaltimezone_set_tzid_prefix(TESTS_TZID_PREFIX); } void test_icalvalue_decode_ical_string(void) -- 2.26.2