Brought over the new ical_dezonify that handles unspecified
[citadel.git] / webcit / ical_dezonify.c
1 /* 
2  * $Id$ 
3  */
4 /**
5  * \defgroup IcalDezonify normalize ical dates to UTC
6  * Function to go through an ical component set and convert all non-UTC
7  * date/time properties to UTC.  It also strips out any VTIMEZONE
8  * subcomponents afterwards, because they're irrelevant.
9  *
10  * Everything here will work on both a fully encapsulated VCALENDAR component
11  * or any type of subcomponent.
12  *
13  * \ingroup Calendaring
14  */
15 /*@{*/
16
17 #include "webcit.h"
18 #include "webserver.h"
19
20
21 #ifdef WEBCIT_WITH_CALENDAR_SERVICE
22
23
24 /*
25  * Figure out which time zone needs to be used for timestamps that are
26  * not UTC and do not have a time zone specified.
27  *
28  * FIXME - most sites are not in New York :)
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         lprintf(9, "                * Was: %s\n", icaltime_as_ical_string(TheTime));
98         if (TheTime.is_utc) {
99                 lprintf(9, "                * This property is ALREADY UTC.\n");
100         }
101         else {
102                 /* Do the conversion. */
103                 if (t != NULL) {
104                         lprintf(9, "                * Timezone prop found.  Converting to UTC.\n");
105                 }
106                 else {
107                         lprintf(9, "                * Converting default timezone to UTC.\n");
108                 }
109
110                 if (t == NULL) {
111                         t = get_default_icaltimezone();
112                 }
113
114                 icaltimezone_convert_time(&TheTime,
115                                         t,
116                                         icaltimezone_get_utc_timezone()
117                 );
118                 TheTime.is_utc = 1;
119         }
120
121         icalproperty_remove_parameter_by_kind(prop, ICAL_TZID_PARAMETER);
122         lprintf(9, "                * Now: %s\n", icaltime_as_ical_string(TheTime));
123
124         /* Now add the converted property back in. */
125         if (icalproperty_isa(prop) == ICAL_DTSTART_PROPERTY) {
126                 icalproperty_set_dtstart(prop, TheTime);
127         }
128         else if (icalproperty_isa(prop) == ICAL_DTEND_PROPERTY) {
129                 icalproperty_set_dtend(prop, TheTime);
130         }
131         else if (icalproperty_isa(prop) == ICAL_DUE_PROPERTY) {
132                 icalproperty_set_due(prop, TheTime);
133         }
134         else if (icalproperty_isa(prop) == ICAL_EXDATE_PROPERTY) {
135                 icalproperty_set_exdate(prop, TheTime);
136         }
137 }
138
139
140 /*
141  * Recursive portion of ical_dezonify()
142  */
143 void ical_dezonify_recur(icalcomponent *cal, icalcomponent *rcal) {
144         icalcomponent *c;
145         icalproperty *p;
146
147         /*
148          * Recurse through all subcomponents *except* VTIMEZONE ones.
149          */
150         for (c=icalcomponent_get_first_component(
151                                         rcal, ICAL_ANY_COMPONENT);
152                 c != NULL;
153                 c = icalcomponent_get_next_component(
154                                         rcal, ICAL_ANY_COMPONENT)
155         ) {
156                 if (icalcomponent_isa(c) != ICAL_VTIMEZONE_COMPONENT) {
157                         ical_dezonify_recur(cal, c);
158                 }
159         }
160
161         /*
162          * Now look for DTSTART and DTEND properties
163          */
164         for (p=icalcomponent_get_first_property(
165                                 rcal, ICAL_ANY_PROPERTY);
166                 p != NULL;
167                 p = icalcomponent_get_next_property(
168                                 rcal, ICAL_ANY_PROPERTY)
169         ) {
170                 if (
171                         (icalproperty_isa(p) == ICAL_DTSTART_PROPERTY)
172                         || (icalproperty_isa(p) == ICAL_DTEND_PROPERTY)
173                         || (icalproperty_isa(p) == ICAL_DUE_PROPERTY)
174                         || (icalproperty_isa(p) == ICAL_EXDATE_PROPERTY)
175                    ) {
176                         ical_dezonify_backend(cal, rcal, p);
177                 }
178         }
179 }
180
181
182 /*
183  * Convert all DTSTART and DTEND properties in all subcomponents to UTC.
184  * This function will search any VTIMEZONE subcomponents to learn the
185  * relevant timezone information.
186  */
187 void ical_dezonify(icalcomponent *cal) {
188         icalcomponent *vt = NULL;
189
190         lprintf(9, "ical_dezonify() started\n");
191
192         /* Convert all times to UTC */
193         ical_dezonify_recur(cal, cal);
194
195         /* Strip out VTIMEZONE subcomponents -- we don't need them anymore */
196         while (vt = icalcomponent_get_first_component(
197                         cal, ICAL_VTIMEZONE_COMPONENT), vt != NULL) {
198                 icalcomponent_remove_component(cal, vt);
199                 icalcomponent_free(vt);
200         }
201
202         lprintf(9, "ical_dezonify() completed\n");
203 }
204
205
206 #endif /* WEBCIT_WITH_CALENDAR_SERVICE */