aboutsummaryrefslogblamecommitdiffstats
path: root/calendar/cal-util/cal-component.c
blob: 8263cddbada589a63dd24426d16e99aa0d3e23a8 (plain) (tree)
1
2
3
4
5
6
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796

                                                  
                                  
                                  
  
                                                       
















                                                                            
                   
                   





                          


                                                                                  
                                                
                             

                                       
 
                        
 
                          
 

                             















                                              
                                 
 

                                     
                     


                                            
 
                                                       
 
                                

                              
                                                           







                                          


                              
                            
 
                                                          
                                                               
 








                                              
                          
                                    

                               





                                           







                                           
                                                       
 

                                                              
                               
 



                                            
 


                                   



                                   



                                                                          
  
 

                                  


                                         


                                        


                             
                              

  











                                                                
  

                                                                          
  













































                                                                                            

                                                                          

 














                                                                             









                                                                             












                                                                             
                                    
 
                                                              


                                                    


                               
                         
 

                            
                                
 

                                    
                               
                             
 

                                                                     


                                      




                                        


                                    
                                                           
 


                                         
                         
                                   

                              


                                                         


                                        
                              
 

                                          
 


                                  



                                                                                


                                        














                                                       
                                  

                                                    











                                                                      
  
                                                                  
  





                                                                                
                        













                                                                       

                                                   
                                   







                                          



                     
  


                                                                                
  







                                                                 


                                      
  

                                                                          
  

























                                                                               






















                                                                                                        
                                                  
           
                                                                                 
 
                                  
 
                          
 

                                                                                            

 
                                      
           
                                                    

                                  
                            

                          





                                                                                      
 
 










                                                                                                     
                                      



                                                                   
 


                                                                                            
 
                                               

 









                                                                                              






                                                                  




                                                     



                                  
                                                                                                    

 












                                                                                            




                                                                 

                               

                          

                                       
                       



                                    



                                                                 
                                      
                                        

                      



                                            



                                                            



                                       



                                     
                                       
                                                                
                      




                                                         



                                     






                                                           
 



                                         



                                                            



                                 



                                           



                                                              







                                           



                                                            



                                                            



                                                           



                                      

                                          
                      
 



                                          
                               
                                 
                      
 



                                 




                      



                                                                           
                         

































































































































                                                                                                    
                                                                   

                                                                               





                                       
                          




                                          

                             



                                                                                         
 









                                                                                          

 

























                                                                             
                                                     





                                                                           
   


                                               
  


                                                                                
    

                                                                        
 

                                  
                                
 

                                                   
 
                          
 




                                          
                                                              



                                             

                      

                                            

                      

                                               

                      

                                                

                      

                                                


                      

                                         

         




                                                                                                 
 



                                                           



                                           


   
                                   
                                      
                                
  



                                                                              




                                                                                   
    
        


                                                                             
                                
 

                                                              



                                       
                            


                                  



                                      
 









                                                   


                                           

                    




                                      
  

                                                                           
  

                                                                         
    

                                                    


                                  

                                                             

                          

                                                                      
                              


   
                           
                                      
  
                                                   
  
                                                                   
    

                                            

                                  
                                
 

                                                                              

                          
                                                                             






















                                                                       


   


                               


                                                                                















                                                                             



                                                                      


                                                            
                
                                     
            





                           
                                 

         






































                                                                                

                                      

                                         
                                                                
    

                                                            


                                  


                                                   

                          
                                                  

                                                           
                                     
 
                                                





                                      
  











                                                                    
                                                  
 
                                                           
                                     
 
                                                       


   
                                



                                      
    
    



















                                                                             


               
    
    









                                                                         
                                            


















                                                                                         
                                     
                                      

                                                                              
  

                                                                               
    
    
                                                                           

                                  



                               
 

                                                   
                                              

                          
                                                  
 
                                


                                   
 
                                                                    


                                      




































                                                                         


   
                                     
                                      
                                                       
  
                                                              

    
                                                                          

                                  
                             




                                                   

                                                  
                          


                                                                                         
                 
 


                       
                                                  
                                                           
 
                                
                                                                        

                                
                                                                      
 

   


                                                 
  





































                                                                                          
  



















































                                                                                             


                                 
                                                                  


                           
 
                   
 


                       











                                                                                  
                    
                                         
 
                                               

         





                                    
                                                                   
















                                                                           
                                               





























                                                                                           


   
                                  
                                      


                                                                               
  


                                                                                

    
                                                                       

                                  


                                                   
                                             


                                                  
 

                                                                                
 



                                                    
  







                                                                             
 

                                                   
 

                                                  
 

                                                                                       
 














                                                                             

















                                                                                     


                       





                                                                   


   



                                                                            
  




















                                                                          
  












































                                                                           


















                                                                                



                                                   


   




                                                                                
  








                                                                               
 


                                                   
 

                                                  
 
                                                                                        


   


                                                       
  



                                                                               

    
                                                                          
 
                                  
 

                                                   
 

                                                  
 
                                                                                               
 
 

















                                                                         









































                                                                                          

                                                                                    




                                            
                           
                                      



                                                                          

    
                                                                      




                                                   
                                      



                                                  























                                                                      
                          

                                       


   
                             
                                      
                                      
  

                                                                               

    
                                                                      




                                                   
                                     

                          
                                                  
 



                                                           


   
                             
                                      
                            
  


                                                                          

    
                                                                      




                                                   
                                     



                                                  

















































                                                                            
                          

                                       






                                                                          
  











                                                                    
                                                  







                                                            
  
















                                                                    

                                       
 
 


                                                                                      
                                                                                      











                                               
                                                 




























                                                                                               
                                           

                                                             
                                                 
                                                                  
                                                           










                                                   


                                    
                                                                                        
















                                                                             
                                                 










                                      
                                                 






                                               
                                           


                                                               
                                                 

                                                                      
                                                           





















                                                                               


                                                                           
                                                                    
                                             
  

















                                                                                

                                          
 





                                                                 
 



                                                                            
 
                                                                   







                                                      

                                                          









                                                                       






                                                     
                                    
 




                                                                         







                                               

                                          

                                           
                              
 
                                              
 










                                                                                     






                                                                


                                      
  

                                                                              
  















                                                                            









































































                                                                                  
  


















                                                                                


                                                            
  
                                                                                
















                                                                                


                                                              
  








                                                                      








                                                                                       
   

                                      
  

                                                                              
  


















                                                                            
  

                                                                      
  
                                                                       
    
        





                                                                                    



                                                                           
  
























                                                                        
  































                                                                                  















































                                                                                 










































































































































                                                                                                



                                                                            
  
























                                                                             
  





































                                                                                      
  
























                                                                        
  

































                                                                                       















































                                                                            




                                                                            
  


















                                                                                


                                                        
  








                                                                      




                                                                                       

                                       


   

                                      
  

                                                                               
  
















                                                                             




                                                                              
  


















                                                                              


                                                             
  
                                                                               
















                                                                               


                                                              
  








                                                                     









                                                                                     

                                      
  

                                                                               
  
















                                                                             
                                 
                                     
  

                                                                          
  
                                                                        
    
        





                                                                                  



                                                                               
  


























                                                                
  



































                                                                                       


































































                                                                                     
                             
                                      
                                                                      
  
                                                      

    
                                                                         

                                  


                                                   
                                           


                                                  
 



                                                                               
 



                                                                                        


   
                             
                                      
                                                 
  
                                                   

    
                                                                         

                                  






                                                   



                                                                                           
 

                                                          




                       
                                                  
 





                                                                                        
 

                                                      
 









                                                                                

                                                                                          

                                                  
 




                                                   
  





















                                                                                     
                                                 
                                                           
                                                 








                                                       
  













                                                                                    
 




































                                                                                           
  























                                                                                
  












                                                                             
                              















                                                                                  
 

















































































































































































































































































































                                                                                                            

 

































                                                       



                                                                      






                                                    
                                          

                                           
                              
 



                                              





                                   

                                   
  











                                                                              














                                                                           

                              
  













                                                                       
  











                                                                         






















                                                        

                                                              
  












                                                         
                           





                                  






































                                                                              























                                                        

 











                                                      






                                                              
                                                             

 












                                                                                


                                                                      
 


                                                   
 
                          
 



                                                                           











                                                                              


                                                                 
                             





                                                   
                                                  
 


                                                                 
 


                                                               


 






                                                                              
                          







                                       



                                      








                                                                      






                                                                   
                                   





                                             
                                  
                          





                                                                                  

                                      


                     












                                                                   
   

                                
  

                                                                              
  

                                                                             
    

                                                 

                                  
                 






                                                             

                                                                       
 
                 


   


                                                              
  
                                                                   
  


                                                                                

                   
                                                              

                                  
                             






                                                             
                                                  
 


                                                                 
                                          

                            


   

                                       
  



















                                                      
                                      



                        
                           


  




                                      
                                 

                        

                                             






                                                                           



                              



                     
                             

                                 
                                                                                
   



















                                                                               










                                                      


                                                     
  


                                       
                                                                                 
 
                                     



                                          

                                           
                             
                                         


                       
                                                      
 

                               
                                          


                                 
                                            


                               
                                          


                                   
                                              






                                         
                                            
         





                                  
  


                                     
                                                                                
 
                                     

                                         

                                                       
 

                                           
                         
                             
                                        

                      
                               
                                          

                      
                             
                                        

                      
                                 
                                            



                                        
                                       


                          
                                                             
              
                                                              


                                                                            



                                   
                                               
  


                                         
                                                                                    

                             
                                 
                          






                                           
                                                       


                       


                                                                                        






                                                        
                                        


                                         
                                         





                                                                                                  
                                        


                              
                                




                                                         

                                                     








                                                                                                  
                                                                                 


                                              
                                                                               





                                                        



                                                                         


         



                                    
  

                                     
    
                                                                                   
 
                                 


                                       

                                         
                                                                  


                                           







                                                                                

                           
                                                          
 

                                                       


                                                    
                                    
                                                 

                                             
 

                                                    
                                    
                                                 
                                           

                      

                                            
                                                 



                                        
                       

         







                                                                                        
              





                                                                   
                                                         







                                                                                                  
         
 
 












                                                   
                                                               


                                                     
                          
                             
                              



















                                                                     























































                                                                               
 
/* Evolution calendar - iCalendar component object
 *
 * Copyright (C) 2000 Ximian, Inc.
 * Copyright (C) 2000 Ximian, Inc.
 *
 * Author: Federico Mena-Quintero <federico@ximian.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 */

#include <config.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include "cal-component.h"
#include "timeutil.h"



/* Extension property for alarm components so that we can reference them by UID */
#define EVOLUTION_ALARM_UID_PROPERTY "X-EVOLUTION-ALARM-UID"

/* Private part of the CalComponent structure */
struct _CalComponentPrivate {
    /* The icalcomponent we wrap */
    icalcomponent *icalcomp;

    /* Properties */

    icalproperty *uid;

    icalproperty *status;

    struct attendee {
        icalproperty *prop;
        icalparameter *cutype_param;
        icalparameter *member_param;
        icalparameter *role_param;
        icalparameter *partstat_param;
        icalparameter *rsvp_param;
        icalparameter *delto_param;
        icalparameter *delfrom_param;
        icalparameter *sentby_param;
        icalparameter *cn_param;
        icalparameter *language_param;
    };
    
    GSList *attendee_list;
    
    icalproperty *categories;

    icalproperty *classification;

    struct text {
        icalproperty *prop;
        icalparameter *altrep_param;
    };

    GSList *comment_list; /* list of struct text */

    icalproperty *completed;
    icalproperty *created;

    GSList *description_list; /* list of struct text */

    struct datetime {
        icalproperty *prop;
        icalparameter *tzid_param;
    };

    struct datetime dtstart;
    struct datetime dtend;

    icalproperty *dtstamp;

    struct datetime due;

    GSList *exdate_list; /* list of struct datetime */
    GSList *exrule_list; /* list of icalproperty objects */

    struct organizer {
        icalproperty *prop;
        icalparameter *sentby_param;
        icalparameter *cn_param;
        icalparameter *language_param;
    };

    struct organizer organizer;
    
    icalproperty *geo;
    icalproperty *last_modified;
    icalproperty *percent;
    icalproperty *priority;

    struct period {
        icalproperty *prop;
        icalparameter *value_param;
    };

    struct recur_id {
        struct datetime recur_time;
        
        icalparameter *range_param;
    };

    struct recur_id recur_id;
    
    GSList *rdate_list; /* list of struct period */

    GSList *rrule_list; /* list of icalproperty objects */

    icalproperty *sequence;

    struct {
        icalproperty *prop;
        icalparameter *altrep_param;
    } summary;

    icalproperty *transparency;
    icalproperty *url;

    /* Subcomponents */

    GHashTable *alarm_uid_hash;

    /* Whether we should increment the sequence number when piping the
     * object over the wire.
     */
    guint need_sequence_inc : 1;
};

/* Private structure for alarms */
struct _CalComponentAlarm {
    /* Alarm icalcomponent we wrap */
    icalcomponent *icalcomp;

    /* Our extension UID property */
    icalproperty *uid;

    /* Properties */

    icalproperty *action;
    icalproperty *trigger;
};



static void cal_component_class_init (CalComponentClass *class);
static void cal_component_init (CalComponent *comp);
static void cal_component_destroy (GtkObject *object);

static GtkObjectClass *parent_class;



/**
 * cal_component_get_type:
 *
 * Registers the #CalComponent class if necessary, and returns the type ID
 * associated to it.
 *
 * Return value: The type ID of the #CalComponent class.
 **/
GtkType
cal_component_get_type (void)
{
    static GtkType cal_component_type = 0;

    if (!cal_component_type) {
        static const GtkTypeInfo cal_component_info = {
            "CalComponent",
            sizeof (CalComponent),
            sizeof (CalComponentClass),
            (GtkClassInitFunc) cal_component_class_init,
            (GtkObjectInitFunc) cal_component_init,
            NULL, /* reserved_1 */
            NULL, /* reserved_2 */
            (GtkClassInitFunc) NULL
        };

        cal_component_type = gtk_type_unique (GTK_TYPE_OBJECT, &cal_component_info);
    }

    return cal_component_type;
}

/* Class initialization function for the calendar component object */
static void
cal_component_class_init (CalComponentClass *class)
{
    GtkObjectClass *object_class;

    object_class = (GtkObjectClass *) class;

    parent_class = gtk_type_class (GTK_TYPE_OBJECT);

    object_class->destroy = cal_component_destroy;
}

/* Object initialization function for the calendar component object */
static void
cal_component_init (CalComponent *comp)
{
    CalComponentPrivate *priv;

    priv = g_new0 (CalComponentPrivate, 1);
    comp->priv = priv;

    priv->alarm_uid_hash = g_hash_table_new (g_str_hash, g_str_equal);
}

/* Does a simple g_free() of the elements of a GSList and then frees the list
 * itself.  Returns NULL.
 */
static GSList *
free_slist (GSList *slist)
{
    GSList *l;

    for (l = slist; l; l = l->next)
        g_free (l->data);

    g_slist_free (slist);
    return NULL;
}

/* Used from g_hash_table_foreach_remove() to free the alarm UIDs hash table.
 * We do not need to do anything to individual elements since we were storing
 * the UID pointers inside the icalproperties themselves.
 */
static gboolean
free_alarm_cb (gpointer key, gpointer value, gpointer data)
{
    return TRUE;
}

/* Frees the internal icalcomponent only if it does not have a parent.  If it
 * does, it means we don't own it and we shouldn't free it.
 */
