aboutsummaryrefslogblamecommitdiffstats
path: root/libical/src/libicalss/icalstore.c
blob: 382464e476c54f4f16bb563b6db124a9014e56a0 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
                  


                                                                          
  

            
    

                                   
 



                                                                        
 



                                                                       
 

                                                                    

 
                                                                            


























                                                                      




                    






                        


































                                                         
                              



 
                                





                                                                                      


                      
 
                            



















































                                                                
                        
























                                                            
                                












                                        
                                                                       


                  


                                  




















































































                                                                                      

                                                                              




                                          







                                                         

                                                 






                                                                   
                                                                   








                                                    




                                                                      



                                                                        
                             


                                        
                         








                                                 
                                                                        
 








                                                                           


                 
                                                                                                             







                                               
                                                                            


                                                





                                                                  





                                                     
     





                                   















                                                  
                                                                                  

















                                                                                  






















                                                                                          



                                               
                                       


                                    
                                            









                                                 
                                                                                  

























                                                                      
              








                                                    
            



                                                                     
                                


    

                                                                     
 
                               
                    

                                           



                                                 

                                         
 


                                                                       
 



































                                                                           
        

                                                                      
            

                                                                        
            

                                                                        
            












                                                                       
                            


                              

                                         
         








                                                                               
        






                                                                               
        




                                                               

         




















                                                                                     




































































































                                                                              








                                                                                 




                                              
      



















































                                                                                                                                        
                                                           




                                                                        
                                    
























                                                                 
        
/* -*- Mode: C -*-
    ======================================================================
    FILE: icalstore.c
    CREATOR: eric 28 November 1999
  
    $Id$
    $Locker$
    
    (C) COPYRIGHT 1999 Eric Busboom
    http://www.softwarestudio.org

    The contents of this file are subject to the Mozilla Public License
    Version 1.0 (the "License"); you may not use this file except in
    compliance with the License. You may obtain a copy of the License at
    http://www.mozilla.org/MPL/
 
    Software distributed under the License is distributed on an "AS IS"
    basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
    the License for the specific language governing rights and
    limitations under the License.
 
    The Original Code is eric. The Initial Developer of the Original
    Code is Eric Busboom


    ======================================================================*/


/*
 
  icalstore manages a database of ical components and offers
  interfaces for reading, writting and searching for components.

  icalstore groups components in to clusters based on their DTSTART
  time -- all components that start in the same month are grouped
  together in a single file. All files in a sotre are kept in a single
  directory. ( If a component does not have DTSTART, the store uses
  DTSTAMP or CREATE )

  The primary interfaces are icalstore_first and icalstore_next. These
  routine iterate through all of the components in the store, subject
  to the current gauge. A gauge is an icalcomponent that is tested
  against other componets for a match. If a gauge has been set with
  icalstore_select, icalstore_first and icalstore_next will only
  return componentes that match the gauge.

  The Store generated UIDs for all objects that are stored if they do
  not already have a UID. The UID is the name of the cluster (month &
  year as MMYYYY) plus a unique serial number. The serial number is
  stored as a property of the cluster.

*/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif


#include "ical.h"
#include "icalstore.h"
#include "pvl.h" 
#include "icalerror.h"
#include "icalparser.h"
#include "icalcluster.h"

#include <limits.h>
#include <dirent.h> /* for opendir() */
#include <errno.h>
#include <sys/types.h> /* for opendir() */
#include <sys/stat.h> /* for stat */
#include <unistd.h> /* for stat, getpid */
#include <time.h> /* for clock() */
#include <stdlib.h> /* for rand(), srand() */
#include <sys/utsname.h> /* for uname */
#include <string.h> /* for strdup */


struct icalstore_impl 
{
    char* dir;
    icalcomponent* gauge;
    icalcluster* cluster;
    int first_component;
    pvl_list directory;
    pvl_elem directory_iterator;
};

struct icalstore_impl* icalstore_new_impl()
{
    struct icalstore_impl* comp;

    if ( ( comp = (struct icalstore_impl*)
       malloc(sizeof(struct icalstore_impl))) == 0) {
    icalerror_set_errno(ICAL_NEWFAILED_ERROR);
    return 0;
    }

    return comp;
}

void icalstore_lock(char* dir)
{
}


void icalstore_unlock(char* dir)
{
}

