summaryrefslogtreecommitdiffabout
path: root/libical/src/libical/icalcomponent.c
Unidiff
Diffstat (limited to 'libical/src/libical/icalcomponent.c') (more/less context) (show whitespace changes)
-rw-r--r--libical/src/libical/icalcomponent.c1835
1 files changed, 1471 insertions, 364 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
@@ -1,1488 +1,2595 @@
1/*====================================================================== 1/*======================================================================
2 FILE: icalcomponent.c 2 FILE: icalcomponent.c
3 CREATOR: eric 28 April 1999 3 CREATOR: eric 28 April 1999
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
11 it under the terms of either: 10 it under the terms of either:
12 11
13 The LGPL as published by the Free Software Foundation, version 12 The LGPL as published by the Free Software Foundation, version
14 2.1, available at: http://www.fsf.org/copyleft/lesser.html 13 2.1, available at: http://www.fsf.org/copyleft/lesser.html
15 14
16 Or: 15 Or:
17 16
18 The Mozilla Public License Version 1.0. You may obtain a copy of 17 The Mozilla Public License Version 1.0. You may obtain a copy of
19 the License at http://www.mozilla.org/MPL/ 18 the License at http://www.mozilla.org/MPL/
20 19
21 The original code is icalcomponent.c 20 The original code is icalcomponent.c
22 21
23======================================================================*/ 22======================================================================*/
24 23
25 24
26#ifdef HAVE_CONFIG_H 25#ifdef HAVE_CONFIG_H
27#include "config.h" 26#include "config.h"
28#endif 27#endif
29 28
30#include "icalcomponent.h" 29#include "icalcomponent.h"
31#include "pvl.h" /* "Pointer-to-void list" */ 30#include "pvl.h" /* "Pointer-to-void list" */
32#include "icalerror.h" 31#include "icalerror.h"
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
49struct icalcomponent_impl 50struct icalcomponent_impl
50{ 51{
51 char id[5]; 52 char id[5];
52 icalcomponent_kind kind; 53 icalcomponent_kind kind;
53 char* x_name; 54 char* x_name;
54 pvl_list properties; 55 pvl_list properties;
55 pvl_elem property_iterator; 56 pvl_elem property_iterator;
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 */
62void icalproperty_set_parent(icalproperty* property, 70void icalproperty_set_parent(icalproperty* property,
63 icalcomponent* component); 71 icalcomponent* component);
64icalcomponent* icalproperty_get_parent(icalproperty* property); 72icalcomponent* icalproperty_get_parent(icalproperty* property);
65void icalcomponent_add_children(struct icalcomponent_impl *impl,va_list args); 73void icalcomponent_add_children(icalcomponent *impl,va_list args);
66icalcomponent* icalcomponent_new_impl (icalcomponent_kind kind); 74static icalcomponent* icalcomponent_new_impl (icalcomponent_kind kind);
67int icalcomponent_property_sorter(void *a, void *b); 75
68 76static void icalcomponent_merge_vtimezone (icalcomponent *comp,
69 77 icalcomponent *vtimezone,
70void icalcomponent_add_children(struct icalcomponent_impl *impl,va_list args) 78 icalarray *tzids_to_rename);
79static void icalcomponent_handle_conflicting_vtimezones (icalcomponent *comp,
80 icalcomponent *vtimezone,
81 icalproperty *tzid_prop,
82 const char *tzid,
83 icalarray *tzids_to_rename);
84static unsigned int icalcomponent_get_tzid_prefix_len (const char *tzid);
85static void icalcomponent_rename_tzids(icalcomponent* comp,
86 icalarray* rename_table);
87static 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
95void icalcomponent_add_children(icalcomponent *impl, va_list args)
71{ 96{
72 void* vp; 97 void* vp;
73 98
74 while((vp = va_arg(args, void*)) != 0) { 99 while((vp = va_arg(args, void*)) != 0) {
75 100
76 assert (icalcomponent_isa_component(vp) != 0 || 101 assert (icalcomponent_isa_component(vp) != 0 ||
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
92icalcomponent* 113static icalcomponent*
93icalcomponent_new_impl (icalcomponent_kind kind) 114icalcomponent_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 }
102 125
103 strcpy(comp->id,"comp"); 126 strcpy(comp->id,"comp");
104 127
105 comp->kind = kind; 128 comp->kind = kind;
106 comp->properties = pvl_newlist(); 129 comp->properties = pvl_newlist();
107 comp->property_iterator = 0; 130 comp->property_iterator = 0;
108 comp->components = pvl_newlist(); 131 comp->components = pvl_newlist();
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 */
116icalcomponent* 143icalcomponent*
117icalcomponent_new (icalcomponent_kind kind) 144icalcomponent_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 */
122icalcomponent* 151icalcomponent*
123icalcomponent_vanew (icalcomponent_kind kind, ...) 152icalcomponent_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;
131 } 160 }
132 161
133 va_start(args,kind); 162 va_start(args,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 */
140icalcomponent* icalcomponent_new_from_string(char* str) 171icalcomponent* icalcomponent_new_from_string(char* str)
141{ 172{
142 return icalparser_parse_string(str); 173 return icalparser_parse_string(str);
143} 174}
144 175
145icalcomponent* icalcomponent_new_clone(icalcomponent* component) 176/** @brief Constructor
177 */
178icalcomponent* 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
157 if (new == 0){ 189 if (new == 0){
158 return 0; 190 return 0;
159 } 191 }
160 192
161 193
162 for( itr = pvl_head(old->properties); 194 for( itr = pvl_head(old->properties);
163 itr != 0; 195 itr != 0;
164 itr = pvl_next(itr)) 196 itr = pvl_next(itr))
165 { 197 {
166 p = (icalproperty*)pvl_data(itr); 198 p = (icalproperty*)pvl_data(itr);
167 icalcomponent_add_property(new,icalproperty_new_clone(p)); 199 icalcomponent_add_property(new,icalproperty_new_clone(p));
168 } 200 }
169 201
170 202
171 for( itr = pvl_head(old->components); 203 for( itr = pvl_head(old->components);
172 itr != 0; 204 itr != 0;
173 itr = pvl_next(itr)) 205 itr = pvl_next(itr))
174 { 206 {
175 c = (icalcomponent*)pvl_data(itr); 207 c = (icalcomponent*)pvl_data(itr);
176 icalcomponent_add_component(new,icalcomponent_new_clone(c)); 208 icalcomponent_add_component(new,icalcomponent_new_clone(c));
177 } 209 }
178 210
179 return new; 211 return new;
180 212
181} 213}
182 214
183 215/*** @brief Destructor
216 */
184void 217void
185icalcomponent_free (icalcomponent* component) 218icalcomponent_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");
195#else 227#else
196 if(c->parent != 0){ 228 if(c->parent != 0){
197 return; 229 return;
198 } 230 }
199#endif 231#endif
200 232
201 if(component != 0 ){ 233 if(c != 0 ){
202 234
235 if ( c->properties != 0 )
236 {
203 while( (prop=pvl_pop(c->properties)) != 0){ 237 while( (prop=pvl_pop(c->properties)) != 0){
204 assert(prop != 0); 238 assert(prop != 0);
205 icalproperty_set_parent(prop,0); 239 icalproperty_set_parent(prop,0);
206 icalproperty_free(prop); 240 icalproperty_free(prop);
207 } 241 }
208
209 pvl_free(c->properties); 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
217 pvl_free(c->components); 252 pvl_free(c->components);
218 253
219 if (c->x_name != 0) { 254 if (c->x_name != 0) {
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;
226 c->components = 0; 264 c->components = 0;
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
235char* 274char*
236icalcomponent_as_ical_string (icalcomponent* component) 275icalcomponent_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);
263 306
264 icalerror_check_arg_rz( (kind_string!=0),"Unknown kind of component"); 307 icalerror_check_arg_rz( (kind_string!=0),"Unknown kind of component");
265 308
266 icalmemory_append_string(&buf, &buf_ptr, &buf_size, "BEGIN:"); 309 icalmemory_append_string(&buf, &buf_ptr, &buf_size, "BEGIN:");
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");
280 tmp_buf = icalproperty_as_ical_string(p); 322 tmp_buf = icalproperty_as_ical_string(p);
281 323
282 icalmemory_append_string(&buf, &buf_ptr, &buf_size, tmp_buf); 324 icalmemory_append_string(&buf, &buf_ptr, &buf_size, tmp_buf);
283 } 325 }
284 326
285 327
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);
305 347
306 return out_buf; 348 return out_buf;
307} 349}
308 350
309 351
310int 352int
311icalcomponent_is_valid (icalcomponent* component) 353icalcomponent_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;
321 } 360 }
322 361
323} 362}
324 363
325 364
326icalcomponent_kind 365icalcomponent_kind
327icalcomponent_isa (icalcomponent* component) 366icalcomponent_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;
338} 376}
339 377
340 378
341int 379int
342icalcomponent_isa_component (void* component) 380icalcomponent_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
348 if (strcmp(impl->id,"comp") == 0) { 386 if (strcmp(impl->id,"comp") == 0) {
349 return 1; 387 return 1;
350 } else { 388 } else {
351 return 0; 389 return 0;
352 } 390 }
353 391
354} 392}
355 393
356int 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
371void 394void
372icalcomponent_add_property (icalcomponent* component, icalproperty* property) 395icalcomponent_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
395void 408void
396icalcomponent_remove_property (icalcomponent* component, icalproperty* property) 409icalcomponent_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 {
416 next_itr = pvl_next(itr); 423 next_itr = pvl_next(itr);
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 }
428} 435}
429 436
430int 437int
431icalcomponent_count_properties (icalcomponent* component, 438icalcomponent_count_properties (icalcomponent* component,
432 icalproperty_kind kind) 439 icalproperty_kind kind)
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 {
444 if(kind == icalproperty_isa((icalproperty*)pvl_data(itr)) || 450 if(kind == icalproperty_isa((icalproperty*)pvl_data(itr)) ||
445 kind == ICAL_ANY_PROPERTY){ 451 kind == ICAL_ANY_PROPERTY){
446 count++; 452 count++;
447 } 453 }
448 } 454 }
449 455
450 456
451 return count; 457 return count;
452 458
453} 459}
454 460
455icalproperty* icalcomponent_get_current_property (icalcomponent* component) 461icalproperty* 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
469icalproperty* 472icalproperty*
470icalcomponent_get_first_property (icalcomponent* component, icalproperty_kind kind) 473icalcomponent_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;
477 c->property_iterator = pvl_next(c->property_iterator)) { 479 c->property_iterator = pvl_next(c->property_iterator)) {
478 480
479 icalproperty *p = (icalproperty*) pvl_data(c->property_iterator); 481 icalproperty *p = (icalproperty*) pvl_data(c->property_iterator);
480 482
481 if (icalproperty_isa(p) == kind || kind == ICAL_ANY_PROPERTY) { 483 if (icalproperty_isa(p) == kind || kind == ICAL_ANY_PROPERTY) {
482 484
483 return p; 485 return p;
484 } 486 }
485 } 487 }
486 return 0; 488 return 0;
487} 489}
488 490
489icalproperty* 491icalproperty*
490icalcomponent_get_next_property (icalcomponent* component, icalproperty_kind kind) 492icalcomponent_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;
497 } 498 }
498 499
499 for( c->property_iterator = pvl_next(c->property_iterator); 500 for( c->property_iterator = pvl_next(c->property_iterator);
500 c->property_iterator != 0; 501 c->property_iterator != 0;
501 c->property_iterator = pvl_next(c->property_iterator)) { 502 c->property_iterator = pvl_next(c->property_iterator)) {
502 503
503 icalproperty *p = (icalproperty*) pvl_data(c->property_iterator); 504 icalproperty *p = (icalproperty*) pvl_data(c->property_iterator);
504 505
505 if (icalproperty_isa(p) == kind || kind == ICAL_ANY_PROPERTY) { 506 if (icalproperty_isa(p) == kind || kind == ICAL_ANY_PROPERTY) {
506 507
507 return p; 508 return p;
508 } 509 }
509 } 510 }
510 511
511 return 0; 512 return 0;
512} 513}
513 514
514 515
515icalproperty** 516icalproperty**
516icalcomponent_get_properties (icalcomponent* component, icalproperty_kind kind); 517icalcomponent_get_properties (icalcomponent* component, icalproperty_kind kind);
517 518
518 519
519void 520void
520icalcomponent_add_component (icalcomponent* parent, icalcomponent* child) 521icalcomponent_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);
533
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 ();
535 540
536 pvl_push(impl->components,child); 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
540void 549void
541icalcomponent_remove_component (icalcomponent* parent, icalcomponent* child) 550icalcomponent_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) {
559 icaltimezone *zone;
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 }
551 572
552 for( itr = pvl_head(impl->components); 573 for( itr = pvl_head(parent->components);
553 itr != 0; 574 itr != 0;
554 itr = next_itr) 575 itr = next_itr)
555 { 576 {
556 next_itr = pvl_next(itr); 577 next_itr = pvl_next(itr);
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 }
573} 594}
574 595
575 596
576int 597int
577icalcomponent_count_components (icalcomponent* component, 598icalcomponent_count_components (icalcomponent* component,
578 icalcomponent_kind kind) 599 icalcomponent_kind kind)
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 {
590 if(kind == icalcomponent_isa((icalcomponent*)pvl_data(itr)) || 610 if(kind == icalcomponent_isa((icalcomponent*)pvl_data(itr)) ||
591 kind == ICAL_ANY_COMPONENT){ 611 kind == ICAL_ANY_COMPONENT){
592 count++; 612 count++;
593 } 613 }
594 } 614 }
595 615
596 return count; 616 return count;
597} 617}
598 618
599icalcomponent* 619icalcomponent*
600icalcomponent_get_current_component(icalcomponent* component) 620icalcomponent_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
613icalcomponent* 631icalcomponent*
614icalcomponent_get_first_component (icalcomponent* component, 632icalcomponent_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;
623 c->component_iterator = pvl_next(c->component_iterator)) { 639 c->component_iterator = pvl_next(c->component_iterator)) {
624 640
625 icalcomponent *p = (icalcomponent*) pvl_data(c->component_iterator); 641 icalcomponent *p = (icalcomponent*) pvl_data(c->component_iterator);
626 642
627 if (icalcomponent_isa(p) == kind || kind == ICAL_ANY_COMPONENT) { 643 if (icalcomponent_isa(p) == kind || kind == ICAL_ANY_COMPONENT) {
628 644
629 return p; 645 return p;
630 } 646 }
631 } 647 }
632 648
633 return 0; 649 return 0;
634} 650}
635 651
636 652
637icalcomponent* 653icalcomponent*
638icalcomponent_get_next_component (icalcomponent* component, icalcomponent_kind kind) 654icalcomponent_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;
646 } 660 }
647 661
648 for( c->component_iterator = pvl_next(c->component_iterator); 662 for( c->component_iterator = pvl_next(c->component_iterator);
649 c->component_iterator != 0; 663 c->component_iterator != 0;
650 c->component_iterator = pvl_next(c->component_iterator)) { 664 c->component_iterator = pvl_next(c->component_iterator)) {
651 665
652 icalcomponent *p = (icalcomponent*) pvl_data(c->component_iterator); 666 icalcomponent *p = (icalcomponent*) pvl_data(c->component_iterator);
653 667
654 if (icalcomponent_isa(p) == kind || kind == ICAL_ANY_COMPONENT) { 668 if (icalcomponent_isa(p) == kind || kind == ICAL_ANY_COMPONENT) {
655 669
656 return p; 670 return p;
657 } 671 }
658 } 672 }
659 673
660 return 0; 674 return 0;
661} 675}
662 676
663icalcomponent* icalcomponent_get_first_real_component(icalcomponent *c) 677icalcomponent* icalcomponent_get_first_real_component(icalcomponent *c)
664{ 678{
665 icalcomponent *comp; 679 icalcomponent *comp;
666 680
667 for(comp = icalcomponent_get_first_component(c,ICAL_ANY_COMPONENT); 681 for(comp = icalcomponent_get_first_component(c,ICAL_ANY_COMPONENT);
668 comp != 0; 682 comp != 0;
669 comp = icalcomponent_get_next_component(c,ICAL_ANY_COMPONENT)){ 683 comp = icalcomponent_get_next_component(c,ICAL_ANY_COMPONENT)){
670 684
671 icalcomponent_kind kind = icalcomponent_isa(comp); 685 icalcomponent_kind kind = icalcomponent_isa(comp);
672 686
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
683time_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
701 if(sict.is_utc == 1){
702 /* _as_timet will use gmtime() to do the conversion */
703 convt = icaltime_as_timet(sict);
704
705#ifdef TEST_CONVERT_TIME
706 printf("convert time: use as_timet:\n %s\n %s",
707 icalproperty_as_ical_string(p), ctime(&convt));
708#endif
709
710 } else if (sict.is_utc == 0 && tzp == 0 ) {
711 time_t offset;
712
713 /* _as_timet will use localtime() to do the conversion */
714 convt = icaltime_as_timet(sict);
715 offset = icaltime_utc_offset(sict,0);
716 convt += offset;
717 699
718#ifdef TEST_CONVERT_TIME 700 /**@brief Get the timespan covered by this component, in UTC
719 printf("convert time: use as_timet and adjust:\n %s\n %s", 701 *(deprecated)
720 icalproperty_as_ical_string(p), ctime(&convt)); 702 *
721#endif 703 * see icalcomponent_foreach_recurrence() for a better way to
722 } else { 704 * extract spans from an component.
723 /* Convert the time to UTC for the named timezone*/ 705 *
724 const char* timezone = icalparameter_get_tzid(tzp); 706 *This method can be called on either a VCALENDAR or any real
725 convt = icaltime_as_timet(icaltime_as_utc(sict,timezone)); 707 *component. If the VCALENDAR contains no real component, but
708 *contains a VTIMEZONE, we return that span instead.
709 *This might not be a desirable behavior; we keep it for now
710 *for backward compatibility, but it might be deprecated at a
711 *future time.
712 *
713 *FIXME this API needs to be clarified. DTEND is defined as the
714 *first available time after the end of this event, so the span
715 *should actually end 1 second before DTEND.
716 */
726 717
727#ifdef TEST_CONVERT_TIME 718icaltime_span icalcomponent_get_span(icalcomponent* comp)
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}
735struct 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
756 /* Maybe there is a VTIMEZONE in there */ 739 /* Maybe there is a VTIMEZONE in there */
757 if (inner == 0){ 740 if (inner == 0){
758 inner = icalcomponent_get_first_component(comp, 741 inner = icalcomponent_get_first_component(comp,
759 ICAL_VTIMEZONE_COMPONENT); 742 ICAL_VTIMEZONE_COMPONENT);
760 } 743 }
761 744
762 } else { 745 } else {
763 inner = comp; 746 inner = comp;
764 } 747 }
765 748
766 if (inner == 0){ 749 if (inner == 0){
767 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); 750 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
768 /*icalerror_warn("icalcomponent_get_span: no component specified, or empty VCALENDAR component");*/ 751 /*icalerror_warn("icalcomponent_get_span: no component specified, or empty VCALENDAR component");*/
769 return span; 752 return span;
770 } 753 }
771 754
772 kind = icalcomponent_isa(inner); 755 kind = icalcomponent_isa(inner);
773 756
774 if( !( kind == ICAL_VEVENT_COMPONENT || 757 if( !( kind == ICAL_VEVENT_COMPONENT ||
775 kind == ICAL_VJOURNAL_COMPONENT || 758 kind == ICAL_VJOURNAL_COMPONENT ||
776 kind == ICAL_VTODO_COMPONENT || 759 kind == ICAL_VTODO_COMPONENT ||
777 kind == ICAL_VFREEBUSY_COMPONENT )) { 760 kind == ICAL_VFREEBUSY_COMPONENT )) {
778 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); 761 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
779 /*icalerror_warn("icalcomponent_get_span: no component specified, or empty VCALENDAR component");*/ 762 /*icalerror_warn("icalcomponent_get_span: no component specified, or empty VCALENDAR component");*/
780 return span; 763 return span;
781 764
782 } 765 }
783 766
784
785
786 /* Get to work. starting with DTSTART */ 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());
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 }
787 788
788 p = icalcomponent_get_first_property(inner, ICAL_DTSTART_PROPERTY); 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 }
789 795
790 if (p ==0 ) {
791 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
792 /*icalerror_warn("icalcomponent_get_span: component has no DTSTART time");*/
793 return span; 796 return span;
797
794 } 798 }
795 799
800/**
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
823int 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;
796 834
797 start = icalproperty_get_dtstart(p); 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)) {
798 839
799 icalerror_clear_errno(); 840 struct icaltimetype exdatetime = icalproperty_get_exdate(exdate);
800 841
801 span.start = icalcomponent_convert_time(p); 842 if (icaltime_compare(*recurtime, exdatetime) == 0) {
843 /** MATCHED **/
844 return 1;
845 }
846 }
802 847
803#ifdef TEST_CONVERT_TIME 848 /** Now test against the EXRULEs **/
804 printf("convert time:\n %s %s", 849 for (exrule = icalcomponent_get_first_property(comp,ICAL_EXRULE_PROPERTY);
805 icalproperty_as_ical_string(p), ctime(&span.start)); 850 exdate != NULL;
806#endif 851 exdate = icalcomponent_get_next_property(comp,ICAL_EXRULE_PROPERTY)) {
807 852
808 if(icalerrno != ICAL_NO_ERROR){ 853 struct icalrecurrencetype recur = icalproperty_get_exrule(exrule);
809 span.start = 0; 854 icalrecur_iterator *exrule_itr = icalrecur_iterator_new(recur, *dtstart);
810 return span; 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 **/
811 } 871 }
812 872
813 /* The end time could be specified as either a DTEND or a DURATION */ 873 icalrecur_iterator_free(exrule_itr);
814 p = icalcomponent_get_first_property(inner, ICAL_DTEND_PROPERTY); 874 }
815 duration = icalcomponent_get_first_property(inner, ICAL_DURATION_PROPERTY);
816 875
817 if (p==0 && duration == 0 && start.is_date != 1) { 876 return 0; /** no matches **/
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 } 877 }
823 878
824 if (p!=0){ 879/**
825 span.end = icalcomponent_convert_time(p); 880 * @brief Return the busy status based on the TRANSP property.
826 } else if (start.is_date == 1) { 881 *
827 /* Duration is all day */ 882 * @param comp A valid icalcomponent.
828 span.end = span.start + 60*60*24; 883 *
829 } else { 884 * @return 1 if the event is a busy item, 0 if it is not.
830 /* Use the duration */ 885 */
886
887static int icalcomponent_is_busy(icalcomponent *comp) {
888 icalproperty *transp;
889 enum icalproperty_status status;
890 int ret = 1;
891
892 /** @todo check access control here, converting busy->free if the
893 permissions do not allow access... */
894
895 /* Is this a busy time? Check the TRANSP property */
896 transp = icalcomponent_get_first_property(comp, ICAL_TRANSP_PROPERTY);
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;
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}
929
930
931
932
933/**
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
952void 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;
831 struct icaldurationtype dur; 965 struct icaldurationtype dur;
832 time_t durt; 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;
833 997
834 998
835 dur = icalproperty_get_duration(duration); 999 /* Do the callback for the initial DTSTART entry */
836 1000
837 durt = icaldurationtype_as_int(dur); 1001 if (!icalproperty_recurrence_is_excluded(comp, &dtstart, &dtstart)) {
838 span.end = span.start+durt; 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);
1073 }
1074 comp->property_iterator = property_iterator;
1075 }
839 } 1076 }
840 1077
841 return span;
842 1078
1079
1080int 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
846int icalcomponent_count_errors(icalcomponent* component) 1091int icalcomponent_count_errors(icalcomponent* component)
847{ 1092{
848 int errors = 0; 1093 int errors = 0;
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 {
858 p = (icalproperty*)pvl_data(itr); 1102 p = (icalproperty*)pvl_data(itr);
859 1103
860 if(icalproperty_isa(p) == ICAL_XLICERROR_PROPERTY) 1104 if(icalproperty_isa(p) == ICAL_XLICERROR_PROPERTY)
861 { 1105 {
862 errors++; 1106 errors++;
863 } 1107 }
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 {
871 c = (icalcomponent*)pvl_data(itr); 1115 c = (icalcomponent*)pvl_data(itr);
872 1116
873 errors += icalcomponent_count_errors(c); 1117 errors += icalcomponent_count_errors(c);
874 1118
875 } 1119 }
876 1120
877 return errors; 1121 return errors;
878} 1122}
879 1123
880 1124
881void icalcomponent_strip_errors(icalcomponent* component) 1125void icalcomponent_strip_errors(icalcomponent* component)
882{ 1126{
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 {
892 p = (icalproperty*)pvl_data(itr); 1135 p = (icalproperty*)pvl_data(itr);
893 next_itr = pvl_next(itr); 1136 next_itr = pvl_next(itr);
894 1137
895 if(icalproperty_isa(p) == ICAL_XLICERROR_PROPERTY) 1138 if(icalproperty_isa(p) == ICAL_XLICERROR_PROPERTY)
896 { 1139 {
897 icalcomponent_remove_property(component,p); 1140 icalcomponent_remove_property(component,p);
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 {
905 c = (icalcomponent*)pvl_data(itr); 1148 c = (icalcomponent*)pvl_data(itr);
906 icalcomponent_strip_errors(c); 1149 icalcomponent_strip_errors(c);
907 } 1150 }
908} 1151}
909 1152
910/* Hack. This will change the state of the iterators */ 1153/* Hack. This will change the state of the iterators */
911void icalcomponent_convert_errors(icalcomponent* component) 1154void icalcomponent_convert_errors(icalcomponent* component)
912{ 1155{
913 icalproperty *p, *next_p; 1156 icalproperty *p, *next_p;
914 icalcomponent *c; 1157 icalcomponent *c;
915 1158
916 for(p = icalcomponent_get_first_property(component,ICAL_ANY_PROPERTY); 1159 for(p = icalcomponent_get_first_property(component,ICAL_ANY_PROPERTY);
917 p != 0; 1160 p != 0;
918 p = next_p){ 1161 p = next_p){
919 1162
920 next_p = icalcomponent_get_next_property(component,ICAL_ANY_PROPERTY); 1163 next_p = icalcomponent_get_next_property(component,ICAL_ANY_PROPERTY);
921 1164
922 if(icalproperty_isa(p) == ICAL_XLICERROR_PROPERTY) 1165 if(icalproperty_isa(p) == ICAL_XLICERROR_PROPERTY)
923 { 1166 {
924 struct icalreqstattype rst; 1167 struct icalreqstattype rst;
925 icalparameter *param = icalproperty_get_first_parameter 1168 icalparameter *param = icalproperty_get_first_parameter
926 (p,ICAL_XLICERRORTYPE_PARAMETER); 1169 (p,ICAL_XLICERRORTYPE_PARAMETER);
927 1170
928 rst.code = ICAL_UNKNOWN_STATUS; 1171 rst.code = ICAL_UNKNOWN_STATUS;
929 rst.desc = 0; 1172 rst.desc = 0;
930 1173
931 switch(icalparameter_get_xlicerrortype(param)){ 1174 switch(icalparameter_get_xlicerrortype(param)){
932 1175
933 case ICAL_XLICERRORTYPE_PARAMETERNAMEPARSEERROR: { 1176 case ICAL_XLICERRORTYPE_PARAMETERNAMEPARSEERROR: {
934 rst.code = ICAL_3_2_INVPARAM_STATUS; 1177 rst.code = ICAL_3_2_INVPARAM_STATUS;
935 break; 1178 break;
936 } 1179 }
937 case ICAL_XLICERRORTYPE_PARAMETERVALUEPARSEERROR: { 1180 case ICAL_XLICERRORTYPE_PARAMETERVALUEPARSEERROR: {
938 rst.code = ICAL_3_3_INVPARAMVAL_STATUS; 1181 rst.code = ICAL_3_3_INVPARAMVAL_STATUS;
939 break; 1182 break;
940 } 1183 }
941 case ICAL_XLICERRORTYPE_PROPERTYPARSEERROR: { 1184 case ICAL_XLICERRORTYPE_PROPERTYPARSEERROR: {
942 rst.code = ICAL_3_0_INVPROPNAME_STATUS; 1185 rst.code = ICAL_3_0_INVPROPNAME_STATUS;
943 break; 1186 break;
944 } 1187 }
945 case ICAL_XLICERRORTYPE_VALUEPARSEERROR: { 1188 case ICAL_XLICERRORTYPE_VALUEPARSEERROR: {
946 rst.code = ICAL_3_1_INVPROPVAL_STATUS; 1189 rst.code = ICAL_3_1_INVPROPVAL_STATUS;
947 break; 1190 break;
948 } 1191 }
949 case ICAL_XLICERRORTYPE_COMPONENTPARSEERROR: { 1192 case ICAL_XLICERRORTYPE_COMPONENTPARSEERROR: {
950 rst.code = ICAL_3_4_INVCOMP_STATUS; 1193 rst.code = ICAL_3_4_INVCOMP_STATUS;
951 break; 1194 break;
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){
958 1202
959 rst.debug = icalproperty_get_xlicerror(p); 1203 rst.debug = icalproperty_get_xlicerror(p);
960 icalcomponent_add_property(component, 1204 icalcomponent_add_property(component,
961 icalproperty_new_requeststatus(rst)); 1205 icalproperty_new_requeststatus(rst));
962 1206
963 icalcomponent_remove_property(component,p); 1207 icalcomponent_remove_property(component,p);
964 } 1208 }
965 } 1209 }
966 } 1210 }
967 1211
968 for(c = icalcomponent_get_first_component(component,ICAL_ANY_COMPONENT); 1212 for(c = icalcomponent_get_first_component(component,ICAL_ANY_COMPONENT);
969 c != 0; 1213 c != 0;
970 c = icalcomponent_get_next_component(component,ICAL_ANY_COMPONENT)){ 1214 c = icalcomponent_get_next_component(component,ICAL_ANY_COMPONENT)){
971 1215
972 icalcomponent_convert_errors(c); 1216 icalcomponent_convert_errors(c);
973 } 1217 }
974} 1218}
975 1219
976 1220
977icalcomponent* icalcomponent_get_parent(icalcomponent* component) 1221icalcomponent* 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
984void icalcomponent_set_parent(icalcomponent* component, icalcomponent* parent) 1226void 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
991icalcompiter icalcompiter_null = {ICAL_NO_COMPONENT,0}; 1231icalcompiter icalcompiter_null = {ICAL_NO_COMPONENT,0};
992 1232
993 1233
994struct icalcomponent_kind_map { 1234struct icalcomponent_kind_map {
995 icalcomponent_kind kind; 1235 icalcomponent_kind kind;
996 char name[20]; 1236 char name[20];
997}; 1237};
998 1238
999 1239
1000 1240
1001static struct icalcomponent_kind_map component_map[] = 1241static struct icalcomponent_kind_map component_map[] =
1002{ 1242{
1003 { ICAL_VEVENT_COMPONENT, "VEVENT" }, 1243 { ICAL_VEVENT_COMPONENT, "VEVENT" },
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" },
1010 { ICAL_XSTANDARD_COMPONENT, "STANDARD" }, /*These are part of RFC2445 */ 1251 { ICAL_XSTANDARD_COMPONENT, "STANDARD" }, /*These are part of RFC2445 */
1011 { ICAL_XDAYLIGHT_COMPONENT, "DAYLIGHT" }, /*but are not really components*/ 1252 { ICAL_XDAYLIGHT_COMPONENT, "DAYLIGHT" }, /*but are not really components*/
1012 { ICAL_X_COMPONENT, "X" }, 1253 { ICAL_X_COMPONENT, "X" },
1013 { ICAL_VSCHEDULE_COMPONENT, "SCHEDULE" }, 1254 { ICAL_VSCHEDULE_COMPONENT, "SCHEDULE" },
1014 1255
1015 /* CAP components */ 1256 /* CAP components */
1016 { ICAL_VQUERY_COMPONENT, "VQUERY" }, 1257 { ICAL_VQUERY_COMPONENT, "VQUERY" },
1017 { ICAL_VCAR_COMPONENT, "VCAR" }, 1258 { ICAL_VCAR_COMPONENT, "VCAR" },
1018 { ICAL_VCOMMAND_COMPONENT, "VCOMMAND" }, 1259 { ICAL_VCOMMAND_COMPONENT, "VCOMMAND" },
1019 1260
1020 /* libical private components */ 1261 /* libical private components */
1021 { ICAL_XLICINVALID_COMPONENT, "X-LIC-UNKNOWN" }, 1262 { ICAL_XLICINVALID_COMPONENT, "X-LIC-UNKNOWN" },
1022 { ICAL_XLICMIMEPART_COMPONENT, "X-LIC-MIME-PART" }, 1263 { ICAL_XLICMIMEPART_COMPONENT, "X-LIC-MIME-PART" },
1023 { ICAL_ANY_COMPONENT, "ANY" }, 1264 { ICAL_ANY_COMPONENT, "ANY" },
1024 { ICAL_XROOT_COMPONENT, "XROOT" }, 1265 { ICAL_XROOT_COMPONENT, "XROOT" },
1025 1266
1026 /* End of list */ 1267 /* End of list */
1027 { ICAL_NO_COMPONENT, "" }, 1268 { ICAL_NO_COMPONENT, "" },
1028}; 1269};
1029 1270
1030 1271
1272int 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
1032const char* icalcomponent_kind_to_string(icalcomponent_kind kind) 1283const char* icalcomponent_kind_to_string(icalcomponent_kind kind)
1033{ 1284{
1034 int i; 1285 int i;
1035 1286
1036 for (i=0; component_map[i].kind != ICAL_NO_COMPONENT; i++) { 1287 for (i=0; component_map[i].kind != ICAL_NO_COMPONENT; i++) {
1037 if (component_map[i].kind == kind) { 1288 if (component_map[i].kind == kind) {
1038 return component_map[i].name; 1289 return component_map[i].name;
1039 } 1290 }
1040 } 1291 }
1041 1292
1042 return 0; 1293 return 0;
1043 1294
1044} 1295}
1045 1296
1046icalcomponent_kind icalcomponent_string_to_kind(const char* string) 1297icalcomponent_kind icalcomponent_string_to_kind(const char* string)
1047{ 1298{
1048 int i; 1299 int i;
1049 1300
1050 if (string ==0 ) { 1301 if (string ==0 ) {
1051 return ICAL_NO_COMPONENT; 1302 return ICAL_NO_COMPONENT;
1052 } 1303 }
1053 1304
1054 for (i=0; component_map[i].kind != ICAL_NO_COMPONENT; i++) { 1305 for (i=0; component_map[i].kind != ICAL_NO_COMPONENT; i++) {
1055 if (strcmp(component_map[i].name, string) == 0) { 1306 if (strcmp(component_map[i].name, string) == 0) {
1056 return component_map[i].kind; 1307 return component_map[i].kind;
1057 } 1308 }
1058 } 1309 }
1059 1310
1060 return ICAL_NO_COMPONENT; 1311 return ICAL_NO_COMPONENT;
1061} 1312}
1062 1313
1063 1314
1064 1315
1065icalcompiter 1316icalcompiter
1066icalcomponent_begin_component(icalcomponent* component,icalcomponent_kind kind) 1317icalcomponent_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
1080 if (icalcomponent_isa(c) == kind || kind == ICAL_ANY_COMPONENT) { 1331 if (icalcomponent_isa(c) == kind || kind == ICAL_ANY_COMPONENT) {
1081 1332
1082 itr.iter = i; 1333 itr.iter = i;
1083 1334
1084 return itr; 1335 return itr;
1085 } 1336 }
1086 } 1337 }
1087 1338
1088 return icalcompiter_null; 1339 return icalcompiter_null;
1089} 1340}
1090 1341
1091icalcompiter 1342icalcompiter
1092icalcomponent_end_component(icalcomponent* component,icalcomponent_kind kind) 1343icalcomponent_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
1106 if (icalcomponent_isa(c) == kind || kind == ICAL_ANY_COMPONENT) { 1356 if (icalcomponent_isa(c) == kind || kind == ICAL_ANY_COMPONENT) {
1107 1357
1108 itr.iter = pvl_next(i); 1358 itr.iter = pvl_next(i);
1109 1359
1110 return itr; 1360 return itr;
1111 } 1361 }
1112 } 1362 }
1113 1363
1114 return icalcompiter_null;; 1364 return icalcompiter_null;;
1115} 1365}
1116 1366
1117 1367
1118icalcomponent* icalcompiter_next(icalcompiter* i) 1368icalcomponent* icalcompiter_next(icalcompiter* i)
1119{ 1369{
1120 if (i->iter == 0){ 1370 if (i->iter == 0){
1121 return 0; 1371 return 0;
1122 } 1372 }
1123 1373
1124 icalerror_check_arg_rz( (i!=0),"i"); 1374 icalerror_check_arg_rz( (i!=0),"i");
1125 1375
1126 for( i->iter = pvl_next(i->iter); 1376 for( i->iter = pvl_next(i->iter);
1127 i->iter != 0; 1377 i->iter != 0;
1128 i->iter = pvl_next(i->iter)) { 1378 i->iter = pvl_next(i->iter)) {
1129 1379
1130 icalcomponent *c = (icalcomponent*) pvl_data(i->iter); 1380 icalcomponent *c = (icalcomponent*) pvl_data(i->iter);
1131 1381
1132 if (icalcomponent_isa(c) == i->kind 1382 if (icalcomponent_isa(c) == i->kind
1133 || i->kind == ICAL_ANY_COMPONENT) { 1383 || i->kind == ICAL_ANY_COMPONENT) {
1134 1384
1135 return icalcompiter_deref(i);; 1385 return icalcompiter_deref(i);;
1136 } 1386 }
1137 } 1387 }
1138 1388
1139 return 0; 1389 return 0;
1140 1390
1141} 1391}
1142 1392
1143icalcomponent* icalcompiter_prior(icalcompiter* i) 1393icalcomponent* icalcompiter_prior(icalcompiter* i)
1144{ 1394{
1145 if (i->iter == 0){ 1395 if (i->iter == 0){
1146 return 0; 1396 return 0;
1147 } 1397 }
1148 1398
1149 for( i->iter = pvl_prior(i->iter); 1399 for( i->iter = pvl_prior(i->iter);
1150 i->iter != 0; 1400 i->iter != 0;
1151 i->iter = pvl_prior(i->iter)) { 1401 i->iter = pvl_prior(i->iter)) {
1152 1402
1153 icalcomponent *c = (icalcomponent*) pvl_data(i->iter); 1403 icalcomponent *c = (icalcomponent*) pvl_data(i->iter);
1154 1404
1155 if (icalcomponent_isa(c) == i->kind 1405 if (icalcomponent_isa(c) == i->kind
1156 || i->kind == ICAL_ANY_COMPONENT) { 1406 || i->kind == ICAL_ANY_COMPONENT) {
1157 1407
1158 return icalcompiter_deref(i);; 1408 return icalcompiter_deref(i);;
1159 } 1409 }
1160 } 1410 }
1161 1411
1162 return 0; 1412 return 0;
1163 1413
1164} 1414}
1165icalcomponent* icalcompiter_deref(icalcompiter* i) 1415icalcomponent* icalcompiter_deref(icalcompiter* i)
1166{ 1416{
1167 if(i->iter ==0){ 1417 if(i->iter ==0){
1168 return 0; 1418 return 0;
1169 } 1419 }
1170 1420
1171 return pvl_data(i->iter); 1421 return pvl_data(i->iter);
1172} 1422}
1173 1423
1174icalcomponent* icalcomponent_get_inner(icalcomponent* comp) 1424icalcomponent* icalcomponent_get_inner(icalcomponent* comp)
1175{ 1425{
1176 if (icalcomponent_isa(comp) == ICAL_VCALENDAR_COMPONENT){ 1426 if (icalcomponent_isa(comp) == ICAL_VCALENDAR_COMPONENT){
1177 return icalcomponent_get_first_real_component(comp); 1427 return icalcomponent_get_first_real_component(comp);
1178 } else { 1428 } else {
1179 return comp; 1429 return comp;
1180 } 1430 }
1181} 1431}
1182 1432
1433/** @brief sets the METHOD property to the given method
1434 */
1183 1435
1184void icalcomponent_set_dtstart(icalcomponent* comp, struct icaltimetype v) 1436void 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
1454icalproperty_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 */
1483void 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 */
1511static struct icaltimetype
1512icalcomponent_get_datetime(icalcomponent *comp, icalproperty *prop) {
1513
1514 icalparameter *param;
1515 struct icaltimetyperet;
1201 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}
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 */
1202struct icaltimetype icalcomponent_get_dtstart(icalcomponent* comp) 1541struct 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 1550
1212 return icalproperty_get_dtstart(prop); 1551 return icalcomponent_get_datetime(comp, prop);
1213} 1552}
1214 1553
1215 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 */
1216struct icaltimetype icalcomponent_get_dtend(icalcomponent* comp) 1566struct 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 1583
1238 struct icaltimetype end = icaltime_add(start,duration); 1584 struct icaltimetype end = icaltime_add(start,duration);
1239 1585
1240 return end; 1586 ret = end;
1587 }
1241 1588
1242 } else { 1589 return ret;
1243 /* Error, both duration and dtend have been specified */ 1590}
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 */
1601void icalcomponent_set_dtend(icalcomponent* comp, struct icaltimetype v)
1602{
1603 char *tzid;
1604 ICALSETUPSET(ICAL_DTEND_PROPERTY);
1605
1606 if (icalcomponent_get_first_property(inner,ICAL_DURATION_PROPERTY)
1607 != NULL) {
1244 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); 1608 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
1245 return icaltime_null_time(); 1609 return;
1610 }
1246 1611
1612 if (prop == 0) {
1613 prop = icalproperty_new_dtend(v);
1614 icalcomponent_add_property(inner, prop);
1615 } else {
1616 icalproperty_remove_parameter_by_kind(prop, ICAL_TZID_PARAMETER);
1247 } 1617 }
1248 1618
1619 icalproperty_set_dtend(prop,v);
1620
1621 if ((tzid = icaltime_get_tzid(v)) != NULL && !icaltime_is_utc(v)) {
1622 icalproperty_add_parameter(prop, icalparameter_new_tzid(tzid));
1623 }
1249} 1624}
1250 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 */
1635void icalcomponent_set_duration(icalcomponent* comp,
1636 struct icaldurationtype v)
1637{
1638 ICALSETUPSET(ICAL_DURATION_PROPERTY);
1251 1639
1252void icalcomponent_set_dtend(icalcomponent* comp, struct icaltimetype v) 1640 if (icalcomponent_get_first_property(inner,ICAL_DTEND_PROPERTY) != NULL) {
1641 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
1642 return;
1643 }
1644
1645 if (prop == 0) {
1646 prop = icalproperty_new_duration(v);
1647 icalcomponent_add_property(inner, prop);
1648 } else {
1649 icalproperty_set_duration(prop,v);
1650 }
1651}
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 */
1658struct icaldurationtype icalcomponent_get_duration(icalcomponent* comp)
1253{ 1659{
1254 icalcomponent *inner = icalcomponent_get_inner(comp); 1660 icalcomponent *inner = icalcomponent_get_inner(comp);
1255 1661
1256 icalproperty *end_prop 1662 icalproperty *end_prop
1257 = icalcomponent_get_first_property(inner,ICAL_DTEND_PROPERTY); 1663 = icalcomponent_get_first_property(inner,ICAL_DTEND_PROPERTY);
1258 1664
1259 icalproperty *dur_prop 1665 icalproperty *dur_prop
1260 = icalcomponent_get_first_property(inner,ICAL_DURATION_PROPERTY); 1666 = icalcomponent_get_first_property(inner,ICAL_DURATION_PROPERTY);
1261 1667
1668 struct icaldurationtype ret = icaldurationtype_null_duration();
1262 1669
1263 if( end_prop == 0 && dur_prop == 0){ 1670 if ( dur_prop != 0 && end_prop == 0) {
1264 end_prop = icalproperty_new_dtend(v); 1671 ret = icalproperty_get_duration(dur_prop);
1265 icalcomponent_add_property(inner,end_prop); 1672
1266 } else if ( end_prop != 0) { 1673 } else if ( end_prop != 0 && dur_prop == 0) {
1267 icalproperty_set_dtend(end_prop,v); 1674 /**
1268 } else if ( dur_prop != 0) { 1675 * FIXME
1676 * We assume DTSTART and DTEND are not in different time zones.
1677 * Does the standard actually guarantee this?
1678 */
1269 struct icaltimetype start = 1679 struct icaltimetype start =
1270 icalcomponent_get_dtstart(inner); 1680 icalcomponent_get_dtstart(inner);
1271
1272 struct icaltimetype end = 1681 struct icaltimetype end =
1273 icalcomponent_get_dtend(inner); 1682 icalcomponent_get_dtend(inner);
1274 1683
1275 struct icaldurationtype dur 1684 ret = icaltime_subtract(end, start);
1276 = icaltime_subtract(end,start);
1277
1278 icalproperty_set_duration(dur_prop,dur);
1279
1280 } else { 1685 } else {
1281 /* Error, both duration and dtend have been specified */ 1686 /* Error, both duration and dtend have been specified */
1282 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); 1687 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
1283 } 1688 }
1689 return ret;
1284} 1690}
1285 1691
1286void icalcomponent_set_duration(icalcomponent* comp, 1692void icalcomponent_set_dtstamp(icalcomponent* comp, struct icaltimetype v)
1287 struct icaldurationtype v) 1693{
1694
1695 ICALSETUPSET(ICAL_DTSTAMP_PROPERTY);
1696
1697 if (prop == 0){
1698 prop = icalproperty_new_dtstamp(v);
1699 icalcomponent_add_property(inner, prop);
1700 }
1701
1702 icalproperty_set_dtstamp(prop,v);
1703
1704}
1705
1706
1707struct icaltimetype icalcomponent_get_dtstamp(icalcomponent* comp)
1288{ 1708{
1289 icalcomponent *inner = icalcomponent_get_inner(comp); 1709 icalcomponent *inner = icalcomponent_get_inner(comp);
1710 icalproperty *prop
1711 = icalcomponent_get_first_property(inner,ICAL_DTSTAMP_PROPERTY);
1290 1712
1291 icalproperty *end_prop 1713 if (prop == 0){
1292 = icalcomponent_get_first_property(inner,ICAL_DTEND_PROPERTY); 1714 return icaltime_null_time();
1715 }
1293 1716
1294 icalproperty *dur_prop 1717 return icalproperty_get_dtstamp(prop);
1295 = icalcomponent_get_first_property(inner,ICAL_DURATION_PROPERTY); 1718}
1296 1719
1297 1720
1298 if( end_prop == 0 && dur_prop == 0){ 1721void icalcomponent_set_summary(icalcomponent* comp, const char* v)
1299 dur_prop = icalproperty_new_duration(v); 1722{
1300 icalcomponent_add_property(inner, dur_prop); 1723 ICALSETUPSET(ICAL_SUMMARY_PROPERTY)
1301 } else if ( end_prop != 0) {
1302 struct icaltimetype start =
1303 icalcomponent_get_dtstart(inner);
1304 1724
1305 struct icaltimetype new_end = icaltime_add(start,v); 1725 if (prop == 0){
1726 prop = icalproperty_new_summary(v);
1727 icalcomponent_add_property(inner, prop);
1728 }
1306 1729
1307 icalproperty_set_dtend(end_prop,new_end); 1730 icalproperty_set_summary(prop,v);
1731}
1308 1732
1309 } else if ( dur_prop != 0) { 1733
1310 icalproperty_set_duration(dur_prop,v); 1734const char* icalcomponent_get_summary(icalcomponent* comp)
1311 } else { 1735{
1312 /* Error, both duration and dtend have been specified */ 1736 icalcomponent *inner;
1737 icalproperty *prop;
1738 icalerror_check_arg_rz(comp!=0,"comp");
1739
1740 inner = icalcomponent_get_inner(comp);
1741
1742 if(inner == 0){
1313 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); 1743 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
1744 return 0;
1314 } 1745 }
1746
1747 prop= icalcomponent_get_first_property(inner,ICAL_SUMMARY_PROPERTY);
1748
1749 if (prop == 0){
1750 return 0;
1315} 1751}
1316 1752
1317struct icaldurationtype icalcomponent_get_duration(icalcomponent* comp) 1753 return icalproperty_get_summary(prop);
1318{
1319 icalcomponent *inner = icalcomponent_get_inner(comp);
1320 1754
1321 icalproperty *end_prop 1755}
1322 = icalcomponent_get_first_property(inner,ICAL_DTEND_PROPERTY);
1323 1756
1324 icalproperty *dur_prop 1757void icalcomponent_set_comment(icalcomponent* comp, const char* v)
1325 = icalcomponent_get_first_property(inner,ICAL_DURATION_PROPERTY); 1758{
1759 ICALSETUPSET(ICAL_COMMENT_PROPERTY);
1326 1760
1327 struct icaldurationtype null_duration; 1761 if (prop == 0){
1328 memset(&null_duration,0,sizeof(struct icaldurationtype)); 1762 prop = icalproperty_new_comment(v);
1763 icalcomponent_add_property(inner, prop);
1764 }
1329 1765
1766 icalproperty_set_summary(prop,v);
1330 1767
1331 if( end_prop == 0 && dur_prop == 0){ 1768}
1332 return null_duration; 1769const char* icalcomponent_get_comment(icalcomponent* comp){
1333 } else if ( end_prop != 0) { 1770 icalcomponent *inner;
1334 struct icaltimetype start = 1771 icalproperty *prop;
1335 icalcomponent_get_dtstart(inner); 1772 icalerror_check_arg_rz(comp!=0,"comp");
1336 time_t startt = icaltime_as_timet(start);
1337 1773
1338 struct icaltimetype end = 1774 inner = icalcomponent_get_inner(comp);
1339 icalcomponent_get_dtend(inner);
1340 time_t endt = icaltime_as_timet(end);
1341 1775
1342 return icaldurationtype_from_int(endt-startt); 1776 if(inner == 0){
1343 } else if ( dur_prop != 0) {
1344 return icalproperty_get_duration(dur_prop);
1345 } else {
1346 /* Error, both duration and dtend have been specified */
1347 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); 1777 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
1348 return null_duration; 1778 return 0;
1349 } 1779 }
1780
1781 prop= icalcomponent_get_first_property(inner,ICAL_COMMENT_PROPERTY);
1782
1783 if (prop == 0){
1784 return 0;
1350} 1785}
1351 1786
1352void icalcomponent_set_method(icalcomponent* comp, icalproperty_method method) 1787 return icalproperty_get_comment(prop);
1353{ 1788}
1354 icalproperty *prop
1355 = icalcomponent_get_first_property(comp, ICAL_METHOD_PROPERTY);
1356 1789
1790void icalcomponent_set_uid(icalcomponent* comp, const char* v)
1791{
1792 ICALSETUPSET(ICAL_UID_PROPERTY);
1357 1793
1358 if (prop == 0){ 1794 if (prop == 0){
1359 prop = icalproperty_new_method(method); 1795 prop = icalproperty_new_uid(v);
1360 icalcomponent_add_property(comp, prop); 1796 icalcomponent_add_property(inner, prop);
1361 } 1797 }
1362 1798
1363 icalproperty_set_method(prop,method); 1799 icalproperty_set_summary(prop,v);
1364 1800
1365} 1801}
1802const char* icalcomponent_get_uid(icalcomponent* comp){
1803 icalcomponent *inner;
1804 icalproperty *prop;
1805 icalerror_check_arg_rz(comp!=0,"comp");
1366 1806
1367icalproperty_method icalcomponent_get_method(icalcomponent* comp) 1807 inner = icalcomponent_get_inner(comp);
1368{ 1808
1369 icalproperty *prop 1809 if(inner == 0){
1370 = icalcomponent_get_first_property(comp,ICAL_METHOD_PROPERTY); 1810 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
1811 return 0;
1812 }
1813
1814 prop= icalcomponent_get_first_property(inner,ICAL_UID_PROPERTY);
1371 1815
1372 if (prop == 0){ 1816 if (prop == 0){
1373 return ICAL_METHOD_NONE; 1817 return 0;
1374 } 1818 }
1375 1819
1376 return icalproperty_get_method(prop); 1820 return icalproperty_get_uid(prop);
1377} 1821}
1378 1822
1379void icalcomponent_set_dtstamp(icalcomponent* comp, struct icaltimetype v) 1823void icalcomponent_set_recurrenceid(icalcomponent* comp, struct icaltimetype v)
1380{ 1824{
1825 ICALSETUPSET(ICAL_RECURRENCEID_PROPERTY);
1381 1826
1382 icalcomponent *inner = icalcomponent_get_inner(comp); 1827 if (prop == 0){
1383 icalproperty *prop 1828 prop = icalproperty_new_recurrenceid(v);
1384 = icalcomponent_get_first_property(inner, ICAL_DTSTAMP_PROPERTY); 1829 icalcomponent_add_property(inner, prop);
1830 }
1831
1832 icalproperty_set_recurrenceid(prop,v);
1833}
1834struct 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 }
1385 1842
1843 inner = icalcomponent_get_inner(comp);
1844
1845 if(inner == 0){
1846 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
1847 return icaltime_null_time();
1848 }
1849
1850 prop= icalcomponent_get_first_property(inner, ICAL_RECURRENCEID_PROPERTY);
1386 1851
1387 if (prop == 0){ 1852 if (prop == 0){
1388 prop = icalproperty_new_dtstamp(v); 1853 return icaltime_null_time();
1854 }
1855
1856 return icalproperty_get_recurrenceid(prop);
1857}
1858
1859void 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);
1389 icalcomponent_add_property(inner, prop); 1865 icalcomponent_add_property(inner, prop);
1390 } 1866 }
1391 1867
1392 icalproperty_set_dtstamp(prop,v); 1868 icalproperty_set_description(prop,v);
1869}
1870const 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);
1393 1877
1878 if(inner == 0){
1879 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
1880 return 0;
1394} 1881}
1395 1882
1883 prop= icalcomponent_get_first_property(inner,ICAL_DESCRIPTION_PROPERTY);
1396 1884
1397struct icaltimetype icalcomponent_get_dtstamp(icalcomponent* comp) 1885 if (prop == 0){
1886 return 0;
1887 }
1888
1889 return icalproperty_get_description(prop);
1890}
1891
1892void icalcomponent_set_location(icalcomponent* comp, const char* v)
1398{ 1893{
1399 icalcomponent *inner = icalcomponent_get_inner(comp); 1894 ICALSETUPSET(ICAL_LOCATION_PROPERTY)
1400 icalproperty *prop
1401 = icalcomponent_get_first_property(inner,ICAL_DTSTAMP_PROPERTY);
1402 1895
1403 if (prop == 0){ 1896 if (prop == 0){
1404 return icaltime_null_time(); 1897 prop = icalproperty_new_location(v);
1898 icalcomponent_add_property(inner, prop);
1405 } 1899 }
1406 1900
1407 return icalproperty_get_dtstamp(prop); 1901 icalproperty_set_location(prop,v);
1408} 1902}
1903const char* icalcomponent_get_location(icalcomponent* comp)
1904{
1905 icalcomponent *inner;
1906 icalproperty *prop;
1907 icalerror_check_arg_rz(comp!=0,"comp");
1409 1908
1909 inner = icalcomponent_get_inner(comp);
1410 1910
1411void icalcomponent_set_summary(icalcomponent* comp, const char* v) 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);
1917
1918 if (prop == 0){
1919 return 0;
1920 }
1921
1922 return icalproperty_get_location(prop);
1923}
1924
1925void icalcomponent_set_sequence(icalcomponent* comp, int v)
1412{ 1926{
1413 icalcomponent *inner = icalcomponent_get_inner(comp); 1927 ICALSETUPSET(ICAL_SEQUENCE_PROPERTY);
1414 icalproperty *prop
1415 = icalcomponent_get_first_property(inner, ICAL_SUMMARY_PROPERTY);
1416 1928
1417 if (prop == 0){ 1929 if (prop == 0){
1418 prop = icalproperty_new_summary(v); 1930 prop = icalproperty_new_sequence(v);
1419 icalcomponent_add_property(inner, prop); 1931 icalcomponent_add_property(inner, prop);
1420 } 1932 }
1421 1933
1422 icalproperty_set_summary(prop,v); 1934 icalproperty_set_sequence(prop,v);
1935
1423} 1936}
1937int icalcomponent_get_sequence(icalcomponent* comp){
1938 icalcomponent *inner;
1939 icalproperty *prop;
1940 icalerror_check_arg_rz(comp!=0,"comp");
1424 1941
1942 inner = icalcomponent_get_inner(comp);
1425 1943
1426const char* icalcomponent_get_summary(icalcomponent* comp) 1944 if(inner == 0){
1427{ 1945 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
1428 icalcomponent *inner = icalcomponent_get_inner(comp); 1946 return 0;
1429 icalproperty *prop 1947 }
1430 = icalcomponent_get_first_property(inner,ICAL_SUMMARY_PROPERTY); 1948
1949 prop= icalcomponent_get_first_property(inner,ICAL_SEQUENCE_PROPERTY);
1431 1950
1432 if (prop == 0){ 1951 if (prop == 0){
1433 return 0; 1952 return 0;
1434 } 1953 }
1435 1954
1436 return icalproperty_get_summary(prop); 1955 return icalproperty_get_sequence(prop);
1956}
1957
1958
1959void icalcomponent_set_status(icalcomponent* comp, enum icalproperty_status v)
1960{
1961 ICALSETUPSET(ICAL_STATUS_PROPERTY);
1437 1962
1963 if (prop == 0){
1964 prop = icalproperty_new_status(v);
1965 icalcomponent_add_property(inner, prop);
1438} 1966}
1439 1967
1440void icalcomponent_set_comment(icalcomponent* comp, const char* v); 1968 icalproperty_set_status(prop,v);
1441const char* icalcomponent_get_comment(icalcomponent* comp);
1442 1969
1443void icalcomponent_set_uid(icalcomponent* comp, const char* v); 1970}
1444const char* icalcomponent_get_uid(icalcomponent* comp); 1971enum icalproperty_status icalcomponent_get_status(icalcomponent* comp){
1972 icalcomponent *inner;
1973 icalproperty *prop;
1974 icalerror_check_arg_rz(comp!=0,"comp");
1445 1975
1446void icalcomponent_set_recurrenceid(icalcomponent* comp, 1976 inner = icalcomponent_get_inner(comp);
1447 struct icaltimetype v);
1448struct icaltimetype icalcomponent_get_recurrenceid(icalcomponent* comp);
1449 1977
1978 if(inner == 0){
1979 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
1980 return 0;
1981 }
1450 1982
1983 prop= icalcomponent_get_first_property(inner,ICAL_STATUS_PROPERTY);
1451 1984
1985 if (prop == 0){
1986 return 0;
1987 }
1988
1989 return icalproperty_get_status(prop);
1990}
1452 1991
1453icalcomponent* icalcomponent_new_vcalendar() 1992icalcomponent* icalcomponent_new_vcalendar()
1454{ 1993{
1455 return icalcomponent_new(ICAL_VCALENDAR_COMPONENT); 1994 return icalcomponent_new(ICAL_VCALENDAR_COMPONENT);
1456} 1995}
1457icalcomponent* icalcomponent_new_vevent() 1996icalcomponent* icalcomponent_new_vevent()
1458{ 1997{
1459 return icalcomponent_new(ICAL_VEVENT_COMPONENT); 1998 return icalcomponent_new(ICAL_VEVENT_COMPONENT);
1460} 1999}
1461icalcomponent* icalcomponent_new_vtodo() 2000icalcomponent* icalcomponent_new_vtodo()
1462{ 2001{
1463 return icalcomponent_new(ICAL_VTODO_COMPONENT); 2002 return icalcomponent_new(ICAL_VTODO_COMPONENT);
1464} 2003}
1465icalcomponent* icalcomponent_new_vjournal() 2004icalcomponent* icalcomponent_new_vjournal()
1466{ 2005{
1467 return icalcomponent_new(ICAL_VJOURNAL_COMPONENT); 2006 return icalcomponent_new(ICAL_VJOURNAL_COMPONENT);
1468} 2007}
1469icalcomponent* icalcomponent_new_valarm() 2008icalcomponent* icalcomponent_new_valarm()
1470{ 2009{
1471 return icalcomponent_new(ICAL_VALARM_COMPONENT); 2010 return icalcomponent_new(ICAL_VALARM_COMPONENT);
1472} 2011}
1473icalcomponent* icalcomponent_new_vfreebusy() 2012icalcomponent* icalcomponent_new_vfreebusy()
1474{ 2013{
1475 return icalcomponent_new(ICAL_VFREEBUSY_COMPONENT); 2014 return icalcomponent_new(ICAL_VFREEBUSY_COMPONENT);
1476} 2015}
1477icalcomponent* icalcomponent_new_vtimezone() 2016icalcomponent* icalcomponent_new_vtimezone()
1478{ 2017{
1479 return icalcomponent_new(ICAL_VTIMEZONE_COMPONENT); 2018 return icalcomponent_new(ICAL_VTIMEZONE_COMPONENT);
1480} 2019}
1481icalcomponent* icalcomponent_new_xstandard() 2020icalcomponent* icalcomponent_new_xstandard()
1482{ 2021{
1483 return icalcomponent_new(ICAL_XSTANDARD_COMPONENT); 2022 return icalcomponent_new(ICAL_XSTANDARD_COMPONENT);
1484} 2023}
1485icalcomponent* icalcomponent_new_xdaylight() 2024icalcomponent* icalcomponent_new_xdaylight()
1486{ 2025{
1487 return icalcomponent_new(ICAL_XDAYLIGHT_COMPONENT); 2026 return icalcomponent_new(ICAL_XDAYLIGHT_COMPONENT);
1488} 2027}
2028icalcomponent* icalcomponent_new_vagenda()
2029{
2030 return icalcomponent_new(ICAL_VAGENDA_COMPONENT);
2031}
2032icalcomponent* 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 */
2047void 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
2106static 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
2162static void
2163icalcomponent_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. */
2242static 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 */
2263static 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
2271static 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 */
2295void 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 */
2336icaltimezone* 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
2469void 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
2489const 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
2518struct 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
2563void 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}