static void
free_icalcomponent (CalComponent *comp)
{
    CalComponentPrivate *priv;

    priv = comp->priv;

    if (!priv->icalcomp)
        return;

    /* Free the icalcomponent */

    if (icalcomponent_get_parent (priv->icalcomp) == NULL)
        icalcomponent_free (priv->icalcomp);

    priv->icalcomp = NULL;

    /* Free the mappings */

    priv->uid = NULL;

    priv->status = NULL;

    priv->categories = NULL;

    priv->classification = NULL;
    priv->comment_list = NULL;
    priv->completed = NULL;
    priv->created = NULL;

    priv->description_list = free_slist (priv->description_list);

    priv->dtend.prop = NULL;
    priv->dtend.tzid_param = NULL;

    priv->dtstamp = NULL;

    priv->dtstart.prop = NULL;
    priv->dtstart.tzid_param = NULL;

    priv->due.prop = NULL;
    priv->due.tzid_param = NULL;

    priv->exdate_list = free_slist (priv->exdate_list);

    g_slist_free (priv->exrule_list);
    priv->exrule_list = NULL;

    priv->geo = NULL;
    priv->last_modified = NULL;
    priv->percent = NULL;
    priv->priority = NULL;

    priv->rdate_list = free_slist (priv->rdate_list);

    g_slist_free (priv->rrule_list);
    priv->rrule_list = NULL;

    priv->sequence = NULL;

    priv->summary.prop = NULL;
    priv->summary.altrep_param = NULL;

    priv->transparency = NULL;
    priv->url = NULL;

    /* Free the subcomponents */

    g_hash_table_foreach_remove (priv->alarm_uid_hash, free_alarm_cb, NULL);

    /* Clean up */

    priv->need_sequence_inc = FALSE;
}

/* Destroy handler for the calendar component object */
static void
cal_component_destroy (GtkObject *object)
{
    CalComponent *comp;
    CalComponentPrivate *priv;

    g_return_if_fail (object != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (object));

    comp = CAL_COMPONENT (object);
    priv = comp->priv;

    free_icalcomponent (comp);
    g_hash_table_destroy (priv->alarm_uid_hash);
    priv->alarm_uid_hash = NULL;

    g_free (priv);
    comp->priv = NULL;

    if (GTK_OBJECT_CLASS (parent_class)->destroy)
        (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
}



/**
 * cal_component_gen_uid:
 *
 * Generates a unique identifier suitable for calendar components.
 *
 * Return value: A unique identifier string.  Every time this function is called
 * a different string is returned.
 **/
char *
cal_component_gen_uid (void)
{
        char *iso, *ret;
    static char *hostname;
    time_t t = time (NULL);
    static int serial;

    if (!hostname) {
        static char buffer [512];

        if ((gethostname (buffer, sizeof (buffer) - 1) == 0) &&
            (buffer [0] != 0))
            hostname = buffer;
        else
            hostname = "localhost";
    }

    iso = isodate_from_time_t (t);
    ret = g_strdup_printf ("%s-%d-%d-%d-%d@%s",
                   iso,
                   getpid (),
                   getgid (),
                   getppid (),
                   serial++,
                   hostname);
    g_free (iso);

    return ret;
}

/**
 * cal_component_new:
 *
 * Creates a new empty calendar component object.  You should set it from an
 * #icalcomponent structure by using cal_component_set_icalcomponent() or with a
 * new empty component type by using cal_component_set_new_vtype().
 *
 * Return value: A newly-created calendar component object.
 **/
CalComponent *
cal_component_new (void)
{
    return CAL_COMPONENT (gtk_type_new (CAL_COMPONENT_TYPE));
}

/**
 * cal_component_clone:
 * @comp: A calendar component object.
 *
 * Creates a new calendar component object by copying the information from
 * another one.
 *
 * Return value: A newly-created calendar component with the same values as the
 * original one.
 **/
CalComponent *
cal_component_clone (CalComponent *comp)
{
    CalComponentPrivate *priv;
    CalComponent *new_comp;
    icalcomponent *new_icalcomp;

    g_return_val_if_fail (comp != NULL, NULL);
    g_return_val_if_fail (IS_CAL_COMPONENT (comp), NULL);

    priv = comp->priv;
    g_return_val_if_fail (priv->need_sequence_inc == FALSE, NULL);

    new_comp = cal_component_new ();

    if (priv->icalcomp) {
        new_icalcomp = icalcomponent_new_clone (priv->icalcomp);
        cal_component_set_icalcomponent (new_comp, new_icalcomp);
    }

    return new_comp;
}

/* Scans an attendee property */
static void
scan_attendee (CalComponent *comp, GSList **attendee_list, icalproperty *prop) 
{
    struct attendee *attendee;
    
    attendee = g_new (struct attendee, 1);
    attendee->prop = prop;

    attendee->cutype_param = icalproperty_get_first_parameter (prop, ICAL_CUTYPE_PARAMETER);
    attendee->member_param = icalproperty_get_first_parameter (prop, ICAL_MEMBER_PARAMETER);
    attendee->role_param = icalproperty_get_first_parameter (prop, ICAL_ROLE_PARAMETER);
    attendee->partstat_param = icalproperty_get_first_parameter (prop, ICAL_PARTSTAT_PARAMETER);
    attendee->rsvp_param = icalproperty_get_first_parameter (prop, ICAL_RSVP_PARAMETER);
    attendee->delto_param = icalproperty_get_first_parameter (prop, ICAL_DELEGATEDTO_PARAMETER);
    attendee->delfrom_param = icalproperty_get_first_parameter (prop, ICAL_DELEGATEDFROM_PARAMETER);
    attendee->sentby_param = icalproperty_get_first_parameter (prop, ICAL_SENTBY_PARAMETER);
    attendee->cn_param = icalproperty_get_first_parameter (prop, ICAL_CN_PARAMETER);
    attendee->language_param = icalproperty_get_first_parameter (prop, ICAL_LANGUAGE_PARAMETER);
    
    *attendee_list = g_slist_append (*attendee_list, attendee);
}

/* Scans a date/time and timezone pair property */
static void
scan_datetime (CalComponent *comp, struct datetime *datetime, icalproperty *prop)
{
    CalComponentPrivate *priv;

    priv = comp->priv;

    datetime->prop = prop;
    datetime->tzid_param = icalproperty_get_first_parameter (prop, ICAL_TZID_PARAMETER);
}

/* Scans an exception date property */
static void
scan_exdate (CalComponent *comp, icalproperty *prop)
{
    CalComponentPrivate *priv;
    struct datetime *dt;

    priv = comp->priv;

    dt = g_new (struct datetime, 1);
    dt->prop = prop;
    dt->tzid_param = icalproperty_get_first_parameter (prop, ICAL_TZID_PARAMETER);

    priv->exdate_list = g_slist_append (priv->exdate_list, dt);
}

/* Scans and attendee property */
static void
scan_organizer (CalComponent *comp, struct organizer *organizer, icalproperty *prop) 
{
    organizer->prop = prop;

    organizer->sentby_param = icalproperty_get_first_parameter (prop, ICAL_SENTBY_PARAMETER);
    organizer->cn_param = icalproperty_get_first_parameter (prop, ICAL_CN_PARAMETER);
    organizer->language_param = icalproperty_get_first_parameter (prop, ICAL_LANGUAGE_PARAMETER);
}

/* Scans an icalperiodtype property */
static void
scan_period (CalComponent *comp, GSList **list, icalproperty *prop)
{
    struct period *period;

    period = g_new (struct period, 1);
    period->prop = prop;
    period->value_param = icalproperty_get_first_parameter (prop, ICAL_VALUE_PARAMETER);

    *list = g_slist_append (*list, period);
}


/* Scans an icalrecurtype property */
static void
scan_recur_id (CalComponent *comp, struct recur_id *recur_id, icalproperty *prop)
{
    scan_datetime (comp, &recur_id->recur_time, prop);

    recur_id->range_param = icalproperty_get_first_parameter (prop, ICAL_RANGE_PARAMETER);
}

/* Scans an icalrecurtype property */
static void
scan_recur (CalComponent *comp, GSList **list, icalproperty *prop)
{
    *list = g_slist_append (*list, prop);
}

/* Scans the summary property */
static void
scan_summary (CalComponent *comp, icalproperty *prop)
{
    CalComponentPrivate *priv;

    priv = comp->priv;

    priv->summary.prop = prop;
    priv->summary.altrep_param = icalproperty_get_first_parameter (prop, ICAL_ALTREP_PARAMETER);
}

/* Scans a text (i.e. text + altrep) property */
static void
scan_text (CalComponent *comp, GSList **text_list, icalproperty *prop)
{
    struct text *text;

    text = g_new (struct text, 1);
    text->prop = prop;
    text->altrep_param = icalproperty_get_first_parameter (prop, ICAL_ALTREP_PARAMETER);

    *text_list = g_slist_append (*text_list, text);
}

/* Scans an icalproperty and adds its mapping to the component */
static void
scan_property (CalComponent *comp, icalproperty *prop)
{
    CalComponentPrivate *priv;
    icalproperty_kind kind;

    priv = comp->priv;

    kind = icalproperty_isa (prop);

    switch (kind) {
    case ICAL_STATUS_PROPERTY:
        priv->status = prop;
        break;

    case ICAL_ATTENDEE_PROPERTY:
        scan_attendee (comp, &priv->attendee_list, prop);
        break;

    case ICAL_CATEGORIES_PROPERTY:
        priv->categories = prop;
        break;

    case ICAL_CLASS_PROPERTY:
        priv->classification = prop;
        break;

    case ICAL_COMMENT_PROPERTY:
        scan_text (comp, &priv->comment_list, prop);
        break;

    case ICAL_COMPLETED_PROPERTY:
        priv->completed = prop;
        break;

    case ICAL_CREATED_PROPERTY:
        priv->created = prop;
        break;

    case ICAL_DESCRIPTION_PROPERTY:
        scan_text (comp, &priv->description_list, prop);
        break;

    case ICAL_DTEND_PROPERTY:
        scan_datetime (comp, &priv->dtend, prop);
        break;

    case ICAL_DTSTAMP_PROPERTY:
        priv->dtstamp = prop;
        break;

    case ICAL_DTSTART_PROPERTY:
        scan_datetime (comp, &priv->dtstart, prop);
        break;

    case ICAL_DUE_PROPERTY:
        scan_datetime (comp, &priv->due, prop);
        break;

    case ICAL_EXDATE_PROPERTY:
        scan_exdate (comp, prop);
        break;

    case ICAL_EXRULE_PROPERTY:
        scan_recur (comp, &priv->exrule_list, prop);
        break;

    case ICAL_GEO_PROPERTY:
        priv->geo = prop;
        break;

    case ICAL_LASTMODIFIED_PROPERTY:
        priv->last_modified = prop;
        break;

    case ICAL_ORGANIZER_PROPERTY:
        scan_organizer (comp, &priv->organizer, prop);
        break;

    case ICAL_PERCENTCOMPLETE_PROPERTY:
        priv->percent = prop;
        break;

    case ICAL_PRIORITY_PROPERTY:
        priv->priority = prop;
        break;

    case ICAL_RECURRENCEID_PROPERTY:
        scan_recur_id (comp, &priv->recur_id, prop);
        break;

    case ICAL_RDATE_PROPERTY:
        scan_period (comp, &priv->rdate_list, prop);
        break;

    case ICAL_RRULE_PROPERTY:
        scan_recur (comp, &priv->rrule_list, prop);
        break;

    case ICAL_SEQUENCE_PROPERTY:
        priv->sequence = prop;
        break;

    case ICAL_SUMMARY_PROPERTY:
        scan_summary (comp, prop);
        break;

    case ICAL_TRANSP_PROPERTY:
        priv->transparency = prop;
        break;

    case ICAL_UID_PROPERTY:
        priv->uid = prop;
        break;

    case ICAL_URL_PROPERTY:
        priv->url = prop;
        break;

    default:
        break;
    }
}

/* Gets our alarm UID string from a property that is known to contain it */
static const char *
alarm_uid_from_prop (icalproperty *prop)
{
    const char *xstr;

    g_assert (icalproperty_isa (prop) == ICAL_X_PROPERTY);

    xstr = icalproperty_get_x (prop);
    g_assert (xstr != NULL);

    return xstr;
}

/* Sets our alarm UID extension property on an alarm component.  Returns a
 * pointer to the UID string inside the property itself.
 */
static const char *
set_alarm_uid (icalcomponent *alarm, const char *auid)
{
    icalproperty *prop;
    const char *inprop_auid;

    /* Create the new property */

    prop = icalproperty_new_x ((char *) auid);
    icalproperty_set_x_name (prop, EVOLUTION_ALARM_UID_PROPERTY);

    icalcomponent_add_property (alarm, prop);

    inprop_auid = alarm_uid_from_prop (prop);
    return inprop_auid;
}

/* Removes any alarm UID extension properties from an alarm subcomponent */
static void
remove_alarm_uid (icalcomponent *alarm)
{
    icalproperty *prop;
    GSList *list, *l;

    list = NULL;

    for (prop = icalcomponent_get_first_property (alarm, ICAL_X_PROPERTY);
         prop;
         prop = icalcomponent_get_next_property (alarm, ICAL_X_PROPERTY)) {
        const char *xname;

        xname = icalproperty_get_x_name (prop);
        g_assert (xname != NULL);

        if (strcmp (xname, EVOLUTION_ALARM_UID_PROPERTY) == 0)
            list = g_slist_prepend (list, prop);
    }

    for (l = list; l; l = l->next) {
        prop = l->data;
        icalcomponent_remove_property (alarm, prop);
        icalproperty_free (prop);
    }

    g_slist_free (list);
}

/* Adds an alarm subcomponent to the calendar component's mapping table.  The
 * actual UID with which it gets added may not be the same as the specified one;
 * this function will change it if the table already had an alarm subcomponent
 * with the specified UID.  Returns the actual UID used.
 */
static const char *
add_alarm (CalComponent *comp, icalcomponent *alarm, const char *auid)
{
    CalComponentPrivate *priv;
    icalcomponent *old_alarm;

    priv = comp->priv;

    /* First we see if we already have an alarm with the requested UID.  In
     * that case, we need to change the new UID to something else.  This
     * should never happen, but who knows.
     */

    old_alarm = g_hash_table_lookup (priv->alarm_uid_hash, auid);
    if (old_alarm != NULL) {
        char *new_auid;

        g_message ("add_alarm(): Got alarm with duplicated UID `%s', changing it...", auid);

        remove_alarm_uid (alarm);

        new_auid = cal_component_gen_uid ();
        auid = set_alarm_uid (alarm, new_auid);
        g_free (new_auid);
    }

    g_hash_table_insert (priv->alarm_uid_hash, (char *) auid, alarm);
    return auid;
}

/* Scans an alarm subcomponent, adds an UID extension property to it (so that we
 * can reference alarms by unique IDs), and adds its mapping to the component.  */
static void
scan_alarm (CalComponent *comp, icalcomponent *alarm)
{
    CalComponentPrivate *priv;
    icalproperty *prop;
    const char *auid;
    char *new_auid;

    priv = comp->priv;

    for (prop = icalcomponent_get_first_property (alarm, ICAL_X_PROPERTY);
         prop;
         prop = icalcomponent_get_next_property (alarm, ICAL_X_PROPERTY)) {
        const char *xname;

        xname = icalproperty_get_x_name (prop);
        g_assert (xname != NULL);

        if (strcmp (xname, EVOLUTION_ALARM_UID_PROPERTY) == 0) {
            auid = alarm_uid_from_prop (prop);
            add_alarm (comp, alarm, auid);
            return;
        }
    }

    /* The component has no alarm UID property, so we create one. */

    new_auid = cal_component_gen_uid ();
    auid = set_alarm_uid (alarm, new_auid);
    g_free (new_auid);

    add_alarm (comp, alarm, auid);
}

/* Scans an icalcomponent for its properties so that we can provide
 * random-access to them.  It also builds a hash table of the component's alarm
 * subcomponents.
 */
static void
scan_icalcomponent (CalComponent *comp)
{
    CalComponentPrivate *priv;
    icalproperty *prop;
    icalcompiter iter;

    priv = comp->priv;

    g_assert (priv->icalcomp != NULL);

    /* Scan properties */

    for (prop = icalcomponent_get_first_property (priv->icalcomp, ICAL_ANY_PROPERTY);
         prop;
         prop = icalcomponent_get_next_property (priv->icalcomp, ICAL_ANY_PROPERTY))
        scan_property (comp, prop);

    /* Scan subcomponents */

    for (iter = icalcomponent_begin_component (priv->icalcomp, ICAL_VALARM_COMPONENT);
         icalcompiter_deref (&iter) != NULL;
         icalcompiter_next (&iter)) {
        icalcomponent *subcomp;

        subcomp = icalcompiter_deref (&iter);
        scan_alarm (comp, subcomp);
    }
}

/* Ensures that the mandatory calendar component properties (uid, dtstamp) do
 * exist.  If they don't exist, it creates them automatically.
 */
static void
ensure_mandatory_properties (CalComponent *comp)
{
    CalComponentPrivate *priv;

    priv = comp->priv;
    g_assert (priv->icalcomp != NULL);

    if (!priv->uid) {
        char *uid;

        uid = cal_component_gen_uid ();
        priv->uid = icalproperty_new_uid (uid);
        g_free (uid);

        icalcomponent_add_property (priv->icalcomp, priv->uid);
    }

    if (!priv->dtstamp) {
        time_t tim;
        struct icaltimetype t;

        tim = time (NULL);
        t = icaltime_from_timet (tim, FALSE);

        priv->dtstamp = icalproperty_new_dtstamp (t);
        icalcomponent_add_property (priv->icalcomp, priv->dtstamp);
    }
}

/**
 * cal_component_set_new_vtype:
 * @comp: A calendar component object.
 * @type: Type of calendar component to create.
 *
 * Clears any existing component data from a calendar component object and
 * creates a new #icalcomponent of the specified type for it.  The only property
 * that will be set in the new component will be its unique identifier.
 **/
void
cal_component_set_new_vtype (CalComponent *comp, CalComponentVType type)
{
    CalComponentPrivate *priv;
    icalcomponent *icalcomp;
    icalcomponent_kind kind;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));

    priv = comp->priv;

    free_icalcomponent (comp);

    if (type == CAL_COMPONENT_NO_TYPE)
        return;

    /* Figure out the kind and create the icalcomponent */

    switch (type) {
    case CAL_COMPONENT_EVENT:
        kind = ICAL_VEVENT_COMPONENT;
        break;

    case CAL_COMPONENT_TODO:
        kind = ICAL_VTODO_COMPONENT;
        break;

    case CAL_COMPONENT_JOURNAL:
        kind = ICAL_VJOURNAL_COMPONENT;
        break;

    case CAL_COMPONENT_FREEBUSY:
        kind = ICAL_VFREEBUSY_COMPONENT;
        break;

    case CAL_COMPONENT_TIMEZONE:
        kind = ICAL_VTIMEZONE_COMPONENT;
        break;

    default:
        g_assert_not_reached ();
        kind = ICAL_NO_COMPONENT;
    }

    icalcomp = icalcomponent_new (kind);
    if (!icalcomp) {
        g_message ("cal_component_set_new_vtype(): Could not create the icalcomponent!");
        return;
    }

    /* Scan the component to build our mapping table */

    priv->icalcomp = icalcomp;
    scan_icalcomponent (comp);

    /* Add missing stuff */

    ensure_mandatory_properties (comp);
}

