When finding a non-UTC timestamp with no time
[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 icaltimezone *get_default_icaltimezone(void) {
31
32         char *location = NULL;
33         icaltimezone *zone = NULL;
34
35         location = "America/New_York";
36         if (location) {
37                 zone = icaltimezone_get_builtin_timezone (location);
38         }
39         if (!zone)
40                 zone = icaltimezone_get_utc_timezone ();
41
42         return zone;
43 }
44
45
46 /*
47  * Back end function for ical_dezonify()
48  *
49  * We supply this with the master component, the relevant component,
50  * and the property (which will be a DTSTART, DTEND, etc.)
51  * which we want to convert to UTC.
52  */
53 void ical_dezonify_backend(icalcomponent *cal,
54                         icalcomponent *rcal,
55                         icalproperty *prop) {
56
57         icaltimezone *t = NULL;
58         icalparameter *param;
59         const char *tzid;
60         struct icaltimetype TheTime;
61
62         /* Give me nothing and I will give you nothing in return. */
63         if (cal == NULL) return;
64
65         /* Hunt for a TZID parameter in this property. */
66         param = icalproperty_get_first_parameter(prop, ICAL_TZID_PARAMETER);
67
68         /* Get the stringish name of this TZID. */
69         if (param != NULL) {
70                 tzid = icalparameter_get_tzid(param);
71
72                 /* Convert it to an icaltimezone type. */
73                 if (tzid != NULL) {
74                         t = icalcomponent_get_timezone(cal, tzid);
75                 }
76
77         }
78
79         /* Now we know the timezone.  Convert to UTC. */
80
81         if (icalproperty_isa(prop) == ICAL_DTSTART_PROPERTY) {
82                 TheTime = icalproperty_get_dtstart(prop);
83         }
84         else if (icalproperty_isa(prop) == ICAL_DTEND_PROPERTY) {
85                 TheTime = icalproperty_get_dtend(prop);
86         }
87         else if (icalproperty_isa(prop) == ICAL_DUE_PROPERTY) {
88                 TheTime = icalproperty_get_due(prop);
89         }
90         else if (icalproperty_isa(prop) == ICAL_EXDATE_PROPERTY) {
91                 TheTime = icalproperty_get_exdate(prop);
92         }
93         else {
94                 return;
95         }
96
97         if (TheTime.is_utc) {
98                 lprintf(CTDL_DEBUG, "                * This property is ALREADY UTC.\n");
99         }
100         else {
101                 /* Do the conversion. */
102                 if (t != NULL) {
103                         lprintf(CTDL_DEBUG, "                * Timezone prop found.  Converting to UTC.\n");
104                         icaltimezone_convert_time(&TheTime,
105                                                 t,
106                                                 icaltimezone_get_utc_timezone()
107                         );
108                 }
109                 else {
110                         lprintf(CTDL_DEBUG, "                * Converting default timezone to UTC.\n");
111                         icaltimezone_convert_time(&TheTime,
112                                                 get_default_icaltimezone(),
113                                                 icaltimezone_get_utc_timezone()
114                         );
115                 }
116                 TheTime.is_utc = 1;
117         }
118         icalproperty_remove_parameter_by_kind(prop, ICAL_TZID_PARAMETER);
119
120         /* Now add the converted property back in. */
121         if (icalproperty_isa(prop) == ICAL_DTSTART_PROPERTY) {
122                 icalproperty_set_dtstart(prop, TheTime);
123         }
124         else if (icalproperty_isa(prop) == ICAL_DTEND_PROPERTY) {
125                 icalproperty_set_dtend(prop, TheTime);
126         }
127         else if (icalproperty_isa(prop) == ICAL_DUE_PROPERTY) {
128                 icalproperty_set_due(prop, TheTime);
129         }
130         else if (icalproperty_isa(prop) == ICAL_EXDATE_PROPERTY) {
131                 icalproperty_set_exdate(prop, TheTime);
132         }
133 }
134
135
136 /*
137  * Recursive portion of ical_dezonify()
138  */
139 void ical_dezonify_recur(icalcomponent *cal, icalcomponent *rcal) {
140         icalcomponent *c;
141         icalproperty *p;
142
143         /*
144          * Recurse through all subcomponents *except* VTIMEZONE ones.
145          */
146         for (c=icalcomponent_get_first_component(
147                                         rcal, ICAL_ANY_COMPONENT);
148                 c != NULL;
149                 c = icalcomponent_get_next_component(
150                                         rcal, ICAL_ANY_COMPONENT)
151         ) {
152                 if (icalcomponent_isa(c) != ICAL_VTIMEZONE_COMPONENT) {
153                         ical_dezonify_recur(cal, c);
154                 }
155         }
156
157         /*
158          * Now look for DTSTART and DTEND properties
159          */
160         for (p=icalcomponent_get_first_property(
161                                 rcal, ICAL_ANY_PROPERTY);
162                 p != NULL;
163                 p = icalcomponent_get_next_property(
164                                 rcal, ICAL_ANY_PROPERTY)
165         ) {
166                 if (
167                         (icalproperty_isa(p) == ICAL_DTSTART_PROPERTY)
168                         || (icalproperty_isa(p) == ICAL_DTEND_PROPERTY)
169                         || (icalproperty_isa(p) == ICAL_DUE_PROPERTY)
170                         || (icalproperty_isa(p) == ICAL_EXDATE_PROPERTY)
171                    ) {
172                         ical_dezonify_backend(cal, rcal, p);
173                 }
174         }
175 }
176
177
178 /*
179  * Convert all DTSTART and DTEND properties in all subcomponents to UTC.
180  * This function will search any VTIMEZONE subcomponents to learn the
181  * relevant timezone information.
182  */
183 void ical_dezonify(icalcomponent *cal) {
184         icalcomponent *vt = NULL;
185
186         lprintf(CTDL_DEBUG, "ical_dezonify() started\n");
187
188         /* Convert all times to UTC */
189         ical_dezonify_recur(cal, cal);
190
191         /* Strip out VTIMEZONE subcomponents -- we don't need them anymore */
192         while (vt = icalcomponent_get_first_component(
193                         cal, ICAL_VTIMEZONE_COMPONENT), vt != NULL) {
194                 icalcomponent_remove_component(cal, vt);
195                 icalcomponent_free(vt);
196         }
197
198         lprintf(CTDL_DEBUG, "ical_dezonify() completed\n");
199 }
200
201
202 #endif /* CITADEL_WITH_CALENDAR_SERVICE */