/* Load the contents of the store directory into the store's internal directory list*/
icalerrorenum icalstore_read_directory(struct icalstore_impl* impl)
{
    struct dirent *de;
    DIR* dp;
    char *str;
 
    dp = opendir(impl->dir);
   
    if ( dp == 0) {
    icalerror_set_errno(ICAL_FILE_ERROR);
    return ICAL_FILE_ERROR;
    }

    /* clear contents of directory list */
    while((str = pvl_pop(impl->directory))){
    free(str);
    }
    
    /* load all of the cluster names in the directory list */
    for(de = readdir(dp);
    de != 0;
    de = readdir(dp)){

    /* Remove known directory names  '.' and '..'*/
    if (strcmp(de->d_name,".") == 0 ||
        strcmp(de->d_name,"..") == 0 ){
        continue;
    }

    pvl_push(impl->directory, (void*)strdup(de->d_name));   
    }

    closedir(dp);

    return ICAL_NO_ERROR;
}

icalstore* icalstore_new(char* dir)
{
    struct icalstore_impl *impl = icalstore_new_impl();
    struct stat sbuf;

    if (impl == 0){
    return 0;
    }

    icalerror_check_arg_rz( (dir!=0), "dir");

    if (stat(dir,&sbuf) != 0){
    icalerror_set_errno(ICAL_FILE_ERROR);
    return 0;
    }
    
    /* dir is not the name of a direectory*/
    if (!S_ISDIR(sbuf.st_mode)){ 
    icalerror_set_errno(ICAL_USAGE_ERROR);
    return 0;
    }       

    icalstore_lock(dir);

    impl = icalstore_new_impl();

    if (impl ==0){
    icalerror_set_errno(ICAL_ALLOCATION_ERROR);
    return 0;
    }
    
    impl->directory = pvl_newlist();
    impl->directory_iterator = 0;
    impl->dir = (char*)strdup(dir);
    impl->gauge = 0;
    impl->first_component = 0;
    impl->cluster = 0;

    icalstore_read_directory(impl);

    return (icalstore*) impl;
}

void icalstore_free(icalstore* s)
{
    struct icalstore_impl *impl = (struct icalstore_impl*)s;
    char* str;

    icalstore_unlock(impl->dir);

    if(impl->dir !=0){
    free(impl->dir);
    }

    if(impl->gauge !=0){
    icalcomponent_free(impl->gauge);
    }

    if(impl->cluster !=0){
    icalcluster_free(impl->cluster);
    }

    while(impl->directory !=0 &&  (str=pvl_pop(impl->directory)) != 0){
    free(str);
    }

    if(impl->directory != 0){
    pvl_free(impl->directory);
    }

    impl->directory = 0;
    impl->directory_iterator = 0;
    impl->dir = 0;
    impl->gauge = 0;
    impl->first_component = 0;

    free(impl);

}

/* icalstore_next_uid_number updates a serial number in the Store
   directory in a file called SEQUENCE */

int icalstore_next_uid_number(icalstore* store)
{
    struct icalstore_impl *impl = (struct icalstore_impl*)store;
    char sequence = 0;
    char temp[128];
    char filename[PATH_MAX];
    char *r;
    FILE *f;
    struct stat sbuf;

    icalerror_check_arg_rz( (store!=0), "store");

    sprintf(filename,"%s/%s",impl->dir,"SEQUENCE");

    /* Create the file if it does not exist.*/
    if (stat(filename,&sbuf) == -1 || !S_ISREG(sbuf.st_mode)){

    f = fopen(filename,"w");
    if (f != 0){
        fprintf(f,"0");
        fclose(f);
    } else {
        icalerror_warn("Can't create SEQUENCE file in icalstore_next_uid_number");
        return 0;
    }
    
    }
    
    if ( (f = fopen(filename,"r+")) != 0){

    rewind(f);
    r = fgets(temp,128,f);

    if (r == 0){
        sequence = 1;
    } else {
        sequence = atoi(temp)+1;
    }

    rewind(f);

    fprintf(f,"%d",sequence);

    fclose(f);

    return sequence;
    
    } else {
    icalerror_warn("Can't create SEQUENCE file in icalstore_next_uid_number");
    return 0;
    }

}