/**
 * cal_component_set_icalcomponent:
 * @comp: A calendar component object.
 * @icalcomp: An #icalcomponent.
 *
 * Sets the contents of a calendar component object from an #icalcomponent
 * structure.  If the @comp already had an #icalcomponent set into it, it will
 * will be freed automatically if the #icalcomponent does not have a parent
 * component itself.
 *
 * Supported component types are VEVENT, VTODO, VJOURNAL, VFREEBUSY, and VTIMEZONE.
 *
 * Return value: TRUE on success, FALSE if @icalcomp is an unsupported component
 * type.
 **/
gboolean
cal_component_set_icalcomponent (CalComponent *comp, icalcomponent *icalcomp)
{
    CalComponentPrivate *priv;
    icalcomponent_kind kind;

    g_return_val_if_fail (comp != NULL, FALSE);
    g_return_val_if_fail (IS_CAL_COMPONENT (comp), FALSE);

    priv = comp->priv;

    if (priv->icalcomp == icalcomp)
        return TRUE;

    free_icalcomponent (comp);

    if (!icalcomp) {
        priv->icalcomp = NULL;
        return TRUE;
    }

    kind = icalcomponent_isa (icalcomp);

    if (!(kind == ICAL_VEVENT_COMPONENT
          || kind == ICAL_VTODO_COMPONENT
          || kind == ICAL_VJOURNAL_COMPONENT
          || kind == ICAL_VFREEBUSY_COMPONENT
          || kind == ICAL_VTIMEZONE_COMPONENT))
        return FALSE;

    priv->icalcomp = icalcomp;

    scan_icalcomponent (comp);
    ensure_mandatory_properties (comp);

    return TRUE;
}

/**
 * cal_component_get_icalcomponent:
 * @comp: A calendar component object.
 *
 * Queries the #icalcomponent structure that a calendar component object is
 * wrapping.
 *
 * Return value: An #icalcomponent structure, or NULL if the @comp has no
 * #icalcomponent set to it.
 **/
icalcomponent *
cal_component_get_icalcomponent (CalComponent *comp)
{
    CalComponentPrivate *priv;

    g_return_val_if_fail (comp != NULL, NULL);
    g_return_val_if_fail (IS_CAL_COMPONENT (comp), NULL);

    priv = comp->priv;
    g_return_val_if_fail (priv->need_sequence_inc == FALSE, NULL);

    return priv->icalcomp;
}

/**
 * cal_component_get_vtype:
 * @comp: A calendar component object.
 *
 * Queries the type of a calendar component object.
 *
 * Return value: The type of the component, as defined by RFC 2445.
 **/
CalComponentVType
cal_component_get_vtype (CalComponent *comp)
{
    CalComponentPrivate *priv;
    icalcomponent_kind kind;

    g_return_val_if_fail (comp != NULL, CAL_COMPONENT_NO_TYPE);
    g_return_val_if_fail (IS_CAL_COMPONENT (comp), CAL_COMPONENT_NO_TYPE);

    priv = comp->priv;
    g_return_val_if_fail (priv->icalcomp != NULL, CAL_COMPONENT_NO_TYPE);

    kind = icalcomponent_isa (priv->icalcomp);
    switch (kind) {
    case ICAL_VEVENT_COMPONENT:
        return CAL_COMPONENT_EVENT;

    case ICAL_VTODO_COMPONENT:
        return CAL_COMPONENT_TODO;

    case ICAL_VJOURNAL_COMPONENT:
        return CAL_COMPONENT_JOURNAL;

    case ICAL_VFREEBUSY_COMPONENT:
        return CAL_COMPONENT_FREEBUSY;

    case ICAL_VTIMEZONE_COMPONENT:
        return CAL_COMPONENT_TIMEZONE;

    default:
        /* We should have been loaded with a supported type! */
        g_assert_not_reached ();
        return CAL_COMPONENT_NO_TYPE;
    }
}

/**
 * cal_component_get_as_string:
 * @comp: A calendar component.
 *
 * Gets the iCalendar string representation of a calendar component.  You should
 * call cal_component_commit_sequence() before this function to ensure that the
 * component's sequence number is consistent with the state of the object.
 *
 * Return value: String representation of the calendar component according to
 * RFC 2445.
 **/
char *
cal_component_get_as_string (CalComponent *comp)
{
    CalComponentPrivate *priv;
    char *str, *buf;

    g_return_val_if_fail (comp != NULL, NULL);
    g_return_val_if_fail (IS_CAL_COMPONENT (comp), NULL);

    priv = comp->priv;
    g_return_val_if_fail (priv->icalcomp != NULL, NULL);

    /* Ensure that the user has committed the new SEQUENCE */
    g_return_val_if_fail (priv->need_sequence_inc == FALSE, NULL);

    /* We dup the string; libical owns that memory */

    str = icalcomponent_as_ical_string (priv->icalcomp);

    if (str)
        buf = g_strdup (str);
    else
        buf = NULL;

    return buf;
}

/**
 * cal_component_commit_sequence:
 * @comp:
 *
 * Increments the sequence number property in a calendar component object if it
 * needs it.  This needs to be done when any of a number of properties listed in
 * RFC 2445 change values, such as the start and end dates of a component.
 *
 * This function must be called before calling cal_component_get_as_string() to
 * ensure that the component is fully consistent.
 **/
void
cal_component_commit_sequence (CalComponent *comp)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    if (!priv->need_sequence_inc)
        return;

    if (priv->sequence) {
        int seq;

        seq = icalproperty_get_sequence (priv->sequence);
        icalproperty_set_sequence (priv->sequence, seq + 1);
    } else {
        /* The component had no SEQUENCE property, so assume that the
         * default would have been zero.  Since it needed incrementing
         * anyways, we use a value of 1 here.
         */
        priv->sequence = icalproperty_new_sequence (1);
        icalcomponent_add_property (priv->icalcomp, priv->sequence);
    }

    priv->need_sequence_inc = FALSE;
}

/**
 * cal_component_get_uid:
 * @comp: A calendar component object.
 * @uid: Return value for the UID string.
 *
 * Queries the unique identifier of a calendar component object.
 **/
void
cal_component_get_uid (CalComponent *comp, const char **uid)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));
    g_return_if_fail (uid != NULL);

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    /* This MUST exist, since we ensured that it did */
    g_assert (priv->uid != NULL);

    *uid = icalproperty_get_uid (priv->uid);
}

/**
 * cal_component_set_uid:
 * @comp: A calendar component object.
 * @uid: Unique identifier.
 *
 * Sets the unique identifier string of a calendar component object.
 **/
void
cal_component_set_uid (CalComponent *comp, const char *uid)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));
    g_return_if_fail (uid != NULL);

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    /* This MUST exist, since we ensured that it did */
    g_assert (priv->uid != NULL);

    icalproperty_set_uid (priv->uid, (char *) uid);
}

/**
 * cal_component_get_categories:
 * @comp: A calendar component object.
 * @categories:
 *
 *
 **/
void
cal_component_get_categories (CalComponent *comp, const char **categories)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));
    g_return_if_fail (categories != NULL);

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    if (priv->categories)
        *categories = icalproperty_get_categories (priv->categories);
    else
        *categories = NULL;
}

/**
 * cal_component_set_categories:
 * @comp: A calendar component object.
 * @categories:
 *
 *
 **/
void
cal_component_set_categories (CalComponent *comp, const char *categories)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    if (!categories || !(*categories)) {
        if (priv->categories) {
            icalcomponent_remove_property (priv->icalcomp, priv->categories);
            icalproperty_free (priv->categories);
            priv->url = NULL;
        }

        return;
    }

    if (priv->categories)
        icalproperty_set_categories (priv->categories, (char *) categories);
    else {
        priv->categories = icalproperty_new_categories ((char *) categories);
        icalcomponent_add_property (priv->icalcomp, priv->categories);
    }
}


/**
 * cal_component_get_categories_list:
 * @comp: A calendar component object.
 * @categ_list: Return value for the list of strings, where each string is a
 * category.  This should be freed using cal_component_free_categories_list().
 *
 * Queries the list of categories of a calendar component object.  Each element
 * in the returned categ_list is a string with the corresponding category.
 **/
void
cal_component_get_categories_list (CalComponent *comp, GSList **categ_list)
{
    CalComponentPrivate *priv;
    const char *categories;
    const char *p;
    const char *cat_start;
    char *str;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));
    g_return_if_fail (categ_list != NULL);

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    if (!priv->categories) {
        *categ_list = NULL;
        return;
    }

    categories = icalproperty_get_categories (priv->categories);
    g_assert (categories != NULL);

    cat_start = categories;
    *categ_list = NULL;

    for (p = categories; *p; p++)
        if (*p == ',') {
            str = g_strndup (cat_start, p - cat_start);
            *categ_list = g_slist_prepend (*categ_list, str);

            cat_start = p + 1;
        }

    str = g_strndup (cat_start, p - cat_start);
    *categ_list = g_slist_prepend (*categ_list, str);

    *categ_list = g_slist_reverse (*categ_list);
}

/* Creates a comma-delimited string of categories */
static char *
stringify_categories (GSList *categ_list)
{
    GString *s;
    GSList *l;
    char *str;

    s = g_string_new (NULL);

    for (l = categ_list; l; l = l->next) {
        g_string_append (s, l->data);

        if (l->next != NULL)
            g_string_append (s, ",");
    }

    str = s->str;
    g_string_free (s, FALSE);

    return str;
}

/**
 * cal_component_set_categories_list:
 * @comp: A calendar component object.
 * @categ_list: List of strings, one for each category.
 *
 * Sets the list of categories of a calendar component object.
 **/
void
cal_component_set_categories_list (CalComponent *comp, GSList *categ_list)
{
    CalComponentPrivate *priv;
    char *categories_str;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    if (!categ_list) {
        if (priv->categories) {
            icalcomponent_remove_property (priv->icalcomp, priv->categories);
            icalproperty_free (priv->categories);
        }

        return;
    }

    /* Create a single string of categories */
    categories_str = stringify_categories (categ_list);

    /* Set the categories */
    priv->categories = icalproperty_new_categories (categories_str);
    g_free (categories_str);

    icalcomponent_add_property (priv->icalcomp, priv->categories);
}

/**
 * cal_component_get_classification:
 * @comp: A calendar component object.
 * @classif: Return value for the classification.
 *
 * Queries the classification of a calendar component object.  If the
 * classification property is not set on this component, this function returns
 * #CAL_COMPONENT_CLASS_NONE.
 **/
void
cal_component_get_classification (CalComponent *comp, CalComponentClassification *classif)
{
    CalComponentPrivate *priv;
    const char *class;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));
    g_return_if_fail (classif != NULL);

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    if (!priv->classification) {
        *classif = CAL_COMPONENT_CLASS_NONE;
        return;
    }

    class = icalproperty_get_class (priv->classification);

    if (strcasecmp (class, "PUBLIC") == 0)
        *classif = CAL_COMPONENT_CLASS_PUBLIC;
    else if (strcasecmp (class, "PRIVATE") == 0)
        *classif = CAL_COMPONENT_CLASS_PRIVATE;
    else if (strcasecmp (class, "CONFIDENTIAL") == 0)
        *classif = CAL_COMPONENT_CLASS_CONFIDENTIAL;
    else
        *classif = CAL_COMPONENT_CLASS_UNKNOWN;
}

/**
 * cal_component_set_classification:
 * @comp: A calendar component object.
 * @classif: Classification to use.
 *
 * Sets the classification property of a calendar component object.  To unset
 * the property, specify CAL_COMPONENT_CLASS_NONE for @classif.
 **/
void
cal_component_set_classification (CalComponent *comp, CalComponentClassification classif)
{
    CalComponentPrivate *priv;
    char *str;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));
    g_return_if_fail (classif != CAL_COMPONENT_CLASS_UNKNOWN);

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    if (classif == CAL_COMPONENT_CLASS_NONE) {
        if (priv->classification) {
            icalcomponent_remove_property (priv->icalcomp, priv->classification);
            icalproperty_free (priv->classification);
            priv->classification = NULL;
        }

        return;
    }

    switch (classif) {
    case CAL_COMPONENT_CLASS_PUBLIC:
        str = "PUBLIC";
        break;

    case CAL_COMPONENT_CLASS_PRIVATE:
        str = "PRIVATE";
        break;

    case CAL_COMPONENT_CLASS_CONFIDENTIAL:
        str = "CONFIDENTIAL";
        break;

    default:
        g_assert_not_reached ();
        str = NULL;
    }

    if (priv->classification)
        icalproperty_set_class (priv->classification, str);
    else {
        priv->classification = icalproperty_new_class (str);
        icalcomponent_add_property (priv->icalcomp, priv->classification);
    }
}

