Back to index

citadel  8.12
ical_dezonify.c
Go to the documentation of this file.
00001 /* 
00002  * Function to go through an ical component set and convert all non-UTC
00003  * date/time properties to UTC.  It also strips out any VTIMEZONE
00004  * subcomponents afterwards, because they're irrelevant.
00005  */
00006 
00007 
00008 #include "sysdep.h"
00009 #include <stdlib.h>
00010 #include <unistd.h>
00011 #include <sys/types.h>
00012 #include <limits.h>
00013 #include <stdio.h>
00014 #include <string.h>
00015 #include <strings.h>
00016 #include <syslog.h>
00017 #include <libical/ical.h>
00018 #include <libcitadel.h>
00019 #include "citadel.h"
00020 #include "server.h"
00021 #include "citserver.h"
00022 #include "sysdep_decls.h"
00023 #include "support.h"
00024 #include "config.h"
00025 #include "ical_dezonify.h"
00026 
00027 #include "ctdl_module.h"
00028 
00029 
00030 /*
00031  * Figure out which time zone needs to be used for timestamps that are
00032  * not UTC and do not have a time zone specified.
00033  */
00034 icaltimezone *get_default_icaltimezone(void) {
00035 
00036         icaltimezone *zone = NULL;
00037        char *default_zone_name = config.c_default_cal_zone;
00038        //char *default_zone_name = "America/New_York";
00039 
00040         if (!zone) {
00041                 zone = icaltimezone_get_builtin_timezone(default_zone_name);
00042         }
00043         if (!zone) {
00044               syslog(LOG_ALERT,
00045                      "Unable to load '%s' time zone.  Defaulting to UTC.\n",
00046                      default_zone_name);
00047                 zone = icaltimezone_get_utc_timezone();
00048        }
00049        if (!zone) {
00050               syslog(LOG_ALERT, "Unable to load UTC time zone!\n");
00051        }
00052         return zone;
00053 }
00054 
00055 
00056 /*
00057  * Back end function for ical_dezonify()
00058  *
00059  * We supply this with the master component, the relevant component,
00060  * and the property (which will be a DTSTART, DTEND, etc.)
00061  * which we want to convert to UTC.
00062  */
00063 void ical_dezonify_backend(icalcomponent *cal,
00064                      icalcomponent *rcal,
00065                      icalproperty *prop) {
00066 
00067        icaltimezone *t = NULL;
00068        icalparameter *param;
00069        const char *tzid = NULL;
00070        struct icaltimetype TheTime;
00071        int utc_declared_as_tzid = 0;      
00073        /* Give me nothing and I will give you nothing in return. */
00074        if (cal == NULL) return;
00075 
00076        /* Hunt for a TZID parameter in this property. */
00077        param = icalproperty_get_first_parameter(prop, ICAL_TZID_PARAMETER);
00078 
00079        /* Get the stringish name of this TZID. */
00080        if (param != NULL) {
00081               tzid = icalparameter_get_tzid(param);
00082 
00083               /* Convert it to an icaltimezone type. */
00084               if (tzid != NULL) {
00085                      /* syslog(LOG_DEBUG, "                * Stringy supplied timezone is: '%s'\n", tzid); */
00086                      if ( (!strcasecmp(tzid, "UTC")) || (!strcasecmp(tzid, "GMT")) ) {
00087                             utc_declared_as_tzid = 1;
00088                             /* syslog(LOG_DEBUG, "                * ...and we handle that internally.\n"); */
00089                      }
00090                      else {
00091                             /* try attached first */
00092                             t = icalcomponent_get_timezone(cal, tzid);
00093 /*
00094                             syslog(LOG_DEBUG, "                * ...and I %s have tzdata for that zone.\n",
00095                                    (t ? "DO" : "DO NOT")
00096                             );
00097 */
00098                             /* then try built-in timezones */
00099                             if (!t) {
00100                                    t = icaltimezone_get_builtin_timezone(tzid);
00101 /*
00102                                    if (t) {
00103                                           syslog(LOG_DEBUG, "                * Using system tzdata!\n");
00104                                    }
00105 */
00106                             }
00107                      }
00108               }
00109 
00110        }
00111 
00112        /* Now we know the timezone.  Convert to UTC. */
00113 
00114        if (icalproperty_isa(prop) == ICAL_DTSTART_PROPERTY) {
00115               TheTime = icalproperty_get_dtstart(prop);
00116        }
00117        else if (icalproperty_isa(prop) == ICAL_DTEND_PROPERTY) {
00118               TheTime = icalproperty_get_dtend(prop);
00119        }
00120        else if (icalproperty_isa(prop) == ICAL_DUE_PROPERTY) {
00121               TheTime = icalproperty_get_due(prop);
00122        }
00123        else if (icalproperty_isa(prop) == ICAL_EXDATE_PROPERTY) {
00124               TheTime = icalproperty_get_exdate(prop);
00125        }
00126        else {
00127               return;
00128        }
00129 
00130        /* syslog(LOG_DEBUG, "                * Was: %s\n", icaltime_as_ical_string(TheTime)); */
00131 
00132        if (TheTime.is_utc) {
00133               /* syslog(LOG_DEBUG, "                * This property is ALREADY UTC.\n"); */
00134        }
00135 
00136        else if (utc_declared_as_tzid) {
00137               /* syslog(LOG_DEBUG, "                * Replacing '%s' TZID with 'Z' suffix.\n", tzid); */
00138               TheTime.is_utc = 1;
00139        }
00140 
00141        else {
00142               /* Do the conversion. */
00143               if (t != NULL) {
00144                      /* syslog(LOG_DEBUG, "                * Timezone prop found.  Converting to UTC.\n"); */
00145               }
00146               else {
00147                      /* syslog(LOG_DEBUG, "                * Converting default timezone to UTC.\n"); */
00148               }
00149 
00150               if (t == NULL) {
00151                      t = get_default_icaltimezone();
00152               }
00153 
00154               icaltimezone_convert_time(&TheTime,
00155                                    t,
00156                                    icaltimezone_get_utc_timezone()
00157               );
00158               TheTime.is_utc = 1;
00159        }
00160 
00161        icalproperty_remove_parameter_by_kind(prop, ICAL_TZID_PARAMETER);
00162        /* syslog(LOG_DEBUG, "                * Now: %s\n", icaltime_as_ical_string(TheTime)); */
00163 
00164        /* Now add the converted property back in. */
00165        if (icalproperty_isa(prop) == ICAL_DTSTART_PROPERTY) {
00166               icalproperty_set_dtstart(prop, TheTime);
00167        }
00168        else if (icalproperty_isa(prop) == ICAL_DTEND_PROPERTY) {
00169               icalproperty_set_dtend(prop, TheTime);
00170        }
00171        else if (icalproperty_isa(prop) == ICAL_DUE_PROPERTY) {
00172               icalproperty_set_due(prop, TheTime);
00173        }
00174        else if (icalproperty_isa(prop) == ICAL_EXDATE_PROPERTY) {
00175               icalproperty_set_exdate(prop, TheTime);
00176        }
00177 }
00178 
00179 
00180 /*
00181  * Recursive portion of ical_dezonify()
00182  */
00183 void ical_dezonify_recurse(icalcomponent *cal, icalcomponent *rcal) {
00184        icalcomponent *c;
00185        icalproperty *p;
00186 
00187        /*
00188         * Recurse through all subcomponents *except* VTIMEZONE ones.
00189         */
00190        for (c=icalcomponent_get_first_component(
00191                                    rcal, ICAL_ANY_COMPONENT);
00192               c != NULL;
00193               c = icalcomponent_get_next_component(
00194                                    rcal, ICAL_ANY_COMPONENT)
00195        ) {
00196               if (icalcomponent_isa(c) != ICAL_VTIMEZONE_COMPONENT) {
00197                      ical_dezonify_recurse(cal, c);
00198               }
00199        }
00200 
00201        /*
00202         * Now look for DTSTART and DTEND properties
00203         */
00204        for (p=icalcomponent_get_first_property(rcal, ICAL_ANY_PROPERTY);
00205               p != NULL;
00206               p = icalcomponent_get_next_property(rcal, ICAL_ANY_PROPERTY)
00207        ) {
00208               if (
00209                      (icalproperty_isa(p) == ICAL_DTSTART_PROPERTY)
00210                      || (icalproperty_isa(p) == ICAL_DTEND_PROPERTY)
00211                      || (icalproperty_isa(p) == ICAL_DUE_PROPERTY)
00212                      || (icalproperty_isa(p) == ICAL_EXDATE_PROPERTY)
00213                  ) {
00214                      ical_dezonify_backend(cal, rcal, p);
00215               }
00216        }
00217 }
00218 
00219 
00220 /*
00221  * Convert all DTSTART and DTEND properties in all subcomponents to UTC.
00222  * This function will search any VTIMEZONE subcomponents to learn the
00223  * relevant timezone information.
00224  */
00225 void ical_dezonify(icalcomponent *cal) {
00226        icalcomponent *vt = NULL;
00227 
00228        /* syslog(LOG_DEBUG, "ical_dezonify() started\n"); */
00229 
00230        /* Convert all times to UTC */
00231        ical_dezonify_recurse(cal, cal);
00232 
00233        /* Strip out VTIMEZONE subcomponents -- we don't need them anymore */
00234        while (vt = icalcomponent_get_first_component(
00235                      cal, ICAL_VTIMEZONE_COMPONENT), vt != NULL) {
00236               icalcomponent_remove_component(cal, vt);
00237               icalcomponent_free(vt);
00238        }
00239 
00240        /* syslog(LOG_DEBUG, "ical_dezonify() completed\n"); */
00241 }