icalerrorenum icalstore_next_cluster(icalstore* store)
{
    struct icalstore_impl *impl = (struct icalstore_impl*)store;
    char path[PATH_MAX];

    if (impl->directory_iterator == 0){
    icalerror_set_errno(ICAL_INTERNAL_ERROR);
    return ICAL_INTERNAL_ERROR;
    }       
    impl->directory_iterator = pvl_next(impl->directory_iterator);

    if (impl->directory_iterator == 0){
    /* There are no more clusters */
    impl->cluster = 0;
    return ICAL_NO_ERROR;
    }
        
    sprintf(path,"%s/%s",impl->dir,(char*)pvl_data(impl->directory_iterator));

    icalcluster_free(impl->cluster);

    impl->cluster = icalcluster_new(path);

    return icalerrno;
}

void icalstore_add_uid(icalstore* store, icalstore* comp)
{
    char uidstring[PATH_MAX];
    icalproperty *uid;
    struct utsname unamebuf;

    icalerror_check_arg_rv( (store!=0), "store");
    icalerror_check_arg_rv( (comp!=0), "comp");

    uid = icalcomponent_get_first_property(comp,ICAL_UID_PROPERTY);
    
    if (uid == 0) {
    
    uname(&unamebuf);
    
    sprintf(uidstring,"%d-%s",(int)getpid(),unamebuf.nodename);
    
    uid = icalproperty_new_uid(uidstring);
    icalcomponent_add_property(comp,uid);
    } else {
    
    strcpy(uidstring,icalproperty_get_uid(uid));
    }
}


/* This assumes that the top level component is a VCALENDAR, and there
   is an inner component of type VEVENT, VTODO or VJOURNAL. The inner
   component must have a DTSTART property */

icalerrorenum icalstore_add_component(icalstore* store, icalstore* comp)
{
    struct icalstore_impl *impl;
    char clustername[PATH_MAX];
    icalproperty *dt, *count;
    icalvalue *v;
    struct icaltimetype tm;
    icalerrorenum error = ICAL_NO_ERROR;
    icalcomponent *inner;

    impl = (struct icalstore_impl*)store;
    icalerror_check_arg_rz( (store!=0), "store");
    icalerror_check_arg_rz( (comp!=0), "comp");

    errno = 0;
    
    icalstore_add_uid(store,comp);

    /* Determine which cluster this object belongs in. This is a HACK */

    for(inner = icalcomponent_get_first_component(comp,ICAL_ANY_COMPONENT);
    inner != 0;
    inner = icalcomponent_get_next_component(comp,ICAL_ANY_COMPONENT)){
  
    dt = icalcomponent_get_first_property(inner,ICAL_DTSTART_PROPERTY);
    
    if (dt != 0){
        break; 
    }   
    }

    if (dt == 0){
    icalerror_warn("The component does not have a DTSTART property, so it cannot be added to the store");
    icalerror_set_errno(ICAL_BADARG_ERROR);
    return ICAL_BADARG_ERROR;
    }

    v = icalproperty_get_value(dt);

    tm = icalvalue_get_datetime(v);

    snprintf(clustername,PATH_MAX,"%s/%04d%02d",impl->dir,tm.year,tm.month);

    /* Load the cluster and insert the object */

    if(impl->cluster != 0 && 
       strcmp(clustername,icalcluster_path(impl->cluster)) != 0 ){
    icalcluster_free(impl->cluster);
    impl->cluster = 0;
    }

    if (impl->cluster == 0){
    impl->cluster = icalcluster_new(clustername);

    if (impl->cluster == 0){
        error = icalerrno;
    }
    }
    
    if (error != ICAL_NO_ERROR){
    icalerror_set_errno(error);
    return error;
    }

    /* Add the component to the cluster */

    icalcluster_add_component(impl->cluster,comp);


    /* Increment the clusters count value */
    count = icalcomponent_get_first_property(
    icalcluster_get_component(impl->cluster),
    ICAL_XLICCLUSTERCOUNT_PROPERTY);

    if (count == 0){
    icalerror_set_errno(ICAL_INTERNAL_ERROR);
    return ICAL_INTERNAL_ERROR;
    }

    icalproperty_set_xlicclustercount(count,
                      icalproperty_get_xlicclustercount(count)+1);

    
    icalcluster_mark(impl->cluster);

    return ICAL_NO_ERROR;    
}