/* Gets a text list value */
static void
get_text_list (GSList *text_list,
           const char *(* get_prop_func) (icalproperty *prop),
           GSList **tl)
{
    GSList *l;

    *tl = NULL;

    if (!text_list)
        return;

    for (l = text_list; l; l = l->next) {
        struct text *text;
        CalComponentText *t;

        text = l->data;
        g_assert (text->prop != NULL);

        t = g_new (CalComponentText, 1);
        t->value = (* get_prop_func) (text->prop);

        if (text->altrep_param)
            t->altrep = icalparameter_get_altrep (text->altrep_param);
        else
            t->altrep = NULL;

        *tl = g_slist_prepend (*tl, t);
    }

    *tl = g_slist_reverse (*tl);
}

/* Sets a text list value */
static void
set_text_list (CalComponent *comp,
           icalproperty *(* new_prop_func) (const char *value),
           GSList **text_list,
           GSList *tl)
{
    CalComponentPrivate *priv;
    GSList *l;

    priv = comp->priv;

    /* Remove old texts */

    for (l = *text_list; l; l = l->next) {
        struct text *text;

        text = l->data;
        g_assert (text->prop != NULL);

        icalcomponent_remove_property (priv->icalcomp, text->prop);
        icalproperty_free (text->prop);
        g_free (text);
    }

    g_slist_free (*text_list);
    *text_list = NULL;

    /* Add in new texts */

    for (l = tl; l; l = l->next) {
        CalComponentText *t;
        struct text *text;

        t = l->data;
        g_return_if_fail (t->value != NULL);

        text = g_new (struct text, 1);

        text->prop = (* new_prop_func) ((char *) t->value);
        icalcomponent_add_property (priv->icalcomp, text->prop);

        if (t->altrep) {
            text->altrep_param = icalparameter_new_altrep ((char *) t->altrep);
            icalproperty_add_parameter (text->prop, text->altrep_param);
        } else
            text->altrep_param = NULL;

        *text_list = g_slist_prepend (*text_list, text);
    }

    *text_list = g_slist_reverse (*text_list);
}

/**
 * cal_component_get_comment_list:
 * @comp: A calendar component object.
 * @text_list: Return value for the comment properties and their parameters, as
 * a list of #CalComponentText structures.  This should be freed using the
 * cal_component_free_text_list() function.
 *
 * Queries the comment of a calendar component object.  The comment property can
 * appear several times inside a calendar component, and so a list of
 * #CalComponentText is returned.
 **/
void
cal_component_get_comment_list (CalComponent *comp, GSList **text_list)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));
    g_return_if_fail (text_list != NULL);

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    get_text_list (priv->comment_list, icalproperty_get_comment, text_list);
}

/**
 * cal_component_set_comment_list:
 * @comp: A calendar component object.
 * @text_list: List of #CalComponentText structures.
 *
 * Sets the comment of a calendar component object.  The comment property can
 * appear several times inside a calendar component, and so a list of
 * #CalComponentText structures is used.
 **/
void
cal_component_set_comment_list (CalComponent *comp, GSList *text_list)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    set_text_list (comp, icalproperty_new_comment, &priv->comment_list, text_list);
}

/* Gets a struct icaltimetype value */
static void
get_icaltimetype (icalproperty *prop,
          struct icaltimetype (* get_prop_func) (icalproperty *prop),
          struct icaltimetype **t)
{
    if (!prop) {
        *t = NULL;
        return;
    }

    *t = g_new (struct icaltimetype, 1);
    **t = (* get_prop_func) (prop);
}

/* Sets a struct icaltimetype value */
static void
set_icaltimetype (CalComponent *comp, icalproperty **prop,
          icalproperty *(* prop_new_func) (struct icaltimetype v),
          void (* prop_set_func) (icalproperty *prop, struct icaltimetype v),
          struct icaltimetype *t)
{
    CalComponentPrivate *priv;

    priv = comp->priv;

    if (!t) {
        if (*prop) {
            icalcomponent_remove_property (priv->icalcomp, *prop);
            icalproperty_free (*prop);
            *prop = NULL;
        }

        return;
    }

    if (*prop)
        (* prop_set_func) (*prop, *t);
    else {
        *prop = (* prop_new_func) (*t);
        icalcomponent_add_property (priv->icalcomp, *prop);
    }
}

/**
 * cal_component_get_completed:
 * @comp: A calendar component object.
 * @t: Return value for the completion date.  This should be freed using the
 * cal_component_free_icaltimetype() function.
 *
 * Queries the date at which a calendar compoment object was completed.
 **/
void
cal_component_get_completed (CalComponent *comp, struct icaltimetype **t)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));
    g_return_if_fail (t != NULL);

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    get_icaltimetype (priv->completed, icalproperty_get_completed, t);
}

/**
 * cal_component_set_completed:
 * @comp: A calendar component object.
 * @t: Value for the completion date.
 *
 * Sets the date at which a calendar component object was completed.
 **/
void
cal_component_set_completed (CalComponent *comp, struct icaltimetype *t)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    set_icaltimetype (comp, &priv->completed,
              icalproperty_new_completed,
              icalproperty_set_completed,
              t);
}


/**
 * cal_component_get_created:
 * @comp: A calendar component object.
 * @t: Return value for the creation date.  This should be freed using the
 * cal_component_free_icaltimetype() function.
 *
 * Queries the date in which a calendar component object was created in the
 * calendar store.
 **/
void
cal_component_get_created (CalComponent *comp, struct icaltimetype **t)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));
    g_return_if_fail (t != NULL);

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    get_icaltimetype (priv->created, icalproperty_get_created, t);
}

/**
 * cal_component_set_created:
 * @comp: A calendar component object.
 * @t: Value for the creation date.
 *
 * Sets the date in which a calendar component object is created in the calendar
 * store.  This should only be used inside a calendar store application, i.e.
 * not by calendar user agents.
 **/
void
cal_component_set_created (CalComponent *comp, struct icaltimetype *t)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    set_icaltimetype (comp, &priv->created,
              icalproperty_new_created,
              icalproperty_set_created,
              t);
}

/**
 * cal_component_get_description_list:
 * @comp: A calendar component object.
 * @text_list: Return value for the description properties and their parameters,
 * as a list of #CalComponentText structures.  This should be freed using the
 * cal_component_free_text_list() function.
 *
 * Queries the description of a calendar component object.  Journal components
 * may have more than one description, and as such this function returns a list
 * of #CalComponentText structures.  All other types of components can have at
 * most one description.
 **/
void
cal_component_get_description_list (CalComponent *comp, GSList **text_list)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));
    g_return_if_fail (text_list != NULL);

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    get_text_list (priv->description_list, icalproperty_get_description, text_list);
}

/**
 * cal_component_set_description_list:
 * @comp: A calendar component object.
 * @text_list: List of #CalComponentSummary structures.
 *
 * Sets the description of a calendar component object.  Journal components may
 * have more than one description, and as such this function takes in a list of
 * #CalComponentDescription structures.  All other types of components can have
 * at most one description.
 **/
void
cal_component_set_description_list (CalComponent *comp, GSList *text_list)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    set_text_list (comp, icalproperty_new_description, &priv->description_list, text_list);
}

/* Gets a date/time and timezone pair */
static void
get_datetime (struct datetime *datetime,
          struct icaltimetype (* get_prop_func) (icalproperty *prop),
          CalComponentDateTime *dt)
{
    if (datetime->prop) {
        dt->value = g_new (struct icaltimetype, 1);
        *dt->value = (* get_prop_func) (datetime->prop);
    } else
        dt->value = NULL;

    if (datetime->tzid_param)
        dt->tzid = icalparameter_get_tzid (datetime->tzid_param);
    else
        dt->tzid = NULL;
}

/* Sets a date/time and timezone pair */
static void
set_datetime (CalComponent *comp, struct datetime *datetime,
          icalproperty *(* prop_new_func) (struct icaltimetype v),
          void (* prop_set_func) (icalproperty * prop, struct icaltimetype v),
          CalComponentDateTime *dt)
{
    CalComponentPrivate *priv;

    priv = comp->priv;

    if (!dt) {
        if (datetime->prop) {
            icalcomponent_remove_property (priv->icalcomp, datetime->prop);
            icalproperty_free (datetime->prop);

            datetime->prop = NULL;
            datetime->tzid_param = NULL;
        }

        return;
    }

    g_return_if_fail (dt->value != NULL);

    if (datetime->prop)
        (* prop_set_func) (datetime->prop, *dt->value);
    else {
        datetime->prop = (* prop_new_func) (*dt->value);
        icalcomponent_add_property (priv->icalcomp, datetime->prop);
    }

    if (dt->tzid) {
        g_assert (datetime->prop != NULL);

        if (datetime->tzid_param)
            icalparameter_set_tzid (datetime->tzid_param, (char *) dt->tzid);
        else {
            datetime->tzid_param = icalparameter_new_tzid ((char *) dt->tzid);
            icalproperty_add_parameter (datetime->prop, datetime->tzid_param);
        }
    } else if (datetime->tzid_param) {
        icalproperty_remove_parameter (datetime->prop, ICAL_TZID_PARAMETER);
        icalparameter_free (datetime->tzid_param);
        datetime->tzid_param = NULL;
    }
}

/**
 * cal_component_get_dtend:
 * @comp: A calendar component object.
 * @dt: Return value for the date/time end.  This should be freed with the
 * cal_component_free_datetime() function.
 *
 * Queries the date/time end of a calendar component object.
 **/
void
cal_component_get_dtend (CalComponent *comp, CalComponentDateTime *dt)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));
    g_return_if_fail (dt != NULL);

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    get_datetime (&priv->dtend, icalproperty_get_dtend, dt);
}

/**
 * cal_component_set_dtend:
 * @comp: A calendar component object.
 * @dt: End date/time.
 *
 * Sets the date/time end property of a calendar component object.
 **/
void
cal_component_set_dtend (CalComponent *comp, CalComponentDateTime *dt)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    set_datetime (comp, &priv->dtend,
              icalproperty_new_dtend,
              icalproperty_set_dtend,
              dt);

    priv->need_sequence_inc = TRUE;
}

/**
 * cal_component_get_dtstamp:
 * @comp: A calendar component object.
 * @t: A value for the date/timestamp.
 *
 * Queries the date/timestamp property of a calendar component object, which is
 * the last time at which the object was modified by a calendar user agent.
 **/
void
cal_component_get_dtstamp (CalComponent *comp, struct icaltimetype *t)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));
    g_return_if_fail (t != NULL);

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    /* This MUST exist, since we ensured that it did */
    g_assert (priv->dtstamp != NULL);

    *t = icalproperty_get_dtstamp (priv->dtstamp);
}

/**
 * cal_component_set_dtstamp:
 * @comp: A calendar component object.
 * @t: Date/timestamp value.
 *
 * Sets the date/timestamp of a calendar component object.  This should be
 * called whenever a calendar user agent makes a change to a component's
 * properties.
 **/
void
cal_component_set_dtstamp (CalComponent *comp, struct icaltimetype *t)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));
    g_return_if_fail (t != NULL);

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    /* This MUST exist, since we ensured that it did */
    g_assert (priv->dtstamp != NULL);

    icalproperty_set_dtstamp (priv->dtstamp, *t);
}

/**
 * cal_component_get_dtstart:
 * @comp: A calendar component object.
 * @dt: Return value for the date/time start.  This should be freed with the
 * cal_component_free_datetime() function.
 *
 * Queries the date/time start of a calendar component object.
 **/
void
cal_component_get_dtstart (CalComponent *comp, CalComponentDateTime *dt)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));
    g_return_if_fail (dt != NULL);

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    get_datetime (&priv->dtstart, icalproperty_get_dtstart, dt);
}

/**
 * cal_component_set_dtstart:
 * @comp: A calendar component object.
 * @dt: Start date/time.
 *
 * Sets the date/time start property of a calendar component object.
 **/
void
cal_component_set_dtstart (CalComponent *comp, CalComponentDateTime *dt)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    set_datetime (comp, &priv->dtstart,
              icalproperty_new_dtstart,
              icalproperty_set_dtstart,
              dt);

    priv->need_sequence_inc = TRUE;
}

/**
 * cal_component_get_due:
 * @comp: A calendar component object.
 * @dt: Return value for the due date/time.  This should be freed with the
 * cal_component_free_datetime() function.
 *
 * Queries the due date/time of a calendar component object.
 **/
void
cal_component_get_due (CalComponent *comp, CalComponentDateTime *dt)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));
    g_return_if_fail (dt != NULL);

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    get_datetime (&priv->due, icalproperty_get_due, dt);
}

/**
 * cal_component_set_due:
 * @comp: A calendar component object.
 * @dt: End date/time.
 *
 * Sets the due date/time property of a calendar component object.
 **/
void
cal_component_set_due (CalComponent *comp, CalComponentDateTime *dt)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    set_datetime (comp, &priv->due,
              icalproperty_new_due,
              icalproperty_set_due,
              dt);

    priv->need_sequence_inc = TRUE;
}

/* Builds a list of CalComponentPeriod structures based on a list of icalproperties */
static void
get_period_list (GSList *period_list,
         struct icaldatetimeperiodtype (* get_prop_func) (icalproperty *prop),
         GSList **list)
{
    GSList *l;

    *list = NULL;

    if (!period_list)
        return;

    for (l = period_list; l; l = l->next) {
        struct period *period;
        CalComponentPeriod *p;
        struct icaldatetimeperiodtype ip;

        period = l->data;
        g_assert (period->prop != NULL);

        p = g_new (CalComponentPeriod, 1);

        /* Get value parameter */

        if (period->value_param) {
            icalparameter_value value_type;

            value_type = icalparameter_get_value (period->value_param);

            if (value_type == ICAL_VALUE_DATE || value_type == ICAL_VALUE_DATETIME)
                p->type = CAL_COMPONENT_PERIOD_DATETIME;
            else if (value_type == ICAL_VALUE_DURATION)
                p->type = CAL_COMPONENT_PERIOD_DURATION;
            else {
                g_message ("get_period_list(): Unknown value for period %d; "
                       "using DATETIME", value_type);
                p->type = CAL_COMPONENT_PERIOD_DATETIME;
            }
        } else
            p->type = CAL_COMPONENT_PERIOD_DATETIME;

        /* Get start and end/duration */

        ip = (* get_prop_func) (period->prop);

        p->start = ip.period.start;

        if (p->type == CAL_COMPONENT_PERIOD_DATETIME)
            p->u.end = ip.period.end;
        else if (p->type == CAL_COMPONENT_PERIOD_DURATION)
            p->u.duration = ip.period.duration;
        else
            g_assert_not_reached ();

        /* Put in list */

        *list = g_slist_prepend (*list, p);
    }

    *list = g_slist_reverse (*list);
}

/* Sets a period list value */
static void
set_period_list (CalComponent *comp,
         icalproperty *(* new_prop_func) (struct icaldatetimeperiodtype period),
         GSList **period_list,
         GSList *pl)
{
    CalComponentPrivate *priv;
    GSList *l;

    priv = comp->priv;

    /* Remove old periods */

    for (l = *period_list; l; l = l->next) {
        struct period *period;

        period = l->data;
        g_assert (period->prop != NULL);

        icalcomponent_remove_property (priv->icalcomp, period->prop);
        icalproperty_free (period->prop);
        g_free (period);
    }

    g_slist_free (*period_list);
    *period_list = NULL;

    /* Add in new periods */

    for (l = pl; l; l = l->next) {
        CalComponentPeriod *p;
        struct period *period;
        struct icaldatetimeperiodtype ip;
        icalparameter_value value_type;

        g_assert (l->data != NULL);
        p = l->data;

        /* Create libical value */

        ip.period.start = p->start;

        if (p->type == CAL_COMPONENT_PERIOD_DATETIME) {
            value_type = ICAL_VALUE_DATETIME;
            ip.period.end = p->u.end;
        } else if (p->type == CAL_COMPONENT_PERIOD_DURATION) {
            value_type = ICAL_VALUE_DURATION;
            ip.period.duration = p->u.duration;
        } else {
            g_assert_not_reached ();
            return;
        }

        /* Create property */

        period = g_new (struct period, 1);

        period->prop = (* new_prop_func) (ip);
        period->value_param = icalparameter_new_value (value_type);
        icalproperty_add_parameter (period->prop, period->value_param);

        /* Add to list */

        *period_list = g_slist_prepend (*period_list, period);
    }

    *period_list = g_slist_reverse (*period_list);
}

