671 lines
17 KiB
C
671 lines
17 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;
|
|
}
|
|
|
|
/*
|
|
* For including the .o file in binaries via -Wl,-usyncevo_fetch_timezone.
|
|
* We cannot use -Wl,-uicaltzutil_fetch_timezone because that gets satisfied by
|
|
* libical itself.
|
|
*/
|
|
int syncevo_fetch_timezone;
|
|
|
|
/*
|
|
* Avoid lazy resolution of the methods that we export. client-test otherwise
|
|
* ends up calling the libical version of the methods despite having its own
|
|
* copy compiled into the executable, at least on Ubuntu Saucy and Trusty.
|
|
*/
|
|
/* void *syncevo_fetch_timezone_p = &icaltzutil_fetch_timezone; */
|
|
/* void *syncevo_get_component_p = &icaltimezone_get_component; */
|
|
|
|
#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
|