/* Remove a component in the current cluster */
icalerrorenum icalstore_remove_component(icalstore* store, icalstore* comp)
{
    struct icalstore_impl *impl = (struct icalstore_impl*)store;
    icalproperty *count;

    icalerror_check_arg_re((store!=0),"store",ICAL_BADARG_ERROR);
    icalerror_check_arg_re((comp!=0),"comp",ICAL_BADARG_ERROR);
    icalerror_check_arg_re((impl->cluster!=0),"Cluster pointer",ICAL_USAGE_ERROR);

/* HACK The following code should be used to ensure that the component
   the caller is trying to remove is actually in the cluster, but it
   resets the internal iterators, which immediately ends any loops over
   the cluster the caller may have in progress 

   for(c = icalcluster_get_first_component(
   impl->cluster,
   ICAL_ANY_COMPONENT);
   c != 0;
   c = icalcluster_get_next_component(
   impl->cluster,
   ICAL_ANY_COMPONENT)){

   if (c == comp){
   found = 1;
   }

   }

   if (found != 1){
   icalerror_warn("icalstore_remove_component: component is not part of current cluster");
   icalerror_set_errno(ICAL_USAGE_ERROR);
   return ICAL_USAGE_ERROR;
   }

*/

    icalcluster_remove_component(impl->cluster,
                 comp);

    icalcluster_mark(impl->cluster);

    /* Decrement the clusters count value */
    count = icalcomponent_get_first_property(
    icalcluster_get_component(impl->cluster),
    ICAL_XLICCLUSTERCOUNT_PROPERTY);

    if (count == 0){
    icalerror_set_errno(ICAL_INTERNAL_ERROR);
    return ICAL_INTERNAL_ERROR;
    }

    icalproperty_set_xlicclustercount(count,
                      icalproperty_get_xlicclustercount(count)-1);

    return ICAL_NO_ERROR;
}

/* Convert a VQUERY component into a gauge */
icalcomponent* icalstore_make_gauge(icalcomponent* query);

/* icalstore_test compares a component against a gauge, and returns
   true if the component passes the test 

   The gauge is a VCALENDAR component that specifies how to test the
   target components. The guage holds a collection of VEVENT, VTODO or
   VJOURNAL sub-components. Each of the sub-components has a
   collection of properties that are compared to corresponding
   properties in the target component, according to the
   X-LIC-COMPARETYPE parameters to the gauge's properties.

   When a gauge has several sub-components, the results of testing the
   target against each of them is ORed together - the target
   component will pass if it matches any of the sub-components in the
   gauge. However, the results of matching the proeprties in a
   sub-component are ANDed -- the target must match every property in
   a gauge sub-component to match the sub-component.

   Here is an example:

   BEGIN:XROOT
   BEGIN:VCOMPONENT
   BEGIN:VEVENT
   DTSTART;X-LIC-COMPARETYPE=LESS:19981025T020000
   ORGANIZER;X-LIC-COMPARETYPE=EQUAL:mrbig@host.com 
   END:VEVENT
   BEGIN:VEVENT
   LOCATION;X-LIC-COMPARETYPE=EQUAL:McNary's Pub
   END:VEVENT
   END:VCALENDAR
   END:XROOT

   This gauge has two sub-components; one which will match a VEVENT
   based on start time, and organizer, and another that matches based
   on LOCATION. A target component will pass the test if it matched
   either of the sub-components.
   
  */