/**
 * cal_component_get_exdate_list:
 * @comp: A calendar component object.
 * @exdate_list: Return value for the list of exception dates, as a list of
 * #CalComponentDateTime structures.  This should be freed using the
 * cal_component_free_exdate_list() function.
 *
 * Queries the list of exception date properties in a calendar component object.
 **/
void
cal_component_get_exdate_list (CalComponent *comp, GSList **exdate_list)
{
    CalComponentPrivate *priv;
    GSList *l;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));
    g_return_if_fail (exdate_list != NULL);

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    *exdate_list = NULL;

    for (l = priv->exdate_list; l; l = l->next) {
        struct datetime *dt;
        CalComponentDateTime *cdt;

        dt = l->data;

        cdt = g_new (CalComponentDateTime, 1);
        cdt->value = g_new (struct icaltimetype, 1);

        *cdt->value = icalproperty_get_exdate (dt->prop);

        if (dt->tzid_param)
            cdt->tzid = icalparameter_get_tzid (dt->tzid_param);
        else
            cdt->tzid = NULL;

        *exdate_list = g_slist_prepend (*exdate_list, cdt);
    }

    *exdate_list = g_slist_reverse (*exdate_list);
}

/**
 * cal_component_set_exdate_list:
 * @comp: A calendar component object.
 * @exdate_list: List of #CalComponentDateTime structures.
 *
 * Sets the list of exception dates in a calendar component object.
 **/
void
cal_component_set_exdate_list (CalComponent *comp, GSList *exdate_list)
{
    CalComponentPrivate *priv;
    GSList *l;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    /* Remove old exception dates */

    for (l = priv->exdate_list; l; l = l->next) {
        struct datetime *dt;

        dt = l->data;

        icalcomponent_remove_property (priv->icalcomp, dt->prop);
        icalproperty_free (dt->prop);
        g_free (dt);
    }

    g_slist_free (priv->exdate_list);
    priv->exdate_list = NULL;

    /* Add in new exception dates */

    for (l = exdate_list; l; l = l->next) {
        CalComponentDateTime *cdt;
        struct datetime *dt;

        g_assert (l->data != NULL);
        cdt = l->data;

        g_assert (cdt->value != NULL);

        dt = g_new (struct datetime, 1);
        dt->prop = icalproperty_new_exdate (*cdt->value);

        if (cdt->tzid) {
            dt->tzid_param = icalparameter_new_tzid ((char *) cdt->tzid);
            icalproperty_add_parameter (dt->prop, dt->tzid_param);
        } else
            dt->tzid_param = NULL;

        icalcomponent_add_property (priv->icalcomp, dt->prop);
        priv->exdate_list = g_slist_prepend (priv->exdate_list, dt);
    }

    priv->exdate_list = g_slist_reverse (priv->exdate_list);

    priv->need_sequence_inc = TRUE;
}

/**
 * cal_component_has_exdates:
 * @comp: A calendar component object.
 *
 * Queries whether a calendar component object has any exception dates defined
 * for it.
 *
 * Return value: TRUE if the component has exception dates, FALSE otherwise.
 **/
gboolean
cal_component_has_exdates (CalComponent *comp)
{
    CalComponentPrivate *priv;

    g_return_val_if_fail (comp != NULL, FALSE);
    g_return_val_if_fail (IS_CAL_COMPONENT (comp), FALSE);

    priv = comp->priv;
    g_return_val_if_fail (priv->icalcomp != NULL, FALSE);

    return (priv->exdate_list != NULL);
}

/* Gets a list of recurrence rules */
static void
get_recur_list (GSList *recur_list,
        struct icalrecurrencetype (* get_prop_func) (icalproperty *prop),
        GSList **list)
{
    GSList *l;

    *list = NULL;

    for (l = recur_list; l; l = l->next) {
        icalproperty *prop;
        struct icalrecurrencetype *r;

        prop = l->data;

        r = g_new (struct icalrecurrencetype, 1);
        *r = (* get_prop_func) (prop);

        *list = g_slist_prepend (*list, r);
    }

    *list = g_slist_reverse (*list);
}

/* Sets a list of recurrence rules */
static void
set_recur_list (CalComponent *comp,
        icalproperty *(* new_prop_func) (struct icalrecurrencetype recur),
        GSList **recur_list,
        GSList *rl)
{
    CalComponentPrivate *priv;
    GSList *l;

    priv = comp->priv;

    /* Remove old recurrences */

    for (l = *recur_list; l; l = l->next) {
        icalproperty *prop;

        prop = l->data;
        icalcomponent_remove_property (priv->icalcomp, prop);
        icalproperty_free (prop);
    }

    g_slist_free (*recur_list);
    *recur_list = NULL;

    /* Add in new recurrences */

    for (l = rl; l; l = l->next) {
        icalproperty *prop;
        struct icalrecurrencetype *recur;

        g_assert (l->data != NULL);
        recur = l->data;

        prop = (* new_prop_func) (*recur);
        icalcomponent_add_property (priv->icalcomp, prop);

        *recur_list = g_slist_prepend (*recur_list, prop);
    }

    *recur_list = g_slist_reverse (*recur_list);
}

/**
 * cal_component_get_exrule_list:
 * @comp: A calendar component object.
 * @recur_list: List of exception rules as struct #icalrecurrencetype
 * structures.  This should be freed using the cal_component_free_recur_list()
 * function.
 *
 * Queries the list of exception rule properties of a calendar component
 * object.
 **/
void
cal_component_get_exrule_list (CalComponent *comp, GSList **recur_list)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));
    g_return_if_fail (recur_list != NULL);

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    get_recur_list (priv->exrule_list, icalproperty_get_exrule, recur_list);
}

/**
 * cal_component_get_exrule_property_list:
 * @comp: A calendar component object.
 * @recur_list: Returns a list of exception rule properties.
 *
 * Queries the list of exception rule properties of a calendar component object.
 **/
void
cal_component_get_exrule_property_list (CalComponent *comp, GSList **recur_list)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));
    g_return_if_fail (recur_list != NULL);

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    *recur_list = priv->exrule_list;
}

/**
 * cal_component_set_exrule_list:
 * @comp: A calendar component object.
 * @recur_list: List of struct #icalrecurrencetype structures.
 *
 * Sets the list of exception rules in a calendar component object.
 **/
void
cal_component_set_exrule_list (CalComponent *comp, GSList *recur_list)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    set_recur_list (comp, icalproperty_new_exrule, &priv->exrule_list, recur_list);

    priv->need_sequence_inc = TRUE;
}

/**
 * cal_component_has_exrules:
 * @comp: A calendar component object.
 *
 * Queries whether a calendar component object has any exception rules defined
 * for it.
 *
 * Return value: TRUE if the component has exception rules, FALSE otherwise.
 **/
gboolean
cal_component_has_exrules (CalComponent *comp)
{
    CalComponentPrivate *priv;

    g_return_val_if_fail (comp != NULL, FALSE);
    g_return_val_if_fail (IS_CAL_COMPONENT (comp), FALSE);

    priv = comp->priv;
    g_return_val_if_fail (priv->icalcomp != NULL, FALSE);

    return (priv->exrule_list != NULL);
}

/**
 * cal_component_has_exceptions:
 * @comp: A calendar component object
 *
 * Queries whether a calendar component object has any exception dates
 * or exception rules.
 *
 * Return value: TRUE if the component has exceptions, FALSE otherwise.
 **/
gboolean
cal_component_has_exceptions (CalComponent *comp)
{
    return cal_component_has_exdates (comp) || cal_component_has_exrules (comp);
}

/**
 * cal_component_get_geo:
 * @comp: A calendar component object.
 * @geo: Return value for the geographic position property.  This should be
 * freed using the cal_component_free_geo() function.
 *
 * Sets the geographic position property of a calendar component object.
 **/
void
cal_component_get_geo (CalComponent *comp, struct icalgeotype **geo)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));
    g_return_if_fail (geo != NULL);

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    if (priv->geo) {
        *geo = g_new (struct icalgeotype, 1);
        **geo = icalproperty_get_geo (priv->geo);
    } else
        *geo = NULL;
}

/**
 * cal_component_set_geo:
 * @comp: A calendar component object.
 * @geo: Value for the geographic position property.
 *
 * Sets the geographic position property on a calendar component object.
 **/
void
cal_component_set_geo (CalComponent *comp, struct icalgeotype *geo)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    if (!geo) {
        if (priv->geo) {
            icalcomponent_remove_property (priv->icalcomp, priv->geo);
            icalproperty_free (priv->geo);
            priv->geo = NULL;
        }

        return;
    }

    if (priv->geo)
        icalproperty_set_geo (priv->geo, *geo);
    else {
        priv->geo = icalproperty_new_geo (*geo);
        icalcomponent_add_property (priv->icalcomp, priv->geo);
    }
}

/**
 * cal_component_get_last_modified:
 * @comp: A calendar component object.
 * @t: Return value for the last modified time value.
 *
 * Queries the time at which a calendar component object was last modified in
 * the calendar store.
 **/
void
cal_component_get_last_modified (CalComponent *comp, struct icaltimetype **t)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));
    g_return_if_fail (t != NULL);

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    get_icaltimetype (priv->last_modified, icalproperty_get_lastmodified, t);
}

/**
 * cal_component_set_last_modified:
 * @comp: A calendar component object.
 * @t: Value for the last time modified.
 *
 * Sets the time at which a calendar component object was last stored in the
 * calendar store.  This should not be called by plain calendar user agents.
 **/
void
cal_component_set_last_modified (CalComponent *comp, struct icaltimetype *t)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    set_icaltimetype (comp, &priv->last_modified,
              icalproperty_new_lastmodified,
              icalproperty_set_lastmodified,
              t);
}

/**
 * cal_component_get_organizer:
 * @comp:  A calendar component object
 * @organizer: A value for the organizer
 * 
 * Queries the organizer property of a calendar component object
 **/
void
cal_component_get_organizer (CalComponent *comp, CalComponentOrganizer *organizer)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));
    g_return_if_fail (organizer != NULL);

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    if (priv->organizer.prop)
        organizer->value = icalproperty_get_organizer (priv->organizer.prop);
    else
        organizer->value = NULL;

    if (priv->organizer.sentby_param)
        organizer->sentby = icalparameter_get_sentby (priv->organizer.sentby_param);
    else
        organizer->sentby = NULL;

    if (priv->organizer.cn_param)
        organizer->cn = icalparameter_get_sentby (priv->organizer.cn_param);
    else
        organizer->cn = NULL;

    if (priv->organizer.language_param)
        organizer->language = icalparameter_get_sentby (priv->organizer.language_param);
    else
        organizer->language = NULL;

}

/**
 * cal_component_set_organizer:
 * @comp:  A calendar component object.
 * @organizer: Value for the organizer property
 * 
 * Sets the organizer of a calendar component object
 **/
void
cal_component_set_organizer (CalComponent *comp, CalComponentOrganizer *organizer)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    if (!organizer) {
        if (priv->organizer.prop) {
            icalcomponent_remove_property (priv->icalcomp, priv->organizer.prop);
            icalproperty_free (priv->organizer.prop);

            priv->organizer.prop = NULL;
            priv->organizer.sentby_param = NULL;
            priv->organizer.cn_param = NULL;
            priv->organizer.language_param = NULL;
        }

        return;
    }

    g_return_if_fail (organizer->value != NULL);

    if (priv->organizer.prop)
        icalproperty_set_organizer (priv->organizer.prop, (char *) organizer->value);
    else {
        priv->organizer.prop = icalproperty_new_organizer ((char *) organizer->value);
        icalcomponent_add_property (priv->icalcomp, priv->organizer.prop);
    }

    if (organizer->sentby) {
        g_assert (priv->organizer.prop != NULL);

        if (priv->organizer.sentby_param)
            icalparameter_set_sentby (priv->organizer.sentby_param,
                          (char *) organizer->sentby);
        else {
            priv->organizer.sentby_param = icalparameter_new_sentby (
                (char *) organizer->sentby);
            icalproperty_add_parameter (priv->organizer.prop,
                            priv->organizer.sentby_param);
        }
    } else if (priv->organizer.sentby_param) {
        icalproperty_remove_parameter (priv->organizer.prop, ICAL_SENTBY_PARAMETER);
        icalparameter_free (priv->organizer.sentby_param);
        priv->organizer.sentby_param = NULL;
    }

    if (organizer->cn) {
        g_assert (priv->organizer.prop != NULL);

        if (priv->organizer.cn_param)
            icalparameter_set_cn (priv->organizer.cn_param,
                          (char *) organizer->cn);
        else {
            priv->organizer.cn_param = icalparameter_new_cn (
                (char *) organizer->cn);
            icalproperty_add_parameter (priv->organizer.prop,
                            priv->organizer.cn_param);
        }
    } else if (priv->organizer.cn_param) {
        icalproperty_remove_parameter (priv->organizer.prop, ICAL_CN_PARAMETER);
        icalparameter_free (priv->organizer.cn_param);
        priv->organizer.cn_param = NULL;
    }

    if (organizer->language) {
        g_assert (priv->organizer.prop != NULL);

        if (priv->organizer.language_param)
            icalparameter_set_language (priv->organizer.language_param,
                          (char *) organizer->language);
        else {
            priv->organizer.language_param = icalparameter_new_language (
                (char *) organizer->language);
            icalproperty_add_parameter (priv->organizer.prop,
                            priv->organizer.language_param);
        }
    } else if (priv->organizer.language_param) {
        icalproperty_remove_parameter (priv->organizer.prop, ICAL_LANGUAGE_PARAMETER);
        icalparameter_free (priv->organizer.language_param);
        priv->organizer.language_param = NULL;
    }


}
        
/**
 * cal_component_get_percent:
 * @comp: A calendar component object.
 * @percent: Return value for the percent-complete property.  This should be
 * freed using the cal_component_free_percent() function.
 *
 * Queries the percent-complete property of a calendar component object.
 **/
void
cal_component_get_percent (CalComponent *comp, int **percent)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));
    g_return_if_fail (percent != NULL);

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    if (priv->percent) {
        *percent = g_new (int, 1);
        **percent = icalproperty_get_percentcomplete (priv->percent);
    } else
        *percent = NULL;
}

/**
 * cal_component_set_percent:
 * @comp: A calendar component object.
 * @percent: Value for the percent-complete property.
 *
 * Sets the percent-complete property of a calendar component object.
 **/
void
cal_component_set_percent (CalComponent *comp, int *percent)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    if (!percent) {
        if (priv->percent) {
            icalcomponent_remove_property (priv->icalcomp, priv->percent);
            icalproperty_free (priv->percent);
            priv->percent = NULL;
        }

        return;
    }

    g_return_if_fail (*percent >= 0 && *percent <= 100);

    if (priv->percent)
        icalproperty_set_percentcomplete (priv->percent, *percent);
    else {
        priv->percent = icalproperty_new_percentcomplete (*percent);
        icalcomponent_add_property (priv->icalcomp, priv->percent);
    }
}

/**
 * cal_component_get_priority:
 * @comp: A calendar component object.
 * @priority: Return value for the priority property.  This should be freed using
 * the cal_component_free_priority() function.
 *
 * Queries the priority property of a calendar component object.
 **/
void
cal_component_get_priority (CalComponent *comp, int **priority)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));
    g_return_if_fail (priority != NULL);

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    if (priv->priority) {
        *priority = g_new (int, 1);
        **priority = icalproperty_get_priority (priv->priority);
    } else
        *priority = NULL;
}

