Make a note of the fact that we've hardcoded
[citadel.git] / citadel / ical_dezonify.c
1 /* 
2  * $Id$ 
3  *
4  * Function to go through an ical component set and convert all non-UTC
5  * date/time properties to UTC.  It also strips out any VTIMEZONE
6  * subcomponents afterwards, because they're irrelevant.
7  *
8  */
9
10
11 #include "sysdep.h"
12 #include <stdlib.h>
13 #include <unistd.h>
14 #include <sys/types.h>
15 #include <limits.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <strings.h>
19 #include "citadel.h"
20 #include "server.h"
21 #include "citserver.h"
22 #include "sysdep_decls.h"
23 #include "support.h"
24 #include "config.h"
25
26 #ifdef CITADEL_WITH_CALENDAR_SERVICE
27 #include <ical.h>
28 #include "ical_dezonify.h"
29
30
31 /*
32  * Figure out which time zone needs to be used for timestamps that are
33  * not UTC and do not have a time zone specified.
34  *
35  * FIXME - most sites are not in New York :)
36  */
37 icaltimezone *get_default_icaltimezone(void) {
38
39         char *location = NULL;
40         icaltimezone *zone = NULL;
41
42         location = "America/New_York";
43         if (location) {
44                 zone = icaltimezone_get_builtin_timezone(location);
45         }
46         if (!zone) {
47                 zone = icaltimezone_get_utc_timezone();
48         }
49         return zone;
50 }
51
52
53 /*
54  * Back end function for ical_dezonify()
55  *
56  * We supply this with the master component, the relevant component,
57  * and the property (which will be a DTSTART, DTEND, etc.)
58  * which we want to convert to UTC.
59  */
60 void ical_dezonify_backend(icalcomponent *cal,
61                         icalcomponent *rcal,
62                         icalproperty *prop) {
63
64         icaltimezone *t = NULL;
65         icalparameter *param;
66         const char *tzid;
67         struct icaltimetype TheTime;
68
69         /* Give me nothing and I will give you nothing in return. */
70         if (cal == NULL) return;
71
72         /* Hunt for a TZID parameter in this property. */
73         param = icalproperty_get_first_parameter(prop, ICAL_TZID_PARAMETER);
74
75         /* Get the stringish name of this TZID. */
76         if (param != NULL) {
77                 tzid = icalparameter_get_tzid(param);
78
79                 /* Convert it to an icaltimezone type. */
80                 if (tzid != NULL) {
81                         t = icalcomponent_get_timezone(cal, tzid);
82                 }
83
84         }
85
86         /* Now we know the timezone.  Convert to UTC. */
87
88         if (icalproperty_isa(prop) == ICAL_DTSTART_PROPERTY) {
89                 TheTime = icalproperty_get_dtstart(prop);
90         }
91         else if (icalproperty_isa(prop) == ICAL_DTEND_PROPERTY) {
92                 TheTime = icalproperty_get_dtend(prop);
93         }
94         else if (icalproperty_isa(prop) == ICAL_DUE_PROPERTY) {
95                 TheTime = icalproperty_get_due(prop);
96         }
97         else if (icalproperty_isa(prop) == ICAL_EXDATE_PROPERTY) {
98                 TheTime = icalproperty_get_exdate(prop);
99         }
100         else {
101                 return;
102         }
103
104         lprintf(CTDL_DEBUG, "                * Was: %s\n", icaltime_as_ical_string(TheTime));
105         if (TheTime.is_utc) {
106                 lprintf(CTDL_DEBUG, "                * This property is ALREADY UTC.\n");
107         }
108         else {
109                 /* Do the conversion. */
110                 if (t != NULL) {
111                         lprintf(CTDL_DEBUG, "                * Timezone prop found.  Converting to UTC.\n");
112                 }
113                 else {
114                         lprintf(CTDL_DEBUG, "                * Converting default timezone to UTC.\n");
115                 }
116
117                 if (t == NULL) {
118                         t = get_default_icaltimezone();
119                 }
120
121                 icaltimezone_convert_time(&TheTime,
122                                         t,
123                                         icaltimezone_get_utc_timezone()
124                 );
125                 TheTime.is_utc = 1;
126         }
127
128         icalproperty_remove_parameter_by_kind(prop, ICAL_TZID_PARAMETER);
129         lprintf(CTDL_DEBUG, "                * Now: %s\n", icaltime_as_ical_string(TheTime));
130
131         /* Now add the converted property back in. */
132         if (icalproperty_isa(prop) == ICAL_DTSTART_PROPERTY) {
133                 icalproperty_set_dtstart(prop, TheTime);
134         }
135         else if (icalproperty_isa(prop) == ICAL_DTEND_PROPERTY) {
136                 icalproperty_set_dtend(prop, TheTime);
137         }
138         else if (icalproperty_isa(prop) == ICAL_DUE_PROPERTY) {
139                 icalproperty_set_due(prop, TheTime);
140         }
141         else if (icalproperty_isa(prop) == ICAL_EXDATE_PROPERTY) {
142                 icalproperty_set_exdate(prop, TheTime);
143         }
144 }
145
146
147 /*
148  * Recursive portion of ical_dezonify()
149  */
150 void ical_dezonify_recur(icalcomponent *cal, icalcomponent *rcal) {
151         icalcomponent *c;
152         icalproperty *p;
153
154         /*
155          * Recurse through all subcomponents *except* VTIMEZONE ones.
156          */
157         for (c=icalcomponent_get_first_component(
158                                         rcal, ICAL_ANY_COMPONENT);
159                 c != NULL;
160                 c = icalcomponent_get_next_component(
161                                         rcal, ICAL_ANY_COMPONENT)
162         ) {
163                 if (icalcomponent_isa(c) != ICAL_VTIMEZONE_COMPONENT) {
164                         ical_dezonify_recur(cal, c);
165                 }
166         }
167
168         /*
169          * Now look for DTSTART and DTEND properties
170          */
171         for (p=icalcomponent_get_first_property(
172                                 rcal, ICAL_ANY_PROPERTY);
173                 p != NULL;
174                 p = icalcomponent_get_next_property(
175                                 rcal, ICAL_ANY_PROPERTY)
176         ) {
177                 if (
178                         (icalproperty_isa(p) == ICAL_DTSTART_PROPERTY)
179                         || (icalproperty_isa(p) == ICAL_DTEND_PROPERTY)
180                         || (icalproperty_isa(p) == ICAL_DUE_PROPERTY)
181                         || (icalproperty_isa(p) == ICAL_EXDATE_PROPERTY)
182                    ) {
183                         ical_dezonify_backend(cal, rcal, p);
184                 }
185         }
186 }
187
188
189 /*
190  * Convert all DTSTART and DTEND properties in all subcomponents to UTC.
191  * This function will search any VTIMEZONE subcomponents to learn the
192  * relevant timezone information.
193  */
194 void ical_dezonify(icalcomponent *cal) {
195         icalcomponent *vt = NULL;
196
197         lprintf(CTDL_DEBUG, "ical_dezonify() started\n");
198
199         /* Convert all times to UTC */
200         ical_dezonify_recur(cal, cal);
201
202         /* Strip out VTIMEZONE subcomponents -- we don't need them anymore */
203         while (vt = icalcomponent_get_first_component(
204                         cal, ICAL_VTIMEZONE_COMPONENT), vt != NULL) {
205                 icalcomponent_remove_component(cal, vt);
206                 icalcomponent_free(vt);
207         }
208
209         lprintf(CTDL_DEBUG, "ical_dezonify() completed\n");
210 }
211
212
213 #endif /* CITADEL_WITH_CALENDAR_SERVICE */