int icalstore_test_recurse(icalcomponent* comp, icalcomponent* gauge)
{
    int pass = 1,localpass = 0;
    icalproperty *p;
    icalcomponent *child,*subgauge; 
    icalcomponent_kind gaugekind, compkind;

    icalerror_check_arg_rz( (comp!=0), "comp");
    icalerror_check_arg_rz( (gauge!=0), "gauge");

    gaugekind = icalcomponent_isa(gauge);
    compkind = icalcomponent_isa(comp);

    if( ! (gaugekind == compkind || gaugekind == ICAL_ANY_COMPONENT) ){
    return 0;
    }   

    /* Test properties. For each property in the gauge, search through
       the component for a similar property. If one is found, compare
       the two properties value with the comparison specified in the
       gauge with the X-LIC-COMPARETYPE parameter */
    
    for(p = icalcomponent_get_first_property(gauge,ICAL_ANY_PROPERTY);
    p != 0;
    p = icalcomponent_get_next_property(gauge,ICAL_ANY_PROPERTY)){
    
    icalproperty* targetprop; 
    icalparameter* compareparam;
    icalparameter_xliccomparetype compare;
    int rel; /* The relationship between the gauge and target values.*/
    
    /* Extract the comparison type from the gauge. If there is no
       comparison type, assume that it is "EQUAL" */
    
    compareparam = icalproperty_get_first_parameter(
        p,
        ICAL_XLICCOMPARETYPE_PARAMETER);
    
    if (compareparam!=0){
        compare = icalparameter_get_xliccomparetype(compareparam);
    } else {
        compare = ICAL_XLICCOMPARETYPE_EQUAL;
    }
    
    /* Find a property in the component that has the same type
       as the gauge property. HACK -- multiples of a single
       property type in the gauge will match only the first
       instance in the component */
    
    targetprop = icalcomponent_get_first_property(comp,
                              icalproperty_isa(p));
    
    if(targetprop != 0){
    
        /* Compare the values of the gauge property and the target
           property */
        
        rel = icalvalue_compare(icalproperty_get_value(p),
                    icalproperty_get_value(targetprop));
        
        /* Now see if the comparison is equavalent to the comparison
           specified in the gauge */
        
        if (rel == compare){ 
        localpass++; 
        } else if (compare == ICAL_XLICCOMPARETYPE_LESSEQUAL && 
               ( rel == ICAL_XLICCOMPARETYPE_LESS ||
             rel == ICAL_XLICCOMPARETYPE_EQUAL)) {
        localpass++;
        } else if (compare == ICAL_XLICCOMPARETYPE_GREATEREQUAL && 
               ( rel == ICAL_XLICCOMPARETYPE_GREATER ||
             rel == ICAL_XLICCOMPARETYPE_EQUAL)) {
        localpass++;
        } else if (compare == ICAL_XLICCOMPARETYPE_NOTEQUAL && 
               ( rel == ICAL_XLICCOMPARETYPE_GREATER ||
             rel == ICAL_XLICCOMPARETYPE_LESS)) {
        localpass++;
        } else {
        localpass = 0;
        }
        
        pass = pass && (localpass>0);
    }
    }
    
    /* Test subcomponents. Look for a child component that has a
       counterpart in the gauge. If one is found, recursively call
       icalstore_test */
    
    for(subgauge = icalcomponent_get_first_component(gauge,ICAL_ANY_COMPONENT);
    subgauge != 0;
    subgauge = icalcomponent_get_next_component(gauge,ICAL_ANY_COMPONENT)){
    
    gaugekind = icalcomponent_isa(subgauge);

    if (gaugekind == ICAL_ANY_COMPONENT){
        child = icalcomponent_get_first_component(comp,ICAL_ANY_COMPONENT);
    } else {
        child = icalcomponent_get_first_component(comp,gaugekind);
    }
    
    if(child !=0){
        localpass = icalstore_test_recurse(child,subgauge);
        pass = pass && localpass;
    } else {
        pass = 0;
    }
    }
    
    return pass;   
}

/* guagecontainer is an XROOT component that holds several gauges. The
   results of comparing against these gauges are ORed together in this
   routine */
int icalstore_test(icalcomponent* comp, icalcomponent* gaugecontainer)
{
    int pass = 0;
    icalcomponent *gauge; 

    icalerror_check_arg_rz( (comp!=0), "comp");
    icalerror_check_arg_rz( (gauge!=0), "gauge");
    
    for(gauge = icalcomponent_get_first_component(gaugecontainer,ICAL_ANY_COMPONENT);
    gauge != 0;
    gauge = icalcomponent_get_next_component(gaugecontainer,ICAL_ANY_COMPONENT)){

    pass += icalstore_test_recurse(comp, gauge);
    }

    return pass>0;

}
    
icalcomponent* icalstore_query(icalstore* store, icalstore* query);


icalcomponent* icalstore_fetch(icalstore* store, char* uid)
{
    icalcomponent *gauge;
    icalcomponent *old_gauge;
    icalcomponent *c;
    struct icalstore_impl *impl = (struct icalstore_impl*)store;

    icalerror_check_arg_rz( (store!=0), "store");
    icalerror_check_arg_rz( (uid!=0), "uid");

    gauge = 
    icalcomponent_vanew(
        ICAL_VCALENDAR_COMPONENT,
        icalcomponent_vanew(
        ICAL_VEVENT_COMPONENT,  
        icalproperty_vanew_uid(
            uid,
            icalparameter_new_xliccomparetype(
            ICAL_XLICCOMPARETYPE_EQUAL),
            0),
        0),
        0);

    old_gauge = impl->gauge;
    impl->gauge = gauge;

    c= icalstore_get_first_component(store);

    impl->gauge = old_gauge;

    icalcomponent_free(gauge);

    return c;
}


