Back to index

lightning-sunbird  0.9+nobinonly
icalcomponent.c
Go to the documentation of this file.
00001 /*======================================================================
00002   FILE: icalcomponent.c
00003   CREATOR: eric 28 April 1999
00004   
00005   $Id: icalcomponent.c,v 1.57 2004/09/10 07:43:51 acampi Exp $
00006 
00007  (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
00008 
00009  This program is free software; you can redistribute it and/or modify
00010  it under the terms of either: 
00011 
00012     The LGPL as published by the Free Software Foundation, version
00013     2.1, available at: http://www.fsf.org/copyleft/lesser.html
00014 
00015   Or:
00016 
00017     The Mozilla Public License Version 1.0. You may obtain a copy of
00018     the License at http://www.mozilla.org/MPL/
00019 
00020   The original code is icalcomponent.c
00021 
00022 ======================================================================*/
00023 
00024 
00025 #ifdef HAVE_CONFIG_H
00026 #include "config.h"
00027 #endif
00028 
00029 #include "icalcomponent.h"
00030 #include "pvl.h" /* "Pointer-to-void list" */
00031 #include "icalerror.h"
00032 #include "icalmemory.h"
00033 #include "icalenums.h"
00034 #include "icaltime.h"
00035 #include "icalarray.h"
00036 #include "icaltimezone.h"
00037 #include "icalduration.h"
00038 #include "icalperiod.h"
00039 #include "icalparser.h"
00040 #include "icalrestriction.h"
00041 
00042 #include <stdlib.h>  /* for malloc */
00043 #include <stdarg.h> /* for va_list, etc */
00044 #include <errno.h>
00045 #include <assert.h>
00046 #include <stdio.h> /* for fprintf */
00047 #include <string.h> /* for strdup */
00048 #include <limits.h> /* for INT_MAX */
00049 
00050 struct icalcomponent_impl 
00051 {
00052        char id[5];
00053        icalcomponent_kind kind;
00054        char* x_name;
00055        pvl_list properties;
00056        pvl_elem property_iterator;
00057        pvl_list components;
00058        pvl_elem component_iterator;
00059        icalcomponent* parent;
00060 
00065        icalarray* timezones;
00066        int timezones_sorted;
00067 };
00068 
00069 /* icalproperty functions that only components get to use */
00070 void icalproperty_set_parent(icalproperty* property,
00071                           icalcomponent* component);
00072 icalcomponent* icalproperty_get_parent(icalproperty* property);
00073 void icalcomponent_add_children(icalcomponent *impl,va_list args);
00074 static icalcomponent* icalcomponent_new_impl (icalcomponent_kind kind);
00075 
00076 static void icalcomponent_merge_vtimezone (icalcomponent *comp,
00077                                       icalcomponent *vtimezone,
00078                                       icalarray *tzids_to_rename);
00079 static void icalcomponent_handle_conflicting_vtimezones (icalcomponent *comp,
00080                                                   icalcomponent *vtimezone,
00081                                                   icalproperty *tzid_prop,
00082                                                   const char *tzid,
00083                                                   icalarray *tzids_to_rename);
00084 static unsigned int icalcomponent_get_tzid_prefix_len (const char *tzid);
00085 static void icalcomponent_rename_tzids(icalcomponent* comp,
00086                                    icalarray* rename_table);
00087 static void icalcomponent_rename_tzids_callback(icalparameter *param,
00088                                           void *data);
00089 static int icalcomponent_compare_vtimezones (icalcomponent     *vtimezone1,
00090                                         icalcomponent   *vtimezone2);
00091 static int icalcomponent_compare_timezone_fn     (const void   *elem1,
00092                                            const void   *elem2);
00093 
00094 
00095 void icalcomponent_add_children(icalcomponent *impl, va_list args)
00096 {
00097     void* vp;
00098     
00099     while((vp = va_arg(args, void*)) != 0) {
00100 
00101        assert (icalcomponent_isa_component(vp) != 0 ||
00102               icalproperty_isa_property(vp) != 0 ) ;
00103 
00104        if (icalcomponent_isa_component(vp) != 0 ){
00105          icalcomponent_add_component(impl, (icalcomponent*)vp);
00106 
00107        } else if (icalproperty_isa_property(vp) != 0 ){
00108            icalcomponent_add_property(impl, (icalproperty*)vp);
00109        }
00110     }    
00111 }
00112 
00113 static icalcomponent*
00114 icalcomponent_new_impl (icalcomponent_kind kind)
00115 {
00116     icalcomponent* comp;
00117 
00118     if (!icalcomponent_kind_is_valid(kind))
00119        return NULL;
00120 
00121     if ( ( comp = (icalcomponent*) malloc(sizeof(icalcomponent))) == 0) {
00122        icalerror_set_errno(ICAL_NEWFAILED_ERROR);
00123        return 0;
00124     }
00125     
00126     strcpy(comp->id,"comp");
00127 
00128     comp->kind = kind;
00129     comp->properties = pvl_newlist();
00130     comp->property_iterator = 0;
00131     comp->components = pvl_newlist();
00132     comp->component_iterator = 0;
00133     comp->x_name = 0;
00134     comp->parent = 0;
00135     comp->timezones = NULL;
00136     comp->timezones_sorted = 1;
00137 
00138     return comp;
00139 }
00140 
00143 icalcomponent*
00144 icalcomponent_new (icalcomponent_kind kind)
00145 {
00146    return icalcomponent_new_impl(kind);
00147 }
00148 
00151 icalcomponent*
00152 icalcomponent_vanew (icalcomponent_kind kind, ...)
00153 {
00154    va_list args;
00155 
00156    icalcomponent *impl = icalcomponent_new_impl(kind);
00157 
00158     if (impl == 0){
00159        return 0;
00160     }
00161 
00162    va_start(args,kind);
00163    icalcomponent_add_children(impl, args);
00164    va_end(args);
00165 
00166    return impl;
00167 }
00168 
00171 icalcomponent* icalcomponent_new_from_string(char* str)
00172 {
00173     return icalparser_parse_string(str);
00174 }
00175 
00178 icalcomponent* icalcomponent_new_clone(icalcomponent* old)
00179 {
00180     icalcomponent *new;
00181     icalproperty *p;
00182     icalcomponent *c;
00183     pvl_elem itr;
00184 
00185     icalerror_check_arg_rz( (old!=0), "component");
00186 
00187     new = icalcomponent_new_impl(old->kind);
00188 
00189     if (new == 0){
00190        return 0;
00191     }
00192 
00193     
00194     for( itr = pvl_head(old->properties);
00195         itr != 0;
00196         itr = pvl_next(itr))
00197     {  
00198        p = (icalproperty*)pvl_data(itr);
00199        icalcomponent_add_property(new,icalproperty_new_clone(p));
00200     }
00201    
00202    
00203     for( itr = pvl_head(old->components);
00204         itr != 0;
00205         itr = pvl_next(itr))
00206     {  
00207        c = (icalcomponent*)pvl_data(itr);
00208        icalcomponent_add_component(new,icalcomponent_new_clone(c));
00209     }
00210 
00211    return new;
00212 
00213 }
00214 
00217 icalcomponent*
00218 icalcomponent_new_x (const char* x_name)
00219 {
00220     icalcomponent* comp = icalcomponent_new_impl(ICAL_X_COMPONENT);
00221     if (!comp) {
00222        return 0;
00223     }
00224     comp->x_name = icalmemory_strdup(x_name);
00225     return comp;
00226 }
00227 
00228 /*** @brief Destructor
00229  */
00230 void
00231 icalcomponent_free (icalcomponent* c)
00232 {
00233     icalproperty* prop;
00234     icalcomponent* comp;
00235 
00236     icalerror_check_arg_rv( (c!=0), "component");
00237 
00238 #ifdef ICAL_FREE_ON_LIST_IS_ERROR
00239     icalerror_assert( (c->parent ==0),"Tried to free a component that is still attached to a parent component");
00240 #else
00241     if(c->parent != 0){
00242        return;
00243     }
00244 #endif
00245 
00246     if(c != 0 ){
00247        
00248               if ( c->properties != 0 )
00249               {
00250                  while( (prop=pvl_pop(c->properties)) != 0){
00251                  assert(prop != 0);
00252                         icalproperty_set_parent(prop,0);
00253                  icalproperty_free(prop);
00254                  }
00255                pvl_free(c->properties);
00256               }
00257       
00258 
00259        while( (comp=pvl_data(pvl_head(c->components))) != 0){
00260           assert(comp!=0);
00261           icalcomponent_remove_component(c,comp);
00262           icalcomponent_free(comp);
00263        }
00264        
00265        pvl_free(c->components);
00266 
00267        if (c->x_name != 0) {
00268            free(c->x_name);
00269        }
00270 
00271        if (c->timezones)
00272            icaltimezone_array_free (c->timezones);
00273 
00274        c->kind = ICAL_NO_COMPONENT;
00275        c->properties = 0;
00276        c->property_iterator = 0;
00277        c->components = 0;
00278        c->component_iterator = 0;
00279        c->x_name = 0;       
00280        c->id[0] = 'X';
00281        c->timezones = NULL;
00282 
00283        free(c);
00284     }
00285 }
00286 
00287 char*
00288 icalcomponent_as_ical_string (icalcomponent* impl)
00289 {
00290    char* buf, *out_buf;
00291    const char* tmp_buf;
00292    size_t buf_size = 1024;
00293    char* buf_ptr = 0;
00294     pvl_elem itr;
00295 
00296 #ifdef ICAL_UNIX_NEWLINE    
00297     char newline[] = "\n";
00298 #else
00299     char newline[] = "\r\n";
00300 #endif
00301    
00302    icalcomponent *c;
00303    icalproperty *p;
00304    icalcomponent_kind kind = icalcomponent_isa(impl);
00305 
00306    const char* kind_string;
00307 
00308    buf = icalmemory_new_buffer(buf_size);
00309    buf_ptr = buf; 
00310 
00311    icalerror_check_arg_rz( (impl!=0), "component");
00312    icalerror_check_arg_rz( (kind!=ICAL_NO_COMPONENT), "component kind is ICAL_NO_COMPONENT");
00313    
00314    if (kind != ICAL_X_COMPONENT) {
00315        kind_string  = icalcomponent_kind_to_string(kind);
00316    } else {
00317        kind_string = impl->x_name;
00318    }
00319 
00320    icalerror_check_arg_rz( (kind_string!=0),"Unknown kind of component");
00321 
00322    icalmemory_append_string(&buf, &buf_ptr, &buf_size, "BEGIN:");
00323    icalmemory_append_string(&buf, &buf_ptr, &buf_size, kind_string);
00324    icalmemory_append_string(&buf, &buf_ptr, &buf_size, newline);
00325    
00326 
00327 
00328    for( itr = pvl_head(impl->properties);
00329         itr != 0;
00330         itr = pvl_next(itr))
00331     {  
00332        p = (icalproperty*)pvl_data(itr);
00333        
00334        icalerror_assert((p!=0),"Got a null property");
00335        tmp_buf = icalproperty_as_ical_string(p);
00336        
00337        icalmemory_append_string(&buf, &buf_ptr, &buf_size, tmp_buf);
00338     }
00339    
00340    
00341    for( itr = pvl_head(impl->components);
00342        itr != 0;
00343        itr = pvl_next(itr))
00344    {   
00345        c = (icalcomponent*)pvl_data(itr);
00346        
00347        tmp_buf = icalcomponent_as_ical_string(c);
00348        
00349        icalmemory_append_string(&buf, &buf_ptr, &buf_size, tmp_buf);
00350        
00351    }
00352    
00353    icalmemory_append_string(&buf, &buf_ptr, &buf_size, "END:");
00354    icalmemory_append_string(&buf, &buf_ptr, &buf_size, 
00355                          icalcomponent_kind_to_string(kind));
00356    icalmemory_append_string(&buf, &buf_ptr, &buf_size, newline);
00357 
00358    out_buf = icalmemory_tmp_copy(buf);
00359    free(buf);
00360 
00361    return out_buf;
00362 }
00363 
00364 
00365 int
00366 icalcomponent_is_valid (icalcomponent* component)
00367 {
00368     if ( (strcmp(component->id,"comp") == 0) &&
00369         component->kind != ICAL_NO_COMPONENT){
00370        return 1;
00371     } else {
00372        return 0;
00373     }
00374 
00375 }
00376 
00377 
00378 icalcomponent_kind
00379 icalcomponent_isa (const icalcomponent* component)
00380 {
00381    icalerror_check_arg_rx( (component!=0), "component", ICAL_NO_COMPONENT);
00382 
00383    if(component != 0)
00384    {
00385        return component->kind;
00386    }
00387 
00388    return ICAL_NO_COMPONENT;
00389 }
00390 
00391 
00392 int
00393 icalcomponent_isa_component (void* component)
00394 {
00395     icalcomponent *impl = component;
00396 
00397     icalerror_check_arg_rz( (component!=0), "component");
00398 
00399     if (strcmp(impl->id,"comp") == 0) {
00400        return 1;
00401     } else {
00402        return 0;
00403     }
00404 
00405 }
00406 
00407 void
00408 icalcomponent_add_property (icalcomponent* component, icalproperty* property)
00409 {
00410     icalerror_check_arg_rv( (component!=0), "component");
00411     icalerror_check_arg_rv( (property!=0), "property");
00412 
00413     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");
00414 
00415     icalproperty_set_parent(property,component);
00416 
00417     pvl_push(component->properties,property);
00418 }
00419 
00420 
00421 void
00422 icalcomponent_remove_property (icalcomponent* component, icalproperty* property)
00423 {
00424     pvl_elem itr, next_itr;
00425 
00426     icalerror_check_arg_rv( (component!=0), "component");
00427     icalerror_check_arg_rv( (property!=0), "property");
00428     
00429     icalerror_assert( (icalproperty_get_parent(property)),"The property is not a member of a component");
00430 
00431     
00432     for( itr = pvl_head(component->properties);
00433         itr != 0;
00434         itr = next_itr)
00435     {
00436        next_itr = pvl_next(itr);
00437        
00438        if( pvl_data(itr) == (void*)property ){
00439 
00440           if (component->property_iterator == itr){
00441               component->property_iterator = pvl_next(itr);
00442           }
00443 
00444           pvl_remove( component->properties, itr); 
00445          icalproperty_set_parent(property,0);
00446        }
00447     }  
00448 }
00449 
00450 int
00451 icalcomponent_count_properties (icalcomponent* component, 
00452                             icalproperty_kind kind)
00453 {
00454     int count=0;
00455     pvl_elem itr;
00456 
00457     icalerror_check_arg_rz( (component!=0), "component");
00458 
00459     for( itr = pvl_head(component->properties);
00460         itr != 0;
00461         itr = pvl_next(itr))
00462     {  
00463        if(kind == icalproperty_isa((icalproperty*)pvl_data(itr)) ||
00464            kind == ICAL_ANY_PROPERTY){
00465            count++;
00466        }
00467     }
00468 
00469 
00470     return count;
00471 
00472 }
00473 
00474 icalproperty* icalcomponent_get_current_property (icalcomponent* component)
00475 {
00476    icalerror_check_arg_rz( (component!=0),"component");
00477 
00478    if ((component->property_iterator==0)){
00479        return 0;
00480    }
00481 
00482    return (icalproperty*) pvl_data(component->property_iterator);
00483 }
00484 
00485 icalproperty*
00486 icalcomponent_get_first_property (icalcomponent* c, icalproperty_kind kind)
00487 {
00488    icalerror_check_arg_rz( (c!=0),"component");
00489   
00490    for( c->property_iterator = pvl_head(c->properties);
00491        c->property_iterator != 0;
00492        c->property_iterator = pvl_next(c->property_iterator)) {
00493            
00494        icalproperty *p =  (icalproperty*) pvl_data(c->property_iterator);
00495        
00496           if (icalproperty_isa(p) == kind || kind == ICAL_ANY_PROPERTY) {
00497               
00498               return p;
00499           }
00500    }
00501    return 0;
00502 }
00503 
00504 icalproperty*
00505 icalcomponent_get_next_property (icalcomponent* c, icalproperty_kind kind)
00506 {
00507    icalerror_check_arg_rz( (c!=0),"component");
00508 
00509    if (c->property_iterator == 0){
00510        return 0;
00511    }
00512 
00513    for( c->property_iterator = pvl_next(c->property_iterator);
00514        c->property_iterator != 0;
00515        c->property_iterator = pvl_next(c->property_iterator)) {
00516            
00517        icalproperty *p =  (icalproperty*) pvl_data(c->property_iterator);
00518           
00519        if (icalproperty_isa(p) == kind || kind == ICAL_ANY_PROPERTY) {
00520           
00521           return p;
00522        }
00523    }
00524 
00525    return 0;
00526 }
00527 
00528 icalproperty*
00529 icalcomponent_get_first_x_property (icalcomponent* c, const char *name)
00530 {
00531    icalerror_check_arg_rz( (c!=0),"component");
00532   
00533    for( c->property_iterator = pvl_head(c->properties);
00534        c->property_iterator != 0;
00535        c->property_iterator = pvl_next(c->property_iterator)) {
00536            
00537        icalproperty *p =  (icalproperty*) pvl_data(c->property_iterator);
00538        
00539           if (icalproperty_isa(p) == ICAL_X_PROPERTY &&
00540               !strcmp(icalproperty_get_x_name(p), name)) {
00541               
00542               return p;
00543           }
00544    }
00545    return 0;
00546 }
00547 
00548 icalproperty*
00549 icalcomponent_get_next_x_property (icalcomponent* c, const char *name)
00550 {
00551    icalerror_check_arg_rz( (c!=0),"component");
00552 
00553    if (c->property_iterator == 0){
00554        return 0;
00555    }
00556 
00557    for( c->property_iterator = pvl_next(c->property_iterator);
00558        c->property_iterator != 0;
00559        c->property_iterator = pvl_next(c->property_iterator)) {
00560            
00561        icalproperty *p =  (icalproperty*) pvl_data(c->property_iterator);
00562           
00563        if (icalproperty_isa(p) == ICAL_X_PROPERTY &&
00564               !strcmp(icalproperty_get_x_name(p), name)) {
00565           
00566           return p;
00567        }
00568    }
00569 
00570    return 0;
00571 }
00572 
00573 
00574 icalproperty**
00575 icalcomponent_get_properties (icalcomponent* component, icalproperty_kind kind);
00576 
00577 
00578 void
00579 icalcomponent_add_component (icalcomponent* parent, icalcomponent* child)
00580 {
00581     icalerror_check_arg_rv( (parent!=0), "parent");
00582     icalerror_check_arg_rv( (child!=0), "child");
00583     
00584     if (child->parent !=0) {
00585         icalerror_set_errno(ICAL_USAGE_ERROR);
00586     }
00587 
00588     child->parent = parent;
00589 
00590     /* Fix for Mozilla - bug 327602 */
00591     if (child->kind != ICAL_VTIMEZONE_COMPONENT) {
00592         pvl_push(parent->components, child);
00593     } else {
00594         /* VTIMEZONES should be first in the resulting VCALENDAR. */
00595         pvl_unshift(parent->components, child);
00596 
00597     /* Add the VTIMEZONE to our array. */
00598        /* FIXME: Currently we are also creating this array when loading in
00599           a builtin VTIMEZONE, when we don't need it. */
00600        if (!parent->timezones)
00601            parent->timezones = icaltimezone_array_new ();
00602 
00603        icaltimezone_array_append_from_vtimezone (parent->timezones, child);
00604 
00605        /* Flag that we need to sort it before doing any binary searches. */
00606        parent->timezones_sorted = 0;
00607     }
00608 }
00609 
00610 
00611 void
00612 icalcomponent_remove_component (icalcomponent* parent, icalcomponent* child)
00613 {
00614    pvl_elem itr, next_itr;
00615 
00616    icalerror_check_arg_rv( (parent!=0), "parent");
00617    icalerror_check_arg_rv( (child!=0), "child");
00618    
00619     /* If the component is a VTIMEZONE, remove it from our array as well. */
00620     if (child->kind == ICAL_VTIMEZONE_COMPONENT) {
00621        icaltimezone *zone;
00622        int i, num_elements;
00623 
00624        num_elements = parent->timezones ? parent->timezones->num_elements : 0;
00625         for (i = 0; i < num_elements; i++) {
00626            zone = icalarray_element_at (parent->timezones, i);
00627            if (icaltimezone_get_component (zone) == child) {
00628               icaltimezone_free (zone, 0);
00629                icalarray_remove_element_at (parent->timezones, i);
00630               break;
00631            }
00632        }
00633     }
00634 
00635    for( itr = pvl_head(parent->components);
00636        itr != 0;
00637        itr = next_itr)
00638    {
00639        next_itr = pvl_next(itr);
00640        
00641        if( pvl_data(itr) == (void*)child ){
00642 
00643           if (parent->component_iterator == itr){
00644               /* Don't let the current iterator become invalid */
00645 
00646               /* HACK. The semantics for this are troubling. */
00647               parent->component_iterator = 
00648                  pvl_next(parent->component_iterator);
00649                  
00650           }
00651           pvl_remove( parent->components, itr); 
00652           child->parent = 0;
00653           break;
00654        }
00655    }   
00656 }
00657 
00658 
00659 int
00660 icalcomponent_count_components (icalcomponent* component, 
00661                             icalcomponent_kind kind)
00662 {
00663     int count=0;
00664     pvl_elem itr;
00665 
00666     icalerror_check_arg_rz( (component!=0), "component");
00667 
00668     for( itr = pvl_head(component->components);
00669         itr != 0;
00670         itr = pvl_next(itr))
00671     {
00672        if(kind == icalcomponent_isa((icalcomponent*)pvl_data(itr)) ||
00673            kind == ICAL_ANY_COMPONENT){
00674            count++;
00675        }
00676     }
00677 
00678     return count;
00679 }
00680 
00681 icalcomponent*
00682 icalcomponent_get_current_component(icalcomponent* component)
00683 {
00684    icalerror_check_arg_rz( (component!=0),"component");
00685 
00686    if (component->component_iterator == 0){
00687        return 0;
00688    }
00689 
00690    return (icalcomponent*) pvl_data(component->component_iterator);
00691 }
00692 
00693 icalcomponent*
00694 icalcomponent_get_first_component (icalcomponent* c, 
00695                                icalcomponent_kind kind)
00696 {
00697    icalerror_check_arg_rz( (c!=0),"component");
00698   
00699    for( c->component_iterator = pvl_head(c->components);
00700        c->component_iterator != 0;
00701        c->component_iterator = pvl_next(c->component_iterator)) {
00702            
00703        icalcomponent *p =  (icalcomponent*) pvl_data(c->component_iterator);
00704        
00705           if (icalcomponent_isa(p) == kind || kind == ICAL_ANY_COMPONENT) {
00706               
00707               return p;
00708           }
00709    }
00710 
00711    return 0;
00712 }
00713 
00714 
00715 icalcomponent*
00716 icalcomponent_get_next_component (icalcomponent* c, icalcomponent_kind kind)
00717 {
00718    icalerror_check_arg_rz( (c!=0),"component");
00719   
00720    if (c->component_iterator == 0){
00721        return 0;
00722    }
00723 
00724    for( c->component_iterator = pvl_next(c->component_iterator);
00725        c->component_iterator != 0;
00726        c->component_iterator = pvl_next(c->component_iterator)) {
00727            
00728        icalcomponent *p =  (icalcomponent*) pvl_data(c->component_iterator);
00729        
00730           if (icalcomponent_isa(p) == kind || kind == ICAL_ANY_COMPONENT) {
00731               
00732               return p;
00733           }
00734    }
00735 
00736    return 0;
00737 }
00738 
00739 icalcomponent* icalcomponent_get_first_real_component(icalcomponent *c)
00740 {
00741     icalcomponent *comp;
00742 
00743     for(comp = icalcomponent_get_first_component(c,ICAL_ANY_COMPONENT);
00744        comp != 0;
00745        comp = icalcomponent_get_next_component(c,ICAL_ANY_COMPONENT)){
00746 
00747        icalcomponent_kind kind = icalcomponent_isa(comp);
00748 
00749        if(kind == ICAL_VEVENT_COMPONENT ||
00750           kind == ICAL_VTODO_COMPONENT ||
00751           kind == ICAL_VJOURNAL_COMPONENT ||
00752           kind == ICAL_VFREEBUSY_COMPONENT ||
00753           kind == ICAL_VQUERY_COMPONENT ||
00754           kind == ICAL_VREPLY_COMPONENT ||
00755           kind == ICAL_VAGENDA_COMPONENT){
00756            return comp;
00757        }
00758     }
00759     return 0;
00760 }
00761 
00762 
00781 icaltime_span icalcomponent_get_span(icalcomponent* comp)
00782 {
00783     icalcomponent *inner;
00784     icalcomponent_kind kind;
00785     icaltime_span span;
00786     struct icaltimetype start, end;
00787 
00788     span.start = 0;
00789     span.end = 0;
00790     span.is_busy= 1;
00791 
00792     /* initial Error checking */
00793     if (comp == NULL) {
00794        return span;
00795     }
00796 
00797     /* FIXME this might go away */
00798     kind  = icalcomponent_isa(comp);
00799     if(kind == ICAL_VCALENDAR_COMPONENT){
00800        inner = icalcomponent_get_first_real_component(comp);
00801 
00802        /* Maybe there is a VTIMEZONE in there */
00803        if (inner == 0){
00804            inner = icalcomponent_get_first_component(comp,
00805                             ICAL_VTIMEZONE_COMPONENT);
00806        }
00807 
00808     } else {
00809        inner = comp;
00810     }
00811 
00812     if (inner == 0){
00813        icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
00814        /*icalerror_warn("icalcomponent_get_span: no component specified, or empty VCALENDAR component");*/
00815        return span; 
00816     }
00817     
00818     kind  = icalcomponent_isa(inner);
00819 
00820     if( !( kind == ICAL_VEVENT_COMPONENT ||
00821           kind == ICAL_VJOURNAL_COMPONENT ||
00822           kind == ICAL_VTODO_COMPONENT ||    
00823           kind == ICAL_VFREEBUSY_COMPONENT )) {
00824        icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
00825        /*icalerror_warn("icalcomponent_get_span: no component specified, or empty VCALENDAR component");*/
00826        return span; 
00827        
00828     }
00829 
00830     /* Get to work. starting with DTSTART */
00831     start = icalcomponent_get_dtstart(comp);
00832     if (icaltime_is_null_time(start)) {
00833        return span;
00834     }
00835     span.start = icaltime_as_timet_with_zone(start,
00836        icaltimezone_get_utc_timezone());
00837 
00838     /* The end time could be specified as either a DTEND or a DURATION */
00839     /* icalcomponent_get_dtend takes care of these cases. */
00840     end = icalcomponent_get_dtend(comp);
00841     if (icaltime_is_null_time(end)) {
00842        if (!icaltime_is_date(start)) {
00843            /* If dtstart is a DATE-TIME and there is no DTEND nor DURATION
00844               it takes no time */
00845            span.start = 0;
00846            return span;
00847        } else {
00848            end = start;
00849        }
00850     }
00851 
00852     span.end = icaltime_as_timet_with_zone(end,
00853        icaltimezone_get_utc_timezone());
00854     if (icaltime_is_date(start)) {
00855        /* Until the end of the day*/
00856        span.end += 60*60*24 - 1;
00857     }
00858 
00859     return span;
00860 
00861 }
00862 
00886 int icalproperty_recurrence_is_excluded(icalcomponent *comp,
00887                                    struct icaltimetype *dtstart,
00888                                    struct icaltimetype *recurtime) {
00889   icalproperty *exdate, *exrule;
00890 
00891   if (comp == NULL || 
00892       dtstart == NULL || 
00893       recurtime == NULL ||
00894       icaltime_is_null_time(*recurtime))
00895     /* BAD DATA */
00896     return 1; 
00897 
00899   for (exdate = icalcomponent_get_first_property(comp,ICAL_EXDATE_PROPERTY);
00900        exdate != NULL;
00901        exdate = icalcomponent_get_next_property(comp,ICAL_EXDATE_PROPERTY)) {
00902         
00903     struct icaltimetype exdatetime = icalproperty_get_exdate(exdate);
00904 
00905     if (icaltime_compare(*recurtime, exdatetime) == 0) {
00907       return 1;
00908     }
00909   }
00910 
00912   for (exrule = icalcomponent_get_first_property(comp,ICAL_EXRULE_PROPERTY);
00913        exdate != NULL;
00914        exdate = icalcomponent_get_next_property(comp,ICAL_EXRULE_PROPERTY)) {
00915         
00916     struct icalrecurrencetype recur = icalproperty_get_exrule(exrule);
00917     icalrecur_iterator *exrule_itr  = icalrecur_iterator_new(recur, *dtstart);
00918     struct icaltimetype exrule_time;
00919 
00920     while (1) {
00921       int result;
00922       exrule_time = icalrecur_iterator_next(exrule_itr);
00923 
00924       if (icaltime_is_null_time(exrule_time))
00925        break;
00926 
00927       result = icaltime_compare(*recurtime, exrule_time);
00928       if (result == 0) {
00929        icalrecur_iterator_free(exrule_itr);
00930        return 1; 
00931       }
00932       if (result == 1)
00933        break;    
00934     }
00935 
00936     icalrecur_iterator_free(exrule_itr);
00937   }
00938 
00939   return 0;  
00940 }
00941 
00950 static int icalcomponent_is_busy(icalcomponent *comp) {
00951   icalproperty *transp;
00952   enum icalproperty_status status;
00953   int ret = 1;
00954 
00958   /* Is this a busy time?  Check the TRANSP property */
00959   transp = icalcomponent_get_first_property(comp, ICAL_TRANSP_PROPERTY);
00960   
00961   if (transp) {
00962     icalvalue *transp_val = icalproperty_get_value(transp);
00963 
00964     switch (icalvalue_get_transp(transp_val)) {
00965     case ICAL_TRANSP_OPAQUE:
00966     case ICAL_TRANSP_OPAQUENOCONFLICT:
00967     case ICAL_TRANSP_NONE:
00968       ret = 1;
00969       break;
00970     case ICAL_TRANSP_TRANSPARENT:
00971     case ICAL_TRANSP_TRANSPARENTNOCONFLICT:
00972       ret = 0;
00973       break;
00974     default:
00975       ret = 0;
00976       break;
00977     }
00978   }
00979   status = icalcomponent_get_status(comp);
00980   if (ret && status) {
00981      switch (status) {
00982      case ICAL_STATUS_CANCELLED:
00983      case ICAL_STATUS_TENTATIVE:
00984         ret = 0;
00985        break;
00986     default:
00987        break;
00988     }
00989   }
00990   return(ret);
00991 }
00992 
00993 
00994 
00995 
01015 void icalcomponent_foreach_recurrence(icalcomponent* comp,
01016                                   struct icaltimetype start,
01017                                   struct icaltimetype end,
01018                      void (*callback)(icalcomponent *comp, 
01019                                          struct icaltime_span *span, 
01020                                          void *data),
01021                             void *callback_data)
01022 {
01023   struct icaltimetype dtstart, dtend;
01024   icaltime_span recurspan, basespan, limit_span;
01025   time_t limit_start, limit_end;
01026   int dtduration;
01027   icalproperty *rrule, *rdate;
01028   struct icaldurationtype dur;
01029   pvl_elem property_iterator;      /* for saving the iterator */
01030   
01031   if (comp == NULL || callback == NULL)
01032     return;
01033   
01034   dtstart = icalcomponent_get_dtstart(comp);
01035   
01036   if (icaltime_is_null_time(dtstart))
01037     return;                 
01038 
01039 
01040   /* The end time could be specified as either a DTEND or a DURATION */
01041   /* icalcomponent_get_dtend takes care of these cases. */
01042   dtend = icalcomponent_get_dtend(comp);
01043 
01044   /* Now set up the base span for this item, corresponding to the 
01045      base DTSTART and DTEND */
01046   basespan = icaltime_span_new(dtstart, dtend, 1);
01047 
01048   basespan.is_busy = icalcomponent_is_busy(comp);
01049 
01050 
01052   limit_start = icaltime_as_timet_with_zone(start, icaltimezone_get_utc_timezone());
01053   if (!icaltime_is_null_time(end))
01054     limit_end   = icaltime_as_timet_with_zone(end, icaltimezone_get_utc_timezone());
01055   else
01056     limit_end   = INT_MAX;  /* max 32 bit time_t */
01057 
01058   limit_span.start = limit_start;
01059   limit_span.end   = limit_end;
01060 
01061 
01062   /* Do the callback for the initial DTSTART entry */
01063 
01064   if (!icalproperty_recurrence_is_excluded(comp, &dtstart, &dtstart)) {
01066     if (icaltime_span_overlaps(&basespan, &limit_span))
01067     (*callback) (comp, &basespan, callback_data);
01068   }
01069 
01070   recurspan = basespan;
01071   dtduration = basespan.end - basespan.start;
01072   
01073   /* Now cycle through the rrule entries */
01074   for (rrule = icalcomponent_get_first_property(comp,ICAL_RRULE_PROPERTY);
01075        rrule != NULL;
01076        rrule = icalcomponent_get_next_property(comp,ICAL_RRULE_PROPERTY)) {
01077 
01078     struct icalrecurrencetype recur = icalproperty_get_rrule(rrule);
01079     icalrecur_iterator *rrule_itr  = icalrecur_iterator_new(recur, dtstart);
01080     struct icaltimetype rrule_time;
01081     
01082     while (1) {
01083       rrule_time = icalrecur_iterator_next(rrule_itr);
01084 
01085       if (icaltime_is_null_time(rrule_time)) 
01086        break;
01087 
01088       if (!icaltime_compare(rrule_time, dtstart))
01089        continue;
01090 
01091       dur = icaltime_subtract(rrule_time, dtstart);
01092 
01093       recurspan.start = basespan.start + icaldurationtype_as_int(dur);
01094       recurspan.end   = recurspan.start + dtduration;
01095 
01097       property_iterator = comp->property_iterator;
01098 
01099       if (!icalproperty_recurrence_is_excluded(comp, &dtstart, &rrule_time)) {
01101        if (icaltime_span_overlaps(&recurspan, &limit_span))
01102        (*callback) (comp, &recurspan, callback_data);
01103       }
01104       comp->property_iterator = property_iterator;
01105     } /* end of iteration over a specific RRULE */
01106 
01107     icalrecur_iterator_free(rrule_itr);
01108   } /* end of RRULE loop */
01109 
01110 
01112   for (rdate = icalcomponent_get_first_property(comp,ICAL_RDATE_PROPERTY);
01113        rdate != NULL;
01114        rdate = icalcomponent_get_next_property(comp,ICAL_RDATE_PROPERTY)) {
01115 
01116     struct icaldatetimeperiodtype rdate_period = icalproperty_get_rdate(rdate);
01117 
01123     if (icaltime_is_null_time(rdate_period.time)) 
01124       continue;
01125 
01126     dur = icaltime_subtract(rdate_period.time, dtstart);
01127 
01128     recurspan.start = basespan.start + icaldurationtype_as_int(dur);
01129     recurspan.end   = recurspan.start + dtduration;
01130 
01132     property_iterator = comp->property_iterator;
01133 
01134     if (!icalproperty_recurrence_is_excluded(comp, &dtstart, &rdate_period.time)) {
01136       (*callback) (comp, &recurspan, callback_data);
01137     }
01138     comp->property_iterator = property_iterator;
01139   }
01140 }
01141 
01142 
01143 
01144 int icalcomponent_check_restrictions(icalcomponent* comp){
01145     icalerror_check_arg_rz(comp!=0,"comp");
01146     return icalrestriction_check(comp);
01147 }
01148 
01155 int icalcomponent_count_errors(icalcomponent* component)
01156 {
01157     int errors = 0;
01158     icalproperty *p;
01159     icalcomponent *c;
01160     pvl_elem itr;
01161 
01162     for( itr = pvl_head(component->properties);
01163         itr != 0;
01164         itr = pvl_next(itr))
01165     {  
01166        p = (icalproperty*)pvl_data(itr);
01167        
01168        if(icalproperty_isa(p) == ICAL_XLICERROR_PROPERTY)
01169        {
01170            errors++;
01171        }
01172     }
01173 
01174 
01175     for( itr = pvl_head(component->components);
01176         itr != 0;
01177         itr = pvl_next(itr))
01178     {  
01179        c = (icalcomponent*)pvl_data(itr);
01180        
01181        errors += icalcomponent_count_errors(c);
01182        
01183     }
01184 
01185     return errors;
01186 }
01187 
01188 
01189 void icalcomponent_strip_errors(icalcomponent* component)
01190 {
01191     icalproperty *p;
01192     icalcomponent *c;
01193     pvl_elem itr, next_itr;
01194 
01195    for( itr = pvl_head(component->properties);
01196         itr != 0;
01197         itr = next_itr)
01198     {  
01199        p = (icalproperty*)pvl_data(itr);
01200        next_itr = pvl_next(itr);
01201 
01202        if(icalproperty_isa(p) == ICAL_XLICERROR_PROPERTY)
01203        {
01204            icalcomponent_remove_property(component,p);
01205        }
01206     }
01207     
01208     for( itr = pvl_head(component->components);
01209         itr != 0;
01210         itr = pvl_next(itr))
01211     {  
01212        c = (icalcomponent*)pvl_data(itr);
01213        icalcomponent_strip_errors(c);
01214     }
01215 }
01216 
01217 /* Hack. This will change the state of the iterators */
01218 void icalcomponent_convert_errors(icalcomponent* component)
01219 {
01220     icalproperty *p, *next_p;
01221     icalcomponent *c;
01222 
01223     for(p = icalcomponent_get_first_property(component,ICAL_ANY_PROPERTY);
01224        p != 0;
01225        p = next_p){
01226        
01227        next_p = icalcomponent_get_next_property(component,ICAL_ANY_PROPERTY);
01228 
01229        if(icalproperty_isa(p) == ICAL_XLICERROR_PROPERTY)
01230        {
01231            struct icalreqstattype rst;
01232            icalparameter *param  = icalproperty_get_first_parameter
01233               (p,ICAL_XLICERRORTYPE_PARAMETER);
01234 
01235            rst.code = ICAL_UNKNOWN_STATUS;
01236            rst.desc = 0;
01237 
01238            switch(icalparameter_get_xlicerrortype(param)){
01239 
01240               case  ICAL_XLICERRORTYPE_PARAMETERNAMEPARSEERROR: {
01241                   rst.code = ICAL_3_2_INVPARAM_STATUS;
01242                   break;
01243               }
01244               case  ICAL_XLICERRORTYPE_PARAMETERVALUEPARSEERROR: {
01245                   rst.code = ICAL_3_3_INVPARAMVAL_STATUS;
01246                   break;
01247               }
01248               case  ICAL_XLICERRORTYPE_PROPERTYPARSEERROR: {              
01249                   rst.code = ICAL_3_0_INVPROPNAME_STATUS;
01250                   break;
01251               }
01252               case  ICAL_XLICERRORTYPE_VALUEPARSEERROR: {
01253                   rst.code = ICAL_3_1_INVPROPVAL_STATUS;
01254                   break;
01255               }
01256               case  ICAL_XLICERRORTYPE_COMPONENTPARSEERROR: {
01257                   rst.code = ICAL_3_4_INVCOMP_STATUS;
01258                   break;
01259               }
01260 
01261               default: {
01262                   break;
01263               }
01264            }
01265            if (rst.code != ICAL_UNKNOWN_STATUS){
01266               
01267               rst.debug = icalproperty_get_xlicerror(p);
01268               icalcomponent_add_property(component,
01269                                       icalproperty_new_requeststatus(rst));
01270               
01271               icalcomponent_remove_property(component,p);
01272            }
01273        }
01274     }
01275 
01276     for(c = icalcomponent_get_first_component(component,ICAL_ANY_COMPONENT);
01277        c != 0;
01278        c = icalcomponent_get_next_component(component,ICAL_ANY_COMPONENT)){
01279        
01280        icalcomponent_convert_errors(c);
01281     }
01282 }
01283 
01284 
01285 icalcomponent* icalcomponent_get_parent(icalcomponent* component)
01286 {
01287    return component->parent;
01288 }
01289 
01290 void icalcomponent_set_parent(icalcomponent* component, icalcomponent* parent)
01291 {
01292    component->parent = parent;
01293 }
01294 
01295 icalcompiter icalcompiter_null = {ICAL_NO_COMPONENT,0};
01296 
01297 
01298 struct icalcomponent_kind_map {
01299        icalcomponent_kind kind;
01300        char name[20];
01301 };
01302 
01303   
01304 
01305 static struct icalcomponent_kind_map component_map[] = 
01306 {
01307     { ICAL_VEVENT_COMPONENT, "VEVENT" },
01308     { ICAL_VTODO_COMPONENT, "VTODO" },
01309     { ICAL_VJOURNAL_COMPONENT, "VJOURNAL" },
01310     { ICAL_VCALENDAR_COMPONENT, "VCALENDAR" },
01311     { ICAL_VAGENDA_COMPONENT, "VAGENDA" },
01312     { ICAL_VFREEBUSY_COMPONENT, "VFREEBUSY" },
01313     { ICAL_VTIMEZONE_COMPONENT, "VTIMEZONE" },
01314     { ICAL_VALARM_COMPONENT, "VALARM" },
01315     { ICAL_XSTANDARD_COMPONENT, "STANDARD" }, /*These are part of RFC2445 */
01316     { ICAL_XDAYLIGHT_COMPONENT, "DAYLIGHT" }, /*but are not really components*/
01317     { ICAL_X_COMPONENT, "X" },
01318     { ICAL_VSCHEDULE_COMPONENT, "SCHEDULE" },
01319 
01320     /* CAP components */
01321     { ICAL_VCAR_COMPONENT, "VCAR" },  
01322     { ICAL_VCOMMAND_COMPONENT, "VCOMMAND" },  
01323     { ICAL_VQUERY_COMPONENT, "VQUERY" },  
01324     { ICAL_VREPLY_COMPONENT, "VREPLY" },  
01325 
01326     /* libical private components */
01327     { ICAL_XLICINVALID_COMPONENT, "X-LIC-UNKNOWN" },  
01328     { ICAL_XLICMIMEPART_COMPONENT, "X-LIC-MIME-PART" },  
01329     { ICAL_ANY_COMPONENT, "ANY" },  
01330     { ICAL_XROOT_COMPONENT, "XROOT" },  
01331 
01332     /* End of list */
01333     { ICAL_NO_COMPONENT, "" },
01334 };
01335 
01336 
01337 int icalcomponent_kind_is_valid(const icalcomponent_kind kind)
01338 {
01339     int i = 0;
01340     do {
01341       if (component_map[i].kind == kind)
01342        return 1;
01343     } while (component_map[i++].kind != ICAL_NO_COMPONENT);
01344 
01345     return 0;
01346 }
01347 
01348 const char* icalcomponent_kind_to_string(icalcomponent_kind kind)
01349 {
01350     int i;
01351 
01352     for (i=0; component_map[i].kind != ICAL_NO_COMPONENT; i++) {
01353        if (component_map[i].kind == kind) {
01354            return component_map[i].name;
01355        }
01356     }
01357 
01358     return 0;
01359 
01360 }
01361 
01362 icalcomponent_kind icalcomponent_string_to_kind(const char* string)
01363 {
01364     int i;
01365 
01366     if (string ==0 ) { 
01367        return ICAL_NO_COMPONENT;
01368     }
01369 
01370     for (i=0; component_map[i].kind  != ICAL_NO_COMPONENT; i++) {
01371        if (strncmp(string, component_map[i].name, strlen(component_map[i].name)) == 0) {
01372            return component_map[i].kind;
01373        }
01374     }
01375 
01376     return ICAL_NO_COMPONENT;
01377 }
01378 
01379 
01380 
01381 icalcompiter 
01382 icalcomponent_begin_component(icalcomponent* component,icalcomponent_kind kind)
01383 {
01384     icalcompiter itr;
01385     pvl_elem i;
01386 
01387     itr.kind = kind;
01388     itr.iter = NULL;
01389 
01390     icalerror_check_arg_re(component!=0,"component",icalcompiter_null);
01391 
01392     for( i = pvl_head(component->components); i != 0; i = pvl_next(i)) {
01393        
01394        icalcomponent *c =  (icalcomponent*) pvl_data(i);
01395        
01396        if (icalcomponent_isa(c) == kind || kind == ICAL_ANY_COMPONENT) {
01397            
01398            itr.iter = i;
01399 
01400            return itr;
01401        }
01402     }
01403 
01404     return icalcompiter_null;
01405 }
01406 
01407 icalcompiter
01408 icalcomponent_end_component(icalcomponent* component,icalcomponent_kind kind)
01409 {
01410     icalcompiter itr; 
01411     pvl_elem i;
01412 
01413     itr.kind = kind;
01414 
01415     icalerror_check_arg_re(component!=0,"component",icalcompiter_null);
01416 
01417     for( i = pvl_tail(component->components); i != 0; i = pvl_prior(i)) {
01418        
01419        icalcomponent *c =  (icalcomponent*) pvl_data(i);
01420        
01421        if (icalcomponent_isa(c) == kind || kind == ICAL_ANY_COMPONENT) {
01422            
01423            itr.iter = pvl_next(i);
01424 
01425            return itr;
01426        }
01427     }
01428 
01429     return icalcompiter_null;;
01430 }
01431 
01432 
01433 icalcomponent* icalcompiter_next(icalcompiter* i)
01434 {
01435    if (i->iter == 0){
01436        return 0;
01437    }
01438 
01439    icalerror_check_arg_rz( (i!=0),"i");
01440 
01441    for( i->iter = pvl_next(i->iter);
01442        i->iter != 0;
01443        i->iter = pvl_next(i->iter)) {
01444            
01445        icalcomponent *c =  (icalcomponent*) pvl_data(i->iter);
01446        
01447           if (icalcomponent_isa(c) == i->kind 
01448               || i->kind == ICAL_ANY_COMPONENT) {
01449               
01450               return icalcompiter_deref(i);;
01451           }
01452    }
01453 
01454    return 0;
01455 
01456 }
01457 
01458 icalcomponent* icalcompiter_prior(icalcompiter* i)
01459 {
01460    if (i->iter == 0){
01461        return 0;
01462    }
01463 
01464    for( i->iter = pvl_prior(i->iter);
01465        i->iter != 0;
01466        i->iter = pvl_prior(i->iter)) {
01467            
01468        icalcomponent *c =  (icalcomponent*) pvl_data(i->iter);
01469        
01470           if (icalcomponent_isa(c) == i->kind 
01471               || i->kind == ICAL_ANY_COMPONENT) {
01472               
01473               return icalcompiter_deref(i);;
01474           }
01475    }
01476 
01477    return 0;
01478 
01479 }
01480 icalcomponent* icalcompiter_deref(icalcompiter* i)
01481 {
01482     if(i->iter ==0){
01483        return 0;
01484     }
01485 
01486     return pvl_data(i->iter);
01487 }
01488 
01489 icalcomponent* icalcomponent_get_inner(icalcomponent* comp)
01490 {
01491     if (icalcomponent_isa(comp) == ICAL_VCALENDAR_COMPONENT){
01492        return icalcomponent_get_first_real_component(comp);
01493     } else {
01494        return comp;
01495     }
01496 }
01497 
01501 void icalcomponent_set_method(icalcomponent* comp, icalproperty_method method)
01502 {
01503     icalproperty *prop 
01504        = icalcomponent_get_first_property(comp, ICAL_METHOD_PROPERTY);
01505 
01506 
01507     if (prop == 0){
01508        prop = icalproperty_new_method(method);
01509        icalcomponent_add_property(comp, prop);
01510     }
01511     
01512     icalproperty_set_method(prop,method);
01513 
01514 }
01515 
01519 icalproperty_method icalcomponent_get_method(icalcomponent* comp)
01520 {
01521     icalproperty *prop 
01522        = icalcomponent_get_first_property(comp,ICAL_METHOD_PROPERTY);
01523 
01524     if (prop == 0){
01525        return ICAL_METHOD_NONE;
01526     }
01527     
01528     return icalproperty_get_method(prop);
01529 }
01530 
01531 #define ICALSETUPSET(p_kind) \
01532     icalcomponent *inner; \
01533     icalproperty *prop; \
01534     icalerror_check_arg_rv(comp!=0,"comp");\
01535     inner = icalcomponent_get_inner(comp); \
01536     if(inner == 0){\
01537         icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);\
01538         return;\
01539     }\
01540     prop = icalcomponent_get_first_property(inner, p_kind);
01541  
01542 
01548 void icalcomponent_set_dtstart(icalcomponent* comp, struct icaltimetype v)
01549 {
01550     char *tzid;
01551     ICALSETUPSET(ICAL_DTSTART_PROPERTY);
01552 
01553     if (prop == 0){
01554        prop = icalproperty_new_dtstart(v);
01555        icalcomponent_add_property(inner, prop);
01556     } else {
01557         icalproperty_remove_parameter_by_kind(prop, ICAL_TZID_PARAMETER);
01558     }
01559     
01560     icalproperty_set_dtstart(prop,v);
01561 
01562     if ((tzid = icaltime_get_tzid(v)) != NULL && !icaltime_is_utc(v)) {
01563        icalproperty_add_parameter(prop, icalparameter_new_tzid(tzid));
01564     }
01565 }
01566 
01576 static struct icaltimetype
01577 icalcomponent_get_datetime(icalcomponent *comp, icalproperty *prop) {
01578 
01579     icalcomponent      *c;
01580     icalparameter      *param;
01581     struct icaltimetype     ret;
01582 
01583     ret = icalvalue_get_datetime(icalproperty_get_value(prop));
01584 
01585     if ((param = icalproperty_get_first_parameter(prop, ICAL_TZID_PARAMETER))
01586        != NULL) {
01587        const char     *tzid = icalparameter_get_tzid(param);
01588        icaltimezone   *tz = NULL;
01589 
01590        for (c = comp; c != NULL; c = icalcomponent_get_parent(c)) {
01591            tz = icalcomponent_get_timezone(c, tzid);
01592            if (tz != NULL)
01593               break;
01594        }
01595 
01596        if (tz == NULL)
01597            tz = icaltimezone_get_builtin_timezone(tzid);
01598 
01599        if (tz != NULL)
01600            ret = icaltime_set_timezone(&ret, tz);
01601     }
01602 
01603     return ret;
01604 }
01605 
01615 struct icaltimetype icalcomponent_get_dtstart(icalcomponent* comp)
01616 {
01617     icalcomponent *inner = icalcomponent_get_inner(comp); 
01618     icalproperty *prop;
01619 
01620     prop = icalcomponent_get_first_property(inner,ICAL_DTSTART_PROPERTY);
01621     if (prop == 0){
01622        return icaltime_null_time();
01623     }
01624 
01625     return icalcomponent_get_datetime(comp, prop);
01626 }
01627 
01640 struct icaltimetype icalcomponent_get_dtend(icalcomponent* comp)
01641 {
01642     icalcomponent *inner = icalcomponent_get_inner(comp); 
01643     icalproperty *end_prop 
01644        = icalcomponent_get_first_property(inner,ICAL_DTEND_PROPERTY);
01645     icalproperty *dur_prop 
01646        = icalcomponent_get_first_property(inner, ICAL_DURATION_PROPERTY);
01647     struct icaltimetype     ret = icaltime_null_time();
01648 
01649     if ( end_prop != 0) {
01650        ret = icalcomponent_get_datetime(comp, end_prop);
01651     } else if ( dur_prop != 0) { 
01652 
01653        struct icaltimetype start = 
01654            icalcomponent_get_dtstart(inner);
01655        struct icaldurationtype duration = 
01656            icalproperty_get_duration(dur_prop);
01657 
01658        struct icaltimetype end = icaltime_add(start,duration);
01659 
01660        ret = end;
01661     }
01662 
01663     return ret;
01664 }
01665 
01675 void icalcomponent_set_dtend(icalcomponent* comp, struct icaltimetype v)
01676 {
01677     char *tzid;
01678     ICALSETUPSET(ICAL_DTEND_PROPERTY);
01679 
01680     if (icalcomponent_get_first_property(inner,ICAL_DURATION_PROPERTY)
01681        != NULL) {
01682        icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
01683        return;
01684     }
01685 
01686     if (prop == 0) {
01687        prop = icalproperty_new_dtend(v);
01688        icalcomponent_add_property(inner, prop);
01689     } else {
01690         icalproperty_remove_parameter_by_kind(prop, ICAL_TZID_PARAMETER);
01691     }
01692 
01693     icalproperty_set_dtend(prop,v);
01694 
01695     if ((tzid = icaltime_get_tzid(v)) != NULL && !icaltime_is_utc(v)) {
01696        icalproperty_add_parameter(prop, icalparameter_new_tzid(tzid));
01697     }
01698 }
01699 
01709 void icalcomponent_set_duration(icalcomponent* comp, 
01710                             struct icaldurationtype v)
01711 {
01712     ICALSETUPSET(ICAL_DURATION_PROPERTY);
01713 
01714     if (icalcomponent_get_first_property(inner,ICAL_DTEND_PROPERTY) != NULL) {
01715        icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
01716        return;
01717     }
01718 
01719     if (prop == 0) {
01720        prop = icalproperty_new_duration(v);
01721        icalcomponent_add_property(inner, prop);
01722     } else {
01723        icalproperty_set_duration(prop,v);
01724     }
01725 }
01726 
01732 struct icaldurationtype icalcomponent_get_duration(icalcomponent* comp)
01733 {
01734     icalcomponent *inner = icalcomponent_get_inner(comp); 
01735 
01736     icalproperty *end_prop 
01737        = icalcomponent_get_first_property(inner,ICAL_DTEND_PROPERTY);
01738 
01739     icalproperty *dur_prop 
01740        = icalcomponent_get_first_property(inner,ICAL_DURATION_PROPERTY);
01741 
01742     struct icaldurationtype ret = icaldurationtype_null_duration();
01743 
01744     if ( dur_prop != 0 && end_prop == 0) { 
01745        ret = icalproperty_get_duration(dur_prop);
01746 
01747     } else if ( end_prop != 0 && dur_prop == 0) {
01753        struct icaltimetype start = 
01754            icalcomponent_get_dtstart(inner);
01755        struct icaltimetype end = 
01756            icalcomponent_get_dtend(inner);
01757 
01758        ret = icaltime_subtract(end, start);
01759     } else {
01760        /* Error, both duration and dtend have been specified */
01761        icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
01762     }
01763     return ret;
01764 }
01765 
01766 void icalcomponent_set_dtstamp(icalcomponent* comp, struct icaltimetype v)
01767 {
01768 
01769     ICALSETUPSET(ICAL_DTSTAMP_PROPERTY);
01770 
01771     if (prop == 0){
01772        prop = icalproperty_new_dtstamp(v);
01773        icalcomponent_add_property(inner, prop);
01774     }
01775     
01776     icalproperty_set_dtstamp(prop,v);
01777 
01778 }
01779 
01780 
01781 struct icaltimetype icalcomponent_get_dtstamp(icalcomponent* comp)
01782 {
01783     icalcomponent *inner = icalcomponent_get_inner(comp); 
01784     icalproperty *prop 
01785        = icalcomponent_get_first_property(inner,ICAL_DTSTAMP_PROPERTY);
01786 
01787     if (prop == 0){
01788        return icaltime_null_time();
01789     }
01790     
01791     return icalproperty_get_dtstamp(prop);
01792 }
01793 
01794 
01795 void icalcomponent_set_summary(icalcomponent* comp, const char* v)
01796 {
01797     ICALSETUPSET(ICAL_SUMMARY_PROPERTY)
01798  
01799     if (prop == 0){
01800        prop = icalproperty_new_summary(v);
01801        icalcomponent_add_property(inner, prop);
01802     }
01803     
01804     icalproperty_set_summary(prop,v);
01805 }
01806 
01807 
01808 const char* icalcomponent_get_summary(icalcomponent* comp)
01809 {
01810     icalcomponent *inner;
01811     icalproperty *prop;
01812     icalerror_check_arg_rz(comp!=0,"comp");
01813 
01814     inner = icalcomponent_get_inner(comp); 
01815 
01816     if(inner == 0){
01817         icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
01818         return 0;
01819     }
01820 
01821     prop= icalcomponent_get_first_property(inner,ICAL_SUMMARY_PROPERTY);
01822 
01823     if (prop == 0){
01824        return 0;
01825     }
01826     
01827     return icalproperty_get_summary(prop);
01828 
01829 }
01830 
01831 void icalcomponent_set_comment(icalcomponent* comp, const char* v)
01832 {
01833     ICALSETUPSET(ICAL_COMMENT_PROPERTY);
01834 
01835     if (prop == 0){
01836        prop = icalproperty_new_comment(v);
01837        icalcomponent_add_property(inner, prop);
01838     }
01839 
01840     icalproperty_set_summary(prop,v);
01841 
01842 }
01843 const char* icalcomponent_get_comment(icalcomponent* comp){
01844     icalcomponent *inner;
01845     icalproperty *prop;
01846     icalerror_check_arg_rz(comp!=0,"comp");
01847 
01848     inner = icalcomponent_get_inner(comp); 
01849 
01850     if(inner == 0){
01851         icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
01852         return 0;
01853     }
01854 
01855     prop= icalcomponent_get_first_property(inner,ICAL_COMMENT_PROPERTY);
01856 
01857     if (prop == 0){
01858        return 0;
01859     }
01860     
01861     return icalproperty_get_comment(prop);
01862 }
01863 
01864 void icalcomponent_set_uid(icalcomponent* comp, const char* v)
01865 {
01866     ICALSETUPSET(ICAL_UID_PROPERTY);
01867 
01868     if (prop == 0){
01869        prop = icalproperty_new_uid(v);
01870        icalcomponent_add_property(inner, prop);
01871     }
01872 
01873     icalproperty_set_summary(prop,v);
01874 
01875 }
01876 const char* icalcomponent_get_uid(icalcomponent* comp){
01877     icalcomponent *inner;
01878     icalproperty *prop;
01879     icalerror_check_arg_rz(comp!=0,"comp");
01880 
01881     inner = icalcomponent_get_inner(comp); 
01882 
01883     if(inner == 0){
01884         icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
01885         return 0;
01886     }
01887 
01888     prop= icalcomponent_get_first_property(inner,ICAL_UID_PROPERTY);
01889 
01890     if (prop == 0){
01891        return 0;
01892     }
01893     
01894     return icalproperty_get_uid(prop);
01895 }
01896 
01897 void icalcomponent_set_recurrenceid(icalcomponent* comp, struct icaltimetype v)
01898 {
01899     ICALSETUPSET(ICAL_RECURRENCEID_PROPERTY);
01900 
01901     if (prop == 0){
01902         prop = icalproperty_new_recurrenceid(v);
01903         icalcomponent_add_property(inner, prop);
01904     }
01905 
01906     icalproperty_set_recurrenceid(prop,v);
01907 }
01908 struct icaltimetype icalcomponent_get_recurrenceid(icalcomponent* comp)
01909 {
01910     icalcomponent *inner;
01911     icalproperty *prop;
01912     if (comp == 0) {
01913        icalerror_set_errno(ICAL_BADARG_ERROR);
01914         return icaltime_null_time();
01915     }
01916 
01917     inner = icalcomponent_get_inner(comp); 
01918 
01919     if(inner == 0){
01920         icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
01921         return icaltime_null_time();
01922     }
01923 
01924     prop= icalcomponent_get_first_property(inner, ICAL_RECURRENCEID_PROPERTY);
01925 
01926     if (prop == 0){
01927         return icaltime_null_time();
01928     }
01929 
01930     return icalproperty_get_recurrenceid(prop);
01931 }
01932 
01933 void icalcomponent_set_description(icalcomponent* comp, const char* v)
01934 {
01935     ICALSETUPSET(ICAL_DESCRIPTION_PROPERTY);
01936 
01937     if (prop == 0){
01938         prop = icalproperty_new_description(v);
01939         icalcomponent_add_property(inner, prop);
01940     }
01941 
01942     icalproperty_set_description(prop,v);
01943 }
01944 const char* icalcomponent_get_description(icalcomponent* comp)
01945 {
01946     icalcomponent *inner;
01947     icalproperty *prop;
01948     icalerror_check_arg_rz(comp!=0,"comp");
01949 
01950     inner = icalcomponent_get_inner(comp); 
01951 
01952     if(inner == 0){
01953         icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
01954         return 0;
01955     }
01956 
01957     prop= icalcomponent_get_first_property(inner,ICAL_DESCRIPTION_PROPERTY);
01958 
01959     if (prop == 0){
01960         return 0;
01961     }
01962 
01963     return icalproperty_get_description(prop);
01964 }
01965 
01966 void icalcomponent_set_location(icalcomponent* comp, const char* v)
01967 {
01968     ICALSETUPSET(ICAL_LOCATION_PROPERTY)
01969 
01970     if (prop == 0){
01971         prop = icalproperty_new_location(v);
01972         icalcomponent_add_property(inner, prop);
01973     }
01974 
01975     icalproperty_set_location(prop,v);
01976 }
01977 const char* icalcomponent_get_location(icalcomponent* comp)
01978 {
01979     icalcomponent *inner;
01980     icalproperty *prop;
01981     icalerror_check_arg_rz(comp!=0,"comp");
01982 
01983     inner = icalcomponent_get_inner(comp); 
01984 
01985     if(inner == 0){
01986         icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
01987         return 0;
01988     }
01989 
01990     prop= icalcomponent_get_first_property(inner,ICAL_LOCATION_PROPERTY);
01991 
01992     if (prop == 0){
01993         return 0;
01994     }
01995 
01996     return icalproperty_get_location(prop);
01997 }
01998 
01999 void icalcomponent_set_sequence(icalcomponent* comp, int v)
02000 {
02001     ICALSETUPSET(ICAL_SEQUENCE_PROPERTY);
02002 
02003     if (prop == 0){
02004         prop = icalproperty_new_sequence(v);
02005         icalcomponent_add_property(inner, prop);
02006     }
02007 
02008     icalproperty_set_sequence(prop,v);
02009 
02010 }
02011 int icalcomponent_get_sequence(icalcomponent* comp){
02012     icalcomponent *inner;
02013     icalproperty *prop;
02014     icalerror_check_arg_rz(comp!=0,"comp");
02015 
02016     inner = icalcomponent_get_inner(comp);
02017 
02018     if(inner == 0){
02019         icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
02020         return 0;
02021     }
02022 
02023     prop= icalcomponent_get_first_property(inner,ICAL_SEQUENCE_PROPERTY);
02024 
02025     if (prop == 0){
02026         return 0;
02027     }
02028 
02029     return icalproperty_get_sequence(prop);
02030 }
02031 
02032 
02033 void icalcomponent_set_status(icalcomponent* comp, enum icalproperty_status v)
02034 {
02035     ICALSETUPSET(ICAL_STATUS_PROPERTY);
02036 
02037     if (prop == 0){
02038         prop = icalproperty_new_status(v);
02039         icalcomponent_add_property(inner, prop);
02040     }
02041 
02042     icalproperty_set_status(prop,v);
02043 
02044 }
02045 enum icalproperty_status icalcomponent_get_status(icalcomponent* comp){
02046     icalcomponent *inner;
02047     icalproperty *prop;
02048     icalerror_check_arg_rz(comp!=0,"comp");
02049 
02050     inner = icalcomponent_get_inner(comp);
02051 
02052     if(inner == 0){
02053         icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
02054         return 0;
02055     }
02056 
02057     prop= icalcomponent_get_first_property(inner,ICAL_STATUS_PROPERTY);
02058 
02059     if (prop == 0){
02060         return 0;
02061     }
02062 
02063     return icalproperty_get_status(prop);
02064 }
02065 
02066 icalcomponent* icalcomponent_new_vcalendar()
02067 {
02068     return icalcomponent_new(ICAL_VCALENDAR_COMPONENT);
02069 }
02070 icalcomponent* icalcomponent_new_vevent()
02071 {
02072     return icalcomponent_new(ICAL_VEVENT_COMPONENT);
02073 }
02074 icalcomponent* icalcomponent_new_vtodo()
02075 {
02076     return icalcomponent_new(ICAL_VTODO_COMPONENT);
02077 }
02078 icalcomponent* icalcomponent_new_vjournal()
02079 {
02080     return icalcomponent_new(ICAL_VJOURNAL_COMPONENT);
02081 }
02082 icalcomponent* icalcomponent_new_valarm()
02083 {
02084     return icalcomponent_new(ICAL_VALARM_COMPONENT);
02085 }
02086 icalcomponent* icalcomponent_new_vfreebusy()
02087 {
02088     return icalcomponent_new(ICAL_VFREEBUSY_COMPONENT);
02089 }
02090 icalcomponent* icalcomponent_new_vtimezone()
02091 {
02092     return icalcomponent_new(ICAL_VTIMEZONE_COMPONENT);
02093 }
02094 icalcomponent* icalcomponent_new_xstandard()
02095 {
02096     return icalcomponent_new(ICAL_XSTANDARD_COMPONENT);
02097 }
02098 icalcomponent* icalcomponent_new_xdaylight()
02099 {
02100     return icalcomponent_new(ICAL_XDAYLIGHT_COMPONENT);
02101 }
02102 icalcomponent* icalcomponent_new_vagenda()
02103 {
02104     return icalcomponent_new(ICAL_VAGENDA_COMPONENT);
02105 }
02106 icalcomponent* icalcomponent_new_vquery()
02107 {
02108     return icalcomponent_new(ICAL_VQUERY_COMPONENT);
02109 }
02110 icalcomponent* icalcomponent_new_vreply()
02111 {
02112     return icalcomponent_new(ICAL_VREPLY_COMPONENT);
02113 }
02114 
02115 /*
02116  * Timezone stuff.
02117  */
02118 
02119 
02125 void icalcomponent_merge_component(icalcomponent* comp,
02126                                icalcomponent* comp_to_merge)
02127 {
02128   icalcomponent *subcomp, *next_subcomp;
02129   icalarray *tzids_to_rename;
02130   int i;
02131 
02132   /* Check that both components are VCALENDAR components. */
02133   assert (icalcomponent_isa(comp) == ICAL_VCALENDAR_COMPONENT);
02134   assert (icalcomponent_isa(comp_to_merge) == ICAL_VCALENDAR_COMPONENT);
02135 
02136   /* Step through each subcomponent of comp_to_merge, looking for VTIMEZONEs.
02137      For each VTIMEZONE found, check if we need to add it to comp and if we
02138      need to rename it and all TZID references to it. */
02139   tzids_to_rename = icalarray_new (sizeof (char*), 16);
02140   subcomp = icalcomponent_get_first_component (comp_to_merge,
02141                                           ICAL_VTIMEZONE_COMPONENT);
02142   while (subcomp) {
02143     next_subcomp = icalcomponent_get_next_component (comp_to_merge,
02144                                                ICAL_VTIMEZONE_COMPONENT);
02145     /* This will add the VTIMEZONE to comp, if necessary, and also update
02146        the array of TZIDs we need to rename. */
02147     icalcomponent_merge_vtimezone (comp, subcomp, tzids_to_rename);
02148     /* FIXME: Handle possible NEWFAILED error. */
02149 
02150     subcomp = next_subcomp;
02151   }
02152 
02153   /* If we need to do any renaming of TZIDs, do it now. */
02154   if (tzids_to_rename->num_elements != 0) {
02155     icalcomponent_rename_tzids (comp_to_merge, tzids_to_rename);
02156       
02157     /* Now free the tzids_to_rename array. */
02158     for (i = 0; i < tzids_to_rename->num_elements; i++) {
02159       free (icalarray_element_at (tzids_to_rename, i));
02160     }
02161     icalarray_free (tzids_to_rename);
02162   }
02163 
02164   /* Now move all the components from comp_to_merge to comp, excluding
02165      VTIMEZONE components. */
02166   subcomp = icalcomponent_get_first_component (comp_to_merge,
02167                                           ICAL_ANY_COMPONENT);
02168   while (subcomp) {
02169     next_subcomp = icalcomponent_get_next_component (comp_to_merge,
02170                                                ICAL_ANY_COMPONENT);
02171     if (icalcomponent_isa(subcomp) != ICAL_VTIMEZONE_COMPONENT) {
02172       icalcomponent_remove_component (comp_to_merge, subcomp);
02173       icalcomponent_add_component (comp, subcomp);
02174     }
02175     subcomp = next_subcomp;
02176   }
02177 
02178   /* Free comp_to_merge. We have moved most of the subcomponents over to
02179      comp now. */
02180   icalcomponent_free (comp_to_merge);
02181 }
02182 
02183 
02184 static void icalcomponent_merge_vtimezone (icalcomponent *comp,
02185                                       icalcomponent *vtimezone,
02186                                       icalarray *tzids_to_rename)
02187 {
02188   icalproperty *tzid_prop;
02189   const char *tzid;
02190   char *tzid_copy;
02191   icaltimezone *existing_vtimezone;
02192 
02193   /* Get the TZID of the VTIMEZONE. */
02194   tzid_prop = icalcomponent_get_first_property (vtimezone, ICAL_TZID_PROPERTY);
02195   if (!tzid_prop)
02196     return;
02197 
02198   tzid = icalproperty_get_tzid (tzid_prop);
02199   if (!tzid)
02200     return;
02201 
02202   /* See if there is already a VTIMEZONE in comp with the same TZID. */
02203   existing_vtimezone = icalcomponent_get_timezone (comp, tzid);
02204 
02205   /* If there is no existing VTIMEZONE with the same TZID, we can just move
02206      the VTIMEZONE to comp and return. */
02207   if (!existing_vtimezone) {
02208     icalcomponent_remove_component (icalcomponent_get_parent (vtimezone),
02209                                 vtimezone);
02210     icalcomponent_add_component (comp, vtimezone);
02211     return;
02212   }
02213 
02214   /* If the TZID has a '/' prefix, then we don't have to worry about the
02215      clashing TZIDs, as they are supposed to be exactly the same VTIMEZONE. */
02216   if (tzid[0] == '/')
02217     return;
02218 
02219   /* Now we have two VTIMEZONEs with the same TZID (which isn't a globally
02220      unique one), so we compare the VTIMEZONE components to see if they are
02221      the same. If they are, we don't need to do anything. We make a copy of
02222      the tzid, since the parameter may get modified in these calls. */
02223   tzid_copy = strdup (tzid);
02224   if (!tzid_copy) {
02225     icalerror_set_errno(ICAL_NEWFAILED_ERROR);
02226     return;
02227   }
02228 
02229   if (!icalcomponent_compare_vtimezones (comp, vtimezone)) {
02230     /* FIXME: Handle possible NEWFAILED error. */
02231 
02232     /* Now we have two different VTIMEZONEs with the same TZID. */
02233     icalcomponent_handle_conflicting_vtimezones (comp, vtimezone, tzid_prop,
02234                                            tzid_copy, tzids_to_rename);
02235   }
02236   free (tzid_copy);
02237 }
02238 
02239 
02240 static void
02241 icalcomponent_handle_conflicting_vtimezones (icalcomponent *comp,
02242                                         icalcomponent *vtimezone,
02243                                         icalproperty *tzid_prop,
02244                                         const char *tzid,
02245                                         icalarray *tzids_to_rename)
02246 {
02247   int i, suffix, max_suffix = 0, num_elements;
02248   unsigned int tzid_len;
02249   char *tzid_copy, *new_tzid, suffix_buf[32];
02250 
02251   /* Find the length of the TZID without any trailing digits. */
02252   tzid_len = icalcomponent_get_tzid_prefix_len (tzid);
02253 
02254   /* Step through each of the VTIMEZONEs in comp. We may already have the
02255      clashing VTIMEZONE in the calendar, but it may have been renamed
02256      (i.e. a unique number added on the end of the TZID, e.g. 'London2').
02257      So we compare the new VTIMEZONE with any VTIMEZONEs that have the
02258      same prefix (e.g. 'London'). If it matches any of those, we have to
02259      rename the TZIDs to that TZID, else we rename to a new TZID, using
02260      the biggest numeric suffix found + 1. */
02261   num_elements = comp->timezones ? comp->timezones->num_elements : 0;
02262   for (i = 0; i < num_elements; i++) {
02263     icaltimezone *zone;
02264     char *existing_tzid, *existing_tzid_copy;
02265     unsigned int existing_tzid_len;
02266 
02267     zone = icalarray_element_at (comp->timezones, i);
02268     existing_tzid = icaltimezone_get_tzid (zone);
02269 
02270     /* Find the length of the TZID without any trailing digits. */
02271     existing_tzid_len = icalcomponent_get_tzid_prefix_len (existing_tzid);
02272 
02273     /* Check if we have the same prefix. */
02274     if (tzid_len == existing_tzid_len
02275        && !strncmp (tzid, existing_tzid, tzid_len)) {
02276       /* Compare the VTIMEZONEs. */
02277       if (icalcomponent_compare_vtimezones (icaltimezone_get_component (zone),
02278                                        vtimezone)) {
02279        /* The VTIMEZONEs match, so we can use the existing VTIMEZONE. But
02280           we have to rename TZIDs to this TZID. */
02281        tzid_copy = strdup (tzid);
02282        existing_tzid_copy = strdup (existing_tzid);
02283        if (!tzid_copy || !existing_tzid_copy) {
02284          icalerror_set_errno(ICAL_NEWFAILED_ERROR);
02285        } else {
02286          icalarray_append (tzids_to_rename, tzid_copy);
02287          icalarray_append (tzids_to_rename, existing_tzid_copy);
02288        }
02289        return;
02290       } else {
02291        /* FIXME: Handle possible NEWFAILED error. */
02292 
02293        /* Convert the suffix to an integer and remember the maximum numeric
02294           suffix found. */
02295        suffix = atoi (existing_tzid + existing_tzid_len);
02296        if (max_suffix < suffix)
02297          max_suffix = suffix;
02298       }
02299     }
02300   }
02301 
02302   /* We didn't find a VTIMEZONE that matched, so we have to rename the TZID,
02303      using the maximum numerical suffix found + 1. */
02304   tzid_copy = strdup (tzid);
02305   sprintf (suffix_buf, "%i", max_suffix + 1);
02306   new_tzid = malloc (tzid_len + strlen (suffix_buf) + 1);
02307   if (!new_tzid || !tzid_copy) {
02308     icalerror_set_errno(ICAL_NEWFAILED_ERROR);
02309     return;
02310   }
02311 
02312   strncpy (new_tzid, tzid, tzid_len);
02313   strcpy (new_tzid + tzid_len, suffix_buf);
02314   icalarray_append (tzids_to_rename, tzid_copy);
02315   icalarray_append (tzids_to_rename, new_tzid);
02316 }
02317 
02318 
02319 /* Returns the length of the TZID, without any trailing digits. */
02320 static unsigned int icalcomponent_get_tzid_prefix_len (const char *tzid)
02321 {
02322   int len;
02323   const char *p;
02324 
02325   len = strlen (tzid);
02326   p = tzid + len - 1;
02327   while (len > 0 && *p >= '0' && *p <= '9') {
02328     p--;
02329     len--;
02330   }
02331 
02332   return len;
02333 }
02334 
02335 
02341 static void icalcomponent_rename_tzids(icalcomponent* comp,
02342                                    icalarray* rename_table)
02343 {
02344     icalcomponent_foreach_tzid (comp, icalcomponent_rename_tzids_callback,
02345                             rename_table);
02346 }
02347 
02348 
02349 static void icalcomponent_rename_tzids_callback(icalparameter *param, void *data)
02350 {
02351     icalarray *rename_table = data;
02352     const char *tzid;
02353     int i;
02354 
02355     tzid = icalparameter_get_tzid (param);
02356     if (!tzid)
02357         return;
02358 
02359     /* Step through the rename table to see if the current TZID matches
02360        any of the ones we want to rename. */
02361     for (i = 0; i < rename_table->num_elements - 1; i += 2) {
02362         if (!strcmp (tzid, icalarray_element_at (rename_table, i))) {
02363            icalparameter_set_tzid (param, icalarray_element_at (rename_table, i + 1));
02364            break;
02365        }
02366     }
02367 }
02368 
02369 
02373 void icalcomponent_foreach_tzid(icalcomponent* comp,
02374                             void (*callback)(icalparameter *param, void *data),
02375                             void *callback_data)
02376 {
02377     icalproperty *prop;
02378     icalproperty_kind kind;
02379     icalparameter *param;
02380     icalcomponent *subcomp;
02381 
02382     /* First look for any TZID parameters used in this component itself. */
02383     prop = icalcomponent_get_first_property (comp, ICAL_ANY_PROPERTY);
02384     while (prop) {
02385       kind = icalproperty_isa (prop);
02386 
02387       /* These are the only properties that can have a TZID. Note that
02388         COMPLETED, CREATED, DTSTAMP & LASTMODIFIED must be in UTC. */
02389       if (kind == ICAL_DTSTART_PROPERTY || kind == ICAL_DTEND_PROPERTY
02390          || kind == ICAL_DUE_PROPERTY || kind == ICAL_EXDATE_PROPERTY
02391          || kind == ICAL_RDATE_PROPERTY) {
02392        param = icalproperty_get_first_parameter (prop, ICAL_TZID_PARAMETER);
02393        if (param)
02394            (*callback) (param, callback_data);
02395       }
02396 
02397       prop = icalcomponent_get_next_property (comp, ICAL_ANY_PROPERTY);
02398     }
02399 
02400     /* Now recursively check child components. */
02401     subcomp = icalcomponent_get_first_component (comp, ICAL_ANY_COMPONENT);
02402     while (subcomp) {
02403         icalcomponent_foreach_tzid (subcomp, callback, callback_data);
02404         subcomp = icalcomponent_get_next_component (comp, ICAL_ANY_COMPONENT);
02405     }
02406 }
02407 
02408 
02409 
02414 icaltimezone* icalcomponent_get_timezone(icalcomponent* comp, const char *tzid)
02415 {
02416     icaltimezone *zone;
02417     int lower, upper, middle, cmp;
02418     char *zone_tzid;
02419 
02420     if (!comp->timezones)
02421        return NULL;
02422 
02423     /* Sort the array if necessary (by the TZID string). */
02424     if (!comp->timezones_sorted) {
02425        icalarray_sort (comp->timezones, icalcomponent_compare_timezone_fn);
02426        comp->timezones_sorted = 1;
02427     }
02428 
02429     /* Do a simple binary search. */
02430     lower = middle = 0;
02431     upper = comp->timezones->num_elements;
02432 
02433     while (lower < upper) {
02434        middle = (lower + upper) >> 1;
02435        zone = icalarray_element_at (comp->timezones, middle);
02436        zone_tzid = icaltimezone_get_tzid (zone);
02437        cmp = strcmp (tzid, zone_tzid);
02438        if (cmp == 0)
02439            return zone;
02440        else if (cmp < 0)
02441            upper = middle;
02442        else
02443            lower = middle + 1;
02444     }
02445 
02446     return NULL;
02447 }
02448 
02449 
02453 static int icalcomponent_compare_timezone_fn     (const void   *elem1,
02454                                            const void   *elem2)
02455 {
02456     icaltimezone *zone1, *zone2;
02457     const char *zone1_tzid, *zone2_tzid;
02458 
02459     zone1 = (icaltimezone*) elem1;
02460     zone2 = (icaltimezone*) elem2;
02461 
02462     zone1_tzid = icaltimezone_get_tzid (zone1);
02463     zone2_tzid = icaltimezone_get_tzid (zone2);
02464 
02465     return strcmp (zone1_tzid, zone2_tzid);
02466 }
02467 
02468 
02473 static int icalcomponent_compare_vtimezones (icalcomponent     *vtimezone1,
02474                                         icalcomponent   *vtimezone2)
02475 {
02476     icalproperty *prop1, *prop2;
02477     const char *tzid1, *tzid2;
02478     char *tzid2_copy, *string1, *string2;
02479     int cmp;
02480 
02481     /* Get the TZID property of the first VTIMEZONE. */
02482     prop1 = icalcomponent_get_first_property (vtimezone1, ICAL_TZID_PROPERTY);
02483     if (!prop1)
02484        return -1;
02485 
02486     tzid1 = icalproperty_get_tzid (prop1);
02487     if (!tzid1)
02488        return -1;
02489 
02490     /* Get the TZID property of the second VTIMEZONE. */
02491     prop2 = icalcomponent_get_first_property (vtimezone2, ICAL_TZID_PROPERTY);
02492     if (!prop2)
02493        return -1;
02494 
02495     tzid2 = icalproperty_get_tzid (prop2);
02496     if (!tzid2)
02497        return -1;
02498 
02499     /* Copy the second TZID, and set the property to the same as the first
02500        TZID, since we don't care if these match of not. */
02501     tzid2_copy = strdup (tzid2);
02502     if (!tzid2_copy) {
02503       icalerror_set_errno (ICAL_NEWFAILED_ERROR);
02504       return 0;
02505     }
02506 
02507     icalproperty_set_tzid (prop2, tzid1);
02508 
02509     /* Now convert both VTIMEZONEs to strings and compare them. */
02510     string1 = icalcomponent_as_ical_string (vtimezone1);
02511     if (!string1) {
02512        free (tzid2_copy);
02513        return -1;
02514     }
02515 
02516     string2 = icalcomponent_as_ical_string (vtimezone2);
02517     if (!string2) {
02518        free (string1);
02519        free (tzid2_copy);
02520        return -1;
02521     }
02522 
02523     cmp = strcmp (string1, string2);
02524 
02525     free (string1);
02526     free (string2);
02527 
02528     /* Now reset the second TZID. */
02529     icalproperty_set_tzid (prop2, tzid2_copy);
02530     free (tzid2_copy);
02531 
02532     return (cmp == 0) ? 1 : 0;
02533 }
02534 
02535 
02536 
02537 
02538 
02539 
02547 void icalcomponent_set_relcalid(icalcomponent* comp, const char* v)
02548 {
02549   ICALSETUPSET(ICAL_RELCALID_PROPERTY);
02550 
02551   if (prop == 0){
02552     prop = icalproperty_new_relcalid(v);
02553     icalcomponent_add_property(inner, prop);
02554   }
02555 
02556   icalproperty_set_relcalid(prop,v);
02557 
02558 }
02559 
02560 
02567 const char* icalcomponent_get_relcalid(icalcomponent* comp){
02568     icalcomponent *inner;
02569     icalproperty *prop;
02570     icalerror_check_arg_rz(comp!=0,"comp");
02571 
02572     inner = icalcomponent_get_inner(comp);
02573 
02574     if(inner == 0){
02575         return 0;
02576     }
02577 
02578     prop= icalcomponent_get_first_property(inner,ICAL_RELCALID_PROPERTY);
02579 
02580     if (prop == 0){
02581         return 0;
02582     }
02583 
02584     return icalproperty_get_relcalid(prop);
02585 }
02586 
02587 
02596 struct icaltimetype icalcomponent_get_due(icalcomponent* comp)
02597 {
02598     icalcomponent *inner = icalcomponent_get_inner(comp);
02599 
02600     icalproperty *due_prop
02601         = icalcomponent_get_first_property(inner,ICAL_DUE_PROPERTY);
02602 
02603     icalproperty *dur_prop
02604         = icalcomponent_get_first_property(inner, ICAL_DURATION_PROPERTY);
02605 
02606     if( due_prop == 0 && dur_prop == 0){
02607         return icaltime_null_time();
02608     } else if ( due_prop != 0) {
02609         return icalproperty_get_due(due_prop);
02610     } else if ( dur_prop != 0) {
02611 
02612         struct icaltimetype start =
02613             icalcomponent_get_dtstart(inner);
02614         struct icaldurationtype duration =
02615             icalproperty_get_duration(dur_prop);
02616 
02617         struct icaltimetype due = icaltime_add(start,duration);
02618 
02619         return due;
02620 
02621     } else {
02622         /* Error, both duration and due have been specified */
02623         icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
02624         return icaltime_null_time();
02625 
02626     }
02627 
02628 }
02629 
02641 void icalcomponent_set_due(icalcomponent* comp, struct icaltimetype v)
02642 {
02643     icalcomponent *inner = icalcomponent_get_inner(comp);
02644 
02645     icalproperty *due_prop
02646         = icalcomponent_get_first_property(inner,ICAL_DUE_PROPERTY);
02647 
02648     icalproperty *dur_prop
02649         = icalcomponent_get_first_property(inner,ICAL_DURATION_PROPERTY);
02650 
02651 
02652     if( due_prop == 0 && dur_prop == 0){
02653         due_prop = icalproperty_new_due(v);
02654         icalcomponent_add_property(inner,due_prop);
02655     } else if ( due_prop != 0) {
02656         icalproperty_set_due(due_prop,v);
02657     } else if ( dur_prop != 0) {
02658         struct icaltimetype start =
02659             icalcomponent_get_dtstart(inner);
02660 
02661         struct icaltimetype due =
02662             icalcomponent_get_due(inner);
02663 
02664         struct icaldurationtype dur
02665             = icaltime_subtract(due,start);
02666 
02667         icalproperty_set_duration(dur_prop,dur);
02668 
02669     } else {
02670         /* Error, both duration and due have been specified */
02671         icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
02672     }
02673 }