summaryrefslogtreecommitdiffabout
path: root/libical/src/libical/icalcomponent.c
Unidiff
Diffstat (limited to 'libical/src/libical/icalcomponent.c') (more/less context) (ignore whitespace changes)
-rw-r--r--libical/src/libical/icalcomponent.c1891
1 files changed, 1499 insertions, 392 deletions
diff --git a/libical/src/libical/icalcomponent.c b/libical/src/libical/icalcomponent.c
index af0d3ec..fbd0492 100644
--- a/libical/src/libical/icalcomponent.c
+++ b/libical/src/libical/icalcomponent.c
@@ -6,3 +6,2 @@
6 6
7
8 (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org 7 (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
@@ -35,2 +34,4 @@
35#include "icaltime.h" 34#include "icaltime.h"
35#include "icalarray.h"
36#include "icaltimezone.h"
36#include "icalduration.h" 37#include "icalduration.h"
@@ -38,2 +39,3 @@
38#include "icalparser.h" 39#include "icalparser.h"
40#include "icalrestriction.h"
39 41
@@ -44,5 +46,4 @@
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
@@ -58,2 +59,9 @@ struct icalcomponent_impl
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};
@@ -64,8 +72,25 @@ void icalproperty_set_parent(icalproperty* property,
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{
@@ -79,10 +104,6 @@ void icalcomponent_add_children(struct icalcomponent_impl *impl,va_list args)
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 }
@@ -91,9 +112,11 @@ void icalcomponent_add_children(struct icalcomponent_impl *impl,va_list args)
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);
@@ -111,2 +134,4 @@ icalcomponent_new_impl (icalcomponent_kind kind)
111 comp->parent = 0; 134 comp->parent = 0;
135 comp->timezones = NULL;
136 comp->timezones_sorted = 1;
112 137
@@ -115,2 +140,4 @@ icalcomponent_new_impl (icalcomponent_kind kind)
115 140
141/** @brief Constructor
142 */
116icalcomponent* 143icalcomponent*
@@ -118,5 +145,7 @@ icalcomponent_new (icalcomponent_kind kind)
118{ 145{
119 return (icalcomponent*)icalcomponent_new_impl(kind); 146 return icalcomponent_new_impl(kind);
120} 147}
121 148
149/** @brief Constructor
150 */
122icalcomponent* 151icalcomponent*
@@ -126,3 +155,3 @@ icalcomponent_vanew (icalcomponent_kind kind, ...)
126 155
127 struct icalcomponent_impl *impl = icalcomponent_new_impl(kind); 156 icalcomponent *impl = icalcomponent_new_impl(kind);
128 157
@@ -136,5 +165,7 @@ icalcomponent_vanew (icalcomponent_kind kind, ...)
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)
@@ -144,6 +175,7 @@ icalcomponent* icalcomponent_new_from_string(char* str)
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;
@@ -152,3 +184,3 @@ icalcomponent* icalcomponent_new_clone(icalcomponent* component)
152 184
153 icalerror_check_arg_rz( (component!=0), "component"); 185 icalerror_check_arg_rz( (old!=0), "component");
154 186
@@ -182,5 +214,6 @@ icalcomponent* icalcomponent_new_clone(icalcomponent* component)
182 214
183 215/*** @brief Destructor
216 */
184void 217void
185icalcomponent_free (icalcomponent* component) 218icalcomponent_free (icalcomponent* c)
186{ 219{
@@ -188,5 +221,4 @@ icalcomponent_free (icalcomponent* component)
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
@@ -200,11 +232,14 @@ icalcomponent_free (icalcomponent* component)
200 232
201 if(component != 0 ){ 233 if(c != 0 ){
202 234
203 while( (prop=pvl_pop(c->properties)) != 0){ 235 if ( c->properties != 0 )
204 assert(prop != 0); 236 {
205 icalproperty_set_parent(prop,0); 237 while( (prop=pvl_pop(c->properties)) != 0){
206 icalproperty_free(prop); 238 assert(prop != 0);
207 } 239 icalproperty_set_parent(prop,0);
208 240 icalproperty_free(prop);
209 pvl_free(c->properties); 241 }
242 pvl_free(c->properties);
243 }
244
210 245
@@ -212,3 +247,3 @@ icalcomponent_free (icalcomponent* component)
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);
@@ -222,2 +257,5 @@ icalcomponent_free (icalcomponent* component)
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;
@@ -229,2 +267,3 @@ icalcomponent_free (icalcomponent* component)
229 c->id[0] = 'X'; 267 c->id[0] = 'X';
268 c->timezones = NULL;
230 269
@@ -235,3 +274,3 @@ icalcomponent_free (icalcomponent* component)
235char* 274char*
236icalcomponent_as_ical_string (icalcomponent* component) 275icalcomponent_as_ical_string (icalcomponent* impl)
237{ 276{
@@ -242,12 +281,16 @@ icalcomponent_as_ical_string (icalcomponent* component)
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
@@ -258,3 +301,3 @@ icalcomponent_as_ical_string (icalcomponent* component)
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");
@@ -269,3 +312,4 @@ icalcomponent_as_ical_string (icalcomponent* component)
269 312
270 313
314
271 for( itr = pvl_head(impl->properties); 315 for( itr = pvl_head(impl->properties);
@@ -273,5 +317,3 @@ icalcomponent_as_ical_string (icalcomponent* component)
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);
@@ -288,4 +330,3 @@ icalcomponent_as_ical_string (icalcomponent* component)
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);
@@ -293,2 +334,3 @@ icalcomponent_as_ical_string (icalcomponent* component)
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);
@@ -297,6 +339,6 @@ icalcomponent_as_ical_string (icalcomponent* component)
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
@@ -312,7 +354,4 @@ icalcomponent_is_valid (icalcomponent* component)
312{ 354{
313 struct icalcomponent_impl *impl = (struct icalcomponent_impl *)component; 355 if ( (strcmp(component->id,"comp") == 0) &&
314 356 component->kind != ICAL_NO_COMPONENT){
315
316 if ( (strcmp(impl->id,"comp") == 0) &&
317 impl->kind != ICAL_NO_COMPONENT){
318 return 1; 357 return 1;
@@ -326,6 +365,5 @@ icalcomponent_is_valid (icalcomponent* component)
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
@@ -333,3 +371,3 @@ icalcomponent_isa (icalcomponent* component)
333 { 371 {
334 return impl->kind; 372 return component->kind;
335 } 373 }
@@ -343,3 +381,3 @@ icalcomponent_isa_component (void* component)
343{ 381{
344 struct icalcomponent_impl *impl = (struct icalcomponent_impl *)component; 382 icalcomponent *impl = component;
345 383
@@ -355,17 +393,2 @@ icalcomponent_isa_component (void* component)
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
@@ -373,4 +396,2 @@ icalcomponent_add_property (icalcomponent* component, icalproperty* property)
373{ 396{
374 struct icalcomponent_impl *impl;
375
376 icalerror_check_arg_rv( (component!=0), "component"); 397 icalerror_check_arg_rv( (component!=0), "component");
@@ -378,4 +399,2 @@ icalcomponent_add_property (icalcomponent* component, icalproperty* 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");
@@ -384,9 +403,3 @@ icalcomponent_add_property (icalcomponent* component, icalproperty* property)
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}
@@ -397,5 +410,3 @@ icalcomponent_remove_property (icalcomponent* component, icalproperty* property)
397{ 410{
398 struct icalcomponent_impl *impl;
399 pvl_elem itr, next_itr; 411 pvl_elem itr, next_itr;
400 struct icalproperty_impl *pimpl;
401 412
@@ -404,6 +415,2 @@ icalcomponent_remove_property (icalcomponent* component, icalproperty* 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");
@@ -411,3 +418,3 @@ icalcomponent_remove_property (icalcomponent* component, icalproperty* property)
411 418
412 for( itr = pvl_head(impl->properties); 419 for( itr = pvl_head(component->properties);
413 itr != 0; 420 itr != 0;
@@ -419,7 +426,7 @@ icalcomponent_remove_property (icalcomponent* component, icalproperty* 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);
@@ -435,3 +442,2 @@ icalcomponent_count_properties (icalcomponent* component,
435 pvl_elem itr; 442 pvl_elem itr;
436 struct icalcomponent_impl *impl = (struct icalcomponent_impl*)component;
437 443
@@ -439,3 +445,3 @@ icalcomponent_count_properties (icalcomponent* component,
439 445
440 for( itr = pvl_head(impl->properties); 446 for( itr = pvl_head(component->properties);
441 itr != 0; 447 itr != 0;
@@ -456,7 +462,5 @@ icalproperty* icalcomponent_get_current_property (icalcomponent* component)
456{ 462{
457
458 struct icalcomponent_impl *c = (struct icalcomponent_impl*)component;
459 icalerror_check_arg_rz( (component!=0),"component"); 463 icalerror_check_arg_rz( (component!=0),"component");
460 464
461 if ((c->property_iterator==0)){ 465 if ((component->property_iterator==0)){
462 return 0; 466 return 0;
@@ -464,4 +468,3 @@ icalproperty* icalcomponent_get_current_property (icalcomponent* component)
464 468
465 return (icalproperty*) pvl_data(c->property_iterator); 469 return (icalproperty*) pvl_data(component->property_iterator);
466
467} 470}
@@ -469,6 +472,5 @@ icalproperty* icalcomponent_get_current_property (icalcomponent* component)
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
@@ -489,6 +491,5 @@ icalcomponent_get_first_property (icalcomponent* component, icalproperty_kind ki
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
@@ -521,4 +522,2 @@ icalcomponent_add_component (icalcomponent* parent, icalcomponent* child)
521{ 522{
522 struct icalcomponent_impl *impl, *cimpl;
523
524 icalerror_check_arg_rv( (parent!=0), "parent"); 523 icalerror_check_arg_rv( (parent!=0), "parent");
@@ -526,6 +525,3 @@ icalcomponent_add_component (icalcomponent* parent, icalcomponent* 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);
@@ -533,5 +529,18 @@ icalcomponent_add_component (icalcomponent* parent, icalcomponent* child)
533 529
534 cimpl->parent = parent; 530 child->parent = parent;
531
532 pvl_push(parent->components,child);
535 533
536 pvl_push(impl->components,child); 534 /* If the new component is a VTIMEZONE, add it to our array. */
535 if (child->kind == ICAL_VTIMEZONE_COMPONENT) {
536 /* FIXME: Currently we are also creating this array when loading in
537 a builtin VTIMEZONE, when we don't need it. */
538 if (!parent->timezones)
539 parent->timezones = icaltimezone_array_new ();
540
541 icaltimezone_array_append_from_vtimezone (parent->timezones, child);
542
543 /* Flag that we need to sort it before doing any binary searches. */
544 parent->timezones_sorted = 0;
545 }
537} 546}
@@ -542,3 +551,2 @@ icalcomponent_remove_component (icalcomponent* parent, icalcomponent* child)
542{ 551{
543 struct icalcomponent_impl *impl,*cimpl;
544 pvl_elem itr, next_itr; 552 pvl_elem itr, next_itr;
@@ -548,6 +556,19 @@ icalcomponent_remove_component (icalcomponent* parent, icalcomponent* child)
548 556
549 impl = (struct icalcomponent_impl*)parent; 557 /* If the component is a VTIMEZONE, remove it from our array as well. */
550 cimpl = (struct icalcomponent_impl*)child; 558 if (child->kind == ICAL_VTIMEZONE_COMPONENT) {
551 559 icaltimezone *zone;
552 for( itr = pvl_head(impl->components); 560 int i, num_elements;
561
562 num_elements = parent->timezones ? parent->timezones->num_elements : 0;
563 for (i = 0; i < num_elements; i++) {
564 zone = icalarray_element_at (parent->timezones, i);
565 if (icaltimezone_get_component (zone) == child) {
566 icaltimezone_free (zone, 0);
567 icalarray_remove_element_at (parent->timezones, i);
568 break;
569 }
570 }
571 }
572
573 for( itr = pvl_head(parent->components);
553 itr != 0; 574 itr != 0;
@@ -559,3 +580,3 @@ icalcomponent_remove_component (icalcomponent* parent, icalcomponent* 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 */
@@ -563,8 +584,8 @@ icalcomponent_remove_component (icalcomponent* parent, icalcomponent* child)
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;
@@ -581,3 +602,2 @@ icalcomponent_count_components (icalcomponent* component,
581 pvl_elem itr; 602 pvl_elem itr;
582 struct icalcomponent_impl *impl = (struct icalcomponent_impl*)component;
583 603
@@ -585,3 +605,3 @@ icalcomponent_count_components (icalcomponent* component,
585 605
586 for( itr = pvl_head(impl->components); 606 for( itr = pvl_head(component->components);
587 itr != 0; 607 itr != 0;
@@ -601,7 +621,5 @@ icalcomponent_get_current_component(icalcomponent* component)
601{ 621{
602 struct icalcomponent_impl *c = (struct icalcomponent_impl*)component;
603
604 icalerror_check_arg_rz( (component!=0),"component"); 622 icalerror_check_arg_rz( (component!=0),"component");
605 623
606 if (c->component_iterator == 0){ 624 if (component->component_iterator == 0){
607 return 0; 625 return 0;
@@ -609,3 +627,3 @@ icalcomponent_get_current_component(icalcomponent* component)
609 627
610 return (icalcomponent*) pvl_data(c->component_iterator); 628 return (icalcomponent*) pvl_data(component->component_iterator);
611} 629}
@@ -613,8 +631,6 @@ icalcomponent_get_current_component(icalcomponent* component)
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
@@ -637,7 +653,5 @@ icalcomponent_get_first_component (icalcomponent* component,
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
@@ -675,3 +689,5 @@ icalcomponent* icalcomponent_get_first_real_component(icalcomponent *c)
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;
@@ -682,61 +698,27 @@ icalcomponent* icalcomponent_get_first_real_component(icalcomponent *c)
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 699
701 if(sict.is_utc == 1){ 700 /**@brief Get the timespan covered by this component, in UTC
702 /* _as_timet will use gmtime() to do the conversion */ 701 *(deprecated)
703 convt = icaltime_as_timet(sict); 702 *
704 703 * see icalcomponent_foreach_recurrence() for a better way to
705#ifdef TEST_CONVERT_TIME 704 * extract spans from an component.
706 printf("convert time: use as_timet:\n %s\n %s", 705 *
707 icalproperty_as_ical_string(p), ctime(&convt)); 706 *This method can be called on either a VCALENDAR or any real
708#endif 707 *component. If the VCALENDAR contains no real component, but
709 708 *contains a VTIMEZONE, we return that span instead.
710 } else if (sict.is_utc == 0 && tzp == 0 ) { 709 *This might not be a desirable behavior; we keep it for now
711 time_t offset; 710 *for backward compatibility, but it might be deprecated at a
712 711 *future time.
713 /* _as_timet will use localtime() to do the conversion */ 712 *
714 convt = icaltime_as_timet(sict); 713 *FIXME this API needs to be clarified. DTEND is defined as the
715 offset = icaltime_utc_offset(sict,0); 714 *first available time after the end of this event, so the span
716 convt += offset; 715 *should actually end 1 second before DTEND.
717 716 */
718#ifdef TEST_CONVERT_TIME 717
719 printf("convert time: use as_timet and adjust:\n %s\n %s", 718icaltime_span icalcomponent_get_span(icalcomponent* comp)
720 icalproperty_as_ical_string(p), ctime(&convt));
721#endif
722 } else {
723 /* Convert the time to UTC for the named timezone*/
724 const char* timezone = icalparameter_get_tzid(tzp);
725 convt = icaltime_as_timet(icaltime_as_utc(sict,timezone));
726
727#ifdef TEST_CONVERT_TIME
728 printf("convert time: use _as_utc:\n %s\n %s",
729 icalproperty_as_ical_string(p), ctime(&convt));
730#endif
731 }
732
733 return convt;
734}
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
@@ -747,7 +729,8 @@ struct icaltime_span icalcomponent_get_span(icalcomponent* comp)
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){
@@ -783,63 +766,325 @@ struct icaltime_span icalcomponent_get_span(icalcomponent* comp)
783 766
767 /* Get to work. starting with DTSTART */
768 start = icalcomponent_get_dtstart(comp);
769 if (icaltime_is_null_time(start)) {
770 return span;
771 }
772 span.start = icaltime_as_timet_with_zone(start,
773 icaltimezone_get_utc_timezone());
784 774
775 /* The end time could be specified as either a DTEND or a DURATION */
776 /* icalcomponent_get_dtend takes care of these cases. */
777 end = icalcomponent_get_dtend(comp);
778 if (icaltime_is_null_time(end)) {
779 if (!icaltime_is_date(start)) {
780 /* If dtstart is a DATE-TIME and there is no DTEND nor DURATION
781 it takes no time */
782 span.start = 0;
783 return span;
784 } else {
785 end = start;
786 }
787 }
785 788
786 /* Get to work. starting with DTSTART */ 789 span.end = icaltime_as_timet_with_zone(end,
790 icaltimezone_get_utc_timezone());
791 if (icaltime_is_date(start)) {
792 /* Until the end of the day*/
793 span.end += 60*60*24 - 1;
794 }
787 795
788 p = icalcomponent_get_first_property(inner, ICAL_DTSTART_PROPERTY); 796 return span;
789 797
790 if (p ==0 ) { 798}
791 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); 799
792 /*icalerror_warn("icalcomponent_get_span: component has no DTSTART time");*/ 800/**
793 return span; 801 * Decide if this recurrance is acceptable
802 *
803 * @param comp A valid icalcomponent.
804 * @param dtstart The base dtstart value for this component.
805 * @param recurtime The time to test against.
806 *
807 * @return true if the recurrence value is excluded, false otherwise.
808 *
809 * This function decides if a specific recurrence value is
810 * excluded by EXRULE or EXDATE properties.
811 *
812 * It's not the most efficient code. You might get better performance
813 * if you assume that recurtime is always increasing for each
814 * call. Then you could:
815 *
816 * - sort the EXDATE values
817 * - save the state of each EXRULE iterator for the next call.
818 *
819 * In this case though you don't need to worry how you call this
820 * function. It will always return the correct result.
821 */
822
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;
834
835 /** first test against the exdate values **/
836 for (exdate = icalcomponent_get_first_property(comp,ICAL_EXDATE_PROPERTY);
837 exdate != NULL;
838 exdate = icalcomponent_get_next_property(comp,ICAL_EXDATE_PROPERTY)) {
839
840 struct icaltimetype exdatetime = icalproperty_get_exdate(exdate);
841
842 if (icaltime_compare(*recurtime, exdatetime) == 0) {
843 /** MATCHED **/
844 return 1;
845 }
846 }
847
848 /** Now test against the EXRULEs **/
849 for (exrule = icalcomponent_get_first_property(comp,ICAL_EXRULE_PROPERTY);
850 exdate != NULL;
851 exdate = icalcomponent_get_next_property(comp,ICAL_EXRULE_PROPERTY)) {
852
853 struct icalrecurrencetype recur = icalproperty_get_exrule(exrule);
854 icalrecur_iterator *exrule_itr = icalrecur_iterator_new(recur, *dtstart);
855 struct icaltimetype exrule_time;
856
857 while (1) {
858 int result;
859 exrule_time = icalrecur_iterator_next(exrule_itr);
860
861 if (icaltime_is_null_time(exrule_time))
862 break;
863
864 result = icaltime_compare(*recurtime, exrule_time);
865 if (result == 0) {
866 icalrecur_iterator_free(exrule_itr);
867 return 1; /** MATCH **/
868 }
869 if (result == 1)
870 break; /** exrule_time > recurtime **/
794 } 871 }
795 872
873 icalrecur_iterator_free(exrule_itr);
874 }
796 875
797 start = icalproperty_get_dtstart(p); 876 return 0; /** no matches **/
877}
798 878
799 icalerror_clear_errno(); 879/**
880 * @brief Return the busy status based on the TRANSP property.
881 *
882 * @param comp A valid icalcomponent.
883 *
884 * @return 1 if the event is a busy item, 0 if it is not.
885 */
800 886
801 span.start = icalcomponent_convert_time(p); 887static int icalcomponent_is_busy(icalcomponent *comp) {
888 icalproperty *transp;
889 enum icalproperty_status status;
890 int ret = 1;
802 891
803#ifdef TEST_CONVERT_TIME 892 /** @todo check access control here, converting busy->free if the
804 printf("convert time:\n %s %s", 893 permissions do not allow access... */
805 icalproperty_as_ical_string(p), ctime(&span.start));
806#endif
807 894
808 if(icalerrno != ICAL_NO_ERROR){ 895 /* Is this a busy time? Check the TRANSP property */
809 span.start = 0; 896 transp = icalcomponent_get_first_property(comp, ICAL_TRANSP_PROPERTY);
810 return span; 897
898 if (transp) {
899 icalvalue *transp_val = icalproperty_get_value(transp);
900
901 switch (icalvalue_get_transp(transp_val)) {
902 case ICAL_TRANSP_OPAQUE:
903 case ICAL_TRANSP_OPAQUENOCONFLICT:
904 case ICAL_TRANSP_NONE:
905 ret = 1;
906 break;
907 case ICAL_TRANSP_TRANSPARENT:
908 case ICAL_TRANSP_TRANSPARENTNOCONFLICT:
909 ret = 0;
910 break;
911 default:
912 ret = 0;
913 break;
811 } 914 }
915 }
916 status = icalcomponent_get_status(comp);
917 if (ret && status) {
918 switch (status) {
919 case ICAL_STATUS_CANCELLED:
920 case ICAL_STATUS_TENTATIVE:
921 ret = 0;
922 break;
923 default:
924 break;
925 }
926 }
927 return(ret);
928}
812 929
813 /* The end time could be specified as either a DTEND or a DURATION */
814 p = icalcomponent_get_first_property(inner, ICAL_DTEND_PROPERTY);
815 duration = icalcomponent_get_first_property(inner, ICAL_DURATION_PROPERTY);
816 930
817 if (p==0 && duration == 0 && start.is_date != 1) {
818 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
819 /*icalerror_warn("icalcomponent_get_span: component has neither DTEND nor DURATION time");*/
820 span.start = 0;
821 return span;
822 }
823 931
824 if (p!=0){
825 span.end = icalcomponent_convert_time(p);
826 } else if (start.is_date == 1) {
827 /* Duration is all day */
828 span.end = span.start + 60*60*24;
829 } else {
830 /* Use the duration */
831 struct icaldurationtype dur;
832 time_t durt;
833
834
835 dur = icalproperty_get_duration(duration);
836 932
837 durt = icaldurationtype_as_int(dur); 933/**
838 span.end = span.start+durt; 934 * @brief cycle through all recurrances of an event
935 *
936 * @param comp A valid VEVENT component
937 * @param start Ignore timespans before this
938 * @param end Ignore timespans after this
939 * @param callback Function called for each timespan within the range
940 * @param callback_data Pointer passed back to the callback function
941 *
942 * This function will call the specified callback function for once
943 * for the base value of DTSTART, and foreach recurring date/time
944 * value.
945 *
946 * It will filter out events that are specified as an EXDATE or an EXRULE.
947 *
948 * @todo We do not filter out duplicate RRULES/RDATES
949 * @todo We do not handle RDATEs with explicit periods
950 */
951
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;
965 struct icaldurationtype dur;
966 pvl_elem property_iterator;/* for saving the iterator */
967
968 if (comp == NULL || callback == NULL)
969 return;
970
971 dtstart = icalcomponent_get_dtstart(comp);
972
973 if (icaltime_is_null_time(dtstart))
974 return;
975
976
977 /* The end time could be specified as either a DTEND or a DURATION */
978 /* icalcomponent_get_dtend takes care of these cases. */
979 dtend = icalcomponent_get_dtend(comp);
980
981 /* Now set up the base span for this item, corresponding to the
982 base DTSTART and DTEND */
983 basespan = icaltime_span_new(dtstart, dtend, 1);
984
985 basespan.is_busy = icalcomponent_is_busy(comp);
986
987
988 /** Calculate the ceiling and floor values.. **/
989 limit_start = icaltime_as_timet_with_zone(start, icaltimezone_get_utc_timezone());
990 if (!icaltime_is_null_time(end))
991 limit_end = icaltime_as_timet_with_zone(end, icaltimezone_get_utc_timezone());
992 else
993 limit_end = INT_MAX; /* max 32 bit time_t */
994
995 limit_span.start = limit_start;
996 limit_span.end = limit_end;
997
998
999 /* Do the callback for the initial DTSTART entry */
1000
1001 if (!icalproperty_recurrence_is_excluded(comp, &dtstart, &dtstart)) {
1002 /** call callback action **/
1003 if (icaltime_span_overlaps(&basespan, &limit_span))
1004 (*callback) (comp, &basespan, callback_data);
1005 }
1006
1007 recurspan = basespan;
1008 dtduration = basespan.end - basespan.start;
1009
1010 /* Now cycle through the rrule entries */
1011 for (rrule = icalcomponent_get_first_property(comp,ICAL_RRULE_PROPERTY);
1012 rrule != NULL;
1013 rrule = icalcomponent_get_next_property(comp,ICAL_RRULE_PROPERTY)) {
1014
1015 struct icalrecurrencetype recur = icalproperty_get_rrule(rrule);
1016 icalrecur_iterator *rrule_itr = icalrecur_iterator_new(recur, dtstart);
1017 struct icaltimetype rrule_time = icalrecur_iterator_next(rrule_itr);
1018 /** note that icalrecur_iterator_next always returns dtstart
1019 the first time.. **/
1020
1021 while (1) {
1022 rrule_time = icalrecur_iterator_next(rrule_itr);
1023
1024 if (icaltime_is_null_time(rrule_time))
1025 break;
1026
1027 dur = icaltime_subtract(rrule_time, dtstart);
1028
1029 recurspan.start = basespan.start + icaldurationtype_as_int(dur);
1030 recurspan.end = recurspan.start + dtduration;
1031
1032 /** save the iterator ICK! **/
1033 property_iterator = comp->property_iterator;
1034
1035 if (!icalproperty_recurrence_is_excluded(comp, &dtstart, &rrule_time)) {
1036 /** call callback action **/
1037 if (icaltime_span_overlaps(&recurspan, &limit_span))
1038 (*callback) (comp, &recurspan, callback_data);
1039 }
1040 comp->property_iterator = property_iterator;
1041 } /* end of iteration over a specific RRULE */
1042
1043 icalrecur_iterator_free(rrule_itr);
1044 } /* end of RRULE loop */
1045
1046
1047 /** Now process RDATE entries **/
1048 for (rdate = icalcomponent_get_first_property(comp,ICAL_RDATE_PROPERTY);
1049 rdate != NULL;
1050 rdate = icalcomponent_get_next_property(comp,ICAL_RDATE_PROPERTY)) {
1051
1052 struct icaldatetimeperiodtype rdate_period = icalproperty_get_rdate(rdate);
1053
1054 /** RDATES can specify raw datetimes, periods, or dates.
1055 we only support raw datetimes for now..
1056
1057 @todo Add support for other types **/
1058
1059 if (icaltime_is_null_time(rdate_period.time))
1060 continue;
1061
1062 dur = icaltime_subtract(rdate_period.time, dtstart);
1063
1064 recurspan.start = basespan.start + icaldurationtype_as_int(dur);
1065 recurspan.end = recurspan.start + dtduration;
1066
1067 /** save the iterator ICK! **/
1068 property_iterator = comp->property_iterator;
1069
1070 if (!icalproperty_recurrence_is_excluded(comp, &dtstart, &rdate_period.time)) {
1071 /** call callback action **/
1072 (*callback) (comp, &recurspan, callback_data);
839 } 1073 }
1074 comp->property_iterator = property_iterator;
1075 }
1076}
1077
840 1078
841 return span;
842 1079
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
@@ -851,5 +1096,4 @@ int icalcomponent_count_errors(icalcomponent* component)
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;
@@ -866,3 +1110,3 @@ int icalcomponent_count_errors(icalcomponent* component)
866 1110
867 for( itr = pvl_head(impl->components); 1111 for( itr = pvl_head(component->components);
868 itr != 0; 1112 itr != 0;
@@ -885,5 +1129,4 @@ void icalcomponent_strip_errors(icalcomponent* component)
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;
@@ -900,3 +1143,3 @@ void icalcomponent_strip_errors(icalcomponent* component)
900 1143
901 for( itr = pvl_head(impl->components); 1144 for( itr = pvl_head(component->components);
902 itr != 0; 1145 itr != 0;
@@ -954,2 +1197,3 @@ void icalcomponent_convert_errors(icalcomponent* component)
954 default: { 1197 default: {
1198 break;
955 } 1199 }
@@ -978,5 +1222,3 @@ icalcomponent* icalcomponent_get_parent(icalcomponent* component)
978{ 1222{
979 struct icalcomponent_impl *c = (struct icalcomponent_impl*)component; 1223 return component->parent;
980
981 return c->parent;
982} 1224}
@@ -985,5 +1227,3 @@ void icalcomponent_set_parent(icalcomponent* component, icalcomponent* parent)
985{ 1227{
986 struct icalcomponent_impl *c = (struct icalcomponent_impl*)component; 1228 component->parent = parent;
987
988 c->parent = parent;
989} 1229}
@@ -1006,2 +1246,3 @@ static struct icalcomponent_kind_map component_map[] =
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" },
@@ -1030,2 +1271,12 @@ static struct icalcomponent_kind_map component_map[] =
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
@@ -1067,4 +1318,3 @@ icalcomponent_begin_component(icalcomponent* component,icalcomponent_kind kind)
1067{ 1318{
1068 struct icalcomponent_impl *impl = (struct icalcomponent_impl*)component; 1319 icalcompiter itr;
1069 icalcompiter itr = icalcompiter_null;
1070 pvl_elem i; 1320 pvl_elem i;
@@ -1072,6 +1322,7 @@ icalcomponent_begin_component(icalcomponent* component,icalcomponent_kind kind)
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
@@ -1093,3 +1344,2 @@ icalcomponent_end_component(icalcomponent* component,icalcomponent_kind kind)
1093{ 1344{
1094 struct icalcomponent_impl *impl = (struct icalcomponent_impl*)component;
1095 icalcompiter itr; 1345 icalcompiter itr;
@@ -1099,5 +1349,5 @@ icalcomponent_end_component(icalcomponent* component,icalcomponent_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
@@ -1182,10 +1432,56 @@ icalcomponent* icalcomponent_get_inner(icalcomponent* comp)
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
@@ -1194,2 +1490,4 @@ void icalcomponent_set_dtstart(icalcomponent* comp, struct icaltimetype 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 }
@@ -1198,5 +1496,46 @@ void icalcomponent_set_dtstart(icalcomponent* comp, struct icaltimetype 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;
1516
1517 ret = icalvalue_get_datetime(icalproperty_get_value(prop));
1518
1519 if ((param = icalproperty_get_first_parameter(prop, ICAL_TZID_PARAMETER))
1520 != NULL) {
1521 const char *tzid = icalparameter_get_tzid(param);
1522 icaltimezone *tz;
1523
1524 if ((tz = icalcomponent_get_timezone(comp, tzid)) != NULL) {
1525 icaltime_set_timezone(&ret, tz);
1526 }
1527 }
1528
1529 return ret;
1530}
1201 1531
1532 /**@brief Get DTSTART property as an icaltime
1533 *
1534 *If DTSTART is a DATE-TIME with a timezone parameter and a
1535 *corresponding VTIMEZONE is present in the component, the
1536 *returned component will already be in the correct timezone;
1537 *otherwise the caller is responsible for converting it.
1538 *
1539 *FIXME this is useless until we can flag the failure
1540 */
1202struct icaltimetype icalcomponent_get_dtstart(icalcomponent* comp) 1541struct icaltimetype icalcomponent_get_dtstart(icalcomponent* comp)
@@ -1204,5 +1543,5 @@ struct icaltimetype icalcomponent_get_dtstart(icalcomponent* comp)
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){
@@ -1210,7 +1549,18 @@ struct icaltimetype icalcomponent_get_dtstart(icalcomponent* comp)
1210 } 1549 }
1211
1212 return icalproperty_get_dtstart(prop);
1213}
1214 1550
1551 return icalcomponent_get_datetime(comp, prop);
1552}
1215 1553
1554 /**@brief Get DTEND property as an icaltime
1555 *
1556 *If a DTEND property is not present but a DURATION is, we use
1557 *that to determine the proper end.
1558 *
1559 *If DTSTART is a DATE-TIME with a timezone parameter and a
1560 *corresponding VTIMEZONE is present in the component, the
1561 *returned component will already be in the correct timezone;
1562 *otherwise the caller is responsible for converting it.
1563 *
1564 *FIXME this is useless until we can flag the failure
1565 */
1216struct icaltimetype icalcomponent_get_dtend(icalcomponent* comp) 1566struct icaltimetype icalcomponent_get_dtend(icalcomponent* comp)
@@ -1218,16 +1568,12 @@ struct icaltimetype icalcomponent_get_dtend(icalcomponent* comp)
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 =
@@ -1236,48 +1582,42 @@ struct icaltimetype icalcomponent_get_dtend(icalcomponent* comp)
1236 icalproperty_get_duration(dur_prop); 1582 icalproperty_get_duration(dur_prop);
1237
1238 struct icaltimetype end = icaltime_add(start,duration);
1239 1583
1240 return end; 1584 struct icaltimetype end = icaltime_add(start,duration);
1241
1242 } else {
1243 /* Error, both duration and dtend have been specified */
1244 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
1245 return icaltime_null_time();
1246 1585
1586 ret = end;
1247 } 1587 }
1248
1249}
1250 1588
1589 return ret;
1590}
1251 1591
1592 /**@brief Set DTEND property to given icaltime
1593 *
1594 *This method respects the icaltime type (DATE vs DATE-TIME) and
1595 *timezone (or lack thereof).
1596 *
1597 *This also checks that a DURATION property isn't already there,
1598 *and returns an error if it is. It's the caller's responsibility
1599 *to remove it.
1600 */
1252void icalcomponent_set_dtend(icalcomponent* comp, struct icaltimetype v) 1601void icalcomponent_set_dtend(icalcomponent* comp, struct icaltimetype v)
1253{ 1602{
1254 icalcomponent *inner = icalcomponent_get_inner(comp); 1603 char *tzid;
1255 1604 ICALSETUPSET(ICAL_DTEND_PROPERTY);
1256 icalproperty *end_prop
1257 = icalcomponent_get_first_property(inner,ICAL_DTEND_PROPERTY);
1258
1259 icalproperty *dur_prop
1260 = icalcomponent_get_first_property(inner,ICAL_DURATION_PROPERTY);
1261
1262 1605
1263 if( end_prop == 0 && dur_prop == 0){ 1606 if (icalcomponent_get_first_property(inner,ICAL_DURATION_PROPERTY)
1264 end_prop = icalproperty_new_dtend(v); 1607 != NULL) {
1265 icalcomponent_add_property(inner,end_prop); 1608 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
1266 } else if ( end_prop != 0) { 1609 return;
1267 icalproperty_set_dtend(end_prop,v); 1610 }
1268 } else if ( dur_prop != 0) {
1269 struct icaltimetype start =
1270 icalcomponent_get_dtstart(inner);
1271
1272 struct icaltimetype end =
1273 icalcomponent_get_dtend(inner);
1274 1611
1275 struct icaldurationtype dur 1612 if (prop == 0) {
1276 = icaltime_subtract(end,start); 1613 prop = icalproperty_new_dtend(v);
1614 icalcomponent_add_property(inner, prop);
1615 } else {
1616 icalproperty_remove_parameter_by_kind(prop, ICAL_TZID_PARAMETER);
1617 }
1277 1618
1278 icalproperty_set_duration(dur_prop,dur); 1619 icalproperty_set_dtend(prop,v);
1279 1620
1280 } else { 1621 if ((tzid = icaltime_get_tzid(v)) != NULL && !icaltime_is_utc(v)) {
1281 /* Error, both duration and dtend have been specified */ 1622 icalproperty_add_parameter(prop, icalparameter_new_tzid(tzid));
1282 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
1283 } 1623 }
@@ -1285,2 +1625,11 @@ void icalcomponent_set_dtend(icalcomponent* comp, struct icaltimetype v)
1285 1625
1626 /**@brief Set DURATION property to given icalduration
1627 *
1628 *This method respects the icaltime type (DATE vs DATE-TIME) and
1629 *timezone (or lack thereof).
1630 *
1631 *This also checks that a DTEND property isn't already there,
1632 *and returns an error if it is. It's the caller's responsibility
1633 *to remove it.
1634 */
1286void icalcomponent_set_duration(icalcomponent* comp, 1635void icalcomponent_set_duration(icalcomponent* comp,
@@ -1288,27 +1637,14 @@ void icalcomponent_set_duration(icalcomponent* comp,
1288{ 1637{
1289 icalcomponent *inner = icalcomponent_get_inner(comp); 1638 ICALSETUPSET(ICAL_DURATION_PROPERTY);
1290
1291 icalproperty *end_prop
1292 = icalcomponent_get_first_property(inner,ICAL_DTEND_PROPERTY);
1293
1294 icalproperty *dur_prop
1295 = icalcomponent_get_first_property(inner,ICAL_DURATION_PROPERTY);
1296
1297
1298 if( end_prop == 0 && dur_prop == 0){
1299 dur_prop = icalproperty_new_duration(v);
1300 icalcomponent_add_property(inner, dur_prop);
1301 } else if ( end_prop != 0) {
1302 struct icaltimetype start =
1303 icalcomponent_get_dtstart(inner);
1304
1305 struct icaltimetype new_end = icaltime_add(start,v);
1306 1639
1307 icalproperty_set_dtend(end_prop,new_end); 1640 if (icalcomponent_get_first_property(inner,ICAL_DTEND_PROPERTY) != NULL) {
1641 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
1642 return;
1643 }
1308 1644
1309 } else if ( dur_prop != 0) { 1645 if (prop == 0) {
1310 icalproperty_set_duration(dur_prop,v); 1646 prop = icalproperty_new_duration(v);
1647 icalcomponent_add_property(inner, prop);
1311 } else { 1648 } else {
1312 /* Error, both duration and dtend have been specified */ 1649 icalproperty_set_duration(prop,v);
1313 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
1314 } 1650 }
@@ -1316,2 +1652,7 @@ void icalcomponent_set_duration(icalcomponent* comp,
1316 1652
1653 /**@brief Get DURATION property as an icalduration
1654 *
1655 *If a DURATION property is not present but a DTEND is, we use
1656 *that to determine the proper end.
1657 */
1317struct icaldurationtype icalcomponent_get_duration(icalcomponent* comp) 1658struct icaldurationtype icalcomponent_get_duration(icalcomponent* comp)
@@ -1326,20 +1667,19 @@ struct icaldurationtype icalcomponent_get_duration(icalcomponent* comp)
1326 1667
1327 struct icaldurationtype null_duration; 1668 struct icaldurationtype ret = icaldurationtype_null_duration();
1328 memset(&null_duration,0,sizeof(struct icaldurationtype));
1329 1669
1670 if ( dur_prop != 0 && end_prop == 0) {
1671 ret = icalproperty_get_duration(dur_prop);
1330 1672
1331 if( end_prop == 0 && dur_prop == 0){ 1673 } else if ( end_prop != 0 && dur_prop == 0) {
1332 return null_duration; 1674 /**
1333 } else if ( end_prop != 0) { 1675 * FIXME
1676 * We assume DTSTART and DTEND are not in different time zones.
1677 * Does the standard actually guarantee this?
1678 */
1334 struct icaltimetype start = 1679 struct icaltimetype start =
1335 icalcomponent_get_dtstart(inner); 1680 icalcomponent_get_dtstart(inner);
1336 time_t startt = icaltime_as_timet(start);
1337
1338 struct icaltimetype end = 1681 struct icaltimetype end =
1339 icalcomponent_get_dtend(inner); 1682 icalcomponent_get_dtend(inner);
1340 time_t endt = icaltime_as_timet(end); 1683
1341 1684 ret = icaltime_subtract(end, start);
1342 return icaldurationtype_from_int(endt-startt);
1343 } else if ( dur_prop != 0) {
1344 return icalproperty_get_duration(dur_prop);
1345 } else { 1685 } else {
@@ -1347,18 +1687,17 @@ struct icaldurationtype icalcomponent_get_duration(icalcomponent* comp)
1347 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); 1687 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
1348 return null_duration;
1349 } 1688 }
1689 return ret;
1350} 1690}
1351 1691
1352void icalcomponent_set_method(icalcomponent* comp, icalproperty_method method) 1692void icalcomponent_set_dtstamp(icalcomponent* comp, struct icaltimetype v)
1353{ 1693{
1354 icalproperty *prop
1355 = icalcomponent_get_first_property(comp, ICAL_METHOD_PROPERTY);
1356 1694
1695 ICALSETUPSET(ICAL_DTSTAMP_PROPERTY);
1357 1696
1358 if (prop == 0){ 1697 if (prop == 0){
1359 prop = icalproperty_new_method(method); 1698 prop = icalproperty_new_dtstamp(v);
1360 icalcomponent_add_property(comp, prop); 1699 icalcomponent_add_property(inner, prop);
1361 } 1700 }
1362 1701
1363 icalproperty_set_method(prop,method); 1702 icalproperty_set_dtstamp(prop,v);
1364 1703
@@ -1366,28 +1705,50 @@ void icalcomponent_set_method(icalcomponent* comp, icalproperty_method method)
1366 1705
1367icalproperty_method icalcomponent_get_method(icalcomponent* comp) 1706
1707struct icaltimetype icalcomponent_get_dtstamp(icalcomponent* comp)
1368{ 1708{
1709 icalcomponent *inner = icalcomponent_get_inner(comp);
1369 icalproperty *prop 1710 icalproperty *prop
1370 = icalcomponent_get_first_property(comp,ICAL_METHOD_PROPERTY); 1711 = icalcomponent_get_first_property(inner,ICAL_DTSTAMP_PROPERTY);
1371 1712
1372 if (prop == 0){ 1713 if (prop == 0){
1373 return ICAL_METHOD_NONE; 1714 return icaltime_null_time();
1374 } 1715 }
1375 1716
1376 return icalproperty_get_method(prop); 1717 return icalproperty_get_dtstamp(prop);
1377} 1718}
1378 1719
1379void icalcomponent_set_dtstamp(icalcomponent* comp, struct icaltimetype v) 1720
1721void icalcomponent_set_summary(icalcomponent* comp, const char* v)
1722{
1723 ICALSETUPSET(ICAL_SUMMARY_PROPERTY)
1724
1725 if (prop == 0){
1726 prop = icalproperty_new_summary(v);
1727 icalcomponent_add_property(inner, prop);
1728 }
1729
1730 icalproperty_set_summary(prop,v);
1731}
1732
1733
1734const char* icalcomponent_get_summary(icalcomponent* comp)
1380{ 1735{
1736 icalcomponent *inner;
1737 icalproperty *prop;
1738 icalerror_check_arg_rz(comp!=0,"comp");
1381 1739
1382 icalcomponent *inner = icalcomponent_get_inner(comp); 1740 inner = icalcomponent_get_inner(comp);
1383 icalproperty *prop 1741
1384 = icalcomponent_get_first_property(inner, ICAL_DTSTAMP_PROPERTY); 1742 if(inner == 0){
1743 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
1744 return 0;
1745 }
1385 1746
1747 prop= icalcomponent_get_first_property(inner,ICAL_SUMMARY_PROPERTY);
1386 1748
1387 if (prop == 0){ 1749 if (prop == 0){
1388 prop = icalproperty_new_dtstamp(v); 1750 return 0;
1389 icalcomponent_add_property(inner, prop);
1390 } 1751 }
1391 1752
1392 icalproperty_set_dtstamp(prop,v); 1753 return icalproperty_get_summary(prop);
1393 1754
@@ -1395,37 +1756,60 @@ void icalcomponent_set_dtstamp(icalcomponent* comp, struct icaltimetype v)
1395 1756
1396 1757void icalcomponent_set_comment(icalcomponent* comp, const char* v)
1397struct icaltimetype icalcomponent_get_dtstamp(icalcomponent* comp)
1398{ 1758{
1399 icalcomponent *inner = icalcomponent_get_inner(comp); 1759 ICALSETUPSET(ICAL_COMMENT_PROPERTY);
1400 icalproperty *prop
1401 = icalcomponent_get_first_property(inner,ICAL_DTSTAMP_PROPERTY);
1402 1760
1403 if (prop == 0){ 1761 if (prop == 0){
1404 return icaltime_null_time(); 1762 prop = icalproperty_new_comment(v);
1763 icalcomponent_add_property(inner, prop);
1405 } 1764 }
1406 1765
1407 return icalproperty_get_dtstamp(prop); 1766 icalproperty_set_summary(prop,v);
1767
1408} 1768}
1769const char* icalcomponent_get_comment(icalcomponent* comp){
1770 icalcomponent *inner;
1771 icalproperty *prop;
1772 icalerror_check_arg_rz(comp!=0,"comp");
1409 1773
1774 inner = icalcomponent_get_inner(comp);
1410 1775
1411void icalcomponent_set_summary(icalcomponent* comp, const char* v) 1776 if(inner == 0){
1777 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
1778 return 0;
1779 }
1780
1781 prop= icalcomponent_get_first_property(inner,ICAL_COMMENT_PROPERTY);
1782
1783 if (prop == 0){
1784 return 0;
1785 }
1786
1787 return icalproperty_get_comment(prop);
1788}
1789
1790void icalcomponent_set_uid(icalcomponent* comp, const char* v)
1412{ 1791{
1413 icalcomponent *inner = icalcomponent_get_inner(comp); 1792 ICALSETUPSET(ICAL_UID_PROPERTY);
1414 icalproperty *prop
1415 = icalcomponent_get_first_property(inner, ICAL_SUMMARY_PROPERTY);
1416 1793
1417 if (prop == 0){ 1794 if (prop == 0){
1418 prop = icalproperty_new_summary(v); 1795 prop = icalproperty_new_uid(v);
1419 icalcomponent_add_property(inner, prop); 1796 icalcomponent_add_property(inner, prop);
1420 } 1797 }
1421 1798
1422 icalproperty_set_summary(prop,v); 1799 icalproperty_set_summary(prop,v);
1800
1423} 1801}
1802const char* icalcomponent_get_uid(icalcomponent* comp){
1803 icalcomponent *inner;
1804 icalproperty *prop;
1805 icalerror_check_arg_rz(comp!=0,"comp");
1424 1806
1807 inner = icalcomponent_get_inner(comp);
1425 1808
1426const char* icalcomponent_get_summary(icalcomponent* comp) 1809 if(inner == 0){
1427{ 1810 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
1428 icalcomponent *inner = icalcomponent_get_inner(comp); 1811 return 0;
1429 icalproperty *prop 1812 }
1430 = icalcomponent_get_first_property(inner,ICAL_SUMMARY_PROPERTY); 1813
1814 prop= icalcomponent_get_first_property(inner,ICAL_UID_PROPERTY);
1431 1815
@@ -1435,18 +1819,173 @@ const char* icalcomponent_get_summary(icalcomponent* comp)
1435 1819
1436 return icalproperty_get_summary(prop); 1820 return icalproperty_get_uid(prop);
1821}
1437 1822
1823void icalcomponent_set_recurrenceid(icalcomponent* comp, struct icaltimetype v)
1824{
1825 ICALSETUPSET(ICAL_RECURRENCEID_PROPERTY);
1826
1827 if (prop == 0){
1828 prop = icalproperty_new_recurrenceid(v);
1829 icalcomponent_add_property(inner, prop);
1830 }
1831
1832 icalproperty_set_recurrenceid(prop,v);
1438} 1833}
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 }
1439 1842
1440void icalcomponent_set_comment(icalcomponent* comp, const char* v); 1843 inner = icalcomponent_get_inner(comp);
1441const char* icalcomponent_get_comment(icalcomponent* comp);
1442 1844
1443void icalcomponent_set_uid(icalcomponent* comp, const char* v); 1845 if(inner == 0){
1444const char* icalcomponent_get_uid(icalcomponent* comp); 1846 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
1847 return icaltime_null_time();
1848 }
1445 1849
1446void icalcomponent_set_recurrenceid(icalcomponent* comp, 1850 prop= icalcomponent_get_first_property(inner, ICAL_RECURRENCEID_PROPERTY);
1447 struct icaltimetype v);
1448struct icaltimetype icalcomponent_get_recurrenceid(icalcomponent* comp);
1449 1851
1852 if (prop == 0){
1853 return icaltime_null_time();
1854 }
1855
1856 return icalproperty_get_recurrenceid(prop);
1857}
1858
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);
1865 icalcomponent_add_property(inner, prop);
1866 }
1867
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);
1877
1878 if(inner == 0){
1879 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
1880 return 0;
1881 }
1882
1883 prop= icalcomponent_get_first_property(inner,ICAL_DESCRIPTION_PROPERTY);
1884
1885 if (prop == 0){
1886 return 0;
1887 }
1888
1889 return icalproperty_get_description(prop);
1890}
1891
1892void icalcomponent_set_location(icalcomponent* comp, const char* v)
1893{
1894 ICALSETUPSET(ICAL_LOCATION_PROPERTY)
1895
1896 if (prop == 0){
1897 prop = icalproperty_new_location(v);
1898 icalcomponent_add_property(inner, prop);
1899 }
1900
1901 icalproperty_set_location(prop,v);
1902}
1903const char* icalcomponent_get_location(icalcomponent* comp)
1904{
1905 icalcomponent *inner;
1906 icalproperty *prop;
1907 icalerror_check_arg_rz(comp!=0,"comp");
1908
1909 inner = icalcomponent_get_inner(comp);
1910
1911 if(inner == 0){
1912 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
1913 return 0;
1914 }
1915
1916 prop= icalcomponent_get_first_property(inner,ICAL_LOCATION_PROPERTY);
1450 1917
1918 if (prop == 0){
1919 return 0;
1920 }
1921
1922 return icalproperty_get_location(prop);
1923}
1924
1925void icalcomponent_set_sequence(icalcomponent* comp, int v)
1926{
1927 ICALSETUPSET(ICAL_SEQUENCE_PROPERTY);
1928
1929 if (prop == 0){
1930 prop = icalproperty_new_sequence(v);
1931 icalcomponent_add_property(inner, prop);
1932 }
1933
1934 icalproperty_set_sequence(prop,v);
1935
1936}
1937int icalcomponent_get_sequence(icalcomponent* comp){
1938 icalcomponent *inner;
1939 icalproperty *prop;
1940 icalerror_check_arg_rz(comp!=0,"comp");
1941
1942 inner = icalcomponent_get_inner(comp);
1943
1944 if(inner == 0){
1945 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
1946 return 0;
1947 }
1948
1949 prop= icalcomponent_get_first_property(inner,ICAL_SEQUENCE_PROPERTY);
1950
1951 if (prop == 0){
1952 return 0;
1953 }
1954
1955 return icalproperty_get_sequence(prop);
1956}
1957
1958
1959void icalcomponent_set_status(icalcomponent* comp, enum icalproperty_status v)
1960{
1961 ICALSETUPSET(ICAL_STATUS_PROPERTY);
1962
1963 if (prop == 0){
1964 prop = icalproperty_new_status(v);
1965 icalcomponent_add_property(inner, prop);
1966 }
1967
1968 icalproperty_set_status(prop,v);
1969
1970}
1971enum icalproperty_status icalcomponent_get_status(icalcomponent* comp){
1972 icalcomponent *inner;
1973 icalproperty *prop;
1974 icalerror_check_arg_rz(comp!=0,"comp");
1975
1976 inner = icalcomponent_get_inner(comp);
1977
1978 if(inner == 0){
1979 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
1980 return 0;
1981 }
1451 1982
1983 prop= icalcomponent_get_first_property(inner,ICAL_STATUS_PROPERTY);
1984
1985 if (prop == 0){
1986 return 0;
1987 }
1988
1989 return icalproperty_get_status(prop);
1990}
1452 1991
@@ -1488 +2027,569 @@ icalcomponent* icalcomponent_new_xdaylight()
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}