int icalstore_has_uid(icalstore* store, char* uid)
{
    icalcomponent *c;

    icalerror_check_arg_rz( (store!=0), "store");
    icalerror_check_arg_rz( (uid!=0), "uid");
    
    /* HACK. This is a temporary implementation. _has_uid should use a
       database, and _fetch should use _has_uid, not the other way
       around */
    c = icalstore_fetch(store,uid);

    return c!=0;

}


icalerrorenum icalstore_select(icalstore* store, icalcomponent* gauge)
{
    struct icalstore_impl *impl = (struct icalstore_impl*)store;

    icalerror_check_arg_re( (store!=0), "store",ICAL_BADARG_ERROR);
    icalerror_check_arg_re( (gauge!=0), "gauge",ICAL_BADARG_ERROR);

    if (!icalcomponent_is_valid(gauge)){
    return ICAL_BADARG_ERROR;
    }

    impl->gauge = gauge;

    return ICAL_NO_ERROR;
}



icalcomponent* icalstore_get_first_component(icalstore* store)
{
    struct icalstore_impl *impl = (struct icalstore_impl*)store;
    icalerrorenum error;
    char path[PATH_MAX];

    error = icalstore_read_directory(impl);

    if (error != ICAL_NO_ERROR){
    icalerror_set_errno(error);
    return 0;
    }

    impl->directory_iterator = pvl_head(impl->directory);
    
    if (impl->directory_iterator == 0){
    icalerror_set_errno(error);
    return 0;
    }
    
    sprintf(path,"%s/%s",impl->dir,(char*)pvl_data(impl->directory_iterator));

    /* If the next cluster we need is different than the current cluster, 
       delete the current one and get a new one */

    if(impl->cluster != 0 && strcmp(path,icalcluster_path(impl->cluster)) != 0 ){
    icalcluster_free(impl->cluster);
    impl->cluster = 0;
    }
    
    if (impl->cluster == 0){
    impl->cluster = icalcluster_new(path);

    if (impl->cluster == 0){
        error = icalerrno;
    }
    } 

    if (error != ICAL_NO_ERROR){
    icalerror_set_errno(error);
    return 0;
    }

    impl->first_component = 1;

    return icalstore_get_next_component(store);
}

icalcomponent* icalstore_get_next_component(icalstore* store)
{
    struct icalstore_impl *impl;
    icalcomponent *c;
    icalerrorenum error;

    icalerror_check_arg_rz( (store!=0), "store");

    impl = (struct icalstore_impl*)store;

    if(impl->cluster == 0){

    icalerror_warn("icalstore_get_next_component called with a NULL cluster (Caller must call icalstore_get_first_component first");
    icalerror_set_errno(ICAL_USAGE_ERROR);
    return 0;

    }

    /* Set the component iterator for the following for loop */
    if (impl->first_component == 1){
    icalcluster_get_first_component(
        impl->cluster,
        ICAL_ANY_COMPONENT);
    impl->first_component = 0;
    } else {
    icalcluster_get_next_component(
        impl->cluster,
        ICAL_ANY_COMPONENT);
    }


    while(1){
    /* Iterate through all of the objects in the cluster*/
    for( c = icalcluster_get_current_component(
        impl->cluster);
         c != 0;
         c = icalcluster_get_next_component(
         impl->cluster,
         ICAL_ANY_COMPONENT)){
        
        /* If there is a gauge defined and the component does not
           pass the gauge, skip the rest of the loop */
        if (impl->gauge != 0 && icalstore_test(c,impl->gauge) == 0){
        continue;
        }

        /* Either there is no gauge, or the component passed the
           gauge, so return it*/

        return c;
    }

    /* Fell through the loop, so the component we want is not
       in this cluster. Load a new cluster and try again.*/

    error = icalstore_next_cluster(store);

    if(impl->cluster == 0 || error != ICAL_NO_ERROR){
        /* No more clusters */
        return 0;
    } else {
        c = icalcluster_get_first_component(
        impl->cluster,
        ICAL_ANY_COMPONENT);
    }
    }
}