syncevolution.org binaries are now getting compiled on Ubuntu Trusty and thus no longer support distros with older EDS. The code should still compile against older EDS (for example, for Maemo), but that is not getting tested anymore. This allows removing the dynamic linker hacks related to older libraries, which was only used in those binaries. Instead, backends using libical or EDS get compiled on Ubuntu Trusty and then the soname of those libs get patched to make the backend module usable in combination with a different set of libs. That patching is part of a script maintained in the syncevolution.org build infrastructure. This approach was already used before to generate different EDS backends for EDS versions with the newer EClient API, because that turned out to be easier than the dynamic loading approach. It works because none of the methods used by SyncEvolution changed their ABI, only some other parts of the libraries did. Should there ever be a situation again that cannot be handled like this, then backends might also get compiled on different distros than Ubuntu Trusty (however, that may lead to problems due to the libstdc++ ABI changes - to be decided...). libical still requires one special hack: system time zone loading in libical v1 (and only in that version, v2 has builtin support again) must be overridden such that time zones are generated with rules instead of transitions because that is more compatible with the peers that SyncEvolution exchanges data with. That hack now relies on overriding the two relevant functions inside the main binaries (has to be there, otherwise libical still ends up calling its own internal implementation). The overriding code is in libsyncevo-icaltz-util.so.0 and depends on libical.so.1. If libsyncevo-icaltz-util.so.0 can be loaded, the wrappers in the main binary use it, otherwise they fall through to the code from the current libical.so, which then should be libical.so.2 or more recent. This hack is active by default when libical v1 is detected during configuration.
656 lines
16 KiB
C
656 lines
16 KiB
C
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
|
|
/*
|
|
* Authors :
|
|
* Chenthill Palanisamy <pchenthill@novell.com>
|
|
*
|
|
* Copyright 2007, Novell, Inc.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of version 2 of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License for more details.
|
|
*
|
|
* * You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
/*
|
|
* Compile with
|
|
* gcc -c -Wall -DDISABLE_ICALTZUTIL_GET_ZONE_DIRECTORY -DICALTZ_UTIL_MAIN -DHAVE_UNISTD_H -DHAVE_ENDIAN_H -DHAVE_BYTESWAP_H $(pkg-config --cflags --libs libical) -o icaltz-util icaltz-util.c
|
|
* to get an utility which will print the VTIMEZONE definition of
|
|
* a certain location, for example "Europe/Berlin".
|
|
*
|
|
* With -DDISABLE_ICALTZUTIL_GET_ZONE_DIRECTORY the
|
|
* icaltzutil_get_zone_directory() from libical will be used.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
#include <string.h>
|
|
|
|
#ifdef ICALTZ_UTIL_MAIN
|
|
#include <stdio.h>
|
|
#endif
|
|
|
|
#ifdef EVOLUTION_ICAL_COMPATIBILITY
|
|
# include "eds_abi_wrapper.h"
|
|
# else
|
|
# include <libical/icaltimezone.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_STDINT_H
|
|
#include <stdint.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
#if defined(sun) && defined(__SVR4)
|
|
#include <sys/types.h>
|
|
#include <sys/byteorder.h>
|
|
#else
|
|
# ifdef HAVE_BYTESWAP_H
|
|
# include <byteswap.h>
|
|
# endif
|
|
# ifdef HAVE_ENDIAN_H
|
|
# include <endian.h>
|
|
# else
|
|
# ifdef HAVE_SYS_ENDIAN_H
|
|
# include <sys/endian.h>
|
|
# ifdef bswap32
|
|
# define bswap_32 bswap32
|
|
# else
|
|
# define bswap_32 swap32
|
|
# endif
|
|
# endif
|
|
# endif
|
|
#endif
|
|
|
|
#ifdef _MSC_VER
|
|
#if !defined(HAVE_BYTESWAP_H) && !defined(HAVE_SYS_ENDIAN_H) && !defined(HAVE_ENDIAN_H)
|
|
#define bswap_16(x) (((x) << 8) & 0xff00) | (((x) >> 8 ) & 0xff)
|
|
#define bswap_32(x) (((x) << 24) & 0xff000000) \
|
|
| (((x) << 8) & 0xff0000) \
|
|
| (((x) >> 8) & 0xff00) \
|
|
| (((x) >> 24) & 0xff )
|
|
#define bswap_64(x) ((((x) & 0xff00000000000000ull) >> 56) \
|
|
| (((x) & 0x00ff000000000000ull) >> 40) \
|
|
| (((x) & 0x0000ff0000000000ull) >> 24) \
|
|
| (((x) & 0x000000ff00000000ull) >> 8) \
|
|
| (((x) & 0x00000000ff000000ull) << 8) \
|
|
| (((x) & 0x0000000000ff0000ull) << 24) \
|
|
| (((x) & 0x000000000000ff00ull) << 40) \
|
|
| (((x) & 0x00000000000000ffull) << 56))
|
|
#endif
|
|
#include <io.h>
|
|
#endif
|
|
|
|
#if defined(__APPLE__)
|
|
#define bswap_16(x) (((x) << 8) & 0xff00) | (((x) >> 8 ) & 0xff)
|
|
#define bswap_32 __builtin_bswap32
|
|
#define bswap_64 __builtin_bswap64
|
|
#endif
|
|
|
|
#ifndef PATH_MAX
|
|
#define PATH_MAX 512
|
|
#endif
|
|
|
|
#ifndef F_OK
|
|
#define F_OK 0
|
|
#endif
|
|
|
|
#ifndef R_OK
|
|
#define R_OK 4
|
|
#endif
|
|
|
|
#include <limits.h>
|
|
#include <time.h>
|
|
#include <stdlib.h>
|
|
#ifdef HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
#include <libical/icalerror.h>
|
|
#include "icaltz-util.h"
|
|
|
|
typedef struct
|
|
{
|
|
char ttisgmtcnt [4];
|
|
char ttisstdcnt[4];
|
|
char leapcnt[4];
|
|
char timecnt[4];
|
|
char typecnt[4];
|
|
char charcnt[4];
|
|
} tzinfo;
|
|
|
|
static int r_pos [] = {1, 2, 3, -2, -1};
|
|
|
|
#ifndef DISABLE_ICALTZUTIL_GET_ZONE_DIRECTORY
|
|
static char *search_paths [] = {"/usr/share/zoneinfo","/usr/lib/zoneinfo","/etc/zoneinfo","/usr/share/lib/zoneinfo"};
|
|
static char *zdir = NULL;
|
|
#endif
|
|
|
|
#define NUM_SEARCH_PATHS (sizeof (search_paths)/ sizeof (search_paths [0]))
|
|
#define EFREAD(buf,size,num,fs) \
|
|
if (fread (buf, size, num, fs) == 0 && ferror (fs)) {\
|
|
icalerror_set_errno (ICAL_FILE_ERROR); \
|
|
goto error; \
|
|
} \
|
|
|
|
typedef struct
|
|
{
|
|
long int gmtoff;
|
|
unsigned char isdst;
|
|
unsigned int abbr;
|
|
unsigned char isstd;
|
|
unsigned char isgmt;
|
|
char *zname;
|
|
|
|
} ttinfo;
|
|
|
|
typedef struct
|
|
{
|
|
time_t transition;
|
|
long int change;
|
|
} leap;
|
|
|
|
#ifndef EVOLUTION_ICAL_COMPATIBILITY
|
|
extern const char *ical_tzid_prefix;
|
|
#endif
|
|
|
|
static int
|
|
decode (const void *ptr)
|
|
{
|
|
#if defined(sun) && defined(__SVR4)
|
|
if (sizeof (int) == 4)
|
|
#ifdef _BIG_ENDIAN
|
|
return *(const int *) ptr;
|
|
#else
|
|
return BSWAP_32 (*(const int *) ptr);
|
|
#endif
|
|
#else
|
|
if ((BYTE_ORDER == BIG_ENDIAN) && sizeof (int) == 4)
|
|
return *(const int *) ptr;
|
|
else if (BYTE_ORDER == LITTLE_ENDIAN && sizeof (int) == 4)
|
|
return bswap_32 (*(const int *) ptr);
|
|
#endif
|
|
else
|
|
{
|
|
const unsigned char *p = ptr;
|
|
int result = *p & (1 << (CHAR_BIT - 1)) ? ~0 : 0;
|
|
|
|
result = (result << 8) | *p++;
|
|
result = (result << 8) | *p++;
|
|
result = (result << 8) | *p++;
|
|
result = (result << 8) | *p++;
|
|
|
|
return result;
|
|
}
|
|
}
|
|
|
|
static char *
|
|
zname_from_stridx (char *str, long int idx)
|
|
{
|
|
int i = 0;
|
|
char *ret;
|
|
size_t size;
|
|
|
|
i = idx;
|
|
|
|
while (str [i] != '\0')
|
|
i++;
|
|
|
|
size = i - idx;
|
|
str += idx;
|
|
ret = (char *) malloc (size + 1);
|
|
ret = strncpy (ret, str, size);
|
|
ret [size] = '\0';
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void
|
|
find_transidx (time_t *transitions, ttinfo *types, int *trans_idx, long int num_trans, int *stdidx, int *dstidx)
|
|
{
|
|
time_t now, year_start;
|
|
int i, found = 0;
|
|
struct icaltimetype itime;
|
|
|
|
now = time (NULL);
|
|
itime = icaltime_from_timet (now, 0);
|
|
itime.month = itime.day = 1;
|
|
itime.hour = itime.minute = itime.second = 0;
|
|
year_start = icaltime_as_timet(itime);
|
|
|
|
/* Set this by default */
|
|
*stdidx = (num_trans - 1);
|
|
|
|
for (i = (num_trans - 1); i >= 0; --i)
|
|
if (year_start < transitions [i]) {
|
|
int idx;
|
|
found = 1;
|
|
idx = trans_idx [i];
|
|
(types [idx].isdst) ? (*dstidx = i) : (*stdidx = i);
|
|
}
|
|
|
|
/* If the transition found is the last among the list, prepare to use the last two transtions.
|
|
* Using this will most likely throw the DTSTART of the resulting component off by 1 or 2 days
|
|
* but it would set right by the adjustment made.
|
|
* NOTE: We need to use the last two transitions only because there is no data for the future
|
|
* transitions.
|
|
*/
|
|
if (found && (*dstidx == -1)) {
|
|
*dstidx = ((*stdidx) - 1);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
#ifndef DISABLE_ICALTZUTIL_GET_ZONE_DIRECTORY
|
|
static void
|
|
set_zonedir (void)
|
|
{
|
|
char file_path[PATH_MAX];
|
|
const char *fname = ZONES_TAB_SYSTEM_FILENAME;
|
|
int i;
|
|
|
|
for (i = 0;i < NUM_SEARCH_PATHS; i++) {
|
|
sprintf (file_path, "%s/%s", search_paths [i], fname);
|
|
if (!access (file_path, F_OK|R_OK)) {
|
|
zdir = search_paths [i];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
const char *
|
|
icaltzutil_get_zone_directory (void)
|
|
{
|
|
if (!zdir)
|
|
set_zonedir ();
|
|
|
|
return zdir;
|
|
}
|
|
#endif
|
|
|
|
/* Calculate the relative position of the week in a month from a date */
|
|
static int
|
|
calculate_pos (icaltimetype icaltime)
|
|
{
|
|
int pos;
|
|
|
|
pos = (icaltime.day -1) / 7;
|
|
|
|
/* Check if pos 3 is the last occurence of the week day in the month */
|
|
if (pos == 3 && ((icaltime.day + 7) > icaltime_days_in_month (icaltime.month, icaltime.year)))
|
|
pos = 4;
|
|
|
|
return r_pos [pos];
|
|
}
|
|
|
|
static void
|
|
adjust_dtstart_day_to_rrule (icalcomponent *comp, struct icalrecurrencetype rule)
|
|
{
|
|
time_t now, year_start;
|
|
struct icaltimetype start, comp_start, iter_start, itime;
|
|
icalrecur_iterator *iter;
|
|
|
|
now = time (NULL);
|
|
itime = icaltime_from_timet (now, 0);
|
|
itime.month = itime.day = 1;
|
|
itime.hour = itime.minute = itime.second = 0;
|
|
year_start = icaltime_as_timet(itime);
|
|
|
|
comp_start = icalcomponent_get_dtstart (comp);
|
|
start = icaltime_from_timet (year_start, 0);
|
|
|
|
iter = icalrecur_iterator_new (rule, start);
|
|
iter_start = icalrecur_iterator_next (iter);
|
|
icalrecur_iterator_free (iter);
|
|
|
|
if (iter_start.day != comp_start.day) {
|
|
comp_start.day = iter_start.day;
|
|
icalcomponent_set_dtstart (comp, comp_start);
|
|
}
|
|
}
|
|
|
|
icalcomponent*
|
|
icaltzutil_fetch_timezone (const char *location)
|
|
{
|
|
int ret = 0;
|
|
FILE *f;
|
|
tzinfo type_cnts;
|
|
unsigned int i, num_trans, num_types = 0, num_chars, num_leaps, num_isstd, num_isgmt;
|
|
time_t *transitions = NULL;
|
|
time_t trans;
|
|
int *trans_idx = NULL, dstidx = -1, stdidx = -1, pos, sign, zidx, zp_idx;
|
|
ttinfo *types = NULL;
|
|
char *znames = NULL, *full_path, *tzid, *r_trans, *temp = NULL;
|
|
leap *leaps = NULL;
|
|
icalcomponent *tz_comp = NULL, *dst_comp = NULL, *std_comp = NULL;
|
|
icalproperty *icalprop;
|
|
icaltimetype dtstart, icaltime;
|
|
struct icalrecurrencetype ical_recur;
|
|
const char *basedir;
|
|
|
|
/* if (!location) return NULL; */
|
|
|
|
basedir = icaltzutil_get_zone_directory();
|
|
if (!basedir) {
|
|
icalerror_set_errno (ICAL_FILE_ERROR);
|
|
return NULL;
|
|
}
|
|
|
|
full_path = (char *) malloc (strlen (basedir) + strlen (location) + 2);
|
|
sprintf (full_path,"%s/%s",basedir, location);
|
|
|
|
if ((f = fopen (full_path, "rb")) == 0) {
|
|
icalerror_set_errno (ICAL_FILE_ERROR);
|
|
free (full_path);
|
|
return NULL;
|
|
}
|
|
|
|
if ((ret = fseek (f, 20, SEEK_SET)) != 0) {
|
|
icalerror_set_errno (ICAL_FILE_ERROR);
|
|
goto error;
|
|
}
|
|
|
|
EFREAD(&type_cnts, 24, 1, f);
|
|
|
|
num_isgmt = decode (type_cnts.ttisgmtcnt);
|
|
num_leaps = decode (type_cnts.leapcnt);
|
|
num_chars = decode (type_cnts.charcnt);
|
|
num_trans = decode (type_cnts.timecnt);
|
|
num_isstd = decode (type_cnts.ttisstdcnt);
|
|
num_types = decode (type_cnts.typecnt);
|
|
|
|
transitions = calloc (num_trans, sizeof (time_t));
|
|
temp = calloc (num_trans, 4);
|
|
r_trans = temp;
|
|
EFREAD(r_trans, 4, num_trans, f);
|
|
|
|
if (num_trans) {
|
|
trans_idx = calloc (num_trans, sizeof (int));
|
|
for (i = 0; i < num_trans; i++) {
|
|
trans_idx [i] = fgetc (f);
|
|
transitions [i] = decode (r_trans);
|
|
r_trans += 4;
|
|
}
|
|
}
|
|
|
|
free (temp);
|
|
temp = NULL;
|
|
|
|
types = calloc (num_types, sizeof (ttinfo));
|
|
for (i = 0; i < num_types; i++) {
|
|
unsigned char a [4];
|
|
int c;
|
|
|
|
EFREAD(a, 4, 1, f);
|
|
c = fgetc (f);
|
|
types [i].isdst = c;
|
|
if((c = fgetc (f)) < 0) {
|
|
break;
|
|
}
|
|
types [i].abbr = c;
|
|
types [i].gmtoff = decode (a);
|
|
}
|
|
|
|
znames = (char *) malloc (num_chars);
|
|
EFREAD(znames, num_chars, 1, f);
|
|
|
|
/* We got all the information which we need */
|
|
|
|
leaps = calloc (num_leaps, sizeof (leap));
|
|
for (i = 0; i < num_leaps; i++) {
|
|
char c [4];
|
|
|
|
EFREAD (c, 4, 1, f);
|
|
leaps [i].transition = decode (c);
|
|
|
|
EFREAD (c, 4, 1, f);
|
|
leaps [i].change = decode (c);
|
|
}
|
|
|
|
for (i = 0; i < num_isstd; ++i) {
|
|
int c = getc (f);
|
|
types [i].isstd = c != 0;
|
|
}
|
|
|
|
while (i < num_types)
|
|
types [i++].isstd = 0;
|
|
|
|
for (i = 0; i < num_isgmt; ++i) {
|
|
int c = getc (f);
|
|
types [i].isgmt = c != 0;
|
|
}
|
|
|
|
while (i < num_types)
|
|
types [i++].isgmt = 0;
|
|
|
|
/* Read all the contents now */
|
|
|
|
for (i = 0; i < num_types; i++)
|
|
types [i].zname = zname_from_stridx (znames, types [i].abbr);
|
|
|
|
if (num_trans != 0)
|
|
find_transidx (transitions, types, trans_idx, num_trans, &stdidx, &dstidx);
|
|
else
|
|
stdidx = 0;
|
|
|
|
tz_comp = icalcomponent_new (ICAL_VTIMEZONE_COMPONENT);
|
|
|
|
/* Add tzid property */
|
|
tzid = (char *) malloc (strlen (ical_tzid_prefix) + strlen (location) + 8);
|
|
sprintf (tzid, "%sTzfile/%s", ical_tzid_prefix, location);
|
|
icalprop = icalproperty_new_tzid (tzid);
|
|
icalcomponent_add_property (tz_comp, icalprop);
|
|
free (tzid);
|
|
|
|
icalprop = icalproperty_new_x (location);
|
|
icalproperty_set_x_name (icalprop, "X-LIC-LOCATION");
|
|
icalcomponent_add_property (tz_comp, icalprop);
|
|
|
|
if (stdidx != -1) {
|
|
if (num_trans != 0)
|
|
zidx = trans_idx [stdidx];
|
|
else
|
|
zidx = 0;
|
|
|
|
std_comp = icalcomponent_new (ICAL_XSTANDARD_COMPONENT);
|
|
icalprop = icalproperty_new_tzname (types [zidx].zname);
|
|
icalcomponent_add_property (std_comp, icalprop);
|
|
|
|
if (dstidx != -1)
|
|
zp_idx = trans_idx [stdidx-1];
|
|
else
|
|
zp_idx = zidx;
|
|
/* DTSTART localtime uses TZOFFSETFROM UTC offset */
|
|
if (num_trans != 0)
|
|
trans = transitions [stdidx] + types [zp_idx].gmtoff;
|
|
else
|
|
trans = types [zp_idx].gmtoff;
|
|
icaltime = icaltime_from_timet (trans, 0);
|
|
dtstart = icaltime;
|
|
dtstart.year = 1970;
|
|
dtstart.minute = dtstart.second = 0;
|
|
icalprop = icalproperty_new_dtstart (dtstart);
|
|
icalcomponent_add_property (std_comp, icalprop);
|
|
|
|
/* If DST changes are present use RRULE */
|
|
if (dstidx != -1) {
|
|
icalrecurrencetype_clear (&ical_recur);
|
|
ical_recur.freq = ICAL_YEARLY_RECURRENCE;
|
|
ical_recur.by_month [0] = icaltime.month;
|
|
pos = calculate_pos (icaltime);
|
|
pos < 0 ? (sign = -1): (sign = 1);
|
|
ical_recur.by_day [0] = sign * ((abs (pos) * 8) + icaltime_day_of_week (icaltime));
|
|
icalprop = icalproperty_new_rrule (ical_recur);
|
|
icalcomponent_add_property (std_comp, icalprop);
|
|
|
|
adjust_dtstart_day_to_rrule (std_comp, ical_recur);
|
|
}
|
|
icalprop = icalproperty_new_tzoffsetfrom (types [zp_idx].gmtoff);
|
|
icalcomponent_add_property (std_comp, icalprop);
|
|
|
|
icalprop = icalproperty_new_tzoffsetto (types [zidx].gmtoff);
|
|
icalcomponent_add_property (std_comp, icalprop);
|
|
|
|
icalcomponent_add_component (tz_comp, std_comp);
|
|
} else
|
|
icalerror_set_errno (ICAL_MALFORMEDDATA_ERROR);
|
|
|
|
if (dstidx != -1) {
|
|
zidx = trans_idx [dstidx];
|
|
zp_idx = trans_idx [dstidx-1];
|
|
dst_comp = icalcomponent_new (ICAL_XDAYLIGHT_COMPONENT);
|
|
icalprop = icalproperty_new_tzname (types [zidx].zname);
|
|
icalcomponent_add_property (dst_comp, icalprop);
|
|
|
|
/* DTSTART localtime uses TZOFFSETFROM UTC offset */
|
|
if (num_trans != 0)
|
|
trans = transitions [dstidx] + types [zp_idx].gmtoff;
|
|
else
|
|
trans = types [zp_idx].gmtoff;
|
|
icaltime = icaltime_from_timet (trans, 0);
|
|
dtstart = icaltime;
|
|
dtstart.year = 1970;
|
|
dtstart.minute = dtstart.second = 0;
|
|
icalprop = icalproperty_new_dtstart (dtstart);
|
|
icalcomponent_add_property (dst_comp, icalprop);
|
|
|
|
icalrecurrencetype_clear (&ical_recur);
|
|
ical_recur.freq = ICAL_YEARLY_RECURRENCE;
|
|
ical_recur.by_month [0] = icaltime.month;
|
|
pos = calculate_pos (icaltime);
|
|
pos < 0 ? (sign = -1): (sign = 1);
|
|
ical_recur.by_day [0] = sign * ((abs (pos) * 8) + icaltime_day_of_week (icaltime));
|
|
icalprop = icalproperty_new_rrule (ical_recur);
|
|
icalcomponent_add_property (dst_comp, icalprop);
|
|
|
|
adjust_dtstart_day_to_rrule (dst_comp, ical_recur);
|
|
|
|
icalprop = icalproperty_new_tzoffsetfrom (types [zp_idx].gmtoff);
|
|
icalcomponent_add_property (dst_comp, icalprop);
|
|
|
|
icalprop = icalproperty_new_tzoffsetto (types [zidx].gmtoff);
|
|
icalcomponent_add_property (dst_comp, icalprop);
|
|
|
|
icalcomponent_add_component (tz_comp, dst_comp);
|
|
}
|
|
|
|
error:
|
|
if (f)
|
|
fclose (f);
|
|
|
|
if (transitions)
|
|
free (transitions);
|
|
if (trans_idx)
|
|
free (trans_idx);
|
|
if (types) {
|
|
for (i = 0; i < num_types; i++)
|
|
if (types [i].zname)
|
|
free (types [i].zname);
|
|
free (types);
|
|
}
|
|
if (znames)
|
|
free (znames);
|
|
free (full_path);
|
|
if (leaps)
|
|
free (leaps);
|
|
if (temp)
|
|
free (temp);
|
|
|
|
return tz_comp;
|
|
}
|
|
|
|
/*
|
|
* What follows is copied and slightly simplified (not thread-safe!)
|
|
* code from icaltimezone.c.
|
|
*
|
|
* This is necessary because otherwise, when libsynthesis.so calls
|
|
* icaltimezone_get_component(), libical.1.so uses its own builtin
|
|
* icaltzutil_fetch_timezone(). Apparently it exports that without
|
|
* looking it up via the dynamic linker itself. Therefore we have to
|
|
* redirect the original icaltimezone_get_component() call.
|
|
*/
|
|
|
|
static void
|
|
icaltimezone_load_builtin_timezone (icaltimezone *zone)
|
|
{
|
|
icalcomponent *subcomp;
|
|
const char *location;
|
|
|
|
/* If the location isn't set, it isn't a builtin timezone. */
|
|
location = icaltimezone_get_location(zone);
|
|
if (!location || !location[0])
|
|
return;
|
|
|
|
subcomp = icaltzutil_fetch_timezone (location);
|
|
|
|
if (!subcomp) {
|
|
icalerror_set_errno(ICAL_PARSE_ERROR);
|
|
return;
|
|
}
|
|
|
|
icaltimezone_set_component(zone, subcomp);
|
|
}
|
|
|
|
#undef icaltimezone_get_component
|
|
icalcomponent *icaltimezone_get_component(icaltimezone *zone)
|
|
{
|
|
icalcomponent *comp;
|
|
/* If this is a floating time, without a timezone, return NULL. */
|
|
if (!zone)
|
|
return NULL;
|
|
|
|
/*
|
|
* Without this check, icaltimezone_set_component() in
|
|
* icaltimezone_load_builtin_timezone() will discard the
|
|
* already loaded component of builtin timezones and replace
|
|
* it with the new one, so there is no leak. It's just
|
|
* inefficient.
|
|
*
|
|
* However, this method also gets called for non-internal
|
|
* timezones which were created from a VTIMEZONE and in
|
|
* that case not using the existing component is wrong.
|
|
*
|
|
* Hack: duplicate the internal _icaltimezone struct (from
|
|
* icaltimezoneimpl.h).
|
|
*/
|
|
struct _my_icaltimezone {
|
|
char *tzid;
|
|
char *location;
|
|
char *tznames;
|
|
double latitude;
|
|
double longitude;
|
|
icalcomponent *component;
|
|
};
|
|
comp = ((struct _my_icaltimezone *)zone)->component;
|
|
if (!comp) {
|
|
icaltimezone_load_builtin_timezone (zone);
|
|
comp = ((struct _my_icaltimezone *)zone)->component;
|
|
}
|
|
|
|
return comp;
|
|
}
|
|
|
|
#ifdef ICALTZ_UTIL_MAIN
|
|
int
|
|
main (int argc, char *argv [])
|
|
{
|
|
icalcomponent *comp = icaltzutil_fetch_timezone (argv [1]);
|
|
const char *str = comp ? icalcomponent_as_ical_string(comp) : "no such zone";
|
|
puts(str);
|
|
return 0;
|
|
}
|
|
#endif
|