Diffstat (limited to 'libical/src/libical/icalcomponent.c') (more/less context) (ignore whitespace changes)
-rw-r--r-- | libical/src/libical/icalcomponent.c | 1891 |
1 files changed, 1499 insertions, 392 deletions
diff --git a/libical/src/libical/icalcomponent.c b/libical/src/libical/icalcomponent.c index af0d3ec..fbd0492 100644 --- a/libical/src/libical/icalcomponent.c +++ b/libical/src/libical/icalcomponent.c | |||
@@ -4,7 +4,6 @@ | |||
4 | 4 | ||
5 | $Id$ | 5 | $Id$ |
6 | 6 | ||
7 | |||
8 | (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org | 7 | (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org |
9 | 8 | ||
10 | This program is free software; you can redistribute it and/or modify | 9 | This program is free software; you can redistribute it and/or modify |
@@ -33,18 +32,20 @@ | |||
33 | #include "icalmemory.h" | 32 | #include "icalmemory.h" |
34 | #include "icalenums.h" | 33 | #include "icalenums.h" |
35 | #include "icaltime.h" | 34 | #include "icaltime.h" |
35 | #include "icalarray.h" | ||
36 | #include "icaltimezone.h" | ||
36 | #include "icalduration.h" | 37 | #include "icalduration.h" |
37 | #include "icalperiod.h" | 38 | #include "icalperiod.h" |
38 | #include "icalparser.h" | 39 | #include "icalparser.h" |
40 | #include "icalrestriction.h" | ||
39 | 41 | ||
40 | #include <stdlib.h> /* for malloc */ | 42 | #include <stdlib.h> /* for malloc */ |
41 | #include <stdarg.h> /* for va_list, etc */ | 43 | #include <stdarg.h> /* for va_list, etc */ |
42 | #include <errno.h> | 44 | #include <errno.h> |
43 | #include <assert.h> | 45 | #include <assert.h> |
44 | #include <stdio.h> /* for fprintf */ | 46 | #include <stdio.h> /* for fprintf */ |
45 | #include <string.h> | 47 | #include <string.h> /* for strdup */ |
46 | 48 | #include <limits.h> /* for INT_MAX */ | |
47 | #define MAX_TMP 1024 | ||
48 | 49 | ||
49 | struct icalcomponent_impl | 50 | struct icalcomponent_impl |
50 | { | 51 | { |
@@ -56,18 +57,42 @@ struct icalcomponent_impl | |||
56 | pvl_list components; | 57 | pvl_list components; |
57 | pvl_elem component_iterator; | 58 | pvl_elem component_iterator; |
58 | icalcomponent* parent; | 59 | icalcomponent* parent; |
60 | |||
61 | /** An array of icaltimezone structs. We use this so we can do fast | ||
62 | lookup of timezones using binary searches. timezones_sorted is | ||
63 | set to 0 whenever we add a timezone, so we remember to sort the | ||
64 | array before doing a binary search. */ | ||
65 | icalarray* timezones; | ||
66 | int timezones_sorted; | ||
59 | }; | 67 | }; |
60 | 68 | ||
61 | /* icalproperty functions that only components get to use */ | 69 | /* icalproperty functions that only components get to use */ |
62 | void icalproperty_set_parent(icalproperty* property, | 70 | void icalproperty_set_parent(icalproperty* property, |
63 | icalcomponent* component); | 71 | icalcomponent* component); |
64 | icalcomponent* icalproperty_get_parent(icalproperty* property); | 72 | icalcomponent* icalproperty_get_parent(icalproperty* property); |
65 | void icalcomponent_add_children(struct icalcomponent_impl *impl,va_list args); | 73 | void icalcomponent_add_children(icalcomponent *impl,va_list args); |
66 | icalcomponent* icalcomponent_new_impl (icalcomponent_kind kind); | 74 | static icalcomponent* icalcomponent_new_impl (icalcomponent_kind kind); |
67 | int icalcomponent_property_sorter(void *a, void *b); | 75 | |
68 | 76 | static void icalcomponent_merge_vtimezone (icalcomponent *comp, | |
69 | 77 | icalcomponent *vtimezone, | |
70 | void icalcomponent_add_children(struct icalcomponent_impl *impl,va_list args) | 78 | icalarray *tzids_to_rename); |
79 | static void icalcomponent_handle_conflicting_vtimezones (icalcomponent *comp, | ||
80 | icalcomponent *vtimezone, | ||
81 | icalproperty *tzid_prop, | ||
82 | const char *tzid, | ||
83 | icalarray *tzids_to_rename); | ||
84 | static unsigned int icalcomponent_get_tzid_prefix_len (const char *tzid); | ||
85 | static void icalcomponent_rename_tzids(icalcomponent* comp, | ||
86 | icalarray* rename_table); | ||
87 | static void icalcomponent_rename_tzids_callback(icalparameter *param, | ||
88 | void *data); | ||
89 | static int icalcomponent_compare_vtimezones (icalcomponent*vtimezone1, | ||
90 | icalcomponent*vtimezone2); | ||
91 | static int icalcomponent_compare_timezone_fn (const void*elem1, | ||
92 | const void*elem2); | ||
93 | |||
94 | |||
95 | void icalcomponent_add_children(icalcomponent *impl, va_list args) | ||
71 | { | 96 | { |
72 | void* vp; | 97 | void* vp; |
73 | 98 | ||
@@ -77,25 +102,23 @@ void icalcomponent_add_children(struct icalcomponent_impl *impl,va_list args) | |||
77 | icalproperty_isa_property(vp) != 0 ) ; | 102 | icalproperty_isa_property(vp) != 0 ) ; |
78 | 103 | ||
79 | if (icalcomponent_isa_component(vp) != 0 ){ | 104 | if (icalcomponent_isa_component(vp) != 0 ){ |
80 | 105 | icalcomponent_add_component(impl, (icalcomponent*)vp); | |
81 | icalcomponent_add_component((icalcomponent*)impl, | ||
82 | (icalcomponent*)vp); | ||
83 | 106 | ||
84 | } else if (icalproperty_isa_property(vp) != 0 ){ | 107 | } else if (icalproperty_isa_property(vp) != 0 ){ |
85 | 108 | icalcomponent_add_property(impl, (icalproperty*)vp); | |
86 | icalcomponent_add_property((icalcomponent*)impl, | ||
87 | (icalproperty*)vp); | ||
88 | } | 109 | } |
89 | } | 110 | } |
90 | } | 111 | } |
91 | 112 | ||
92 | icalcomponent* | 113 | static icalcomponent* |
93 | icalcomponent_new_impl (icalcomponent_kind kind) | 114 | icalcomponent_new_impl (icalcomponent_kind kind) |
94 | { | 115 | { |
95 | struct icalcomponent_impl* comp; | 116 | icalcomponent* comp; |
96 | 117 | ||
97 | if ( ( comp = (struct icalcomponent_impl*) | 118 | if (!icalcomponent_kind_is_valid(kind)) |
98 | malloc(sizeof(struct icalcomponent_impl))) == 0) { | 119 | return NULL; |
120 | |||
121 | if ( ( comp = (icalcomponent*) malloc(sizeof(icalcomponent))) == 0) { | ||
99 | icalerror_set_errno(ICAL_NEWFAILED_ERROR); | 122 | icalerror_set_errno(ICAL_NEWFAILED_ERROR); |
100 | return 0; | 123 | return 0; |
101 | } | 124 | } |
@@ -109,22 +132,28 @@ icalcomponent_new_impl (icalcomponent_kind kind) | |||
109 | comp->component_iterator = 0; | 132 | comp->component_iterator = 0; |
110 | comp->x_name = 0; | 133 | comp->x_name = 0; |
111 | comp->parent = 0; | 134 | comp->parent = 0; |
135 | comp->timezones = NULL; | ||
136 | comp->timezones_sorted = 1; | ||
112 | 137 | ||
113 | return comp; | 138 | return comp; |
114 | } | 139 | } |
115 | 140 | ||
141 | /** @brief Constructor | ||
142 | */ | ||
116 | icalcomponent* | 143 | icalcomponent* |
117 | icalcomponent_new (icalcomponent_kind kind) | 144 | icalcomponent_new (icalcomponent_kind kind) |
118 | { | 145 | { |
119 | return (icalcomponent*)icalcomponent_new_impl(kind); | 146 | return icalcomponent_new_impl(kind); |
120 | } | 147 | } |
121 | 148 | ||
149 | /** @brief Constructor | ||
150 | */ | ||
122 | icalcomponent* | 151 | icalcomponent* |
123 | icalcomponent_vanew (icalcomponent_kind kind, ...) | 152 | icalcomponent_vanew (icalcomponent_kind kind, ...) |
124 | { | 153 | { |
125 | va_list args; | 154 | va_list args; |
126 | 155 | ||
127 | struct icalcomponent_impl *impl = icalcomponent_new_impl(kind); | 156 | icalcomponent *impl = icalcomponent_new_impl(kind); |
128 | 157 | ||
129 | if (impl == 0){ | 158 | if (impl == 0){ |
130 | return 0; | 159 | return 0; |
@@ -134,23 +163,26 @@ icalcomponent_vanew (icalcomponent_kind kind, ...) | |||
134 | icalcomponent_add_children(impl, args); | 163 | icalcomponent_add_children(impl, args); |
135 | va_end(args); | 164 | va_end(args); |
136 | 165 | ||
137 | return (icalcomponent*) impl; | 166 | return impl; |
138 | } | 167 | } |
139 | 168 | ||
169 | /** @brief Constructor | ||
170 | */ | ||
140 | icalcomponent* icalcomponent_new_from_string(char* str) | 171 | icalcomponent* icalcomponent_new_from_string(char* str) |
141 | { | 172 | { |
142 | return icalparser_parse_string(str); | 173 | return icalparser_parse_string(str); |
143 | } | 174 | } |
144 | 175 | ||
145 | icalcomponent* icalcomponent_new_clone(icalcomponent* component) | 176 | /** @brief Constructor |
177 | */ | ||
178 | icalcomponent* icalcomponent_new_clone(icalcomponent* old) | ||
146 | { | 179 | { |
147 | struct icalcomponent_impl *old = (struct icalcomponent_impl*)component; | 180 | icalcomponent *new; |
148 | struct icalcomponent_impl *new; | ||
149 | icalproperty *p; | 181 | icalproperty *p; |
150 | icalcomponent *c; | 182 | icalcomponent *c; |
151 | pvl_elem itr; | 183 | pvl_elem itr; |
152 | 184 | ||
153 | icalerror_check_arg_rz( (component!=0), "component"); | 185 | icalerror_check_arg_rz( (old!=0), "component"); |
154 | 186 | ||
155 | new = icalcomponent_new_impl(old->kind); | 187 | new = icalcomponent_new_impl(old->kind); |
156 | 188 | ||
@@ -180,15 +212,15 @@ icalcomponent* icalcomponent_new_clone(icalcomponent* component) | |||
180 | 212 | ||
181 | } | 213 | } |
182 | 214 | ||
183 | 215 | /*** @brief Destructor | |
216 | */ | ||
184 | void | 217 | void |
185 | icalcomponent_free (icalcomponent* component) | 218 | icalcomponent_free (icalcomponent* c) |
186 | { | 219 | { |
187 | icalproperty* prop; | 220 | icalproperty* prop; |
188 | icalcomponent* comp; | 221 | icalcomponent* comp; |
189 | struct icalcomponent_impl *c = (struct icalcomponent_impl*)component; | ||
190 | 222 | ||
191 | icalerror_check_arg_rv( (component!=0), "component"); | 223 | icalerror_check_arg_rv( (c!=0), "component"); |
192 | 224 | ||
193 | #ifdef ICAL_FREE_ON_LIST_IS_ERROR | 225 | #ifdef ICAL_FREE_ON_LIST_IS_ERROR |
194 | icalerror_assert( (c->parent ==0),"Tried to free a component that is still attached to a parent component"); | 226 | icalerror_assert( (c->parent ==0),"Tried to free a component that is still attached to a parent component"); |
@@ -198,19 +230,22 @@ icalcomponent_free (icalcomponent* component) | |||
198 | } | 230 | } |
199 | #endif | 231 | #endif |
200 | 232 | ||
201 | if(component != 0 ){ | 233 | if(c != 0 ){ |
202 | 234 | ||
203 | while( (prop=pvl_pop(c->properties)) != 0){ | 235 | if ( c->properties != 0 ) |
204 | assert(prop != 0); | 236 | { |
205 | icalproperty_set_parent(prop,0); | 237 | while( (prop=pvl_pop(c->properties)) != 0){ |
206 | icalproperty_free(prop); | 238 | assert(prop != 0); |
207 | } | 239 | icalproperty_set_parent(prop,0); |
208 | 240 | icalproperty_free(prop); | |
209 | pvl_free(c->properties); | 241 | } |
242 | pvl_free(c->properties); | ||
243 | } | ||
244 | |||
210 | 245 | ||
211 | while( (comp=pvl_data(pvl_head(c->components))) != 0){ | 246 | while( (comp=pvl_data(pvl_head(c->components))) != 0){ |
212 | assert(comp!=0); | 247 | assert(comp!=0); |
213 | icalcomponent_remove_component(component,comp); | 248 | icalcomponent_remove_component(c,comp); |
214 | icalcomponent_free(comp); | 249 | icalcomponent_free(comp); |
215 | } | 250 | } |
216 | 251 | ||
@@ -220,6 +255,9 @@ icalcomponent_free (icalcomponent* component) | |||
220 | free(c->x_name); | 255 | free(c->x_name); |
221 | } | 256 | } |
222 | 257 | ||
258 | if (c->timezones) | ||
259 | icaltimezone_array_free (c->timezones); | ||
260 | |||
223 | c->kind = ICAL_NO_COMPONENT; | 261 | c->kind = ICAL_NO_COMPONENT; |
224 | c->properties = 0; | 262 | c->properties = 0; |
225 | c->property_iterator = 0; | 263 | c->property_iterator = 0; |
@@ -227,36 +265,41 @@ icalcomponent_free (icalcomponent* component) | |||
227 | c->component_iterator = 0; | 265 | c->component_iterator = 0; |
228 | c->x_name = 0; | 266 | c->x_name = 0; |
229 | c->id[0] = 'X'; | 267 | c->id[0] = 'X'; |
268 | c->timezones = NULL; | ||
230 | 269 | ||
231 | free(c); | 270 | free(c); |
232 | } | 271 | } |
233 | } | 272 | } |
234 | 273 | ||
235 | char* | 274 | char* |
236 | icalcomponent_as_ical_string (icalcomponent* component) | 275 | icalcomponent_as_ical_string (icalcomponent* impl) |
237 | { | 276 | { |
238 | char* buf, *out_buf; | 277 | char* buf, *out_buf; |
239 | const char* tmp_buf; | 278 | const char* tmp_buf; |
240 | size_t buf_size = 1024; | 279 | size_t buf_size = 1024; |
241 | char* buf_ptr = 0; | 280 | char* buf_ptr = 0; |
242 | pvl_elem itr; | 281 | pvl_elem itr; |
243 | struct icalcomponent_impl *impl = (struct icalcomponent_impl*)component; | ||
244 | 282 | ||
283 | /* WIN32 automatically adds the \r, Anybody else need it? | ||
245 | #ifdef ICAL_UNIX_NEWLINE | 284 | #ifdef ICAL_UNIX_NEWLINE |
285 | */ | ||
246 | char newline[] = "\n"; | 286 | char newline[] = "\n"; |
287 | /* | ||
247 | #else | 288 | #else |
248 | char newline[] = "\n"; | 289 | char newline[] = "\r\n"; |
249 | #endif | 290 | #endif |
291 | */ | ||
292 | |||
250 | icalcomponent *c; | 293 | icalcomponent *c; |
251 | icalproperty *p; | 294 | icalproperty *p; |
252 | icalcomponent_kind kind = icalcomponent_isa(component); | 295 | icalcomponent_kind kind = icalcomponent_isa(impl); |
253 | 296 | ||
254 | const char* kind_string; | 297 | const char* kind_string; |
255 | 298 | ||
256 | buf = icalmemory_new_buffer(buf_size); | 299 | buf = icalmemory_new_buffer(buf_size); |
257 | buf_ptr = buf; | 300 | buf_ptr = buf; |
258 | 301 | ||
259 | icalerror_check_arg_rz( (component!=0), "component"); | 302 | icalerror_check_arg_rz( (impl!=0), "component"); |
260 | icalerror_check_arg_rz( (kind!=ICAL_NO_COMPONENT), "component kind is ICAL_NO_COMPONENT"); | 303 | icalerror_check_arg_rz( (kind!=ICAL_NO_COMPONENT), "component kind is ICAL_NO_COMPONENT"); |
261 | 304 | ||
262 | kind_string = icalcomponent_kind_to_string(kind); | 305 | kind_string = icalcomponent_kind_to_string(kind); |
@@ -267,13 +310,12 @@ icalcomponent_as_ical_string (icalcomponent* component) | |||
267 | icalmemory_append_string(&buf, &buf_ptr, &buf_size, kind_string); | 310 | icalmemory_append_string(&buf, &buf_ptr, &buf_size, kind_string); |
268 | icalmemory_append_string(&buf, &buf_ptr, &buf_size, newline); | 311 | icalmemory_append_string(&buf, &buf_ptr, &buf_size, newline); |
269 | 312 | ||
270 | 313 | ||
314 | |||
271 | for( itr = pvl_head(impl->properties); | 315 | for( itr = pvl_head(impl->properties); |
272 | itr != 0; | 316 | itr != 0; |
273 | itr = pvl_next(itr)) | 317 | itr = pvl_next(itr)) |
274 | { | 318 | { |
275 | // printf("3333calcomponent_as_ical_string System Timezone2: %s %s \n", *tzname, getenv("TZ") ); | ||
276 | |||
277 | p = (icalproperty*)pvl_data(itr); | 319 | p = (icalproperty*)pvl_data(itr); |
278 | 320 | ||
279 | icalerror_assert((p!=0),"Got a null property"); | 321 | icalerror_assert((p!=0),"Got a null property"); |
@@ -286,19 +328,19 @@ icalcomponent_as_ical_string (icalcomponent* component) | |||
286 | for( itr = pvl_head(impl->components); | 328 | for( itr = pvl_head(impl->components); |
287 | itr != 0; | 329 | itr != 0; |
288 | itr = pvl_next(itr)) | 330 | itr = pvl_next(itr)) |
289 | { | 331 | { |
290 | |||
291 | c = (icalcomponent*)pvl_data(itr); | 332 | c = (icalcomponent*)pvl_data(itr); |
292 | 333 | ||
293 | tmp_buf = icalcomponent_as_ical_string(c); | 334 | tmp_buf = icalcomponent_as_ical_string(c); |
335 | |||
294 | icalmemory_append_string(&buf, &buf_ptr, &buf_size, tmp_buf); | 336 | icalmemory_append_string(&buf, &buf_ptr, &buf_size, tmp_buf); |
295 | 337 | ||
296 | } | 338 | } |
297 | 339 | ||
298 | icalmemory_append_string(&buf, &buf_ptr, &buf_size, "END:"); //tzset(); | 340 | icalmemory_append_string(&buf, &buf_ptr, &buf_size, "END:"); |
299 | icalmemory_append_string(&buf, &buf_ptr, &buf_size, | 341 | icalmemory_append_string(&buf, &buf_ptr, &buf_size, |
300 | icalcomponent_kind_to_string(kind)); | 342 | icalcomponent_kind_to_string(kind)); |
301 | icalmemory_append_string(&buf, &buf_ptr, &buf_size, newline); //tzset(); | 343 | icalmemory_append_string(&buf, &buf_ptr, &buf_size, newline); |
302 | 344 | ||
303 | out_buf = icalmemory_tmp_copy(buf); | 345 | out_buf = icalmemory_tmp_copy(buf); |
304 | free(buf); | 346 | free(buf); |
@@ -310,11 +352,8 @@ icalcomponent_as_ical_string (icalcomponent* component) | |||
310 | int | 352 | int |
311 | icalcomponent_is_valid (icalcomponent* component) | 353 | icalcomponent_is_valid (icalcomponent* component) |
312 | { | 354 | { |
313 | struct icalcomponent_impl *impl = (struct icalcomponent_impl *)component; | 355 | if ( (strcmp(component->id,"comp") == 0) && |
314 | 356 | component->kind != ICAL_NO_COMPONENT){ | |
315 | |||
316 | if ( (strcmp(impl->id,"comp") == 0) && | ||
317 | impl->kind != ICAL_NO_COMPONENT){ | ||
318 | return 1; | 357 | return 1; |
319 | } else { | 358 | } else { |
320 | return 0; | 359 | return 0; |
@@ -324,14 +363,13 @@ icalcomponent_is_valid (icalcomponent* component) | |||
324 | 363 | ||
325 | 364 | ||
326 | icalcomponent_kind | 365 | icalcomponent_kind |
327 | icalcomponent_isa (icalcomponent* component) | 366 | icalcomponent_isa (const icalcomponent* component) |
328 | { | 367 | { |
329 | struct icalcomponent_impl *impl = (struct icalcomponent_impl *)component; | 368 | icalerror_check_arg_rx( (component!=0), "component", ICAL_NO_COMPONENT); |
330 | icalerror_check_arg_rz( (component!=0), "component"); | ||
331 | 369 | ||
332 | if(component != 0) | 370 | if(component != 0) |
333 | { | 371 | { |
334 | return impl->kind; | 372 | return component->kind; |
335 | } | 373 | } |
336 | 374 | ||
337 | return ICAL_NO_COMPONENT; | 375 | return ICAL_NO_COMPONENT; |
@@ -341,7 +379,7 @@ icalcomponent_isa (icalcomponent* component) | |||
341 | int | 379 | int |
342 | icalcomponent_isa_component (void* component) | 380 | icalcomponent_isa_component (void* component) |
343 | { | 381 | { |
344 | struct icalcomponent_impl *impl = (struct icalcomponent_impl *)component; | 382 | icalcomponent *impl = component; |
345 | 383 | ||
346 | icalerror_check_arg_rz( (component!=0), "component"); | 384 | icalerror_check_arg_rz( (component!=0), "component"); |
347 | 385 | ||
@@ -353,63 +391,32 @@ icalcomponent_isa_component (void* component) | |||
353 | 391 | ||
354 | } | 392 | } |
355 | 393 | ||
356 | int icalcomponent_property_sorter(void *a, void *b) | ||
357 | { | ||
358 | icalproperty_kind kinda, kindb; | ||
359 | const char *ksa, *ksb; | ||
360 | |||
361 | kinda = icalproperty_isa((icalproperty*)a); | ||
362 | kindb = icalproperty_isa((icalproperty*)b); | ||
363 | |||
364 | ksa = icalproperty_kind_to_string(kinda); | ||
365 | ksb = icalproperty_kind_to_string(kindb); | ||
366 | |||
367 | return strcmp(ksa,ksb); | ||
368 | } | ||
369 | |||
370 | |||
371 | void | 394 | void |
372 | icalcomponent_add_property (icalcomponent* component, icalproperty* property) | 395 | icalcomponent_add_property (icalcomponent* component, icalproperty* property) |
373 | { | 396 | { |
374 | struct icalcomponent_impl *impl; | ||
375 | |||
376 | icalerror_check_arg_rv( (component!=0), "component"); | 397 | icalerror_check_arg_rv( (component!=0), "component"); |
377 | icalerror_check_arg_rv( (property!=0), "property"); | 398 | icalerror_check_arg_rv( (property!=0), "property"); |
378 | 399 | ||
379 | impl = (struct icalcomponent_impl*)component; | ||
380 | |||
381 | icalerror_assert( (!icalproperty_get_parent(property)),"The property has already been added to a component. Remove the property with icalcomponent_remove_property before calling icalcomponent_add_property"); | 400 | icalerror_assert( (!icalproperty_get_parent(property)),"The property has already been added to a component. Remove the property with icalcomponent_remove_property before calling icalcomponent_add_property"); |
382 | 401 | ||
383 | icalproperty_set_parent(property,component); | 402 | icalproperty_set_parent(property,component); |
384 | 403 | ||
385 | #ifdef ICAL_INSERT_ORDERED | 404 | pvl_push(component->properties,property); |
386 | pvl_insert_ordered(impl->properties, | ||
387 | icalcomponent_property_sorter,property); | ||
388 | #else | ||
389 | pvl_push(impl->properties,property); | ||
390 | #endif | ||
391 | |||
392 | } | 405 | } |
393 | 406 | ||
394 | 407 | ||
395 | void | 408 | void |
396 | icalcomponent_remove_property (icalcomponent* component, icalproperty* property) | 409 | icalcomponent_remove_property (icalcomponent* component, icalproperty* property) |
397 | { | 410 | { |
398 | struct icalcomponent_impl *impl; | ||
399 | pvl_elem itr, next_itr; | 411 | pvl_elem itr, next_itr; |
400 | struct icalproperty_impl *pimpl; | ||
401 | 412 | ||
402 | icalerror_check_arg_rv( (component!=0), "component"); | 413 | icalerror_check_arg_rv( (component!=0), "component"); |
403 | icalerror_check_arg_rv( (property!=0), "property"); | 414 | icalerror_check_arg_rv( (property!=0), "property"); |
404 | 415 | ||
405 | impl = (struct icalcomponent_impl*)component; | ||
406 | |||
407 | pimpl = (struct icalproperty_impl*)property; | ||
408 | |||
409 | icalerror_assert( (icalproperty_get_parent(property)),"The property is not a member of a component"); | 416 | icalerror_assert( (icalproperty_get_parent(property)),"The property is not a member of a component"); |
410 | 417 | ||
411 | 418 | ||
412 | for( itr = pvl_head(impl->properties); | 419 | for( itr = pvl_head(component->properties); |
413 | itr != 0; | 420 | itr != 0; |
414 | itr = next_itr) | 421 | itr = next_itr) |
415 | { | 422 | { |
@@ -417,11 +424,11 @@ icalcomponent_remove_property (icalcomponent* component, icalproperty* property) | |||
417 | 424 | ||
418 | if( pvl_data(itr) == (void*)property ){ | 425 | if( pvl_data(itr) == (void*)property ){ |
419 | 426 | ||
420 | if (impl->property_iterator == itr){ | 427 | if (component->property_iterator == itr){ |
421 | impl->property_iterator = pvl_next(itr); | 428 | component->property_iterator = pvl_next(itr); |
422 | } | 429 | } |
423 | 430 | ||
424 | pvl_remove( impl->properties, itr); | 431 | pvl_remove( component->properties, itr); |
425 | icalproperty_set_parent(property,0); | 432 | icalproperty_set_parent(property,0); |
426 | } | 433 | } |
427 | } | 434 | } |
@@ -433,11 +440,10 @@ icalcomponent_count_properties (icalcomponent* component, | |||
433 | { | 440 | { |
434 | int count=0; | 441 | int count=0; |
435 | pvl_elem itr; | 442 | pvl_elem itr; |
436 | struct icalcomponent_impl *impl = (struct icalcomponent_impl*)component; | ||
437 | 443 | ||
438 | icalerror_check_arg_rz( (component!=0), "component"); | 444 | icalerror_check_arg_rz( (component!=0), "component"); |
439 | 445 | ||
440 | for( itr = pvl_head(impl->properties); | 446 | for( itr = pvl_head(component->properties); |
441 | itr != 0; | 447 | itr != 0; |
442 | itr = pvl_next(itr)) | 448 | itr = pvl_next(itr)) |
443 | { | 449 | { |
@@ -454,23 +460,19 @@ icalcomponent_count_properties (icalcomponent* component, | |||
454 | 460 | ||
455 | icalproperty* icalcomponent_get_current_property (icalcomponent* component) | 461 | icalproperty* icalcomponent_get_current_property (icalcomponent* component) |
456 | { | 462 | { |
457 | |||
458 | struct icalcomponent_impl *c = (struct icalcomponent_impl*)component; | ||
459 | icalerror_check_arg_rz( (component!=0),"component"); | 463 | icalerror_check_arg_rz( (component!=0),"component"); |
460 | 464 | ||
461 | if ((c->property_iterator==0)){ | 465 | if ((component->property_iterator==0)){ |
462 | return 0; | 466 | return 0; |
463 | } | 467 | } |
464 | 468 | ||
465 | return (icalproperty*) pvl_data(c->property_iterator); | 469 | return (icalproperty*) pvl_data(component->property_iterator); |
466 | |||
467 | } | 470 | } |
468 | 471 | ||
469 | icalproperty* | 472 | icalproperty* |
470 | icalcomponent_get_first_property (icalcomponent* component, icalproperty_kind kind) | 473 | icalcomponent_get_first_property (icalcomponent* c, icalproperty_kind kind) |
471 | { | 474 | { |
472 | struct icalcomponent_impl *c = (struct icalcomponent_impl*)component; | 475 | icalerror_check_arg_rz( (c!=0),"component"); |
473 | icalerror_check_arg_rz( (component!=0),"component"); | ||
474 | 476 | ||
475 | for( c->property_iterator = pvl_head(c->properties); | 477 | for( c->property_iterator = pvl_head(c->properties); |
476 | c->property_iterator != 0; | 478 | c->property_iterator != 0; |
@@ -487,10 +489,9 @@ icalcomponent_get_first_property (icalcomponent* component, icalproperty_kind ki | |||
487 | } | 489 | } |
488 | 490 | ||
489 | icalproperty* | 491 | icalproperty* |
490 | icalcomponent_get_next_property (icalcomponent* component, icalproperty_kind kind) | 492 | icalcomponent_get_next_property (icalcomponent* c, icalproperty_kind kind) |
491 | { | 493 | { |
492 | struct icalcomponent_impl *c = (struct icalcomponent_impl*)component; | 494 | icalerror_check_arg_rz( (c!=0),"component"); |
493 | icalerror_check_arg_rz( (component!=0),"component"); | ||
494 | 495 | ||
495 | if (c->property_iterator == 0){ | 496 | if (c->property_iterator == 0){ |
496 | return 0; | 497 | return 0; |
@@ -519,37 +520,57 @@ icalcomponent_get_properties (icalcomponent* component, icalproperty_kind kind); | |||
519 | void | 520 | void |
520 | icalcomponent_add_component (icalcomponent* parent, icalcomponent* child) | 521 | icalcomponent_add_component (icalcomponent* parent, icalcomponent* child) |
521 | { | 522 | { |
522 | struct icalcomponent_impl *impl, *cimpl; | ||
523 | |||
524 | icalerror_check_arg_rv( (parent!=0), "parent"); | 523 | icalerror_check_arg_rv( (parent!=0), "parent"); |
525 | icalerror_check_arg_rv( (child!=0), "child"); | 524 | icalerror_check_arg_rv( (child!=0), "child"); |
526 | 525 | ||
527 | impl = (struct icalcomponent_impl*)parent; | 526 | if (child->parent !=0) { |
528 | cimpl = (struct icalcomponent_impl*)child; | ||
529 | |||
530 | if (cimpl->parent !=0) { | ||
531 | icalerror_set_errno(ICAL_USAGE_ERROR); | 527 | icalerror_set_errno(ICAL_USAGE_ERROR); |
532 | } | 528 | } |
533 | 529 | ||
534 | cimpl->parent = parent; | 530 | child->parent = parent; |
531 | |||
532 | pvl_push(parent->components,child); | ||
535 | 533 | ||
536 | pvl_push(impl->components,child); | 534 | /* If the new component is a VTIMEZONE, add it to our array. */ |
535 | if (child->kind == ICAL_VTIMEZONE_COMPONENT) { | ||
536 | /* FIXME: Currently we are also creating this array when loading in | ||
537 | a builtin VTIMEZONE, when we don't need it. */ | ||
538 | if (!parent->timezones) | ||
539 | parent->timezones = icaltimezone_array_new (); | ||
540 | |||
541 | icaltimezone_array_append_from_vtimezone (parent->timezones, child); | ||
542 | |||
543 | /* Flag that we need to sort it before doing any binary searches. */ | ||
544 | parent->timezones_sorted = 0; | ||
545 | } | ||
537 | } | 546 | } |
538 | 547 | ||
539 | 548 | ||
540 | void | 549 | void |
541 | icalcomponent_remove_component (icalcomponent* parent, icalcomponent* child) | 550 | icalcomponent_remove_component (icalcomponent* parent, icalcomponent* child) |
542 | { | 551 | { |
543 | struct icalcomponent_impl *impl,*cimpl; | ||
544 | pvl_elem itr, next_itr; | 552 | pvl_elem itr, next_itr; |
545 | 553 | ||
546 | icalerror_check_arg_rv( (parent!=0), "parent"); | 554 | icalerror_check_arg_rv( (parent!=0), "parent"); |
547 | icalerror_check_arg_rv( (child!=0), "child"); | 555 | icalerror_check_arg_rv( (child!=0), "child"); |
548 | 556 | ||
549 | impl = (struct icalcomponent_impl*)parent; | 557 | /* If the component is a VTIMEZONE, remove it from our array as well. */ |
550 | cimpl = (struct icalcomponent_impl*)child; | 558 | if (child->kind == ICAL_VTIMEZONE_COMPONENT) { |
551 | 559 | icaltimezone *zone; | |
552 | for( itr = pvl_head(impl->components); | 560 | int i, num_elements; |
561 | |||
562 | num_elements = parent->timezones ? parent->timezones->num_elements : 0; | ||
563 | for (i = 0; i < num_elements; i++) { | ||
564 | zone = icalarray_element_at (parent->timezones, i); | ||
565 | if (icaltimezone_get_component (zone) == child) { | ||
566 | icaltimezone_free (zone, 0); | ||
567 | icalarray_remove_element_at (parent->timezones, i); | ||
568 | break; | ||
569 | } | ||
570 | } | ||
571 | } | ||
572 | |||
573 | for( itr = pvl_head(parent->components); | ||
553 | itr != 0; | 574 | itr != 0; |
554 | itr = next_itr) | 575 | itr = next_itr) |
555 | { | 576 | { |
@@ -557,16 +578,16 @@ icalcomponent_remove_component (icalcomponent* parent, icalcomponent* child) | |||
557 | 578 | ||
558 | if( pvl_data(itr) == (void*)child ){ | 579 | if( pvl_data(itr) == (void*)child ){ |
559 | 580 | ||
560 | if (impl->component_iterator == itr){ | 581 | if (parent->component_iterator == itr){ |
561 | /* Don't let the current iterator become invalid */ | 582 | /* Don't let the current iterator become invalid */ |
562 | 583 | ||
563 | /* HACK. The semantics for this are troubling. */ | 584 | /* HACK. The semantics for this are troubling. */ |
564 | impl->component_iterator = | 585 | parent->component_iterator = |
565 | pvl_next(impl->component_iterator); | 586 | pvl_next(parent->component_iterator); |
566 | 587 | ||
567 | } | 588 | } |
568 | pvl_remove( impl->components, itr); | 589 | pvl_remove( parent->components, itr); |
569 | cimpl->parent = 0; | 590 | child->parent = 0; |
570 | break; | 591 | break; |
571 | } | 592 | } |
572 | } | 593 | } |
@@ -579,11 +600,10 @@ icalcomponent_count_components (icalcomponent* component, | |||
579 | { | 600 | { |
580 | int count=0; | 601 | int count=0; |
581 | pvl_elem itr; | 602 | pvl_elem itr; |
582 | struct icalcomponent_impl *impl = (struct icalcomponent_impl*)component; | ||
583 | 603 | ||
584 | icalerror_check_arg_rz( (component!=0), "component"); | 604 | icalerror_check_arg_rz( (component!=0), "component"); |
585 | 605 | ||
586 | for( itr = pvl_head(impl->components); | 606 | for( itr = pvl_head(component->components); |
587 | itr != 0; | 607 | itr != 0; |
588 | itr = pvl_next(itr)) | 608 | itr = pvl_next(itr)) |
589 | { | 609 | { |
@@ -599,24 +619,20 @@ icalcomponent_count_components (icalcomponent* component, | |||
599 | icalcomponent* | 619 | icalcomponent* |
600 | icalcomponent_get_current_component(icalcomponent* component) | 620 | icalcomponent_get_current_component(icalcomponent* component) |
601 | { | 621 | { |
602 | struct icalcomponent_impl *c = (struct icalcomponent_impl*)component; | ||
603 | |||
604 | icalerror_check_arg_rz( (component!=0),"component"); | 622 | icalerror_check_arg_rz( (component!=0),"component"); |
605 | 623 | ||
606 | if (c->component_iterator == 0){ | 624 | if (component->component_iterator == 0){ |
607 | return 0; | 625 | return 0; |
608 | } | 626 | } |
609 | 627 | ||
610 | return (icalcomponent*) pvl_data(c->component_iterator); | 628 | return (icalcomponent*) pvl_data(component->component_iterator); |
611 | } | 629 | } |
612 | 630 | ||
613 | icalcomponent* | 631 | icalcomponent* |
614 | icalcomponent_get_first_component (icalcomponent* component, | 632 | icalcomponent_get_first_component (icalcomponent* c, |
615 | icalcomponent_kind kind) | 633 | icalcomponent_kind kind) |
616 | { | 634 | { |
617 | struct icalcomponent_impl *c = (struct icalcomponent_impl*)component; | 635 | icalerror_check_arg_rz( (c!=0),"component"); |
618 | |||
619 | icalerror_check_arg_rz( (component!=0),"component"); | ||
620 | 636 | ||
621 | for( c->component_iterator = pvl_head(c->components); | 637 | for( c->component_iterator = pvl_head(c->components); |
622 | c->component_iterator != 0; | 638 | c->component_iterator != 0; |
@@ -635,11 +651,9 @@ icalcomponent_get_first_component (icalcomponent* component, | |||
635 | 651 | ||
636 | 652 | ||
637 | icalcomponent* | 653 | icalcomponent* |
638 | icalcomponent_get_next_component (icalcomponent* component, icalcomponent_kind kind) | 654 | icalcomponent_get_next_component (icalcomponent* c, icalcomponent_kind kind) |
639 | { | 655 | { |
640 | struct icalcomponent_impl *c = (struct icalcomponent_impl*)component; | 656 | icalerror_check_arg_rz( (c!=0),"component"); |
641 | |||
642 | icalerror_check_arg_rz( (component!=0),"component"); | ||
643 | 657 | ||
644 | if (c->component_iterator == 0){ | 658 | if (c->component_iterator == 0){ |
645 | return 0; | 659 | return 0; |
@@ -673,83 +687,52 @@ icalcomponent* icalcomponent_get_first_real_component(icalcomponent *c) | |||
673 | if(kind == ICAL_VEVENT_COMPONENT || | 687 | if(kind == ICAL_VEVENT_COMPONENT || |
674 | kind == ICAL_VTODO_COMPONENT || | 688 | kind == ICAL_VTODO_COMPONENT || |
675 | kind == ICAL_VJOURNAL_COMPONENT || | 689 | kind == ICAL_VJOURNAL_COMPONENT || |
676 | kind == ICAL_VFREEBUSY_COMPONENT ){ | 690 | kind == ICAL_VFREEBUSY_COMPONENT || |
691 | kind == ICAL_VQUERY_COMPONENT || | ||
692 | kind == ICAL_VAGENDA_COMPONENT){ | ||
677 | return comp; | 693 | return comp; |
678 | } | 694 | } |
679 | } | 695 | } |
680 | return 0; | 696 | return 0; |
681 | } | 697 | } |
682 | 698 | ||
683 | time_t icalcomponent_convert_time(icalproperty *p) | ||
684 | { | ||
685 | struct icaltimetype sict; | ||
686 | time_t convt; | ||
687 | icalproperty *tzp; | ||
688 | |||
689 | |||
690 | /* Though it says _dtstart, it will work for dtend too */ | ||
691 | sict = icalproperty_get_dtstart(p); | ||
692 | |||
693 | tzp = icalproperty_get_first_parameter(p,ICAL_TZID_PARAMETER); | ||
694 | |||
695 | if (sict.is_utc == 1 && tzp != 0){ | ||
696 | icalerror_warn("icalcomponent_get_span: component has a UTC DTSTART with a timezone specified "); | ||
697 | icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); | ||
698 | return 0; | ||
699 | } | ||
700 | 699 | ||
701 | if(sict.is_utc == 1){ | 700 | /**@brief Get the timespan covered by this component, in UTC |
702 | /* _as_timet will use gmtime() to do the conversion */ | 701 | *(deprecated) |
703 | convt = icaltime_as_timet(sict); | 702 | * |
704 | 703 | * see icalcomponent_foreach_recurrence() for a better way to | |
705 | #ifdef TEST_CONVERT_TIME | 704 | * extract spans from an component. |
706 | printf("convert time: use as_timet:\n %s\n %s", | 705 | * |
707 | icalproperty_as_ical_string(p), ctime(&convt)); | 706 | *This method can be called on either a VCALENDAR or any real |
708 | #endif | 707 | *component. If the VCALENDAR contains no real component, but |
709 | 708 | *contains a VTIMEZONE, we return that span instead. | |
710 | } else if (sict.is_utc == 0 && tzp == 0 ) { | 709 | *This might not be a desirable behavior; we keep it for now |
711 | time_t offset; | 710 | *for backward compatibility, but it might be deprecated at a |
712 | 711 | *future time. | |
713 | /* _as_timet will use localtime() to do the conversion */ | 712 | * |
714 | convt = icaltime_as_timet(sict); | 713 | *FIXME this API needs to be clarified. DTEND is defined as the |
715 | offset = icaltime_utc_offset(sict,0); | 714 | *first available time after the end of this event, so the span |
716 | convt += offset; | 715 | *should actually end 1 second before DTEND. |
717 | 716 | */ | |
718 | #ifdef TEST_CONVERT_TIME | 717 | |
719 | printf("convert time: use as_timet and adjust:\n %s\n %s", | 718 | icaltime_span icalcomponent_get_span(icalcomponent* comp) |
720 | icalproperty_as_ical_string(p), ctime(&convt)); | ||
721 | #endif | ||
722 | } else { | ||
723 | /* Convert the time to UTC for the named timezone*/ | ||
724 | const char* timezone = icalparameter_get_tzid(tzp); | ||
725 | convt = icaltime_as_timet(icaltime_as_utc(sict,timezone)); | ||
726 | |||
727 | #ifdef TEST_CONVERT_TIME | ||
728 | printf("convert time: use _as_utc:\n %s\n %s", | ||
729 | icalproperty_as_ical_string(p), ctime(&convt)); | ||
730 | #endif | ||
731 | } | ||
732 | |||
733 | return convt; | ||
734 | } | ||
735 | struct icaltime_span icalcomponent_get_span(icalcomponent* comp) | ||
736 | { | 719 | { |
737 | icalcomponent *inner; | 720 | icalcomponent *inner; |
738 | icalproperty *p, *duration; | ||
739 | icalcomponent_kind kind; | 721 | icalcomponent_kind kind; |
740 | struct icaltime_span span; | 722 | icaltime_span span; |
741 | struct icaltimetype start; | 723 | struct icaltimetype start, end; |
742 | 724 | ||
743 | span.start = 0; | 725 | span.start = 0; |
744 | span.end = 0; | 726 | span.end = 0; |
745 | span.is_busy= 1; | 727 | span.is_busy= 1; |
746 | 728 | ||
747 | /* initial Error checking */ | 729 | /* initial Error checking */ |
730 | if (comp == NULL) { | ||
731 | return span; | ||
732 | } | ||
748 | 733 | ||
749 | /* icalerror_check_arg_rz( (comp!=0),"comp");*/ | 734 | /* FIXME this might go away */ |
750 | |||
751 | kind = icalcomponent_isa(comp); | 735 | kind = icalcomponent_isa(comp); |
752 | |||
753 | if(kind == ICAL_VCALENDAR_COMPONENT){ | 736 | if(kind == ICAL_VCALENDAR_COMPONENT){ |
754 | inner = icalcomponent_get_first_real_component(comp); | 737 | inner = icalcomponent_get_first_real_component(comp); |
755 | 738 | ||
@@ -781,67 +764,329 @@ struct icaltime_span icalcomponent_get_span(icalcomponent* comp) | |||
781 | 764 | ||
782 | } | 765 | } |
783 | 766 | ||
767 | /* Get to work. starting with DTSTART */ | ||
768 | start = icalcomponent_get_dtstart(comp); | ||
769 | if (icaltime_is_null_time(start)) { | ||
770 | return span; | ||
771 | } | ||
772 | span.start = icaltime_as_timet_with_zone(start, | ||
773 | icaltimezone_get_utc_timezone()); | ||
784 | 774 | ||
775 | /* The end time could be specified as either a DTEND or a DURATION */ | ||
776 | /* icalcomponent_get_dtend takes care of these cases. */ | ||
777 | end = icalcomponent_get_dtend(comp); | ||
778 | if (icaltime_is_null_time(end)) { | ||
779 | if (!icaltime_is_date(start)) { | ||
780 | /* If dtstart is a DATE-TIME and there is no DTEND nor DURATION | ||
781 | it takes no time */ | ||
782 | span.start = 0; | ||
783 | return span; | ||
784 | } else { | ||
785 | end = start; | ||
786 | } | ||
787 | } | ||
785 | 788 | ||
786 | /* Get to work. starting with DTSTART */ | 789 | span.end = icaltime_as_timet_with_zone(end, |
790 | icaltimezone_get_utc_timezone()); | ||
791 | if (icaltime_is_date(start)) { | ||
792 | /* Until the end of the day*/ | ||
793 | span.end += 60*60*24 - 1; | ||
794 | } | ||
787 | 795 | ||
788 | p = icalcomponent_get_first_property(inner, ICAL_DTSTART_PROPERTY); | 796 | return span; |
789 | 797 | ||
790 | if (p ==0 ) { | 798 | } |
791 | icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); | 799 | |
792 | /*icalerror_warn("icalcomponent_get_span: component has no DTSTART time");*/ | 800 | /** |
793 | return span; | 801 | * Decide if this recurrance is acceptable |
802 | * | ||
803 | * @param comp A valid icalcomponent. | ||
804 | * @param dtstart The base dtstart value for this component. | ||
805 | * @param recurtime The time to test against. | ||
806 | * | ||
807 | * @return true if the recurrence value is excluded, false otherwise. | ||
808 | * | ||
809 | * This function decides if a specific recurrence value is | ||
810 | * excluded by EXRULE or EXDATE properties. | ||
811 | * | ||
812 | * It's not the most efficient code. You might get better performance | ||
813 | * if you assume that recurtime is always increasing for each | ||
814 | * call. Then you could: | ||
815 | * | ||
816 | * - sort the EXDATE values | ||
817 | * - save the state of each EXRULE iterator for the next call. | ||
818 | * | ||
819 | * In this case though you don't need to worry how you call this | ||
820 | * function. It will always return the correct result. | ||
821 | */ | ||
822 | |||
823 | int icalproperty_recurrence_is_excluded(icalcomponent *comp, | ||
824 | struct icaltimetype *dtstart, | ||
825 | struct icaltimetype *recurtime) { | ||
826 | icalproperty *exdate, *exrule; | ||
827 | |||
828 | if (comp == NULL || | ||
829 | dtstart == NULL || | ||
830 | recurtime == NULL || | ||
831 | icaltime_is_null_time(*recurtime)) | ||
832 | /* BAD DATA */ | ||
833 | return 1; | ||
834 | |||
835 | /** first test against the exdate values **/ | ||
836 | for (exdate = icalcomponent_get_first_property(comp,ICAL_EXDATE_PROPERTY); | ||
837 | exdate != NULL; | ||
838 | exdate = icalcomponent_get_next_property(comp,ICAL_EXDATE_PROPERTY)) { | ||
839 | |||
840 | struct icaltimetype exdatetime = icalproperty_get_exdate(exdate); | ||
841 | |||
842 | if (icaltime_compare(*recurtime, exdatetime) == 0) { | ||
843 | /** MATCHED **/ | ||
844 | return 1; | ||
845 | } | ||
846 | } | ||
847 | |||
848 | /** Now test against the EXRULEs **/ | ||
849 | for (exrule = icalcomponent_get_first_property(comp,ICAL_EXRULE_PROPERTY); | ||
850 | exdate != NULL; | ||
851 | exdate = icalcomponent_get_next_property(comp,ICAL_EXRULE_PROPERTY)) { | ||
852 | |||
853 | struct icalrecurrencetype recur = icalproperty_get_exrule(exrule); | ||
854 | icalrecur_iterator *exrule_itr = icalrecur_iterator_new(recur, *dtstart); | ||
855 | struct icaltimetype exrule_time; | ||
856 | |||
857 | while (1) { | ||
858 | int result; | ||
859 | exrule_time = icalrecur_iterator_next(exrule_itr); | ||
860 | |||
861 | if (icaltime_is_null_time(exrule_time)) | ||
862 | break; | ||
863 | |||
864 | result = icaltime_compare(*recurtime, exrule_time); | ||
865 | if (result == 0) { | ||
866 | icalrecur_iterator_free(exrule_itr); | ||
867 | return 1; /** MATCH **/ | ||
868 | } | ||
869 | if (result == 1) | ||
870 | break; /** exrule_time > recurtime **/ | ||
794 | } | 871 | } |
795 | 872 | ||
873 | icalrecur_iterator_free(exrule_itr); | ||
874 | } | ||
796 | 875 | ||
797 | start = icalproperty_get_dtstart(p); | 876 | return 0; /** no matches **/ |
877 | } | ||
798 | 878 | ||
799 | icalerror_clear_errno(); | 879 | /** |
880 | * @brief Return the busy status based on the TRANSP property. | ||
881 | * | ||
882 | * @param comp A valid icalcomponent. | ||
883 | * | ||
884 | * @return 1 if the event is a busy item, 0 if it is not. | ||
885 | */ | ||
800 | 886 | ||
801 | span.start = icalcomponent_convert_time(p); | 887 | static int icalcomponent_is_busy(icalcomponent *comp) { |
888 | icalproperty *transp; | ||
889 | enum icalproperty_status status; | ||
890 | int ret = 1; | ||
802 | 891 | ||
803 | #ifdef TEST_CONVERT_TIME | 892 | /** @todo check access control here, converting busy->free if the |
804 | printf("convert time:\n %s %s", | 893 | permissions do not allow access... */ |
805 | icalproperty_as_ical_string(p), ctime(&span.start)); | ||
806 | #endif | ||
807 | 894 | ||
808 | if(icalerrno != ICAL_NO_ERROR){ | 895 | /* Is this a busy time? Check the TRANSP property */ |
809 | span.start = 0; | 896 | transp = icalcomponent_get_first_property(comp, ICAL_TRANSP_PROPERTY); |
810 | return span; | 897 | |
898 | if (transp) { | ||
899 | icalvalue *transp_val = icalproperty_get_value(transp); | ||
900 | |||
901 | switch (icalvalue_get_transp(transp_val)) { | ||
902 | case ICAL_TRANSP_OPAQUE: | ||
903 | case ICAL_TRANSP_OPAQUENOCONFLICT: | ||
904 | case ICAL_TRANSP_NONE: | ||
905 | ret = 1; | ||
906 | break; | ||
907 | case ICAL_TRANSP_TRANSPARENT: | ||
908 | case ICAL_TRANSP_TRANSPARENTNOCONFLICT: | ||
909 | ret = 0; | ||
910 | break; | ||
911 | default: | ||
912 | ret = 0; | ||
913 | break; | ||
811 | } | 914 | } |
915 | } | ||
916 | status = icalcomponent_get_status(comp); | ||
917 | if (ret && status) { | ||
918 | switch (status) { | ||
919 | case ICAL_STATUS_CANCELLED: | ||
920 | case ICAL_STATUS_TENTATIVE: | ||
921 | ret = 0; | ||
922 | break; | ||
923 | default: | ||
924 | break; | ||
925 | } | ||
926 | } | ||
927 | return(ret); | ||
928 | } | ||
812 | 929 | ||
813 | /* The end time could be specified as either a DTEND or a DURATION */ | ||
814 | p = icalcomponent_get_first_property(inner, ICAL_DTEND_PROPERTY); | ||
815 | duration = icalcomponent_get_first_property(inner, ICAL_DURATION_PROPERTY); | ||
816 | 930 | ||
817 | if (p==0 && duration == 0 && start.is_date != 1) { | ||
818 | icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); | ||
819 | /*icalerror_warn("icalcomponent_get_span: component has neither DTEND nor DURATION time");*/ | ||
820 | span.start = 0; | ||
821 | return span; | ||
822 | } | ||
823 | 931 | ||
824 | if (p!=0){ | ||
825 | span.end = icalcomponent_convert_time(p); | ||
826 | } else if (start.is_date == 1) { | ||
827 | /* Duration is all day */ | ||
828 | span.end = span.start + 60*60*24; | ||
829 | } else { | ||
830 | /* Use the duration */ | ||
831 | struct icaldurationtype dur; | ||
832 | time_t durt; | ||
833 | |||
834 | |||
835 | dur = icalproperty_get_duration(duration); | ||
836 | 932 | ||
837 | durt = icaldurationtype_as_int(dur); | 933 | /** |
838 | span.end = span.start+durt; | 934 | * @brief cycle through all recurrances of an event |
935 | * | ||
936 | * @param comp A valid VEVENT component | ||
937 | * @param start Ignore timespans before this | ||
938 | * @param end Ignore timespans after this | ||
939 | * @param callback Function called for each timespan within the range | ||
940 | * @param callback_data Pointer passed back to the callback function | ||
941 | * | ||
942 | * This function will call the specified callback function for once | ||
943 | * for the base value of DTSTART, and foreach recurring date/time | ||
944 | * value. | ||
945 | * | ||
946 | * It will filter out events that are specified as an EXDATE or an EXRULE. | ||
947 | * | ||
948 | * @todo We do not filter out duplicate RRULES/RDATES | ||
949 | * @todo We do not handle RDATEs with explicit periods | ||
950 | */ | ||
951 | |||
952 | void icalcomponent_foreach_recurrence(icalcomponent* comp, | ||
953 | struct icaltimetype start, | ||
954 | struct icaltimetype end, | ||
955 | void (*callback)(icalcomponent *comp, | ||
956 | struct icaltime_span *span, | ||
957 | void *data), | ||
958 | void *callback_data) | ||
959 | { | ||
960 | struct icaltimetype dtstart, dtend; | ||
961 | icaltime_span recurspan, basespan, limit_span; | ||
962 | time_t limit_start, limit_end; | ||
963 | int dtduration; | ||
964 | icalproperty *rrule, *rdate; | ||
965 | struct icaldurationtype dur; | ||
966 | pvl_elem property_iterator;/* for saving the iterator */ | ||
967 | |||
968 | if (comp == NULL || callback == NULL) | ||
969 | return; | ||
970 | |||
971 | dtstart = icalcomponent_get_dtstart(comp); | ||
972 | |||
973 | if (icaltime_is_null_time(dtstart)) | ||
974 | return; | ||
975 | |||
976 | |||
977 | /* The end time could be specified as either a DTEND or a DURATION */ | ||
978 | /* icalcomponent_get_dtend takes care of these cases. */ | ||
979 | dtend = icalcomponent_get_dtend(comp); | ||
980 | |||
981 | /* Now set up the base span for this item, corresponding to the | ||
982 | base DTSTART and DTEND */ | ||
983 | basespan = icaltime_span_new(dtstart, dtend, 1); | ||
984 | |||
985 | basespan.is_busy = icalcomponent_is_busy(comp); | ||
986 | |||
987 | |||
988 | /** Calculate the ceiling and floor values.. **/ | ||
989 | limit_start = icaltime_as_timet_with_zone(start, icaltimezone_get_utc_timezone()); | ||
990 | if (!icaltime_is_null_time(end)) | ||
991 | limit_end = icaltime_as_timet_with_zone(end, icaltimezone_get_utc_timezone()); | ||
992 | else | ||
993 | limit_end = INT_MAX; /* max 32 bit time_t */ | ||
994 | |||
995 | limit_span.start = limit_start; | ||
996 | limit_span.end = limit_end; | ||
997 | |||
998 | |||
999 | /* Do the callback for the initial DTSTART entry */ | ||
1000 | |||
1001 | if (!icalproperty_recurrence_is_excluded(comp, &dtstart, &dtstart)) { | ||
1002 | /** call callback action **/ | ||
1003 | if (icaltime_span_overlaps(&basespan, &limit_span)) | ||
1004 | (*callback) (comp, &basespan, callback_data); | ||
1005 | } | ||
1006 | |||
1007 | recurspan = basespan; | ||
1008 | dtduration = basespan.end - basespan.start; | ||
1009 | |||
1010 | /* Now cycle through the rrule entries */ | ||
1011 | for (rrule = icalcomponent_get_first_property(comp,ICAL_RRULE_PROPERTY); | ||
1012 | rrule != NULL; | ||
1013 | rrule = icalcomponent_get_next_property(comp,ICAL_RRULE_PROPERTY)) { | ||
1014 | |||
1015 | struct icalrecurrencetype recur = icalproperty_get_rrule(rrule); | ||
1016 | icalrecur_iterator *rrule_itr = icalrecur_iterator_new(recur, dtstart); | ||
1017 | struct icaltimetype rrule_time = icalrecur_iterator_next(rrule_itr); | ||
1018 | /** note that icalrecur_iterator_next always returns dtstart | ||
1019 | the first time.. **/ | ||
1020 | |||
1021 | while (1) { | ||
1022 | rrule_time = icalrecur_iterator_next(rrule_itr); | ||
1023 | |||
1024 | if (icaltime_is_null_time(rrule_time)) | ||
1025 | break; | ||
1026 | |||
1027 | dur = icaltime_subtract(rrule_time, dtstart); | ||
1028 | |||
1029 | recurspan.start = basespan.start + icaldurationtype_as_int(dur); | ||
1030 | recurspan.end = recurspan.start + dtduration; | ||
1031 | |||
1032 | /** save the iterator ICK! **/ | ||
1033 | property_iterator = comp->property_iterator; | ||
1034 | |||
1035 | if (!icalproperty_recurrence_is_excluded(comp, &dtstart, &rrule_time)) { | ||
1036 | /** call callback action **/ | ||
1037 | if (icaltime_span_overlaps(&recurspan, &limit_span)) | ||
1038 | (*callback) (comp, &recurspan, callback_data); | ||
1039 | } | ||
1040 | comp->property_iterator = property_iterator; | ||
1041 | } /* end of iteration over a specific RRULE */ | ||
1042 | |||
1043 | icalrecur_iterator_free(rrule_itr); | ||
1044 | } /* end of RRULE loop */ | ||
1045 | |||
1046 | |||
1047 | /** Now process RDATE entries **/ | ||
1048 | for (rdate = icalcomponent_get_first_property(comp,ICAL_RDATE_PROPERTY); | ||
1049 | rdate != NULL; | ||
1050 | rdate = icalcomponent_get_next_property(comp,ICAL_RDATE_PROPERTY)) { | ||
1051 | |||
1052 | struct icaldatetimeperiodtype rdate_period = icalproperty_get_rdate(rdate); | ||
1053 | |||
1054 | /** RDATES can specify raw datetimes, periods, or dates. | ||
1055 | we only support raw datetimes for now.. | ||
1056 | |||
1057 | @todo Add support for other types **/ | ||
1058 | |||
1059 | if (icaltime_is_null_time(rdate_period.time)) | ||
1060 | continue; | ||
1061 | |||
1062 | dur = icaltime_subtract(rdate_period.time, dtstart); | ||
1063 | |||
1064 | recurspan.start = basespan.start + icaldurationtype_as_int(dur); | ||
1065 | recurspan.end = recurspan.start + dtduration; | ||
1066 | |||
1067 | /** save the iterator ICK! **/ | ||
1068 | property_iterator = comp->property_iterator; | ||
1069 | |||
1070 | if (!icalproperty_recurrence_is_excluded(comp, &dtstart, &rdate_period.time)) { | ||
1071 | /** call callback action **/ | ||
1072 | (*callback) (comp, &recurspan, callback_data); | ||
839 | } | 1073 | } |
1074 | comp->property_iterator = property_iterator; | ||
1075 | } | ||
1076 | } | ||
1077 | |||
840 | 1078 | ||
841 | return span; | ||
842 | 1079 | ||
1080 | int icalcomponent_check_restrictions(icalcomponent* comp){ | ||
1081 | icalerror_check_arg_rz(comp!=0,"comp"); | ||
1082 | return icalrestriction_check(comp); | ||
843 | } | 1083 | } |
844 | 1084 | ||
1085 | /** @brief returns the number of errors encountered parsing the data | ||
1086 | * | ||
1087 | * This function counts the number times the X-LIC-ERROR occurs | ||
1088 | * in the data structure. | ||
1089 | */ | ||
845 | 1090 | ||
846 | int icalcomponent_count_errors(icalcomponent* component) | 1091 | int icalcomponent_count_errors(icalcomponent* component) |
847 | { | 1092 | { |
@@ -849,9 +1094,8 @@ int icalcomponent_count_errors(icalcomponent* component) | |||
849 | icalproperty *p; | 1094 | icalproperty *p; |
850 | icalcomponent *c; | 1095 | icalcomponent *c; |
851 | pvl_elem itr; | 1096 | pvl_elem itr; |
852 | struct icalcomponent_impl *impl = (struct icalcomponent_impl*)component; | ||
853 | 1097 | ||
854 | for( itr = pvl_head(impl->properties); | 1098 | for( itr = pvl_head(component->properties); |
855 | itr != 0; | 1099 | itr != 0; |
856 | itr = pvl_next(itr)) | 1100 | itr = pvl_next(itr)) |
857 | { | 1101 | { |
@@ -864,7 +1108,7 @@ int icalcomponent_count_errors(icalcomponent* component) | |||
864 | } | 1108 | } |
865 | 1109 | ||
866 | 1110 | ||
867 | for( itr = pvl_head(impl->components); | 1111 | for( itr = pvl_head(component->components); |
868 | itr != 0; | 1112 | itr != 0; |
869 | itr = pvl_next(itr)) | 1113 | itr = pvl_next(itr)) |
870 | { | 1114 | { |
@@ -883,9 +1127,8 @@ void icalcomponent_strip_errors(icalcomponent* component) | |||
883 | icalproperty *p; | 1127 | icalproperty *p; |
884 | icalcomponent *c; | 1128 | icalcomponent *c; |
885 | pvl_elem itr, next_itr; | 1129 | pvl_elem itr, next_itr; |
886 | struct icalcomponent_impl *impl = (struct icalcomponent_impl*)component; | ||
887 | 1130 | ||
888 | for( itr = pvl_head(impl->properties); | 1131 | for( itr = pvl_head(component->properties); |
889 | itr != 0; | 1132 | itr != 0; |
890 | itr = next_itr) | 1133 | itr = next_itr) |
891 | { | 1134 | { |
@@ -898,7 +1141,7 @@ void icalcomponent_strip_errors(icalcomponent* component) | |||
898 | } | 1141 | } |
899 | } | 1142 | } |
900 | 1143 | ||
901 | for( itr = pvl_head(impl->components); | 1144 | for( itr = pvl_head(component->components); |
902 | itr != 0; | 1145 | itr != 0; |
903 | itr = pvl_next(itr)) | 1146 | itr = pvl_next(itr)) |
904 | { | 1147 | { |
@@ -952,6 +1195,7 @@ void icalcomponent_convert_errors(icalcomponent* component) | |||
952 | } | 1195 | } |
953 | 1196 | ||
954 | default: { | 1197 | default: { |
1198 | break; | ||
955 | } | 1199 | } |
956 | } | 1200 | } |
957 | if (rst.code != ICAL_UNKNOWN_STATUS){ | 1201 | if (rst.code != ICAL_UNKNOWN_STATUS){ |
@@ -976,16 +1220,12 @@ void icalcomponent_convert_errors(icalcomponent* component) | |||
976 | 1220 | ||
977 | icalcomponent* icalcomponent_get_parent(icalcomponent* component) | 1221 | icalcomponent* icalcomponent_get_parent(icalcomponent* component) |
978 | { | 1222 | { |
979 | struct icalcomponent_impl *c = (struct icalcomponent_impl*)component; | 1223 | return component->parent; |
980 | |||
981 | return c->parent; | ||
982 | } | 1224 | } |
983 | 1225 | ||
984 | void icalcomponent_set_parent(icalcomponent* component, icalcomponent* parent) | 1226 | void icalcomponent_set_parent(icalcomponent* component, icalcomponent* parent) |
985 | { | 1227 | { |
986 | struct icalcomponent_impl *c = (struct icalcomponent_impl*)component; | 1228 | component->parent = parent; |
987 | |||
988 | c->parent = parent; | ||
989 | } | 1229 | } |
990 | 1230 | ||
991 | icalcompiter icalcompiter_null = {ICAL_NO_COMPONENT,0}; | 1231 | icalcompiter icalcompiter_null = {ICAL_NO_COMPONENT,0}; |
@@ -1004,6 +1244,7 @@ static struct icalcomponent_kind_map component_map[] = | |||
1004 | { ICAL_VTODO_COMPONENT, "VTODO" }, | 1244 | { ICAL_VTODO_COMPONENT, "VTODO" }, |
1005 | { ICAL_VJOURNAL_COMPONENT, "VJOURNAL" }, | 1245 | { ICAL_VJOURNAL_COMPONENT, "VJOURNAL" }, |
1006 | { ICAL_VCALENDAR_COMPONENT, "VCALENDAR" }, | 1246 | { ICAL_VCALENDAR_COMPONENT, "VCALENDAR" }, |
1247 | { ICAL_VAGENDA_COMPONENT, "VAGENDA" }, | ||
1007 | { ICAL_VFREEBUSY_COMPONENT, "VFREEBUSY" }, | 1248 | { ICAL_VFREEBUSY_COMPONENT, "VFREEBUSY" }, |
1008 | { ICAL_VTIMEZONE_COMPONENT, "VTIMEZONE" }, | 1249 | { ICAL_VTIMEZONE_COMPONENT, "VTIMEZONE" }, |
1009 | { ICAL_VALARM_COMPONENT, "VALARM" }, | 1250 | { ICAL_VALARM_COMPONENT, "VALARM" }, |
@@ -1028,6 +1269,16 @@ static struct icalcomponent_kind_map component_map[] = | |||
1028 | }; | 1269 | }; |
1029 | 1270 | ||
1030 | 1271 | ||
1272 | int icalcomponent_kind_is_valid(const icalcomponent_kind kind) | ||
1273 | { | ||
1274 | int i = 0; | ||
1275 | do { | ||
1276 | if (component_map[i].kind == kind) | ||
1277 | return 1; | ||
1278 | } while (component_map[i++].kind != ICAL_NO_COMPONENT); | ||
1279 | |||
1280 | return 0; | ||
1281 | } | ||
1031 | 1282 | ||
1032 | const char* icalcomponent_kind_to_string(icalcomponent_kind kind) | 1283 | const char* icalcomponent_kind_to_string(icalcomponent_kind kind) |
1033 | { | 1284 | { |
@@ -1065,15 +1316,15 @@ icalcomponent_kind icalcomponent_string_to_kind(const char* string) | |||
1065 | icalcompiter | 1316 | icalcompiter |
1066 | icalcomponent_begin_component(icalcomponent* component,icalcomponent_kind kind) | 1317 | icalcomponent_begin_component(icalcomponent* component,icalcomponent_kind kind) |
1067 | { | 1318 | { |
1068 | struct icalcomponent_impl *impl = (struct icalcomponent_impl*)component; | 1319 | icalcompiter itr; |
1069 | icalcompiter itr = icalcompiter_null; | ||
1070 | pvl_elem i; | 1320 | pvl_elem i; |
1071 | 1321 | ||
1072 | itr.kind = kind; | 1322 | itr.kind = kind; |
1323 | itr.iter = NULL; | ||
1073 | 1324 | ||
1074 | icalerror_check_arg_re( (component!=0),"component",icalcompiter_null); | 1325 | icalerror_check_arg_re(component!=0,"component",icalcompiter_null); |
1075 | 1326 | ||
1076 | for( i = pvl_head(impl->components); i != 0; i = pvl_next(itr.iter)) { | 1327 | for( i = pvl_head(component->components); i != 0; i = pvl_next(i)) { |
1077 | 1328 | ||
1078 | icalcomponent *c = (icalcomponent*) pvl_data(i); | 1329 | icalcomponent *c = (icalcomponent*) pvl_data(i); |
1079 | 1330 | ||
@@ -1091,15 +1342,14 @@ icalcomponent_begin_component(icalcomponent* component,icalcomponent_kind kind) | |||
1091 | icalcompiter | 1342 | icalcompiter |
1092 | icalcomponent_end_component(icalcomponent* component,icalcomponent_kind kind) | 1343 | icalcomponent_end_component(icalcomponent* component,icalcomponent_kind kind) |
1093 | { | 1344 | { |
1094 | struct icalcomponent_impl *impl = (struct icalcomponent_impl*)component; | ||
1095 | icalcompiter itr; | 1345 | icalcompiter itr; |
1096 | pvl_elem i; | 1346 | pvl_elem i; |
1097 | 1347 | ||
1098 | itr.kind = kind; | 1348 | itr.kind = kind; |
1099 | 1349 | ||
1100 | icalerror_check_arg_re( (component!=0),"component",icalcompiter_null); | 1350 | icalerror_check_arg_re(component!=0,"component",icalcompiter_null); |
1101 | 1351 | ||
1102 | for( i = pvl_tail(impl->components); i != 0; i = pvl_prior(i)) { | 1352 | for( i = pvl_tail(component->components); i != 0; i = pvl_prior(i)) { |
1103 | 1353 | ||
1104 | icalcomponent *c = (icalcomponent*) pvl_data(i); | 1354 | icalcomponent *c = (icalcomponent*) pvl_data(i); |
1105 | 1355 | ||
@@ -1180,140 +1430,231 @@ icalcomponent* icalcomponent_get_inner(icalcomponent* comp) | |||
1180 | } | 1430 | } |
1181 | } | 1431 | } |
1182 | 1432 | ||
1433 | /** @brief sets the METHOD property to the given method | ||
1434 | */ | ||
1183 | 1435 | ||
1184 | void icalcomponent_set_dtstart(icalcomponent* comp, struct icaltimetype v) | 1436 | void icalcomponent_set_method(icalcomponent* comp, icalproperty_method method) |
1185 | { | 1437 | { |
1438 | icalproperty *prop | ||
1439 | = icalcomponent_get_first_property(comp, ICAL_METHOD_PROPERTY); | ||
1186 | 1440 | ||
1187 | icalcomponent *inner = icalcomponent_get_inner(comp); | 1441 | |
1442 | if (prop == 0){ | ||
1443 | prop = icalproperty_new_method(method); | ||
1444 | icalcomponent_add_property(comp, prop); | ||
1445 | } | ||
1446 | |||
1447 | icalproperty_set_method(prop,method); | ||
1448 | |||
1449 | } | ||
1450 | |||
1451 | /** @brief returns the METHOD property | ||
1452 | */ | ||
1453 | |||
1454 | icalproperty_method icalcomponent_get_method(icalcomponent* comp) | ||
1455 | { | ||
1188 | icalproperty *prop | 1456 | icalproperty *prop |
1189 | = icalcomponent_get_first_property(inner, ICAL_DTSTART_PROPERTY); | 1457 | = icalcomponent_get_first_property(comp,ICAL_METHOD_PROPERTY); |
1190 | 1458 | ||
1459 | if (prop == 0){ | ||
1460 | return ICAL_METHOD_NONE; | ||
1461 | } | ||
1462 | |||
1463 | return icalproperty_get_method(prop); | ||
1464 | } | ||
1465 | |||
1466 | #define ICALSETUPSET(p_kind) \ | ||
1467 | icalcomponent *inner; \ | ||
1468 | icalproperty *prop; \ | ||
1469 | icalerror_check_arg_rv(comp!=0,"comp");\ | ||
1470 | inner = icalcomponent_get_inner(comp); \ | ||
1471 | if(inner == 0){\ | ||
1472 | icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);\ | ||
1473 | return;\ | ||
1474 | }\ | ||
1475 | prop = icalcomponent_get_first_property(inner, p_kind); | ||
1476 | |||
1477 | |||
1478 | /**@brief Set DTSTART property to given icaltime | ||
1479 | * | ||
1480 | *This method respects the icaltime type (DATE vs DATE-TIME) and | ||
1481 | *timezone (or lack thereof). | ||
1482 | */ | ||
1483 | void icalcomponent_set_dtstart(icalcomponent* comp, struct icaltimetype v) | ||
1484 | { | ||
1485 | char *tzid; | ||
1486 | ICALSETUPSET(ICAL_DTSTART_PROPERTY); | ||
1191 | 1487 | ||
1192 | if (prop == 0){ | 1488 | if (prop == 0){ |
1193 | prop = icalproperty_new_dtstart(v); | 1489 | prop = icalproperty_new_dtstart(v); |
1194 | icalcomponent_add_property(inner, prop); | 1490 | icalcomponent_add_property(inner, prop); |
1491 | } else { | ||
1492 | icalproperty_remove_parameter_by_kind(prop, ICAL_TZID_PARAMETER); | ||
1195 | } | 1493 | } |
1196 | 1494 | ||
1197 | icalproperty_set_dtstart(prop,v); | 1495 | icalproperty_set_dtstart(prop,v); |
1198 | 1496 | ||
1497 | if ((tzid = icaltime_get_tzid(v)) != NULL && !icaltime_is_utc(v)) { | ||
1498 | icalproperty_add_parameter(prop, icalparameter_new_tzid(tzid)); | ||
1499 | } | ||
1199 | } | 1500 | } |
1200 | 1501 | ||
1502 | /**@brief Get a DATE or DATE-TIME property as an icaltime | ||
1503 | * | ||
1504 | *If the property is a DATE-TIME with a timezone parameter and a | ||
1505 | *corresponding VTIMEZONE is present in the component, the | ||
1506 | *returned component will already be in the correct timezone; | ||
1507 | *otherwise the caller is responsible for converting it. | ||
1508 | * | ||
1509 | *FIXME this is useless until we can flag the failure | ||
1510 | */ | ||
1511 | static struct icaltimetype | ||
1512 | icalcomponent_get_datetime(icalcomponent *comp, icalproperty *prop) { | ||
1513 | |||
1514 | icalparameter *param; | ||
1515 | struct icaltimetyperet; | ||
1516 | |||
1517 | ret = icalvalue_get_datetime(icalproperty_get_value(prop)); | ||
1518 | |||
1519 | if ((param = icalproperty_get_first_parameter(prop, ICAL_TZID_PARAMETER)) | ||
1520 | != NULL) { | ||
1521 | const char *tzid = icalparameter_get_tzid(param); | ||
1522 | icaltimezone *tz; | ||
1523 | |||
1524 | if ((tz = icalcomponent_get_timezone(comp, tzid)) != NULL) { | ||
1525 | icaltime_set_timezone(&ret, tz); | ||
1526 | } | ||
1527 | } | ||
1528 | |||
1529 | return ret; | ||
1530 | } | ||
1201 | 1531 | ||
1532 | /**@brief Get DTSTART property as an icaltime | ||
1533 | * | ||
1534 | *If DTSTART is a DATE-TIME with a timezone parameter and a | ||
1535 | *corresponding VTIMEZONE is present in the component, the | ||
1536 | *returned component will already be in the correct timezone; | ||
1537 | *otherwise the caller is responsible for converting it. | ||
1538 | * | ||
1539 | *FIXME this is useless until we can flag the failure | ||
1540 | */ | ||
1202 | struct icaltimetype icalcomponent_get_dtstart(icalcomponent* comp) | 1541 | struct icaltimetype icalcomponent_get_dtstart(icalcomponent* comp) |
1203 | { | 1542 | { |
1204 | icalcomponent *inner = icalcomponent_get_inner(comp); | 1543 | icalcomponent *inner = icalcomponent_get_inner(comp); |
1205 | icalproperty *prop | 1544 | icalproperty *prop; |
1206 | = icalcomponent_get_first_property(inner,ICAL_DTSTART_PROPERTY); | ||
1207 | 1545 | ||
1546 | prop = icalcomponent_get_first_property(inner,ICAL_DTSTART_PROPERTY); | ||
1208 | if (prop == 0){ | 1547 | if (prop == 0){ |
1209 | return icaltime_null_time(); | 1548 | return icaltime_null_time(); |
1210 | } | 1549 | } |
1211 | |||
1212 | return icalproperty_get_dtstart(prop); | ||
1213 | } | ||
1214 | 1550 | ||
1551 | return icalcomponent_get_datetime(comp, prop); | ||
1552 | } | ||
1215 | 1553 | ||
1554 | /**@brief Get DTEND property as an icaltime | ||
1555 | * | ||
1556 | *If a DTEND property is not present but a DURATION is, we use | ||
1557 | *that to determine the proper end. | ||
1558 | * | ||
1559 | *If DTSTART is a DATE-TIME with a timezone parameter and a | ||
1560 | *corresponding VTIMEZONE is present in the component, the | ||
1561 | *returned component will already be in the correct timezone; | ||
1562 | *otherwise the caller is responsible for converting it. | ||
1563 | * | ||
1564 | *FIXME this is useless until we can flag the failure | ||
1565 | */ | ||
1216 | struct icaltimetype icalcomponent_get_dtend(icalcomponent* comp) | 1566 | struct icaltimetype icalcomponent_get_dtend(icalcomponent* comp) |
1217 | { | 1567 | { |
1218 | icalcomponent *inner = icalcomponent_get_inner(comp); | 1568 | icalcomponent *inner = icalcomponent_get_inner(comp); |
1219 | |||
1220 | icalproperty *end_prop | 1569 | icalproperty *end_prop |
1221 | = icalcomponent_get_first_property(inner,ICAL_DTEND_PROPERTY); | 1570 | = icalcomponent_get_first_property(inner,ICAL_DTEND_PROPERTY); |
1222 | |||
1223 | icalproperty *dur_prop | 1571 | icalproperty *dur_prop |
1224 | = icalcomponent_get_first_property(inner, ICAL_DURATION_PROPERTY); | 1572 | = icalcomponent_get_first_property(inner, ICAL_DURATION_PROPERTY); |
1573 | struct icaltimetyperet = icaltime_null_time(); | ||
1225 | 1574 | ||
1226 | 1575 | if ( end_prop != 0) { | |
1227 | if( end_prop == 0 && dur_prop == 0){ | 1576 | ret = icalcomponent_get_datetime(comp, end_prop); |
1228 | return icaltime_null_time(); | ||
1229 | } else if ( end_prop != 0) { | ||
1230 | return icalproperty_get_dtend(end_prop); | ||
1231 | } else if ( dur_prop != 0) { | 1577 | } else if ( dur_prop != 0) { |
1232 | 1578 | ||
1233 | struct icaltimetype start = | 1579 | struct icaltimetype start = |
1234 | icalcomponent_get_dtstart(inner); | 1580 | icalcomponent_get_dtstart(inner); |
1235 | struct icaldurationtype duration = | 1581 | struct icaldurationtype duration = |
1236 | icalproperty_get_duration(dur_prop); | 1582 | icalproperty_get_duration(dur_prop); |
1237 | |||
1238 | struct icaltimetype end = icaltime_add(start,duration); | ||
1239 | 1583 | ||
1240 | return end; | 1584 | struct icaltimetype end = icaltime_add(start,duration); |
1241 | |||
1242 | } else { | ||
1243 | /* Error, both duration and dtend have been specified */ | ||
1244 | icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); | ||
1245 | return icaltime_null_time(); | ||
1246 | 1585 | ||
1586 | ret = end; | ||
1247 | } | 1587 | } |
1248 | |||
1249 | } | ||
1250 | 1588 | ||
1589 | return ret; | ||
1590 | } | ||
1251 | 1591 | ||
1592 | /**@brief Set DTEND property to given icaltime | ||
1593 | * | ||
1594 | *This method respects the icaltime type (DATE vs DATE-TIME) and | ||
1595 | *timezone (or lack thereof). | ||
1596 | * | ||
1597 | *This also checks that a DURATION property isn't already there, | ||
1598 | *and returns an error if it is. It's the caller's responsibility | ||
1599 | *to remove it. | ||
1600 | */ | ||
1252 | void icalcomponent_set_dtend(icalcomponent* comp, struct icaltimetype v) | 1601 | void icalcomponent_set_dtend(icalcomponent* comp, struct icaltimetype v) |
1253 | { | 1602 | { |
1254 | icalcomponent *inner = icalcomponent_get_inner(comp); | 1603 | char *tzid; |
1255 | 1604 | ICALSETUPSET(ICAL_DTEND_PROPERTY); | |
1256 | icalproperty *end_prop | ||
1257 | = icalcomponent_get_first_property(inner,ICAL_DTEND_PROPERTY); | ||
1258 | |||
1259 | icalproperty *dur_prop | ||
1260 | = icalcomponent_get_first_property(inner,ICAL_DURATION_PROPERTY); | ||
1261 | |||
1262 | 1605 | ||
1263 | if( end_prop == 0 && dur_prop == 0){ | 1606 | if (icalcomponent_get_first_property(inner,ICAL_DURATION_PROPERTY) |
1264 | end_prop = icalproperty_new_dtend(v); | 1607 | != NULL) { |
1265 | icalcomponent_add_property(inner,end_prop); | 1608 | icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); |
1266 | } else if ( end_prop != 0) { | 1609 | return; |
1267 | icalproperty_set_dtend(end_prop,v); | 1610 | } |
1268 | } else if ( dur_prop != 0) { | ||
1269 | struct icaltimetype start = | ||
1270 | icalcomponent_get_dtstart(inner); | ||
1271 | |||
1272 | struct icaltimetype end = | ||
1273 | icalcomponent_get_dtend(inner); | ||
1274 | 1611 | ||
1275 | struct icaldurationtype dur | 1612 | if (prop == 0) { |
1276 | = icaltime_subtract(end,start); | 1613 | prop = icalproperty_new_dtend(v); |
1614 | icalcomponent_add_property(inner, prop); | ||
1615 | } else { | ||
1616 | icalproperty_remove_parameter_by_kind(prop, ICAL_TZID_PARAMETER); | ||
1617 | } | ||
1277 | 1618 | ||
1278 | icalproperty_set_duration(dur_prop,dur); | 1619 | icalproperty_set_dtend(prop,v); |
1279 | 1620 | ||
1280 | } else { | 1621 | if ((tzid = icaltime_get_tzid(v)) != NULL && !icaltime_is_utc(v)) { |
1281 | /* Error, both duration and dtend have been specified */ | 1622 | icalproperty_add_parameter(prop, icalparameter_new_tzid(tzid)); |
1282 | icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); | ||
1283 | } | 1623 | } |
1284 | } | 1624 | } |
1285 | 1625 | ||
1626 | /**@brief Set DURATION property to given icalduration | ||
1627 | * | ||
1628 | *This method respects the icaltime type (DATE vs DATE-TIME) and | ||
1629 | *timezone (or lack thereof). | ||
1630 | * | ||
1631 | *This also checks that a DTEND property isn't already there, | ||
1632 | *and returns an error if it is. It's the caller's responsibility | ||
1633 | *to remove it. | ||
1634 | */ | ||
1286 | void icalcomponent_set_duration(icalcomponent* comp, | 1635 | void icalcomponent_set_duration(icalcomponent* comp, |
1287 | struct icaldurationtype v) | 1636 | struct icaldurationtype v) |
1288 | { | 1637 | { |
1289 | icalcomponent *inner = icalcomponent_get_inner(comp); | 1638 | ICALSETUPSET(ICAL_DURATION_PROPERTY); |
1290 | |||
1291 | icalproperty *end_prop | ||
1292 | = icalcomponent_get_first_property(inner,ICAL_DTEND_PROPERTY); | ||
1293 | |||
1294 | icalproperty *dur_prop | ||
1295 | = icalcomponent_get_first_property(inner,ICAL_DURATION_PROPERTY); | ||
1296 | |||
1297 | |||
1298 | if( end_prop == 0 && dur_prop == 0){ | ||
1299 | dur_prop = icalproperty_new_duration(v); | ||
1300 | icalcomponent_add_property(inner, dur_prop); | ||
1301 | } else if ( end_prop != 0) { | ||
1302 | struct icaltimetype start = | ||
1303 | icalcomponent_get_dtstart(inner); | ||
1304 | |||
1305 | struct icaltimetype new_end = icaltime_add(start,v); | ||
1306 | 1639 | ||
1307 | icalproperty_set_dtend(end_prop,new_end); | 1640 | if (icalcomponent_get_first_property(inner,ICAL_DTEND_PROPERTY) != NULL) { |
1641 | icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); | ||
1642 | return; | ||
1643 | } | ||
1308 | 1644 | ||
1309 | } else if ( dur_prop != 0) { | 1645 | if (prop == 0) { |
1310 | icalproperty_set_duration(dur_prop,v); | 1646 | prop = icalproperty_new_duration(v); |
1647 | icalcomponent_add_property(inner, prop); | ||
1311 | } else { | 1648 | } else { |
1312 | /* Error, both duration and dtend have been specified */ | 1649 | icalproperty_set_duration(prop,v); |
1313 | icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); | ||
1314 | } | 1650 | } |
1315 | } | 1651 | } |
1316 | 1652 | ||
1653 | /**@brief Get DURATION property as an icalduration | ||
1654 | * | ||
1655 | *If a DURATION property is not present but a DTEND is, we use | ||
1656 | *that to determine the proper end. | ||
1657 | */ | ||
1317 | struct icaldurationtype icalcomponent_get_duration(icalcomponent* comp) | 1658 | struct icaldurationtype icalcomponent_get_duration(icalcomponent* comp) |
1318 | { | 1659 | { |
1319 | icalcomponent *inner = icalcomponent_get_inner(comp); | 1660 | icalcomponent *inner = icalcomponent_get_inner(comp); |
@@ -1324,131 +1665,329 @@ struct icaldurationtype icalcomponent_get_duration(icalcomponent* comp) | |||
1324 | icalproperty *dur_prop | 1665 | icalproperty *dur_prop |
1325 | = icalcomponent_get_first_property(inner,ICAL_DURATION_PROPERTY); | 1666 | = icalcomponent_get_first_property(inner,ICAL_DURATION_PROPERTY); |
1326 | 1667 | ||
1327 | struct icaldurationtype null_duration; | 1668 | struct icaldurationtype ret = icaldurationtype_null_duration(); |
1328 | memset(&null_duration,0,sizeof(struct icaldurationtype)); | ||
1329 | 1669 | ||
1670 | if ( dur_prop != 0 && end_prop == 0) { | ||
1671 | ret = icalproperty_get_duration(dur_prop); | ||
1330 | 1672 | ||
1331 | if( end_prop == 0 && dur_prop == 0){ | 1673 | } else if ( end_prop != 0 && dur_prop == 0) { |
1332 | return null_duration; | 1674 | /** |
1333 | } else if ( end_prop != 0) { | 1675 | * FIXME |
1676 | * We assume DTSTART and DTEND are not in different time zones. | ||
1677 | * Does the standard actually guarantee this? | ||
1678 | */ | ||
1334 | struct icaltimetype start = | 1679 | struct icaltimetype start = |
1335 | icalcomponent_get_dtstart(inner); | 1680 | icalcomponent_get_dtstart(inner); |
1336 | time_t startt = icaltime_as_timet(start); | ||
1337 | |||
1338 | struct icaltimetype end = | 1681 | struct icaltimetype end = |
1339 | icalcomponent_get_dtend(inner); | 1682 | icalcomponent_get_dtend(inner); |
1340 | time_t endt = icaltime_as_timet(end); | 1683 | |
1341 | 1684 | ret = icaltime_subtract(end, start); | |
1342 | return icaldurationtype_from_int(endt-startt); | ||
1343 | } else if ( dur_prop != 0) { | ||
1344 | return icalproperty_get_duration(dur_prop); | ||
1345 | } else { | 1685 | } else { |
1346 | /* Error, both duration and dtend have been specified */ | 1686 | /* Error, both duration and dtend have been specified */ |
1347 | icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); | 1687 | icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); |
1348 | return null_duration; | ||
1349 | } | 1688 | } |
1689 | return ret; | ||
1350 | } | 1690 | } |
1351 | 1691 | ||
1352 | void icalcomponent_set_method(icalcomponent* comp, icalproperty_method method) | 1692 | void icalcomponent_set_dtstamp(icalcomponent* comp, struct icaltimetype v) |
1353 | { | 1693 | { |
1354 | icalproperty *prop | ||
1355 | = icalcomponent_get_first_property(comp, ICAL_METHOD_PROPERTY); | ||
1356 | 1694 | ||
1695 | ICALSETUPSET(ICAL_DTSTAMP_PROPERTY); | ||
1357 | 1696 | ||
1358 | if (prop == 0){ | 1697 | if (prop == 0){ |
1359 | prop = icalproperty_new_method(method); | 1698 | prop = icalproperty_new_dtstamp(v); |
1360 | icalcomponent_add_property(comp, prop); | 1699 | icalcomponent_add_property(inner, prop); |
1361 | } | 1700 | } |
1362 | 1701 | ||
1363 | icalproperty_set_method(prop,method); | 1702 | icalproperty_set_dtstamp(prop,v); |
1364 | 1703 | ||
1365 | } | 1704 | } |
1366 | 1705 | ||
1367 | icalproperty_method icalcomponent_get_method(icalcomponent* comp) | 1706 | |
1707 | struct icaltimetype icalcomponent_get_dtstamp(icalcomponent* comp) | ||
1368 | { | 1708 | { |
1709 | icalcomponent *inner = icalcomponent_get_inner(comp); | ||
1369 | icalproperty *prop | 1710 | icalproperty *prop |
1370 | = icalcomponent_get_first_property(comp,ICAL_METHOD_PROPERTY); | 1711 | = icalcomponent_get_first_property(inner,ICAL_DTSTAMP_PROPERTY); |
1371 | 1712 | ||
1372 | if (prop == 0){ | 1713 | if (prop == 0){ |
1373 | return ICAL_METHOD_NONE; | 1714 | return icaltime_null_time(); |
1374 | } | 1715 | } |
1375 | 1716 | ||
1376 | return icalproperty_get_method(prop); | 1717 | return icalproperty_get_dtstamp(prop); |
1377 | } | 1718 | } |
1378 | 1719 | ||
1379 | void icalcomponent_set_dtstamp(icalcomponent* comp, struct icaltimetype v) | 1720 | |
1721 | void icalcomponent_set_summary(icalcomponent* comp, const char* v) | ||
1722 | { | ||
1723 | ICALSETUPSET(ICAL_SUMMARY_PROPERTY) | ||
1724 | |||
1725 | if (prop == 0){ | ||
1726 | prop = icalproperty_new_summary(v); | ||
1727 | icalcomponent_add_property(inner, prop); | ||
1728 | } | ||
1729 | |||
1730 | icalproperty_set_summary(prop,v); | ||
1731 | } | ||
1732 | |||
1733 | |||
1734 | const char* icalcomponent_get_summary(icalcomponent* comp) | ||
1380 | { | 1735 | { |
1736 | icalcomponent *inner; | ||
1737 | icalproperty *prop; | ||
1738 | icalerror_check_arg_rz(comp!=0,"comp"); | ||
1381 | 1739 | ||
1382 | icalcomponent *inner = icalcomponent_get_inner(comp); | 1740 | inner = icalcomponent_get_inner(comp); |
1383 | icalproperty *prop | 1741 | |
1384 | = icalcomponent_get_first_property(inner, ICAL_DTSTAMP_PROPERTY); | 1742 | if(inner == 0){ |
1743 | icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); | ||
1744 | return 0; | ||
1745 | } | ||
1385 | 1746 | ||
1747 | prop= icalcomponent_get_first_property(inner,ICAL_SUMMARY_PROPERTY); | ||
1386 | 1748 | ||
1387 | if (prop == 0){ | 1749 | if (prop == 0){ |
1388 | prop = icalproperty_new_dtstamp(v); | 1750 | return 0; |
1389 | icalcomponent_add_property(inner, prop); | ||
1390 | } | 1751 | } |
1391 | 1752 | ||
1392 | icalproperty_set_dtstamp(prop,v); | 1753 | return icalproperty_get_summary(prop); |
1393 | 1754 | ||
1394 | } | 1755 | } |
1395 | 1756 | ||
1396 | 1757 | void icalcomponent_set_comment(icalcomponent* comp, const char* v) | |
1397 | struct icaltimetype icalcomponent_get_dtstamp(icalcomponent* comp) | ||
1398 | { | 1758 | { |
1399 | icalcomponent *inner = icalcomponent_get_inner(comp); | 1759 | ICALSETUPSET(ICAL_COMMENT_PROPERTY); |
1400 | icalproperty *prop | ||
1401 | = icalcomponent_get_first_property(inner,ICAL_DTSTAMP_PROPERTY); | ||
1402 | 1760 | ||
1403 | if (prop == 0){ | 1761 | if (prop == 0){ |
1404 | return icaltime_null_time(); | 1762 | prop = icalproperty_new_comment(v); |
1763 | icalcomponent_add_property(inner, prop); | ||
1405 | } | 1764 | } |
1406 | 1765 | ||
1407 | return icalproperty_get_dtstamp(prop); | 1766 | icalproperty_set_summary(prop,v); |
1767 | |||
1408 | } | 1768 | } |
1769 | const char* icalcomponent_get_comment(icalcomponent* comp){ | ||
1770 | icalcomponent *inner; | ||
1771 | icalproperty *prop; | ||
1772 | icalerror_check_arg_rz(comp!=0,"comp"); | ||
1409 | 1773 | ||
1774 | inner = icalcomponent_get_inner(comp); | ||
1410 | 1775 | ||
1411 | void icalcomponent_set_summary(icalcomponent* comp, const char* v) | 1776 | if(inner == 0){ |
1777 | icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); | ||
1778 | return 0; | ||
1779 | } | ||
1780 | |||
1781 | prop= icalcomponent_get_first_property(inner,ICAL_COMMENT_PROPERTY); | ||
1782 | |||
1783 | if (prop == 0){ | ||
1784 | return 0; | ||
1785 | } | ||
1786 | |||
1787 | return icalproperty_get_comment(prop); | ||
1788 | } | ||
1789 | |||
1790 | void icalcomponent_set_uid(icalcomponent* comp, const char* v) | ||
1412 | { | 1791 | { |
1413 | icalcomponent *inner = icalcomponent_get_inner(comp); | 1792 | ICALSETUPSET(ICAL_UID_PROPERTY); |
1414 | icalproperty *prop | ||
1415 | = icalcomponent_get_first_property(inner, ICAL_SUMMARY_PROPERTY); | ||
1416 | 1793 | ||
1417 | if (prop == 0){ | 1794 | if (prop == 0){ |
1418 | prop = icalproperty_new_summary(v); | 1795 | prop = icalproperty_new_uid(v); |
1419 | icalcomponent_add_property(inner, prop); | 1796 | icalcomponent_add_property(inner, prop); |
1420 | } | 1797 | } |
1421 | 1798 | ||
1422 | icalproperty_set_summary(prop,v); | 1799 | icalproperty_set_summary(prop,v); |
1800 | |||
1423 | } | 1801 | } |
1802 | const char* icalcomponent_get_uid(icalcomponent* comp){ | ||
1803 | icalcomponent *inner; | ||
1804 | icalproperty *prop; | ||
1805 | icalerror_check_arg_rz(comp!=0,"comp"); | ||
1424 | 1806 | ||
1807 | inner = icalcomponent_get_inner(comp); | ||
1425 | 1808 | ||
1426 | const char* icalcomponent_get_summary(icalcomponent* comp) | 1809 | if(inner == 0){ |
1427 | { | 1810 | icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); |
1428 | icalcomponent *inner = icalcomponent_get_inner(comp); | 1811 | return 0; |
1429 | icalproperty *prop | 1812 | } |
1430 | = icalcomponent_get_first_property(inner,ICAL_SUMMARY_PROPERTY); | 1813 | |
1814 | prop= icalcomponent_get_first_property(inner,ICAL_UID_PROPERTY); | ||
1431 | 1815 | ||
1432 | if (prop == 0){ | 1816 | if (prop == 0){ |
1433 | return 0; | 1817 | return 0; |
1434 | } | 1818 | } |
1435 | 1819 | ||
1436 | return icalproperty_get_summary(prop); | 1820 | return icalproperty_get_uid(prop); |
1821 | } | ||
1437 | 1822 | ||
1823 | void icalcomponent_set_recurrenceid(icalcomponent* comp, struct icaltimetype v) | ||
1824 | { | ||
1825 | ICALSETUPSET(ICAL_RECURRENCEID_PROPERTY); | ||
1826 | |||
1827 | if (prop == 0){ | ||
1828 | prop = icalproperty_new_recurrenceid(v); | ||
1829 | icalcomponent_add_property(inner, prop); | ||
1830 | } | ||
1831 | |||
1832 | icalproperty_set_recurrenceid(prop,v); | ||
1438 | } | 1833 | } |
1834 | struct icaltimetype icalcomponent_get_recurrenceid(icalcomponent* comp) | ||
1835 | { | ||
1836 | icalcomponent *inner; | ||
1837 | icalproperty *prop; | ||
1838 | if (comp == 0) { | ||
1839 | icalerror_set_errno(ICAL_BADARG_ERROR); | ||
1840 | return icaltime_null_time(); | ||
1841 | } | ||
1439 | 1842 | ||
1440 | void icalcomponent_set_comment(icalcomponent* comp, const char* v); | 1843 | inner = icalcomponent_get_inner(comp); |
1441 | const char* icalcomponent_get_comment(icalcomponent* comp); | ||
1442 | 1844 | ||
1443 | void icalcomponent_set_uid(icalcomponent* comp, const char* v); | 1845 | if(inner == 0){ |
1444 | const char* icalcomponent_get_uid(icalcomponent* comp); | 1846 | icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); |
1847 | return icaltime_null_time(); | ||
1848 | } | ||
1445 | 1849 | ||
1446 | void icalcomponent_set_recurrenceid(icalcomponent* comp, | 1850 | prop= icalcomponent_get_first_property(inner, ICAL_RECURRENCEID_PROPERTY); |
1447 | struct icaltimetype v); | ||
1448 | struct icaltimetype icalcomponent_get_recurrenceid(icalcomponent* comp); | ||
1449 | 1851 | ||
1852 | if (prop == 0){ | ||
1853 | return icaltime_null_time(); | ||
1854 | } | ||
1855 | |||
1856 | return icalproperty_get_recurrenceid(prop); | ||
1857 | } | ||
1858 | |||
1859 | void icalcomponent_set_description(icalcomponent* comp, const char* v) | ||
1860 | { | ||
1861 | ICALSETUPSET(ICAL_DESCRIPTION_PROPERTY); | ||
1862 | |||
1863 | if (prop == 0){ | ||
1864 | prop = icalproperty_new_description(v); | ||
1865 | icalcomponent_add_property(inner, prop); | ||
1866 | } | ||
1867 | |||
1868 | icalproperty_set_description(prop,v); | ||
1869 | } | ||
1870 | const char* icalcomponent_get_description(icalcomponent* comp) | ||
1871 | { | ||
1872 | icalcomponent *inner; | ||
1873 | icalproperty *prop; | ||
1874 | icalerror_check_arg_rz(comp!=0,"comp"); | ||
1875 | |||
1876 | inner = icalcomponent_get_inner(comp); | ||
1877 | |||
1878 | if(inner == 0){ | ||
1879 | icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); | ||
1880 | return 0; | ||
1881 | } | ||
1882 | |||
1883 | prop= icalcomponent_get_first_property(inner,ICAL_DESCRIPTION_PROPERTY); | ||
1884 | |||
1885 | if (prop == 0){ | ||
1886 | return 0; | ||
1887 | } | ||
1888 | |||
1889 | return icalproperty_get_description(prop); | ||
1890 | } | ||
1891 | |||
1892 | void icalcomponent_set_location(icalcomponent* comp, const char* v) | ||
1893 | { | ||
1894 | ICALSETUPSET(ICAL_LOCATION_PROPERTY) | ||
1895 | |||
1896 | if (prop == 0){ | ||
1897 | prop = icalproperty_new_location(v); | ||
1898 | icalcomponent_add_property(inner, prop); | ||
1899 | } | ||
1900 | |||
1901 | icalproperty_set_location(prop,v); | ||
1902 | } | ||
1903 | const char* icalcomponent_get_location(icalcomponent* comp) | ||
1904 | { | ||
1905 | icalcomponent *inner; | ||
1906 | icalproperty *prop; | ||
1907 | icalerror_check_arg_rz(comp!=0,"comp"); | ||
1908 | |||
1909 | inner = icalcomponent_get_inner(comp); | ||
1910 | |||
1911 | if(inner == 0){ | ||
1912 | icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); | ||
1913 | return 0; | ||
1914 | } | ||
1915 | |||
1916 | prop= icalcomponent_get_first_property(inner,ICAL_LOCATION_PROPERTY); | ||
1450 | 1917 | ||
1918 | if (prop == 0){ | ||
1919 | return 0; | ||
1920 | } | ||
1921 | |||
1922 | return icalproperty_get_location(prop); | ||
1923 | } | ||
1924 | |||
1925 | void icalcomponent_set_sequence(icalcomponent* comp, int v) | ||
1926 | { | ||
1927 | ICALSETUPSET(ICAL_SEQUENCE_PROPERTY); | ||
1928 | |||
1929 | if (prop == 0){ | ||
1930 | prop = icalproperty_new_sequence(v); | ||
1931 | icalcomponent_add_property(inner, prop); | ||
1932 | } | ||
1933 | |||
1934 | icalproperty_set_sequence(prop,v); | ||
1935 | |||
1936 | } | ||
1937 | int icalcomponent_get_sequence(icalcomponent* comp){ | ||
1938 | icalcomponent *inner; | ||
1939 | icalproperty *prop; | ||
1940 | icalerror_check_arg_rz(comp!=0,"comp"); | ||
1941 | |||
1942 | inner = icalcomponent_get_inner(comp); | ||
1943 | |||
1944 | if(inner == 0){ | ||
1945 | icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); | ||
1946 | return 0; | ||
1947 | } | ||
1948 | |||
1949 | prop= icalcomponent_get_first_property(inner,ICAL_SEQUENCE_PROPERTY); | ||
1950 | |||
1951 | if (prop == 0){ | ||
1952 | return 0; | ||
1953 | } | ||
1954 | |||
1955 | return icalproperty_get_sequence(prop); | ||
1956 | } | ||
1957 | |||
1958 | |||
1959 | void icalcomponent_set_status(icalcomponent* comp, enum icalproperty_status v) | ||
1960 | { | ||
1961 | ICALSETUPSET(ICAL_STATUS_PROPERTY); | ||
1962 | |||
1963 | if (prop == 0){ | ||
1964 | prop = icalproperty_new_status(v); | ||
1965 | icalcomponent_add_property(inner, prop); | ||
1966 | } | ||
1967 | |||
1968 | icalproperty_set_status(prop,v); | ||
1969 | |||
1970 | } | ||
1971 | enum icalproperty_status icalcomponent_get_status(icalcomponent* comp){ | ||
1972 | icalcomponent *inner; | ||
1973 | icalproperty *prop; | ||
1974 | icalerror_check_arg_rz(comp!=0,"comp"); | ||
1975 | |||
1976 | inner = icalcomponent_get_inner(comp); | ||
1977 | |||
1978 | if(inner == 0){ | ||
1979 | icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); | ||
1980 | return 0; | ||
1981 | } | ||
1451 | 1982 | ||
1983 | prop= icalcomponent_get_first_property(inner,ICAL_STATUS_PROPERTY); | ||
1984 | |||
1985 | if (prop == 0){ | ||
1986 | return 0; | ||
1987 | } | ||
1988 | |||
1989 | return icalproperty_get_status(prop); | ||
1990 | } | ||
1452 | 1991 | ||
1453 | icalcomponent* icalcomponent_new_vcalendar() | 1992 | icalcomponent* icalcomponent_new_vcalendar() |
1454 | { | 1993 | { |
@@ -1486,3 +2025,571 @@ icalcomponent* icalcomponent_new_xdaylight() | |||
1486 | { | 2025 | { |
1487 | return icalcomponent_new(ICAL_XDAYLIGHT_COMPONENT); | 2026 | return icalcomponent_new(ICAL_XDAYLIGHT_COMPONENT); |
1488 | } | 2027 | } |
2028 | icalcomponent* icalcomponent_new_vagenda() | ||
2029 | { | ||
2030 | return icalcomponent_new(ICAL_VAGENDA_COMPONENT); | ||
2031 | } | ||
2032 | icalcomponent* icalcomponent_new_vquery() | ||
2033 | { | ||
2034 | return icalcomponent_new(ICAL_VQUERY_COMPONENT); | ||
2035 | } | ||
2036 | |||
2037 | /* | ||
2038 | * Timezone stuff. | ||
2039 | */ | ||
2040 | |||
2041 | |||
2042 | /** | ||
2043 | * This takes 2 VCALENDAR components and merges the second one into the first, | ||
2044 | * resolving any problems with conflicting TZIDs. comp_to_merge will no | ||
2045 | * longer exist after calling this function. | ||
2046 | */ | ||
2047 | void icalcomponent_merge_component(icalcomponent* comp, | ||
2048 | icalcomponent* comp_to_merge) | ||
2049 | { | ||
2050 | icalcomponent *subcomp, *next_subcomp; | ||
2051 | icalarray *tzids_to_rename; | ||
2052 | int i; | ||
2053 | |||
2054 | /* Check that both components are VCALENDAR components. */ | ||
2055 | assert (icalcomponent_isa(comp) == ICAL_VCALENDAR_COMPONENT); | ||
2056 | assert (icalcomponent_isa(comp_to_merge) == ICAL_VCALENDAR_COMPONENT); | ||
2057 | |||
2058 | /* Step through each subcomponent of comp_to_merge, looking for VTIMEZONEs. | ||
2059 | For each VTIMEZONE found, check if we need to add it to comp and if we | ||
2060 | need to rename it and all TZID references to it. */ | ||
2061 | tzids_to_rename = icalarray_new (sizeof (char*), 16); | ||
2062 | subcomp = icalcomponent_get_first_component (comp_to_merge, | ||
2063 | ICAL_VTIMEZONE_COMPONENT); | ||
2064 | while (subcomp) { | ||
2065 | next_subcomp = icalcomponent_get_next_component (comp_to_merge, | ||
2066 | ICAL_VTIMEZONE_COMPONENT); | ||
2067 | /* This will add the VTIMEZONE to comp, if necessary, and also update | ||
2068 | the array of TZIDs we need to rename. */ | ||
2069 | icalcomponent_merge_vtimezone (comp, subcomp, tzids_to_rename); | ||
2070 | /* FIXME: Handle possible NEWFAILED error. */ | ||
2071 | |||
2072 | subcomp = next_subcomp; | ||
2073 | } | ||
2074 | |||
2075 | /* If we need to do any renaming of TZIDs, do it now. */ | ||
2076 | if (tzids_to_rename->num_elements != 0) { | ||
2077 | icalcomponent_rename_tzids (comp_to_merge, tzids_to_rename); | ||
2078 | |||
2079 | /* Now free the tzids_to_rename array. */ | ||
2080 | for (i = 0; i < tzids_to_rename->num_elements; i++) { | ||
2081 | free (icalarray_element_at (tzids_to_rename, i)); | ||
2082 | } | ||
2083 | icalarray_free (tzids_to_rename); | ||
2084 | } | ||
2085 | |||
2086 | /* Now move all the components from comp_to_merge to comp, excluding | ||
2087 | VTIMEZONE components. */ | ||
2088 | subcomp = icalcomponent_get_first_component (comp_to_merge, | ||
2089 | ICAL_ANY_COMPONENT); | ||
2090 | while (subcomp) { | ||
2091 | next_subcomp = icalcomponent_get_next_component (comp_to_merge, | ||
2092 | ICAL_ANY_COMPONENT); | ||
2093 | if (icalcomponent_isa(subcomp) != ICAL_VTIMEZONE_COMPONENT) { | ||
2094 | icalcomponent_remove_component (comp_to_merge, subcomp); | ||
2095 | icalcomponent_add_component (comp, subcomp); | ||
2096 | } | ||
2097 | subcomp = next_subcomp; | ||
2098 | } | ||
2099 | |||
2100 | /* Free comp_to_merge. We have moved most of the subcomponents over to | ||
2101 | comp now. */ | ||
2102 | icalcomponent_free (comp_to_merge); | ||
2103 | } | ||
2104 | |||
2105 | |||
2106 | static void icalcomponent_merge_vtimezone (icalcomponent *comp, | ||
2107 | icalcomponent *vtimezone, | ||
2108 | icalarray *tzids_to_rename) | ||
2109 | { | ||
2110 | icalproperty *tzid_prop; | ||
2111 | const char *tzid; | ||
2112 | char *tzid_copy; | ||
2113 | icaltimezone *existing_vtimezone; | ||
2114 | |||
2115 | /* Get the TZID of the VTIMEZONE. */ | ||
2116 | tzid_prop = icalcomponent_get_first_property (vtimezone, ICAL_TZID_PROPERTY); | ||
2117 | if (!tzid_prop) | ||
2118 | return; | ||
2119 | |||
2120 | tzid = icalproperty_get_tzid (tzid_prop); | ||
2121 | if (!tzid) | ||
2122 | return; | ||
2123 | |||
2124 | /* See if there is already a VTIMEZONE in comp with the same TZID. */ | ||
2125 | existing_vtimezone = icalcomponent_get_timezone (comp, tzid); | ||
2126 | |||
2127 | /* If there is no existing VTIMEZONE with the same TZID, we can just move | ||
2128 | the VTIMEZONE to comp and return. */ | ||
2129 | if (!existing_vtimezone) { | ||
2130 | icalcomponent_remove_component (icalcomponent_get_parent (vtimezone), | ||
2131 | vtimezone); | ||
2132 | icalcomponent_add_component (comp, vtimezone); | ||
2133 | return; | ||
2134 | } | ||
2135 | |||
2136 | /* If the TZID has a '/' prefix, then we don't have to worry about the | ||
2137 | clashing TZIDs, as they are supposed to be exactly the same VTIMEZONE. */ | ||
2138 | if (tzid[0] == '/') | ||
2139 | return; | ||
2140 | |||
2141 | /* Now we have two VTIMEZONEs with the same TZID (which isn't a globally | ||
2142 | unique one), so we compare the VTIMEZONE components to see if they are | ||
2143 | the same. If they are, we don't need to do anything. We make a copy of | ||
2144 | the tzid, since the parameter may get modified in these calls. */ | ||
2145 | tzid_copy = strdup (tzid); | ||
2146 | if (!tzid_copy) { | ||
2147 | icalerror_set_errno(ICAL_NEWFAILED_ERROR); | ||
2148 | return; | ||
2149 | } | ||
2150 | |||
2151 | if (!icalcomponent_compare_vtimezones (comp, vtimezone)) { | ||
2152 | /* FIXME: Handle possible NEWFAILED error. */ | ||
2153 | |||
2154 | /* Now we have two different VTIMEZONEs with the same TZID. */ | ||
2155 | icalcomponent_handle_conflicting_vtimezones (comp, vtimezone, tzid_prop, | ||
2156 | tzid_copy, tzids_to_rename); | ||
2157 | } | ||
2158 | free (tzid_copy); | ||
2159 | } | ||
2160 | |||
2161 | |||
2162 | static void | ||
2163 | icalcomponent_handle_conflicting_vtimezones (icalcomponent *comp, | ||
2164 | icalcomponent *vtimezone, | ||
2165 | icalproperty *tzid_prop, | ||
2166 | const char *tzid, | ||
2167 | icalarray *tzids_to_rename) | ||
2168 | { | ||
2169 | int i, suffix, max_suffix = 0, num_elements; | ||
2170 | unsigned int tzid_len; | ||
2171 | char *tzid_copy, *new_tzid, suffix_buf[32]; | ||
2172 | |||
2173 | /* Find the length of the TZID without any trailing digits. */ | ||
2174 | tzid_len = icalcomponent_get_tzid_prefix_len (tzid); | ||
2175 | |||
2176 | /* Step through each of the VTIMEZONEs in comp. We may already have the | ||
2177 | clashing VTIMEZONE in the calendar, but it may have been renamed | ||
2178 | (i.e. a unique number added on the end of the TZID, e.g. 'London2'). | ||
2179 | So we compare the new VTIMEZONE with any VTIMEZONEs that have the | ||
2180 | same prefix (e.g. 'London'). If it matches any of those, we have to | ||
2181 | rename the TZIDs to that TZID, else we rename to a new TZID, using | ||
2182 | the biggest numeric suffix found + 1. */ | ||
2183 | num_elements = comp->timezones ? comp->timezones->num_elements : 0; | ||
2184 | for (i = 0; i < num_elements; i++) { | ||
2185 | icaltimezone *zone; | ||
2186 | char *existing_tzid, *existing_tzid_copy; | ||
2187 | unsigned int existing_tzid_len; | ||
2188 | |||
2189 | zone = icalarray_element_at (comp->timezones, i); | ||
2190 | existing_tzid = icaltimezone_get_tzid (zone); | ||
2191 | |||
2192 | /* Find the length of the TZID without any trailing digits. */ | ||
2193 | existing_tzid_len = icalcomponent_get_tzid_prefix_len (existing_tzid); | ||
2194 | |||
2195 | /* Check if we have the same prefix. */ | ||
2196 | if (tzid_len == existing_tzid_len | ||
2197 | && !strncmp (tzid, existing_tzid, tzid_len)) { | ||
2198 | /* Compare the VTIMEZONEs. */ | ||
2199 | if (icalcomponent_compare_vtimezones (icaltimezone_get_component (zone), | ||
2200 | vtimezone)) { | ||
2201 | /* The VTIMEZONEs match, so we can use the existing VTIMEZONE. But | ||
2202 | we have to rename TZIDs to this TZID. */ | ||
2203 | tzid_copy = strdup (tzid); | ||
2204 | existing_tzid_copy = strdup (existing_tzid); | ||
2205 | if (!tzid_copy || !existing_tzid_copy) { | ||
2206 | icalerror_set_errno(ICAL_NEWFAILED_ERROR); | ||
2207 | } else { | ||
2208 | icalarray_append (tzids_to_rename, tzid_copy); | ||
2209 | icalarray_append (tzids_to_rename, existing_tzid_copy); | ||
2210 | } | ||
2211 | return; | ||
2212 | } else { | ||
2213 | /* FIXME: Handle possible NEWFAILED error. */ | ||
2214 | |||
2215 | /* Convert the suffix to an integer and remember the maximum numeric | ||
2216 | suffix found. */ | ||
2217 | suffix = atoi (existing_tzid + existing_tzid_len); | ||
2218 | if (max_suffix < suffix) | ||
2219 | max_suffix = suffix; | ||
2220 | } | ||
2221 | } | ||
2222 | } | ||
2223 | |||
2224 | /* We didn't find a VTIMEZONE that matched, so we have to rename the TZID, | ||
2225 | using the maximum numerical suffix found + 1. */ | ||
2226 | tzid_copy = strdup (tzid); | ||
2227 | sprintf (suffix_buf, "%i", max_suffix + 1); | ||
2228 | new_tzid = malloc (tzid_len + strlen (suffix_buf) + 1); | ||
2229 | if (!new_tzid || !tzid_copy) { | ||
2230 | icalerror_set_errno(ICAL_NEWFAILED_ERROR); | ||
2231 | return; | ||
2232 | } | ||
2233 | |||
2234 | strncpy (new_tzid, tzid, tzid_len); | ||
2235 | strcpy (new_tzid + tzid_len, suffix_buf); | ||
2236 | icalarray_append (tzids_to_rename, tzid_copy); | ||
2237 | icalarray_append (tzids_to_rename, new_tzid); | ||
2238 | } | ||
2239 | |||
2240 | |||
2241 | /* Returns the length of the TZID, without any trailing digits. */ | ||
2242 | static unsigned int icalcomponent_get_tzid_prefix_len (const char *tzid) | ||
2243 | { | ||
2244 | int len; | ||
2245 | const char *p; | ||
2246 | |||
2247 | len = strlen (tzid); | ||
2248 | p = tzid + len - 1; | ||
2249 | while (len > 0 && *p >= '0' && *p <= '9') { | ||
2250 | p--; | ||
2251 | len--; | ||
2252 | } | ||
2253 | |||
2254 | return len; | ||
2255 | } | ||
2256 | |||
2257 | |||
2258 | /** | ||
2259 | * Renames all references to the given TZIDs to a new name. rename_table | ||
2260 | * contains pairs of strings - a current TZID, and the new TZID to rename it | ||
2261 | * to. | ||
2262 | */ | ||
2263 | static void icalcomponent_rename_tzids(icalcomponent* comp, | ||
2264 | icalarray* rename_table) | ||
2265 | { | ||
2266 | icalcomponent_foreach_tzid (comp, icalcomponent_rename_tzids_callback, | ||
2267 | rename_table); | ||
2268 | } | ||
2269 | |||
2270 | |||
2271 | static void icalcomponent_rename_tzids_callback(icalparameter *param, void *data) | ||
2272 | { | ||
2273 | icalarray *rename_table = data; | ||
2274 | const char *tzid; | ||
2275 | int i; | ||
2276 | |||
2277 | tzid = icalparameter_get_tzid (param); | ||
2278 | if (!tzid) | ||
2279 | return; | ||
2280 | |||
2281 | /* Step through the rename table to see if the current TZID matches | ||
2282 | any of the ones we want to rename. */ | ||
2283 | for (i = 0; i < rename_table->num_elements - 1; i += 2) { | ||
2284 | if (!strcmp (tzid, icalarray_element_at (rename_table, i))) { | ||
2285 | icalparameter_set_tzid (param, icalarray_element_at (rename_table, i + 1)); | ||
2286 | break; | ||
2287 | } | ||
2288 | } | ||
2289 | } | ||
2290 | |||
2291 | |||
2292 | /** | ||
2293 | * Calls the given function for each TZID parameter found in the component. | ||
2294 | */ | ||
2295 | void icalcomponent_foreach_tzid(icalcomponent* comp, | ||
2296 | void (*callback)(icalparameter *param, void *data), | ||
2297 | void *callback_data) | ||
2298 | { | ||
2299 | icalproperty *prop; | ||
2300 | icalproperty_kind kind; | ||
2301 | icalparameter *param; | ||
2302 | icalcomponent *subcomp; | ||
2303 | |||
2304 | /* First look for any TZID parameters used in this component itself. */ | ||
2305 | prop = icalcomponent_get_first_property (comp, ICAL_ANY_PROPERTY); | ||
2306 | while (prop) { | ||
2307 | kind = icalproperty_isa (prop); | ||
2308 | |||
2309 | /* These are the only properties that can have a TZID. Note that | ||
2310 | COMPLETED, CREATED, DTSTAMP & LASTMODIFIED must be in UTC. */ | ||
2311 | if (kind == ICAL_DTSTART_PROPERTY || kind == ICAL_DTEND_PROPERTY | ||
2312 | || kind == ICAL_DUE_PROPERTY || kind == ICAL_EXDATE_PROPERTY | ||
2313 | || kind == ICAL_RDATE_PROPERTY) { | ||
2314 | param = icalproperty_get_first_parameter (prop, ICAL_TZID_PARAMETER); | ||
2315 | if (param) | ||
2316 | (*callback) (param, callback_data); | ||
2317 | } | ||
2318 | |||
2319 | prop = icalcomponent_get_next_property (comp, ICAL_ANY_PROPERTY); | ||
2320 | } | ||
2321 | |||
2322 | /* Now recursively check child components. */ | ||
2323 | subcomp = icalcomponent_get_first_component (comp, ICAL_ANY_COMPONENT); | ||
2324 | while (subcomp) { | ||
2325 | icalcomponent_foreach_tzid (subcomp, callback, callback_data); | ||
2326 | subcomp = icalcomponent_get_next_component (comp, ICAL_ANY_COMPONENT); | ||
2327 | } | ||
2328 | } | ||
2329 | |||
2330 | |||
2331 | |||
2332 | /** | ||
2333 | * Returns the icaltimezone from the component corresponding to the given | ||
2334 | * TZID, or NULL if the component does not have a corresponding VTIMEZONE. | ||
2335 | */ | ||
2336 | icaltimezone* icalcomponent_get_timezone(icalcomponent* comp, const char *tzid) | ||
2337 | { | ||
2338 | icaltimezone *zone; | ||
2339 | int lower, upper, middle, cmp; | ||
2340 | char *zone_tzid; | ||
2341 | |||
2342 | if (!comp->timezones) | ||
2343 | return NULL; | ||
2344 | |||
2345 | /* Sort the array if necessary (by the TZID string). */ | ||
2346 | if (!comp->timezones_sorted) { | ||
2347 | icalarray_sort (comp->timezones, icalcomponent_compare_timezone_fn); | ||
2348 | comp->timezones_sorted = 1; | ||
2349 | } | ||
2350 | |||
2351 | /* Do a simple binary search. */ | ||
2352 | lower = middle = 0; | ||
2353 | upper = comp->timezones->num_elements; | ||
2354 | |||
2355 | while (lower < upper) { | ||
2356 | middle = (lower + upper) >> 1; | ||
2357 | zone = icalarray_element_at (comp->timezones, middle); | ||
2358 | zone_tzid = icaltimezone_get_tzid (zone); | ||
2359 | cmp = strcmp (tzid, zone_tzid); | ||
2360 | if (cmp == 0) | ||
2361 | return zone; | ||
2362 | else if (cmp < 0) | ||
2363 | upper = middle; | ||
2364 | else | ||
2365 | lower = middle + 1; | ||
2366 | } | ||
2367 | |||
2368 | return NULL; | ||
2369 | } | ||
2370 | |||
2371 | |||
2372 | /** | ||
2373 | * A function to compare 2 icaltimezone elements, used for qsort(). | ||
2374 | */ | ||
2375 | static int icalcomponent_compare_timezone_fn (const void*elem1, | ||
2376 | const void*elem2) | ||
2377 | { | ||
2378 | icaltimezone *zone1, *zone2; | ||
2379 | const char *zone1_tzid, *zone2_tzid; | ||
2380 | |||
2381 | zone1 = (icaltimezone*) elem1; | ||
2382 | zone2 = (icaltimezone*) elem2; | ||
2383 | |||
2384 | zone1_tzid = icaltimezone_get_tzid (zone1); | ||
2385 | zone2_tzid = icaltimezone_get_tzid (zone2); | ||
2386 | |||
2387 | return strcmp (zone1_tzid, zone2_tzid); | ||
2388 | } | ||
2389 | |||
2390 | |||
2391 | /** | ||
2392 | * Compares 2 VTIMEZONE components to see if they match, ignoring their TZIDs. | ||
2393 | * It returns 1 if they match, 0 if they don't, or -1 on error. | ||
2394 | */ | ||
2395 | static int icalcomponent_compare_vtimezones (icalcomponent*vtimezone1, | ||
2396 | icalcomponent*vtimezone2) | ||
2397 | { | ||
2398 | icalproperty *prop1, *prop2; | ||
2399 | const char *tzid1, *tzid2; | ||
2400 | char *tzid2_copy, *string1, *string2; | ||
2401 | int cmp; | ||
2402 | |||
2403 | /* Get the TZID property of the first VTIMEZONE. */ | ||
2404 | prop1 = icalcomponent_get_first_property (vtimezone1, ICAL_TZID_PROPERTY); | ||
2405 | if (!prop1) | ||
2406 | return -1; | ||
2407 | |||
2408 | tzid1 = icalproperty_get_tzid (prop1); | ||
2409 | if (!tzid1) | ||
2410 | return -1; | ||
2411 | |||
2412 | /* Get the TZID property of the second VTIMEZONE. */ | ||
2413 | prop2 = icalcomponent_get_first_property (vtimezone2, ICAL_TZID_PROPERTY); | ||
2414 | if (!prop2) | ||
2415 | return -1; | ||
2416 | |||
2417 | tzid2 = icalproperty_get_tzid (prop2); | ||
2418 | if (!tzid2) | ||
2419 | return -1; | ||
2420 | |||
2421 | /* Copy the second TZID, and set the property to the same as the first | ||
2422 | TZID, since we don't care if these match of not. */ | ||
2423 | tzid2_copy = strdup (tzid2); | ||
2424 | if (!tzid2_copy) { | ||
2425 | icalerror_set_errno (ICAL_NEWFAILED_ERROR); | ||
2426 | return 0; | ||
2427 | } | ||
2428 | |||
2429 | icalproperty_set_tzid (prop2, tzid1); | ||
2430 | |||
2431 | /* Now convert both VTIMEZONEs to strings and compare them. */ | ||
2432 | string1 = icalcomponent_as_ical_string (vtimezone1); | ||
2433 | if (!string1) { | ||
2434 | free (tzid2_copy); | ||
2435 | return -1; | ||
2436 | } | ||
2437 | |||
2438 | string2 = icalcomponent_as_ical_string (vtimezone2); | ||
2439 | if (!string2) { | ||
2440 | free (string1); | ||
2441 | free (tzid2_copy); | ||
2442 | return -1; | ||
2443 | } | ||
2444 | |||
2445 | cmp = strcmp (string1, string2); | ||
2446 | |||
2447 | free (string1); | ||
2448 | free (string2); | ||
2449 | |||
2450 | /* Now reset the second TZID. */ | ||
2451 | icalproperty_set_tzid (prop2, tzid2_copy); | ||
2452 | free (tzid2_copy); | ||
2453 | |||
2454 | return (cmp == 0) ? 1 : 0; | ||
2455 | } | ||
2456 | |||
2457 | |||
2458 | |||
2459 | |||
2460 | |||
2461 | |||
2462 | /** | ||
2463 | * @brief set the RELCALID property of a component. | ||
2464 | * | ||
2465 | * @param comp Valid calendar component. | ||
2466 | * @param v Relcalid URL value | ||
2467 | */ | ||
2468 | |||
2469 | void icalcomponent_set_relcalid(icalcomponent* comp, const char* v) | ||
2470 | { | ||
2471 | ICALSETUPSET(ICAL_RELCALID_PROPERTY); | ||
2472 | |||
2473 | if (prop == 0){ | ||
2474 | prop = icalproperty_new_relcalid(v); | ||
2475 | icalcomponent_add_property(inner, prop); | ||
2476 | } | ||
2477 | |||
2478 | icalproperty_set_relcalid(prop,v); | ||
2479 | |||
2480 | } | ||
2481 | |||
2482 | |||
2483 | /** | ||
2484 | * @brief get the RELCALID property of a component. | ||
2485 | * | ||
2486 | * @param comp Valid calendar component. | ||
2487 | */ | ||
2488 | |||
2489 | const char* icalcomponent_get_relcalid(icalcomponent* comp){ | ||
2490 | icalcomponent *inner; | ||
2491 | icalproperty *prop; | ||
2492 | icalerror_check_arg_rz(comp!=0,"comp"); | ||
2493 | |||
2494 | inner = icalcomponent_get_inner(comp); | ||
2495 | |||
2496 | if(inner == 0){ | ||
2497 | return 0; | ||
2498 | } | ||
2499 | |||
2500 | prop= icalcomponent_get_first_property(inner,ICAL_RELCALID_PROPERTY); | ||
2501 | |||
2502 | if (prop == 0){ | ||
2503 | return 0; | ||
2504 | } | ||
2505 | |||
2506 | return icalproperty_get_relcalid(prop); | ||
2507 | } | ||
2508 | |||
2509 | |||
2510 | /** @brief Return the time a TODO task is DUE. | ||
2511 | * | ||
2512 | * @param comp Valid calendar component. | ||
2513 | * | ||
2514 | * Uses the DUE: property if it exists, otherwise we calculate the DUE | ||
2515 | * value by adding the task's duration to the DTSTART time | ||
2516 | */ | ||
2517 | |||
2518 | struct icaltimetype icalcomponent_get_due(icalcomponent* comp) | ||
2519 | { | ||
2520 | icalcomponent *inner = icalcomponent_get_inner(comp); | ||
2521 | |||
2522 | icalproperty *due_prop | ||
2523 | = icalcomponent_get_first_property(inner,ICAL_DUE_PROPERTY); | ||
2524 | |||
2525 | icalproperty *dur_prop | ||
2526 | = icalcomponent_get_first_property(inner, ICAL_DURATION_PROPERTY); | ||
2527 | |||
2528 | if( due_prop == 0 && dur_prop == 0){ | ||
2529 | return icaltime_null_time(); | ||
2530 | } else if ( due_prop != 0) { | ||
2531 | return icalproperty_get_due(due_prop); | ||
2532 | } else if ( dur_prop != 0) { | ||
2533 | |||
2534 | struct icaltimetype start = | ||
2535 | icalcomponent_get_dtstart(inner); | ||
2536 | struct icaldurationtype duration = | ||
2537 | icalproperty_get_duration(dur_prop); | ||
2538 | |||
2539 | struct icaltimetype due = icaltime_add(start,duration); | ||
2540 | |||
2541 | return due; | ||
2542 | |||
2543 | } else { | ||
2544 | /* Error, both duration and due have been specified */ | ||
2545 | icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); | ||
2546 | return icaltime_null_time(); | ||
2547 | |||
2548 | } | ||
2549 | |||
2550 | } | ||
2551 | |||
2552 | /** @brief Set the due date of a VTODO task. | ||
2553 | * | ||
2554 | * @param comp Valid VTODO component. | ||
2555 | * @param v Valid due date time. | ||
2556 | * | ||
2557 | * - If no duration or due properties then set the DUE property. | ||
2558 | * - If a DUE property is already set, then reset it to the value v. | ||
2559 | * - If a DURATION property is already set, then calculate the new | ||
2560 | * duration based on the supplied value of v. | ||
2561 | */ | ||
2562 | |||
2563 | void icalcomponent_set_due(icalcomponent* comp, struct icaltimetype v) | ||
2564 | { | ||
2565 | icalcomponent *inner = icalcomponent_get_inner(comp); | ||
2566 | |||
2567 | icalproperty *due_prop | ||
2568 | = icalcomponent_get_first_property(inner,ICAL_DUE_PROPERTY); | ||
2569 | |||
2570 | icalproperty *dur_prop | ||
2571 | = icalcomponent_get_first_property(inner,ICAL_DURATION_PROPERTY); | ||
2572 | |||
2573 | |||
2574 | if( due_prop == 0 && dur_prop == 0){ | ||
2575 | due_prop = icalproperty_new_due(v); | ||
2576 | icalcomponent_add_property(inner,due_prop); | ||
2577 | } else if ( due_prop != 0) { | ||
2578 | icalproperty_set_due(due_prop,v); | ||
2579 | } else if ( dur_prop != 0) { | ||
2580 | struct icaltimetype start = | ||
2581 | icalcomponent_get_dtstart(inner); | ||
2582 | |||
2583 | struct icaltimetype due = | ||
2584 | icalcomponent_get_due(inner); | ||
2585 | |||
2586 | struct icaldurationtype dur | ||
2587 | = icaltime_subtract(due,start); | ||
2588 | |||
2589 | icalproperty_set_duration(dur_prop,dur); | ||
2590 | |||
2591 | } else { | ||
2592 | /* Error, both duration and due have been specified */ | ||
2593 | icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); | ||
2594 | } | ||
2595 | } | ||