/**
 * cal_component_set_priority:
 * @comp: A calendar component object.
 * @priority: Value for the priority property.
 *
 * Sets the priority property of a calendar component object.
 **/
void
cal_component_set_priority (CalComponent *comp, int *priority)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    if (!priority) {
        if (priv->priority) {
            icalcomponent_remove_property (priv->icalcomp, priv->priority);
            icalproperty_free (priv->priority);
            priv->priority = NULL;
        }

        return;
    }

    g_return_if_fail (*priority >= 0 && *priority <= 9);

    if (priv->priority)
        icalproperty_set_priority (priv->priority, *priority);
    else {
        priv->priority = icalproperty_new_priority (*priority);
        icalcomponent_add_property (priv->icalcomp, priv->priority);
    }
}

/**
 * cal_component_get_recurid:
 * @comp: A calendar component object.
 * @recur_id: Return value for the recurrence id property
 * 
 * Queries the recurrence id property of a calendar component object
 **/
void 
cal_component_get_recurid (CalComponent *comp, CalComponentRange **recur_id)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));
    g_return_if_fail (recur_id != NULL);

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    get_datetime (&priv->recur_id.recur_time, 
              icalproperty_get_recurrenceid, 
              (*recur_id)->datetime);
}

/**
 * cal_component_set_recurid:
 * @comp: A calendar component object.
 * @recur_id: Value for the recurrence id property.
 * 
 * Sets the recurrence id property of a calendar component object.
 **/
void
cal_component_set_recurid (CalComponent *comp, CalComponentRange *recur_id)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);
    
    set_datetime (comp, &priv->recur_id.recur_time,
              icalproperty_new_recurrenceid,
              icalproperty_set_recurrenceid,
              recur_id->datetime);
}

/**
 * cal_component_get_rdate_list:
 * @comp: A calendar component object.
 * @period_list: Return value for the list of recurrence dates, as a list of
 * #CalComponentPeriod structures.  This should be freed using the
 * cal_component_free_period_list() function.
 *
 * Queries the list of recurrence date properties in a calendar component
 * object.
 **/
void
cal_component_get_rdate_list (CalComponent *comp, GSList **period_list)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));
    g_return_if_fail (period_list != NULL);

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    get_period_list (priv->rdate_list, icalproperty_get_rdate, period_list);
}

/**
 * cal_component_set_rdate_list:
 * @comp: A calendar component object.
 * @period_list: List of #CalComponentPeriod structures.
 *
 * Sets the list of recurrence dates in a calendar component object.
 **/
void
cal_component_set_rdate_list (CalComponent *comp, GSList *period_list)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    set_period_list (comp, icalproperty_new_rdate, &priv->rdate_list, period_list);

    priv->need_sequence_inc = TRUE;
}

/**
 * cal_component_has_rdates:
 * @comp: A calendar component object.
 *
 * Queries whether a calendar component object has any recurrence dates defined
 * for it.
 *
 * Return value: TRUE if the component has recurrence dates, FALSE otherwise.
 **/
gboolean
cal_component_has_rdates (CalComponent *comp)
{
    CalComponentPrivate *priv;

    g_return_val_if_fail (comp != NULL, FALSE);
    g_return_val_if_fail (IS_CAL_COMPONENT (comp), FALSE);

    priv = comp->priv;
    g_return_val_if_fail (priv->icalcomp != NULL, FALSE);

    return (priv->rdate_list != NULL);
}

/**
 * cal_component_get_rrule_list:
 * @comp: A calendar component object.
 * @recur_list: List of recurrence rules as struct #icalrecurrencetype
 * structures.  This should be freed using the cal_component_free_recur_list()
 * function.
 *
 * Queries the list of recurrence rule properties of a calendar component
 * object.
 **/
void
cal_component_get_rrule_list (CalComponent *comp, GSList **recur_list)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));
    g_return_if_fail (recur_list != NULL);

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    get_recur_list (priv->rrule_list, icalproperty_get_rrule, recur_list);
}

/**
 * cal_component_get_rrule_property_list:
 * @comp: A calendar component object.
 * @recur_list: Returns a list of recurrence rule properties.
 *
 * Queries a list of recurrence rule properties of a calendar component object.
 **/
void
cal_component_get_rrule_property_list (CalComponent *comp, GSList **recur_list)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));
    g_return_if_fail (recur_list != NULL);

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    *recur_list = priv->rrule_list;
}

/**
 * cal_component_set_rrule_list:
 * @comp: A calendar component object.
 * @recur_list: List of struct #icalrecurrencetype structures.
 *
 * Sets the list of recurrence rules in a calendar component object.
 **/
void
cal_component_set_rrule_list (CalComponent *comp, GSList *recur_list)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    set_recur_list (comp, icalproperty_new_rrule, &priv->rrule_list, recur_list);

    priv->need_sequence_inc = TRUE;
}

/**
 * cal_component_has_rrules:
 * @comp: A calendar component object.
 *
 * Queries whether a calendar component object has any recurrence rules defined
 * for it.
 *
 * Return value: TRUE if the component has recurrence rules, FALSE otherwise.
 **/
gboolean
cal_component_has_rrules (CalComponent *comp)
{
    CalComponentPrivate *priv;

    g_return_val_if_fail (comp != NULL, FALSE);
    g_return_val_if_fail (IS_CAL_COMPONENT (comp), FALSE);

    priv = comp->priv;
    g_return_val_if_fail (priv->icalcomp != NULL, FALSE);

    return (priv->rrule_list != NULL);
}

/**
 * cal_component_has_recurrences:
 * @comp: A calendar component object
 *
 * Queries whether a calendar component object has any recurrence dates or
 * recurrence rules.
 *
 * Return value: TRUE if the component has recurrences, FALSE otherwise.
 **/
gboolean
cal_component_has_recurrences (CalComponent *comp)
{
    return cal_component_has_rdates (comp) || cal_component_has_rrules (comp);
}

/**
 * cal_component_get_sequence:
 * @comp: A calendar component object.
 * @sequence: Return value for the sequence number.  This should be freed using
 * cal_component_free_sequence().
 *
 * Queries the sequence number of a calendar component object.
 **/
void
cal_component_get_sequence (CalComponent *comp, int **sequence)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));
    g_return_if_fail (sequence != NULL);

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    if (!priv->sequence) {
        *sequence = NULL;
        return;
    }

    *sequence = g_new (int, 1);
    **sequence = icalproperty_get_sequence (priv->sequence);
}

/**
 * cal_component_set_sequence:
 * @comp: A calendar component object.
 * @sequence: Sequence number value.
 *
 * Sets the sequence number of a calendar component object.  Normally this
 * function should not be called, since the sequence number is incremented
 * automatically at the proper times.
 **/
void
cal_component_set_sequence (CalComponent *comp, int *sequence)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    priv->need_sequence_inc = FALSE;

    if (!sequence) {
        if (priv->sequence) {
            icalcomponent_remove_property (priv->icalcomp, priv->sequence);
            icalproperty_free (priv->sequence);
            priv->sequence = NULL;
        }

        return;
    }

    if (priv->sequence)
        icalproperty_set_sequence (priv->sequence, *sequence);
    else {
        priv->sequence = icalproperty_new_sequence (*sequence);
        icalcomponent_add_property (priv->icalcomp, priv->sequence);
    }
}

/**
 * cal_component_get_status:
 * @comp: A calendar component object.
 * @status: Return value for the status value.  It is set to #ICAL_STATUS_NONE
 * if the component has no status property.
 *
 * Queries the status property of a calendar component object.
 **/
void
cal_component_get_status (CalComponent *comp, icalproperty_status *status)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));
    g_return_if_fail (status != NULL);

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    if (!priv->status) {
        *status = ICAL_STATUS_NONE;
        return;
    }

    *status = icalproperty_get_status (priv->status);
}

/**
 * cal_component_set_status:
 * @comp: A calendar component object.
 * @status: Status value.  You should use #ICAL_STATUS_NONE if you want to unset
 * this property.
 *
 * Sets the status property of a calendar component object.
 **/
void
cal_component_set_status (CalComponent *comp, icalproperty_status status)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    priv->need_sequence_inc = TRUE;

    if (status == ICAL_STATUS_NONE) {
        if (priv->status) {
            icalcomponent_remove_property (priv->icalcomp, priv->status);
            icalproperty_free (priv->status);
            priv->status = NULL;
        }

        return;
    }

    if (priv->status) {
        icalproperty_set_status (priv->status, status);
    } else {
        priv->status = icalproperty_new_status (status);
        icalcomponent_add_property (priv->icalcomp, priv->status);
    }
}

/**
 * cal_component_get_summary:
 * @comp: A calendar component object.
 * @summary: Return value for the summary property and its parameters.
 *
 * Queries the summary of a calendar component object.
 **/
void
cal_component_get_summary (CalComponent *comp, CalComponentText *summary)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));
    g_return_if_fail (summary != NULL);

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    if (priv->summary.prop)
        summary->value = icalproperty_get_summary (priv->summary.prop);
    else
        summary->value = NULL;

    if (priv->summary.altrep_param)
        summary->altrep = icalparameter_get_altrep (priv->summary.altrep_param);
    else
        summary->altrep = NULL;
}

/**
 * cal_component_set_summary:
 * @comp: A calendar component object.
 * @summary: Summary property and its parameters.
 *
 * Sets the summary of a calendar component object.
 **/
void
cal_component_set_summary (CalComponent *comp, CalComponentText *summary)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    if (!summary) {
        if (priv->summary.prop) {
            icalcomponent_remove_property (priv->icalcomp, priv->summary.prop);
            icalproperty_free (priv->summary.prop);

            priv->summary.prop = NULL;
            priv->summary.altrep_param = NULL;
        }

        return;
    }

    g_return_if_fail (summary->value != NULL);

    if (priv->summary.prop)
        icalproperty_set_summary (priv->summary.prop, (char *) summary->value);
    else {
        priv->summary.prop = icalproperty_new_summary ((char *) summary->value);
        icalcomponent_add_property (priv->icalcomp, priv->summary.prop);
    }

    if (summary->altrep) {
        g_assert (priv->summary.prop != NULL);

        if (priv->summary.altrep_param)
            icalparameter_set_altrep (priv->summary.altrep_param,
                          (char *) summary->altrep);
        else {
            priv->summary.altrep_param = icalparameter_new_altrep (
                (char *) summary->altrep);
            icalproperty_add_parameter (priv->summary.prop,
                            priv->summary.altrep_param);
        }
    } else if (priv->summary.altrep_param) {
        icalproperty_remove_parameter (priv->summary.prop, ICAL_ALTREP_PARAMETER);
        icalparameter_free (priv->summary.altrep_param);
        priv->summary.altrep_param = NULL;
    }
}

/**
 * cal_component_get_transparency:
 * @comp: A calendar component object.
 * @transp: Return value for the time transparency.
 *
 * Queries the time transparency of a calendar component object.
 **/
void
cal_component_get_transparency (CalComponent *comp, CalComponentTransparency *transp)
{
    CalComponentPrivate *priv;
    const char *val;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));
    g_return_if_fail (transp != NULL);

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    if (!priv->transparency) {
        *transp = CAL_COMPONENT_TRANSP_NONE;
        return;
    }

    val = icalproperty_get_transp (priv->transparency);

    if (strcasecmp (val, "TRANSPARENT") == 0)
        *transp = CAL_COMPONENT_TRANSP_TRANSPARENT;
    else if (strcasecmp (val, "OPAQUE") == 0)
        *transp = CAL_COMPONENT_TRANSP_OPAQUE;
    else
        *transp = CAL_COMPONENT_TRANSP_UNKNOWN;
}

/**
 * cal_component_set_transparency:
 * @comp: A calendar component object.
 * @transp: Time transparency value.
 *
 * Sets the time transparency of a calendar component object.
 **/
void
cal_component_set_transparency (CalComponent *comp, CalComponentTransparency transp)
{
    CalComponentPrivate *priv;
    char *str;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));
    g_return_if_fail (transp != CAL_COMPONENT_TRANSP_UNKNOWN);

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);


    if (transp == CAL_COMPONENT_TRANSP_NONE) {
        if (priv->transparency) {
            icalcomponent_remove_property (priv->icalcomp, priv->transparency);
            icalproperty_free (priv->transparency);
            priv->transparency = NULL;
        }

        return;
    }

    switch (transp) {
    case CAL_COMPONENT_TRANSP_TRANSPARENT:
        str = "TRANSPARENT";
        break;

    case CAL_COMPONENT_TRANSP_OPAQUE:
        str = "OPAQUE";
        break;

    default:
        g_assert_not_reached ();
        str = NULL;
    }

    if (priv->transparency)
        icalproperty_set_transp (priv->transparency, str);
    else {
        priv->transparency = icalproperty_new_transp (str);
        icalcomponent_add_property (priv->icalcomp, priv->transparency);
    }
}

/**
 * cal_component_get_url:
 * @comp: A calendar component object.
 * @url: Return value for the URL.
 *
 * Queries the uniform resource locator property of a calendar component object.
 **/
void
cal_component_get_url (CalComponent *comp, const char **url)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));
    g_return_if_fail (url != NULL);

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    if (priv->url)
        *url = icalproperty_get_url (priv->url);
    else
        *url = NULL;
}

/**
 * cal_component_set_url:
 * @comp: A calendar component object.
 * @url: URL value.
 *
 * Sets the uniform resource locator property of a calendar component object.
 **/
void
cal_component_set_url (CalComponent *comp, const char *url)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    if (!url || !(*url)) {
        if (priv->url) {
            icalcomponent_remove_property (priv->icalcomp, priv->url);
            icalproperty_free (priv->url);
            priv->url = NULL;
        }

        return;
    }

    if (priv->url)
        icalproperty_set_url (priv->url, (char *) url);
    else {
        priv->url = icalproperty_new_url ((char *) url);
        icalcomponent_add_property (priv->icalcomp, priv->url);
    }
}

/* Gets a text list value */
static void
get_attendee_list (GSList *attendee_list, GSList **al)
{
    GSList *l;

    *al = NULL;

    if (!attendee_list)
        return;

    for (l = attendee_list; l; l = l->next) {
        struct attendee *attendee;
        CalComponentAttendee *a;

        attendee = l->data;
        g_assert (attendee->prop != NULL);

        a = g_new0 (CalComponentAttendee, 1);
        a->value = icalproperty_get_attendee (attendee->prop);

        if (attendee->member_param)
            a->member = icalparameter_get_member (attendee->member_param);
        if (attendee->cutype_param) {
            switch (icalparameter_get_cutype (attendee->cutype_param)) {
            case ICAL_CUTYPE_INDIVIDUAL:
                a->cutype = CAL_COMPONENT_CUTYPE_INDIVIDUAL;
                break;
            case ICAL_CUTYPE_GROUP:
                a->cutype = CAL_COMPONENT_CUTYPE_GROUP;
                break;
            case ICAL_CUTYPE_RESOURCE:
                a->cutype = CAL_COMPONENT_CUTYPE_RESOURCE;
                break;
            case ICAL_CUTYPE_ROOM:
                a->cutype = CAL_COMPONENT_CUTYPE_ROOM;
                break;
            default:
                a->cutype = CAL_COMPONENT_CUTYPE_UNKNOWN;
            }
        }
            
        if (attendee->role_param) {
            switch (icalparameter_get_role (attendee->role_param)) {
            case ICAL_ROLE_CHAIR:
                a->role = CAL_COMPONENT_ROLE_CHAIR;
                break;
            case ICAL_ROLE_REQPARTICIPANT:
                a->role = CAL_COMPONENT_ROLE_REQUIRED;
                break;
            case ICAL_ROLE_OPTPARTICIPANT:
                a->role = CAL_COMPONENT_ROLE_OPTIONAL;
                break;
            case ICAL_ROLE_NONPARTICIPANT:
                a->role = CAL_COMPONENT_ROLE_NON;
                break;
            default:
                a->role = CAL_COMPONENT_ROLE_UNKNOWN;
            }
        }

        if (attendee->partstat_param) {
            switch (icalparameter_get_role (attendee->partstat_param)) {
            case ICAL_PARTSTAT_NEEDSACTION:
                a->status = CAL_COMPONENT_PARTSTAT_NEEDSACTION;
                break;
            case ICAL_PARTSTAT_ACCEPTED:
                a->status = CAL_COMPONENT_PARTSTAT_ACCEPTED;
                break;
            case ICAL_PARTSTAT_DECLINED:
                a->status = CAL_COMPONENT_PARTSTAT_DECLINED;
                break;
            case ICAL_PARTSTAT_TENTATIVE:
                a->status = CAL_COMPONENT_PARTSTAT_TENTATIVE;
                break;
            case ICAL_PARTSTAT_DELEGATED:
                a->status = CAL_COMPONENT_PARTSTAT_DELEGATED;
                break;
            case ICAL_PARTSTAT_COMPLETED:
                a->status = CAL_COMPONENT_PARTSTAT_COMPLETED;
                break;
            case ICAL_PARTSTAT_INPROCESS:
                a->status = CAL_COMPONENT_PARTSTAT_INPROCESS;
                break;
            default:
                a->status = CAL_COMPONENT_PARTSTAT_UNKNOWN;
            }
        }

        if (attendee->rsvp_param && icalparameter_get_rsvp (attendee->rsvp_param) == ICAL_RSVP_TRUE)
            a->rsvp = TRUE;
        else
            a->rsvp = FALSE;

        if (attendee->delfrom_param)
            a->delfrom = icalparameter_get_sentby (attendee->delfrom_param);
        if (attendee->delto_param)
            a->delto = icalparameter_get_sentby (attendee->delto_param);
        if (attendee->sentby_param)
            a->sentby = icalparameter_get_sentby (attendee->sentby_param);
        if (attendee->cn_param)
            a->cn = icalparameter_get_sentby (attendee->cn_param);
        if (attendee->language_param)
            a->language = icalparameter_get_sentby (attendee->language_param);

        *al = g_slist_prepend (*al, a);
    }

    *al = g_slist_reverse (*al);
}


/* Sets a text list value */
static void
set_attendee_list (CalComponent *comp,
           GSList **attendee_list,
           GSList *al)
{
    CalComponentPrivate *priv;
    GSList *l;

    priv = comp->priv;

    /* Remove old attendees */

    for (l = *attendee_list; l; l = l->next) {
        struct attendee *attendee;

        attendee = l->data;
        g_assert (attendee->prop != NULL);

        icalcomponent_remove_property (priv->icalcomp, attendee->prop);
        icalproperty_free (attendee->prop);
        g_free (attendee);
    }

    g_slist_free (*attendee_list);
    *attendee_list = NULL;

    /* Add in new attendees */

    for (l = al; l; l = l->next) {
        CalComponentAttendee *a;
        struct attendee *attendee;
        icalparameter_cutype ct;
        icalparameter_role r;
        icalparameter_partstat p;

        a = l->data;
        g_return_if_fail (a->value != NULL);

        attendee = g_new0 (struct attendee, 1);

        attendee->prop = icalproperty_new_attendee (a->value);
        icalcomponent_add_property (priv->icalcomp, attendee->prop);

        if (a->member) {
            attendee->member_param = icalparameter_new_member (a->member);
            icalproperty_add_parameter (attendee->prop, attendee->member_param);
        }

        switch (a->cutype) {
            case CAL_COMPONENT_CUTYPE_INDIVIDUAL:
                ct = ICAL_CUTYPE_INDIVIDUAL;
                break;
            case CAL_COMPONENT_CUTYPE_GROUP:
                ct = ICAL_CUTYPE_GROUP;
                break;
            case CAL_COMPONENT_CUTYPE_RESOURCE:
                ct = ICAL_CUTYPE_RESOURCE;
                break;
            case CAL_COMPONENT_CUTYPE_ROOM:
                ct = ICAL_CUTYPE_ROOM;
                break;
            default:
                ct = ICAL_CUTYPE_UNKNOWN;
        }
        attendee->cutype_param = icalparameter_new_cutype (ct);
        icalproperty_add_parameter (attendee->prop, attendee->cutype_param);

        switch (a->role) {
            case CAL_COMPONENT_ROLE_CHAIR:
                r = ICAL_ROLE_CHAIR;
                break;
            case CAL_COMPONENT_ROLE_REQUIRED:
                r = ICAL_ROLE_REQPARTICIPANT;
                break;
            case CAL_COMPONENT_ROLE_OPTIONAL:
                r = ICAL_ROLE_OPTPARTICIPANT;
                break;
            case CAL_COMPONENT_ROLE_NON:
                r = ICAL_ROLE_NONPARTICIPANT;
                break;
            default:
                r = ICAL_ROLE_NONE;
        }
        attendee->role_param = icalparameter_new_role (r);
        icalproperty_add_parameter (attendee->prop, attendee->role_param);

        switch (a->status) {
            case CAL_COMPONENT_PARTSTAT_NEEDSACTION:
                p = ICAL_PARTSTAT_NEEDSACTION;
                break;
            case CAL_COMPONENT_PARTSTAT_ACCEPTED:
                p = ICAL_PARTSTAT_ACCEPTED;
                break;
            case CAL_COMPONENT_PARTSTAT_DECLINED:
                p = ICAL_PARTSTAT_DECLINED;
                break;
            case CAL_COMPONENT_PARTSTAT_TENTATIVE:
                p = ICAL_PARTSTAT_TENTATIVE;
                break;
            case CAL_COMPONENT_PARTSTAT_DELEGATED:
                p = ICAL_PARTSTAT_DELEGATED;
                break;
            case CAL_COMPONENT_PARTSTAT_COMPLETED:
                p = ICAL_PARTSTAT_COMPLETED;
                break;
            case CAL_COMPONENT_PARTSTAT_INPROCESS:
                p = ICAL_PARTSTAT_INPROCESS;
                break;
            default:
                p = ICAL_PARTSTAT_NONE;
        }
        attendee->partstat_param = icalparameter_new_partstat (p);
        icalproperty_add_parameter (attendee->prop, attendee->partstat_param);

        if (a->rsvp)
            attendee->rsvp_param = icalparameter_new_rsvp (ICAL_RSVP_TRUE);
        else
            attendee->rsvp_param = icalparameter_new_rsvp (ICAL_RSVP_FALSE);
        icalproperty_add_parameter (attendee->prop, attendee->rsvp_param);
    
        if (a->delfrom) {
            attendee->delfrom_param = icalparameter_new_delegatedfrom (a->delfrom);
            icalproperty_add_parameter (attendee->prop, attendee->delfrom_param);
        }
        if (a->delto) {
            attendee->delto_param = icalparameter_new_delegatedto (a->delto);
            icalproperty_add_parameter (attendee->prop, attendee->delfrom_param);
        }
        if (a->sentby) {
            attendee->sentby_param = icalparameter_new_sentby (a->sentby);
            icalproperty_add_parameter (attendee->prop, attendee->sentby_param);
        }
        if (a->cn) {
            attendee->cn_param = icalparameter_new_cn (a->cn);
            icalproperty_add_parameter (attendee->prop, attendee->cn_param);
        }
        if (a->language) {
            attendee->language_param = icalparameter_new_language (a->cn);
            icalproperty_add_parameter (attendee->prop, attendee->language_param);
        }

        *attendee_list = g_slist_prepend (*attendee_list, attendee);
    }

    *attendee_list = g_slist_reverse (*attendee_list);
}

/**
 * cal_component_get_attendee_list: 
 * @comp: A calendar component object. 
 * @attendee_list: Return value for the attendee property.
 * This should be freed using the cal_component_free_attendee_list ()
 * function.
 * 
 * Queries the attendee properties of the calendar component object
 **/
void
cal_component_get_attendee_list (CalComponent *comp, GSList **attendee_list)
{
    CalComponentPrivate *priv;
    
    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));
    g_return_if_fail (attendee_list != NULL);

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    get_attendee_list (priv->attendee_list, attendee_list);
}

/**
 * cal_component_set_attendee_list:
 * @comp: A calendar component object. 
 * @attendee_list: Values for attendee properties
 * 
 * Sets the attendees of a calendar component object
 **/
void
cal_component_set_attendee_list (CalComponent *comp, GSList *attendee_list)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    set_attendee_list (comp, &priv->attendee_list, attendee_list);
}




/**
 * cal_component_free_categories_list:
 * @categ_list: List of category strings.
 *
 * Frees a list of category strings.
 **/
void
cal_component_free_categories_list (GSList *categ_list)
{
    GSList *l;

    for (l = categ_list; l; l = l->next)
        g_free (l->data);

    g_slist_free (categ_list);
}

/**
 * cal_component_free_datetime:
 * @dt: A date/time structure.
 *
 * Frees a date/time structure.
 **/
void
cal_component_free_datetime (CalComponentDateTime *dt)
{
    g_return_if_fail (dt != NULL);

    if (dt->value)
        g_free (dt->value);
}

/**
 * cal_component_free_exdate_list:
 * @exdate_list: List of #CalComponentDateTime structures.
 *
 * Frees a list of #CalComponentDateTime structures as returned by the
 * cal_component_get_exdate_list() function.
 **/
void
cal_component_free_exdate_list (GSList *exdate_list)
{
    GSList *l;

    for (l = exdate_list; l; l = l->next) {
        CalComponentDateTime *cdt;

        g_assert (l->data != NULL);
        cdt = l->data;

        g_assert (cdt->value != NULL);
        g_free (cdt->value);

        g_free (cdt);
    }

    g_slist_free (exdate_list);
}

/**
 * cal_component_free_geo:
 * @geo: An #icalgeotype structure.
 *
 * Frees a struct #icalgeotype structure as returned by the calendar component
 * functions.
 **/
void
cal_component_free_geo (struct icalgeotype *geo)
{
    g_return_if_fail (geo != NULL);

    g_free (geo);
}

/**
 * cal_component_free_icaltimetype:
 * @t: An #icaltimetype structure.
 *
 * Frees a struct #icaltimetype value as returned by the calendar component
 * functions.
 **/
void
cal_component_free_icaltimetype (struct icaltimetype *t)
{
    g_return_if_fail (t != NULL);

    g_free (t);
}

/**
 * cal_component_free_percent:
 * @percent: Percent value.
 *
 * Frees a percent value as returned by the cal_component_get_percent()
 * function.
 **/
void
cal_component_free_percent (int *percent)
{
    g_return_if_fail (percent != NULL);

    g_free (percent);
}

/**
 * cal_component_free_priority:
 * @priority: Priority value.
 *
 * Frees a priority value as returned by the cal_component_get_priority()
 * function.
 **/
void
cal_component_free_priority (int *priority)
{
    g_return_if_fail (priority != NULL);

    g_free (priority);
}

/**
 * cal_component_free_period_list:
 * @period_list: List of #CalComponentPeriod structures.
 *
 * Frees a list of #CalComponentPeriod structures.
 **/
void
cal_component_free_period_list (GSList *period_list)
{
    GSList *l;

    for (l = period_list; l; l = l->next) {
        CalComponentPeriod *period;

        g_assert (l->data != NULL);

        period = l->data;
        g_free (period);
    }

    g_slist_free (period_list);
}

/**
 * cal_component_free_recur_list:
 * @recur_list: List of struct #icalrecurrencetype structures.
 *
 * Frees a list of struct #icalrecurrencetype structures.
 **/
void
cal_component_free_recur_list (GSList *recur_list)
{
    GSList *l;

    for (l = recur_list; l; l = l->next) {
        struct icalrecurrencetype *r;

        g_assert (l->data != NULL);
        r = l->data;

        g_free (r);
    }

    g_slist_free (recur_list);
}

/**
 * cal_component_free_sequence:
 * @sequence: Sequence number value.
 *
 * Frees a sequence number value.
 **/
void
cal_component_free_sequence (int *sequence)
{
    g_return_if_fail (sequence != NULL);

    g_free (sequence);
}

/**
 * cal_component_free_text_list:
 * @text_list: List of #CalComponentText structures.
 *
 * Frees a list of #CalComponentText structures.  This function should only be
 * used to free lists of text values as returned by the other getter functions
 * of #CalComponent.
 **/
void
cal_component_free_text_list (GSList *text_list)
{
    GSList *l;

    for (l = text_list; l; l = l->next) {
        CalComponentText *text;

        g_assert (l->data != NULL);

        text = l->data;
        g_return_if_fail (text != NULL);
        g_free (text);
    }

    g_slist_free (text_list);
}

/**
 * cal_component_free_attendee_list:
 * @attendee_list: 
 * 
 * 
 **/
void
cal_component_free_attendee_list (GSList *attendee_list)
{
    GSList *l;

    for (l = attendee_list; l; l = l->next) {
        CalComponentAttendee *attendee;

        g_assert (l->data != NULL);

        attendee = l->data;
        g_return_if_fail (attendee != NULL);
        g_free (attendee);
    }

    g_slist_free (attendee_list);
}



/**
 * cal_component_has_alarms:
 * @comp: A calendar component object.
 *
 * Checks whether the component has any alarms.
 *
 * Return value: TRUE if the component has any alarms.
 **/
gboolean
cal_component_has_alarms (CalComponent *comp)
{
    CalComponentPrivate *priv;

    g_return_val_if_fail (comp != NULL, FALSE);
    g_return_val_if_fail (IS_CAL_COMPONENT (comp), FALSE);

    priv = comp->priv;
    g_return_val_if_fail (priv->icalcomp != NULL, FALSE);

    return g_hash_table_size (priv->alarm_uid_hash) != 0;
}

/**
 * cal_component_add_alarm:
 * @comp: A calendar component.
 * @alarm: An alarm.
 * 
 * Adds an alarm subcomponent to a calendar component.  You should have created
 * the @alarm by using cal_component_alarm_new(); it is invalid to use a
 * #CalComponentAlarm structure that came from cal_component_get_alarm().  After
 * adding the alarm, the @alarm structure is no longer valid because the
 * internal structures may change and you should get rid of it by using
 * cal_component_alarm_free().
 **/
void
cal_component_add_alarm (CalComponent *comp, CalComponentAlarm *alarm)
{
    CalComponentPrivate *priv;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));
    g_return_if_fail (alarm != NULL);

    priv = comp->priv;

    add_alarm (comp, alarm->icalcomp, icalproperty_get_x (alarm->uid));
    icalcomponent_add_component (priv->icalcomp, alarm->icalcomp);
}

/**
 * cal_component_remove_alarm:
 * @comp: A calendar component.
 * @auid: UID of the alarm to remove.
 * 
 * Removes an alarm subcomponent from a calendar component.  If the alarm that
 * corresponds to the specified @auid had been fetched with
 * cal_component_get_alarm(), then those alarm structures will be invalid; you
 * should get rid of them with cal_component_alarm_free() before using this
 * function.
 **/
void
cal_component_remove_alarm (CalComponent *comp, const char *auid)
{
    CalComponentPrivate *priv;
    icalcomponent *alarm;

    g_return_if_fail (comp != NULL);
    g_return_if_fail (IS_CAL_COMPONENT (comp));
    g_return_if_fail (auid != NULL);

    priv = comp->priv;
    g_return_if_fail (priv->icalcomp != NULL);

    alarm = g_hash_table_lookup (priv->alarm_uid_hash, auid);
    if (!alarm)
        return;

    g_hash_table_remove (priv->alarm_uid_hash, auid);
    icalcomponent_remove_component (priv->icalcomp, alarm);
    icalcomponent_free (alarm);
}


/* Scans an icalproperty from a calendar component and adds its mapping to our
 * own alarm structure.
 */
static void
scan_alarm_property (CalComponentAlarm *alarm, icalproperty *prop)
{
    icalproperty_kind kind;
    const char *xname;

    kind = icalproperty_isa (prop);

    switch (kind) {
    case ICAL_ACTION_PROPERTY:
        alarm->action = prop;
        break;

    case ICAL_TRIGGER_PROPERTY:
        alarm->trigger = prop;
        break;

    case ICAL_X_PROPERTY:
        xname = icalproperty_get_x_name (prop);
        g_assert (xname != NULL);

        if (strcmp (xname, EVOLUTION_ALARM_UID_PROPERTY) == 0)
            alarm->uid = prop;

        break;

    default:
        break;
    }
}

/* Creates a CalComponentAlarm from a libical alarm subcomponent */
static CalComponentAlarm *
make_alarm (icalcomponent *subcomp)
{
    CalComponentAlarm *alarm;
    icalproperty *prop;

    alarm = g_new (CalComponentAlarm, 1);

    alarm->icalcomp = subcomp;
    alarm->uid = NULL;

    for (prop = icalcomponent_get_first_property (subcomp, ICAL_ANY_PROPERTY);
         prop;
         prop = icalcomponent_get_next_property (subcomp, ICAL_ANY_PROPERTY))
        scan_alarm_property (alarm, prop);

    g_assert (alarm->uid != NULL);

    return alarm;
}

/* Used from g_hash_table_foreach(); adds an alarm UID to a list */
static void
add_alarm_uid (gpointer key, gpointer value, gpointer data)
{
    const char *auid;
    GList **l;

    auid = key;
    l = data;

    *l = g_list_prepend (*l, g_strdup (auid));
}

/**
 * cal_component_get_alarm_uids:
 * @comp: A calendar component.
 *
 * Builds a list of the unique identifiers of the alarm subcomponents inside a
 * calendar component.
 *
 * Return value: List of unique identifiers for alarms.  This should be freed
 * using cal_obj_uid_list_free().
 **/
GList *
cal_component_get_alarm_uids (CalComponent *comp)
{
    CalComponentPrivate *priv;
    GList *l;

    g_return_val_if_fail (comp != NULL, NULL);
    g_return_val_if_fail (IS_CAL_COMPONENT (comp), NULL);

    priv = comp->priv;
    g_return_val_if_fail (priv->icalcomp != NULL, NULL);

    l = NULL;
    g_hash_table_foreach (priv->alarm_uid_hash, add_alarm_uid, &l);

    return l;
}

/**
 * cal_component_get_alarm:
 * @comp: A calendar component.
 * @auid: Unique identifier for the sought alarm subcomponent.
 *
 * Queries a particular alarm subcomponent of a calendar component.
 *
 * Return value: The alarm subcomponent that corresponds to the specified @auid,
 * or #NULL if no alarm exists with that UID.  This should be freed using
 * cal_component_alarm_free().
 **/
CalComponentAlarm *
cal_component_get_alarm (CalComponent *comp, const char *auid)
{
    CalComponentPrivate *priv;
    icalcomponent *alarm;

    g_return_val_if_fail (comp != NULL, NULL);
    g_return_val_if_fail (IS_CAL_COMPONENT (comp), NULL);

    priv = comp->priv;
    g_return_val_if_fail (priv->icalcomp != NULL, NULL);

    g_return_val_if_fail (auid != NULL, NULL);

    alarm = g_hash_table_lookup (priv->alarm_uid_hash, auid);

    if (alarm)
        return make_alarm (alarm);
    else
        return NULL;
}

/**
 * cal_component_alarms_free:
 * @alarms: Component alarms structure.
 *
 * Frees a #CalComponentAlarms structure.
 **/
void
cal_component_alarms_free (CalComponentAlarms *alarms)
{
    GSList *l;

    g_return_if_fail (alarms != NULL);

    g_assert (alarms->comp != NULL);
    gtk_object_unref (GTK_OBJECT (alarms->comp));

    for (l = alarms->alarms; l; l = l->next) {
        CalAlarmInstance *instance;

        instance = l->data;
        g_assert (instance != NULL);
        g_free (instance);
    }

    g_slist_free (alarms->alarms);
    g_free (alarms);
}

/**
 * cal_component_alarm_new:
 *
 *
 *
 * Return value: a new alarm component
 **/
CalComponentAlarm *
cal_component_alarm_new (void)
{
    CalComponentAlarm *alarm;
    char *new_auid ;

    alarm = g_new (CalComponentAlarm, 1);

    alarm->icalcomp = icalcomponent_new (ICAL_VALARM_COMPONENT);

    new_auid = cal_component_gen_uid ();
    alarm->uid = icalproperty_new_x (new_auid);
    icalproperty_set_x_name (alarm->uid, EVOLUTION_ALARM_UID_PROPERTY);
    icalcomponent_add_property (alarm->icalcomp, alarm->uid);
    g_free (new_auid);

    alarm->action = NULL;
    alarm->trigger = NULL;

    return alarm;
}

/**
 * cal_component_alarm_clone:
 * @alarm: An alarm subcomponent.
 * 
 * Creates a new alarm subcomponent by copying the information from another one.
 * 
 * Return value: A newly-created alarm subcomponent with the same values as the
 * original one.  Should be freed with cal_component_alarm_free().
 **/
CalComponentAlarm *
cal_component_alarm_clone (CalComponentAlarm *alarm)
{
    icalcomponent *icalcomp;

    g_return_val_if_fail (alarm != NULL, NULL);

    icalcomp = icalcomponent_new_clone (alarm->icalcomp);
    return make_alarm (icalcomp);
}

/**
 * cal_component_alarm_get_uid:
 * @alarm: An alarm subcomponent.
 *
 * Queries the unique identifier of an alarm subcomponent.
 *
 * Return value: UID of the alarm.
 **/
const char *
cal_component_alarm_get_uid (CalComponentAlarm *alarm)
{
    g_return_val_if_fail (alarm != NULL, NULL);

    return alarm_uid_from_prop (alarm->uid);
}

/**
 * cal_component_alarm_get_action:
 * @alarm: An alarm.
 * @action: Return value for the alarm's action type.
 *
 * Queries the action type of an alarm.
 **/
void
cal_component_alarm_get_action (CalComponentAlarm *alarm, CalAlarmAction *action)
{
    enum icalproperty_action ipa;

    g_return_if_fail (alarm != NULL);
    g_return_if_fail (action != NULL);

    g_assert (alarm->icalcomp != NULL);

    if (!alarm->action) {
        *action = CAL_ALARM_NONE;
        return;
    }

    ipa = icalproperty_get_action (alarm->action);

    switch (ipa) {
    case ICAL_ACTION_AUDIO:
        *action = CAL_ALARM_AUDIO;
        break;

    case ICAL_ACTION_DISPLAY:
        *action = CAL_ALARM_DISPLAY;
        break;

    case ICAL_ACTION_EMAIL:
        *action = CAL_ALARM_EMAIL;
        break;

    case ICAL_ACTION_PROCEDURE:
        *action = CAL_ALARM_PROCEDURE;
        break;

    case ICAL_ACTION_NONE:
        *action = CAL_ALARM_NONE;
        break;

    default:
        *action = CAL_ALARM_UNKNOWN;
    }
}

/**
 * cal_component_alarm_set_action:
 * @alarm: An alarm.
 * @action: Action type.
 *
 * Sets the action type for an alarm.
 **/
void
cal_component_alarm_set_action (CalComponentAlarm *alarm, CalAlarmAction action)
{
    enum icalproperty_action ipa;

    g_return_if_fail (alarm != NULL);
    g_return_if_fail (action != CAL_ALARM_NONE);
    g_return_if_fail (action != CAL_ALARM_UNKNOWN);

    g_assert (alarm->icalcomp != NULL);

    switch (action) {
    case CAL_ALARM_AUDIO:
        ipa = ICAL_ACTION_AUDIO;
        break;

    case CAL_ALARM_DISPLAY:
        ipa = ICAL_ACTION_DISPLAY;
        break;

    case CAL_ALARM_EMAIL:
        ipa = ICAL_ACTION_EMAIL;
        break;

    case CAL_ALARM_PROCEDURE:
        ipa = ICAL_ACTION_PROCEDURE;
        break;

    default:
        g_assert_not_reached ();
        ipa = ICAL_ACTION_NONE;
    }

    if (alarm->action)
        icalproperty_set_action (alarm->action, ipa);
    else {
        alarm->action = icalproperty_new_action (ipa);
        icalcomponent_add_property (alarm->icalcomp, alarm->action);
    }
}

/**
 * cal_component_alarm_get_trigger:
 * @alarm: An alarm.
 * @trigger: Return value for the trigger time.
 *
 * Queries the trigger time for an alarm.
 **/
void
cal_component_alarm_get_trigger (CalComponentAlarm *alarm, CalAlarmTrigger *trigger)
{
    icalparameter *param;
    struct icaltriggertype t;
    gboolean relative;

    g_return_if_fail (alarm != NULL);
    g_return_if_fail (trigger != NULL);

    g_assert (alarm->icalcomp != NULL);

    if (!alarm->trigger) {
        trigger->type = CAL_ALARM_TRIGGER_NONE;
        return;
    }

    /* Get trigger type */

    param = icalproperty_get_first_parameter (alarm->trigger, ICAL_VALUE_PARAMETER);
    if (param) {
        icalparameter_value value;

        value = icalparameter_get_value (param);

        switch (value) {
        case ICAL_VALUE_DURATION:
            relative = TRUE;
            break;

        case ICAL_VALUE_DATETIME:
            relative = FALSE;
            break;

        default:
            g_message ("cal_component_alarm_get_trigger(): Unknown value for trigger "
                   "value %d; using RELATIVE", value);

            relative = TRUE;
            break;
        }
    } else
        relative = TRUE;

    /* Get trigger value and the RELATED parameter */

    t = icalproperty_get_trigger (alarm->trigger);

    if (relative) {
        trigger->u.rel_duration = t.duration;

        param = icalproperty_get_first_parameter (alarm->trigger, ICAL_RELATED_PARAMETER);
        if (param) {
            icalparameter_related rel;

            rel = icalparameter_get_related (param);

            switch (rel) {
            case ICAL_RELATED_START:
                trigger->type = CAL_ALARM_TRIGGER_RELATIVE_START;
                break;

            case ICAL_RELATED_END:
                trigger->type = CAL_ALARM_TRIGGER_RELATIVE_END;
                break;

            default:
                g_assert_not_reached ();
            }
        } else
            trigger->type = CAL_ALARM_TRIGGER_RELATIVE_START;
    } else {
        trigger->u.abs_time = t.time;
        trigger->type = CAL_ALARM_TRIGGER_ABSOLUTE;
    }
}

/**
 * cal_component_alarm_set_trigger:
 * @alarm: An alarm.
 * @trigger: Trigger time structure.
 *
 * Sets the trigger time of an alarm.
 **/
void
cal_component_alarm_set_trigger (CalComponentAlarm *alarm, CalAlarmTrigger trigger)
{
    struct icaltriggertype t;
    icalparameter *param;
    icalparameter_value value_type;
    icalparameter_related related;

    g_return_if_fail (alarm != NULL);
    g_return_if_fail (trigger.type != CAL_ALARM_TRIGGER_NONE);

    g_assert (alarm->icalcomp != NULL);

    /* Delete old trigger */

    if (alarm->trigger) {
        icalcomponent_remove_property (alarm->icalcomp, alarm->trigger);
        icalproperty_free (alarm->trigger);
        alarm->trigger = NULL;
    }

    /* Set the value */

    related = ICAL_RELATED_START; /* Keep GCC happy */

    t.time = icaltime_null_time ();
    t.duration = icaldurationtype_null_duration ();
    switch (trigger.type) {
    case CAL_ALARM_TRIGGER_RELATIVE_START:
        t.duration = trigger.u.rel_duration;
        t.time.is_date = -1;
        value_type = ICAL_VALUE_DURATION;
        related = ICAL_RELATED_START;
        break;

    case CAL_ALARM_TRIGGER_RELATIVE_END:
        t.duration = trigger.u.rel_duration;
        t.time.is_date = -1;
        value_type = ICAL_VALUE_DURATION;
        related = ICAL_RELATED_END;
        break;

    case CAL_ALARM_TRIGGER_ABSOLUTE:
        t.time = trigger.u.abs_time;
        value_type = ICAL_VALUE_DATETIME;
        break;

    default:
        g_assert_not_reached ();
        return;
    }

    alarm->trigger = icalproperty_new_trigger (t);
    icalcomponent_add_property (alarm->icalcomp, alarm->trigger);

    /* Value parameters */

    param = icalproperty_get_first_parameter (alarm->trigger, ICAL_VALUE_PARAMETER);
    if (param)
        icalparameter_set_value (param, value_type);
    else {
        param = icalparameter_new_value (value_type);
        icalproperty_add_parameter (alarm->trigger, param);
    }

    /* Related parameter */

    if (trigger.type != CAL_ALARM_TRIGGER_ABSOLUTE) {
        param = icalproperty_get_first_parameter (alarm->trigger, ICAL_RELATED_PARAMETER);

        if (param)
            icalparameter_set_related (param, related);
        else {
            param = icalparameter_new_related (related);
            icalproperty_add_parameter (alarm->trigger, param);
        }
    }
}

/**
 * cal_component_alarm_free:
 * @alarm: A calendar alarm.
 *
 * Frees an alarm structure.
 **/
void
cal_component_alarm_free (CalComponentAlarm *alarm)
{
    g_return_if_fail (alarm != NULL);

    g_assert (alarm->icalcomp != NULL);

    if (icalcomponent_get_parent (alarm->icalcomp) == NULL)
        icalcomponent_free (alarm->icalcomp);

    alarm->icalcomp = NULL;
    alarm->uid = NULL;
    alarm->action = NULL;
    alarm->trigger = NULL;

    g_free (alarm);
}


/* Returns TRUE if both strings match, i.e. they are both NULL or the
   strings are equal. */
static gboolean
cal_component_strings_match (const gchar    *string1,
                 const gchar    *string2)
{
    if (string1 == NULL || string2 == NULL)
        return (string1 == string2) ? TRUE : FALSE;

    if (!strcmp (string1, string2))
        return TRUE;

    return FALSE;
}


/**
 * cal_component_event_dates_match:
 * @comp1: A calendar component object.
 * @comp2: A calendar component object.
 *
 * Checks if the DTSTART and DTEND properties of the 2 components match.
 * Note that the events may have different recurrence properties which are not
 * taken into account here.
 *
 * Returns: TRUE if the DTSTART and DTEND properties of the 2 components match.
 **/
gboolean
cal_component_event_dates_match (CalComponent *comp1,
                 CalComponent *comp2)
{
    CalComponentDateTime comp1_dtstart, comp1_dtend;
    CalComponentDateTime comp2_dtstart, comp2_dtend;

    cal_component_get_dtstart (comp1, &comp1_dtstart);
    cal_component_get_dtend   (comp1, &comp1_dtend);
    cal_component_get_dtstart (comp2, &comp2_dtstart);
    cal_component_get_dtend   (comp2, &comp2_dtend);

    /* If either value is NULL they must both be NULL to match. */
    if (comp1_dtstart.value == NULL || comp2_dtstart.value == NULL) {
        if (comp1_dtstart.value != comp2_dtstart.value)
            return FALSE;
    } else {
        if (icaltime_compare (*comp1_dtstart.value,
                      *comp2_dtstart.value))
            return FALSE;
    }

    if (comp1_dtend.value == NULL || comp2_dtend.value == NULL) {
        if (comp1_dtend.value != comp2_dtend.value)
            return FALSE;
    } else {
        if (icaltime_compare (*comp1_dtend.value,
                      *comp2_dtend.value))
            return FALSE;
    }

    /* Now check the timezones. */
    if (!cal_component_strings_match (comp1_dtstart.tzid,
                      comp2_dtstart.tzid))
        return FALSE;

    if (!cal_component_strings_match (comp1_dtend.tzid,
                      comp2_dtend.tzid))
        return FALSE;

    return TRUE;
}