Fix FSF address (Tobias Mueller, #470445)
[platform/upstream/evolution-data-server.git] / calendar / libecal / e-cal-component.c
1 /* Evolution calendar - iCalendar component object
2  *
3  * Copyright (C) 2000 Ximian, Inc.
4  * Copyright (C) 2000 Ximian, Inc.
5  *
6  * Author: Federico Mena-Quintero <federico@ximian.com>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of version 2 of the GNU Lesser General Public
10  * License as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  */
21
22 #include <config.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <glib.h>
27 #include <glib/gi18n-lib.h>
28 #include "e-cal-component.h"
29 #include "e-cal-time-util.h"
30
31 \f
32
33 #ifdef G_OS_WIN32
34 #define getgid() 0
35 #define getppid() 0
36 #endif
37
38 /* Extension property for alarm components so that we can reference them by UID */
39 #define EVOLUTION_ALARM_UID_PROPERTY "X-EVOLUTION-ALARM-UID"
40
41
42 struct attendee {
43         icalproperty *prop;
44         icalparameter *cutype_param;
45         icalparameter *member_param;
46         icalparameter *role_param;
47         icalparameter *partstat_param;
48         icalparameter *rsvp_param;
49         icalparameter *delto_param;
50         icalparameter *delfrom_param;
51         icalparameter *sentby_param;
52         icalparameter *cn_param;
53         icalparameter *language_param;
54 };
55
56 struct attachment {
57         icalproperty *prop;
58         icalattach *attach;
59 };
60
61 struct text {
62         icalproperty *prop;
63         icalparameter *altrep_param;
64 };
65
66 struct datetime {
67         icalproperty *prop;
68         icalparameter *tzid_param;
69 };
70
71 struct organizer {
72         icalproperty *prop;
73         icalparameter *sentby_param;
74         icalparameter *cn_param;
75         icalparameter *language_param;
76 };
77
78 struct period {
79         icalproperty *prop;
80         icalparameter *value_param;
81 };
82
83 struct recur_id {
84         struct datetime recur_time;
85         
86         icalparameter *range_param;
87 };
88
89 /* Private part of the CalComponent structure */
90 struct _ECalComponentPrivate {
91         /* The icalcomponent we wrap */
92         icalcomponent *icalcomp;
93
94         /* Properties */
95
96         icalproperty *uid;
97
98         icalproperty *status;
99         GSList *attendee_list;
100         
101         icalproperty *categories;
102
103         icalproperty *classification;
104
105         GSList *comment_list; /* list of struct text */
106
107         icalproperty *completed;
108
109         GSList *contact_list; /* list of struct text */
110
111         icalproperty *created;
112
113         GSList *description_list; /* list of struct text */
114
115         struct datetime dtstart;
116         struct datetime dtend;
117
118         icalproperty *dtstamp;
119
120         /* The DURATION property can be used instead of the VEVENT DTEND or
121            the VTODO DUE dates. We do not use it directly ourselves, but we
122            must be able to handle it from incoming data. If a DTEND or DUE
123            is requested, we convert the DURATION if necessary. If DTEND or
124            DUE is set, we remove any DURATION. */
125         icalproperty *duration;
126
127         struct datetime due;
128
129         GSList *exdate_list; /* list of struct datetime */
130         GSList *exrule_list; /* list of icalproperty objects */
131
132         struct organizer organizer;
133         
134         icalproperty *geo;
135         icalproperty *last_modified;
136         icalproperty *percent;
137         icalproperty *priority;
138
139         struct recur_id recur_id;
140         
141         GSList *rdate_list; /* list of struct period */
142
143         GSList *rrule_list; /* list of icalproperty objects */
144
145         icalproperty *sequence;
146
147         struct {
148                 icalproperty *prop;
149                 icalparameter *altrep_param;
150         } summary;
151
152         icalproperty *transparency;
153         icalproperty *url;
154         icalproperty *location;
155
156         GSList *attachment_list;
157
158         /* Subcomponents */
159
160         GHashTable *alarm_uid_hash;
161
162         /* Whether we should increment the sequence number when piping the
163          * object over the wire.
164          */
165         guint need_sequence_inc : 1;
166 };
167
168 /* Private structure for alarms */
169 struct _ECalComponentAlarm {
170         /* Alarm icalcomponent we wrap */
171         icalcomponent *icalcomp;
172
173         /* Our extension UID property */
174         icalproperty *uid;
175
176         /* Properties */
177
178         icalproperty *action;
179         icalproperty *attach; /* FIXME: see scan_alarm_property() below */
180
181         struct {
182                 icalproperty *prop;
183                 icalparameter *altrep_param;
184         } description;
185
186         icalproperty *duration;
187         icalproperty *repeat;
188         icalproperty *trigger;
189
190         GSList *attendee_list;
191 };
192
193 \f
194
195 static void e_cal_component_class_init (ECalComponentClass *klass);
196 static void e_cal_component_init (ECalComponent *comp, ECalComponentClass *klass);
197 static void e_cal_component_finalize (GObject *object);
198
199 static GObjectClass *parent_class;
200
201 \f
202
203 /**
204  * e_cal_component_get_type:
205  *
206  * Registers the #ECalComponent class if necessary, and returns the type ID
207  * associated to it.
208  *
209  * Return value: The type ID of the #ECalComponent class.
210  **/
211 GType
212 e_cal_component_get_type (void)
213 {
214         static GType e_cal_component_type = 0;
215
216         if (!e_cal_component_type) {
217                 static GTypeInfo info = {
218                         sizeof (ECalComponentClass),
219                         (GBaseInitFunc) NULL,
220                         (GBaseFinalizeFunc) NULL,
221                         (GClassInitFunc) e_cal_component_class_init,
222                         NULL, NULL,
223                         sizeof (ECalComponent),
224                         0,
225                         (GInstanceInitFunc) e_cal_component_init
226                 };
227                 e_cal_component_type = g_type_register_static (G_TYPE_OBJECT, "ECalComponent", &info, 0);
228         }
229
230         return e_cal_component_type;
231 }
232
233 /* Class initialization function for the calendar component object */
234 static void
235 e_cal_component_class_init (ECalComponentClass *klass)
236 {
237         GObjectClass *object_class;
238
239         object_class = (GObjectClass *) klass;
240
241         parent_class = g_type_class_peek_parent (klass);
242
243         object_class->finalize = e_cal_component_finalize;
244 }
245
246 /* Object initialization function for the calendar component object */
247 static void
248 e_cal_component_init (ECalComponent *comp, ECalComponentClass *klass)
249 {
250         ECalComponentPrivate *priv;
251
252         priv = g_new0 (ECalComponentPrivate, 1);
253         comp->priv = priv;
254
255         priv->alarm_uid_hash = g_hash_table_new (g_str_hash, g_str_equal);
256 }
257
258 /* Does a simple g_free() of the elements of a GSList and then frees the list
259  * itself.  Returns NULL.
260  */
261 static GSList *
262 free_slist (GSList *slist)
263 {
264         GSList *l;
265
266         for (l = slist; l; l = l->next)
267                 g_free (l->data);
268
269         g_slist_free (slist);
270         return NULL;
271 }
272
273 /* Used from g_hash_table_foreach_remove() to free the alarm UIDs hash table.
274  * We do not need to do anything to individual elements since we were storing
275  * the UID pointers inside the icalproperties themselves.
276  */
277 static gboolean
278 free_alarm_cb (gpointer key, gpointer value, gpointer data)
279 {
280         return TRUE;
281 }
282
283 /* Frees the internal icalcomponent only if it does not have a parent.  If it
284  * does, it means we don't own it and we shouldn't free it.
285  */
286 static void
287 free_icalcomponent (ECalComponent *comp, gboolean free)
288 {
289         ECalComponentPrivate *priv;
290         GSList *l;
291         
292         priv = comp->priv;
293
294         if (!priv->icalcomp)
295                 return;
296
297         /* Free the icalcomponent */
298
299         if (free && icalcomponent_get_parent (priv->icalcomp) == NULL) {
300                 icalcomponent_free (priv->icalcomp);
301                 priv->icalcomp = NULL;
302         }
303         
304         /* Free the mappings */
305
306         priv->uid = NULL;
307
308         priv->status = NULL;
309
310         for (l = priv->attachment_list; l != NULL; l = l->next)
311                 g_free (l->data);
312         g_slist_free (priv->attachment_list);
313         priv->attachment_list = NULL;
314
315         for (l = priv->attendee_list; l != NULL; l = l->next)
316                 g_free (l->data);
317         g_slist_free (priv->attendee_list);
318         priv->attendee_list = NULL;
319         
320         priv->categories = NULL;
321
322         priv->classification = NULL;
323         priv->comment_list = NULL;
324         priv->completed = NULL;
325         priv->contact_list = NULL;
326         priv->created = NULL;
327
328         priv->description_list = free_slist (priv->description_list);
329
330         priv->dtend.prop = NULL;
331         priv->dtend.tzid_param = NULL;
332
333         priv->dtstamp = NULL;
334
335         priv->dtstart.prop = NULL;
336         priv->dtstart.tzid_param = NULL;
337
338         priv->due.prop = NULL;
339         priv->due.tzid_param = NULL;
340
341         priv->duration = NULL;
342
343         priv->exdate_list = free_slist (priv->exdate_list);
344
345         g_slist_free (priv->exrule_list);
346         priv->exrule_list = NULL;
347
348         priv->geo = NULL;
349         priv->last_modified = NULL;
350         priv->percent = NULL;
351         priv->priority = NULL;
352
353         priv->rdate_list = free_slist (priv->rdate_list);
354
355         g_slist_free (priv->rrule_list);
356         priv->rrule_list = NULL;
357
358         priv->sequence = NULL;
359
360         priv->summary.prop = NULL;
361         priv->summary.altrep_param = NULL;
362
363         priv->transparency = NULL;
364         priv->url = NULL;
365         priv->location = NULL;
366
367         /* Free the subcomponents */
368
369         g_hash_table_foreach_remove (priv->alarm_uid_hash, free_alarm_cb, NULL);
370
371         /* Clean up */
372
373         priv->need_sequence_inc = FALSE;
374 }
375
376 /* Finalize handler for the calendar component object */
377 static void
378 e_cal_component_finalize (GObject *object)
379 {
380         ECalComponent *comp;
381         ECalComponentPrivate *priv;
382
383         g_return_if_fail (object != NULL);
384         g_return_if_fail (E_IS_CAL_COMPONENT (object));
385
386         comp = E_CAL_COMPONENT (object);
387         priv = comp->priv;
388
389         free_icalcomponent (comp, TRUE);
390         g_hash_table_destroy (priv->alarm_uid_hash);
391         priv->alarm_uid_hash = NULL;
392
393         g_free (priv);
394         comp->priv = NULL;
395
396         if (G_OBJECT_CLASS (parent_class)->finalize)
397                 (* G_OBJECT_CLASS (parent_class)->finalize) (object);
398 }
399
400 \f
401
402 /**
403  * e_cal_component_gen_uid:
404  *
405  * Generates a unique identifier suitable for calendar components.
406  *
407  * Return value: A unique identifier string.  Every time this function is called
408  * a different string is returned.
409  **/
410 char *
411 e_cal_component_gen_uid (void)
412 {
413         char *iso, *ret;
414         static char *hostname;
415         time_t t = time (NULL);
416         static int serial;
417
418         if (!hostname) {
419 #ifndef G_OS_WIN32
420                 static char buffer [512];
421
422                 if ((gethostname (buffer, sizeof (buffer) - 1) == 0) &&
423                     (buffer [0] != 0))
424                         hostname = buffer;
425                 else
426                         hostname = "localhost";
427 #else
428                 hostname = g_get_host_name ();
429 #endif
430         }
431
432         iso = isodate_from_time_t (t);
433         ret = g_strdup_printf ("%s-%d-%d-%d-%d@%s",
434                                iso,
435                                getpid (),
436                                getgid (),
437                                getppid (),
438                                serial++,
439                                hostname);
440         g_free (iso);
441
442         return ret;
443 }
444
445 /**
446  * e_cal_component_new:
447  *
448  * Creates a new empty calendar component object.  Once created, you should set it from an
449  * existing #icalcomponent structure by using e_cal_component_set_icalcomponent() or with a
450  * new empty component type by using e_cal_component_set_new_vtype().
451  *
452  * Return value: A newly-created calendar component object.
453  **/
454 ECalComponent *
455 e_cal_component_new (void)
456 {
457         return E_CAL_COMPONENT (g_object_new (E_TYPE_CAL_COMPONENT, NULL));
458 }
459
460 /**
461  * e_cal_component_new_from_string:
462  * @calobj: A string representation of an iCalendar component.
463  *
464  * Creates a new calendar component object from the given iCalendar string.
465  *
466  * Return value: A calendar component representing the given iCalendar string on
467  * success, NULL if there was an error.
468  **/
469 ECalComponent *
470 e_cal_component_new_from_string (const char *calobj)
471 {
472         ECalComponent *comp;
473         icalcomponent *icalcomp;
474
475         g_return_val_if_fail (calobj != NULL, NULL);
476
477         icalcomp = icalparser_parse_string (calobj);
478         if (!icalcomp)
479                 return NULL;
480
481         comp = e_cal_component_new ();
482         if (!e_cal_component_set_icalcomponent (comp, icalcomp)) {
483                 icalcomponent_free (icalcomp);
484                 g_object_unref (comp);
485
486                 return NULL;
487         }
488
489         return comp;
490 }
491
492 /**
493  * e_cal_component_clone:
494  * @comp: A calendar component object.
495  *
496  * Creates a new calendar component object by copying the information from
497  * another one.
498  *
499  * Return value: A newly-created calendar component with the same values as the
500  * original one.
501  **/
502 ECalComponent *
503 e_cal_component_clone (ECalComponent *comp)
504 {
505         ECalComponentPrivate *priv;
506         ECalComponent *new_comp;
507         icalcomponent *new_icalcomp;
508
509         g_return_val_if_fail (comp != NULL, NULL);
510         g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
511
512         priv = comp->priv;
513         g_return_val_if_fail (priv->need_sequence_inc == FALSE, NULL);
514
515         new_comp = e_cal_component_new ();
516
517         if (priv->icalcomp) {
518                 new_icalcomp = icalcomponent_new_clone (priv->icalcomp);
519                 e_cal_component_set_icalcomponent (new_comp, new_icalcomp);
520         }
521
522         return new_comp;
523 }
524
525 /* Scans an attachment property */
526 static void
527 scan_attachment (GSList **attachment_list, icalproperty *prop) 
528 {
529         struct attachment *attachment;
530         
531         attachment = g_new (struct attachment, 1);
532         attachment->prop = prop;
533
534         attachment->attach = icalproperty_get_attach (prop);
535
536         *attachment_list = g_slist_append (*attachment_list, attachment);
537 }
538
539 /* Scans an attendee property */
540 static void
541 scan_attendee (GSList **attendee_list, icalproperty *prop) 
542 {
543         struct attendee *attendee;
544         
545         attendee = g_new (struct attendee, 1);
546         attendee->prop = prop;
547
548         attendee->cutype_param = icalproperty_get_first_parameter (prop, ICAL_CUTYPE_PARAMETER);
549         attendee->member_param = icalproperty_get_first_parameter (prop, ICAL_MEMBER_PARAMETER);
550         attendee->role_param = icalproperty_get_first_parameter (prop, ICAL_ROLE_PARAMETER);
551         attendee->partstat_param = icalproperty_get_first_parameter (prop, ICAL_PARTSTAT_PARAMETER);
552         attendee->rsvp_param = icalproperty_get_first_parameter (prop, ICAL_RSVP_PARAMETER);
553         attendee->delto_param = icalproperty_get_first_parameter (prop, ICAL_DELEGATEDTO_PARAMETER);
554         attendee->delfrom_param = icalproperty_get_first_parameter (prop, ICAL_DELEGATEDFROM_PARAMETER);
555         attendee->sentby_param = icalproperty_get_first_parameter (prop, ICAL_SENTBY_PARAMETER);
556         attendee->cn_param = icalproperty_get_first_parameter (prop, ICAL_CN_PARAMETER);
557         attendee->language_param = icalproperty_get_first_parameter (prop, ICAL_LANGUAGE_PARAMETER);
558         
559         *attendee_list = g_slist_append (*attendee_list, attendee);
560 }
561
562 /* Scans a date/time and timezone pair property */
563 static void
564 scan_datetime (ECalComponent *comp, struct datetime *datetime, icalproperty *prop)
565 {
566         ECalComponentPrivate *priv;
567
568         priv = comp->priv;
569
570         datetime->prop = prop;
571         datetime->tzid_param = icalproperty_get_first_parameter (prop, ICAL_TZID_PARAMETER);
572 }
573
574 /* Scans an exception date property */
575 static void
576 scan_exdate (ECalComponent *comp, icalproperty *prop)
577 {
578         ECalComponentPrivate *priv;
579         struct datetime *dt;
580
581         priv = comp->priv;
582
583         dt = g_new (struct datetime, 1);
584         dt->prop = prop;
585         dt->tzid_param = icalproperty_get_first_parameter (prop, ICAL_TZID_PARAMETER);
586
587         priv->exdate_list = g_slist_append (priv->exdate_list, dt);
588 }
589
590 /* Scans and attendee property */
591 static void
592 scan_organizer (ECalComponent *comp, struct organizer *organizer, icalproperty *prop) 
593 {
594         organizer->prop = prop;
595
596         organizer->sentby_param = icalproperty_get_first_parameter (prop, ICAL_SENTBY_PARAMETER);
597         organizer->cn_param = icalproperty_get_first_parameter (prop, ICAL_CN_PARAMETER);
598         organizer->language_param = icalproperty_get_first_parameter (prop, ICAL_LANGUAGE_PARAMETER);
599 }
600
601 /* Scans an icalperiodtype property */
602 static void
603 scan_period (ECalComponent *comp, GSList **list, icalproperty *prop)
604 {
605         struct period *period;
606
607         period = g_new (struct period, 1);
608         period->prop = prop;
609         period->value_param = icalproperty_get_first_parameter (prop, ICAL_VALUE_PARAMETER);
610
611         *list = g_slist_append (*list, period);
612 }
613
614
615 /* Scans an icalrecurtype property */
616 static void
617 scan_recur_id (ECalComponent *comp, struct recur_id *recur_id, icalproperty *prop)
618 {
619         scan_datetime (comp, &recur_id->recur_time, prop);
620
621         recur_id->range_param = icalproperty_get_first_parameter (prop, ICAL_RANGE_PARAMETER);
622 }
623
624 /* Scans an icalrecurtype property */
625 static void
626 scan_recur (ECalComponent *comp, GSList **list, icalproperty *prop)
627 {
628         *list = g_slist_append (*list, prop);
629 }
630
631 /* Scans the summary property */
632 static void
633 scan_summary (ECalComponent *comp, icalproperty *prop)
634 {
635         ECalComponentPrivate *priv;
636
637         priv = comp->priv;
638
639         priv->summary.prop = prop;
640         priv->summary.altrep_param = icalproperty_get_first_parameter (prop, ICAL_ALTREP_PARAMETER);
641 }
642
643 /* Scans a text (i.e. text + altrep) property */
644 static void
645 scan_text (ECalComponent *comp, GSList **text_list, icalproperty *prop)
646 {
647         struct text *text;
648
649         text = g_new (struct text, 1);
650         text->prop = prop;
651         text->altrep_param = icalproperty_get_first_parameter (prop, ICAL_ALTREP_PARAMETER);
652
653         *text_list = g_slist_append (*text_list, text);
654 }
655
656 /* Scans an icalproperty and adds its mapping to the component */
657 static void
658 scan_property (ECalComponent *comp, icalproperty *prop)
659 {
660         ECalComponentPrivate *priv;
661         icalproperty_kind kind;
662
663         priv = comp->priv;
664
665         kind = icalproperty_isa (prop);
666
667         switch (kind) {
668         case ICAL_STATUS_PROPERTY:
669                 priv->status = prop;
670                 break;
671
672         case ICAL_ATTACH_PROPERTY:
673                 scan_attachment (&priv->attachment_list, prop);
674                 break;
675
676         case ICAL_ATTENDEE_PROPERTY:
677                 scan_attendee (&priv->attendee_list, prop);
678                 break;
679
680         case ICAL_CATEGORIES_PROPERTY:
681                 priv->categories = prop;
682                 break;
683
684         case ICAL_CLASS_PROPERTY:
685                 priv->classification = prop;
686                 break;
687
688         case ICAL_COMMENT_PROPERTY:
689                 scan_text (comp, &priv->comment_list, prop);
690                 break;
691
692         case ICAL_COMPLETED_PROPERTY:
693                 priv->completed = prop;
694                 break;
695
696         case ICAL_CONTACT_PROPERTY:
697                 scan_text (comp, &priv->contact_list, prop);
698                 break;
699
700         case ICAL_CREATED_PROPERTY:
701                 priv->created = prop;
702                 break;
703
704         case ICAL_DESCRIPTION_PROPERTY:
705                 scan_text (comp, &priv->description_list, prop);
706                 break;
707
708         case ICAL_DTEND_PROPERTY:
709                 scan_datetime (comp, &priv->dtend, prop);
710                 break;
711
712         case ICAL_DTSTAMP_PROPERTY:
713                 priv->dtstamp = prop;
714                 break;
715
716         case ICAL_DTSTART_PROPERTY:
717                 scan_datetime (comp, &priv->dtstart, prop);
718                 break;
719
720         case ICAL_DUE_PROPERTY:
721                 scan_datetime (comp, &priv->due, prop);
722                 break;
723
724         case ICAL_DURATION_PROPERTY:
725                 priv->duration = prop;
726                 break;
727
728         case ICAL_EXDATE_PROPERTY:
729                 scan_exdate (comp, prop);
730                 break;
731
732         case ICAL_EXRULE_PROPERTY:
733                 scan_recur (comp, &priv->exrule_list, prop);
734                 break;
735
736         case ICAL_GEO_PROPERTY:
737                 priv->geo = prop;
738                 break;
739
740         case ICAL_LASTMODIFIED_PROPERTY:
741                 priv->last_modified = prop;
742                 break;
743
744         case ICAL_ORGANIZER_PROPERTY:
745                 scan_organizer (comp, &priv->organizer, prop);
746                 break;
747
748         case ICAL_PERCENTCOMPLETE_PROPERTY:
749                 priv->percent = prop;
750                 break;
751
752         case ICAL_PRIORITY_PROPERTY:
753                 priv->priority = prop;
754                 break;
755
756         case ICAL_RECURRENCEID_PROPERTY:
757                 scan_recur_id (comp, &priv->recur_id, prop);
758                 break;
759
760         case ICAL_RDATE_PROPERTY:
761                 scan_period (comp, &priv->rdate_list, prop);
762                 break;
763
764         case ICAL_RRULE_PROPERTY:
765                 scan_recur (comp, &priv->rrule_list, prop);
766                 break;
767
768         case ICAL_SEQUENCE_PROPERTY:
769                 priv->sequence = prop;
770                 break;
771
772         case ICAL_SUMMARY_PROPERTY:
773                 scan_summary (comp, prop);
774                 break;
775
776         case ICAL_TRANSP_PROPERTY:
777                 priv->transparency = prop;
778                 break;
779
780         case ICAL_UID_PROPERTY:
781                 priv->uid = prop;
782                 break;
783
784         case ICAL_URL_PROPERTY:
785                 priv->url = prop;
786                 break;
787
788         case ICAL_LOCATION_PROPERTY :
789                 priv->location = prop;
790                 break;
791
792         default:
793                 break;
794         }
795 }
796
797 /* Gets our alarm UID string from a property that is known to contain it */
798 static const char *
799 alarm_uid_from_prop (icalproperty *prop)
800 {
801         const char *xstr;
802
803         g_assert (icalproperty_isa (prop) == ICAL_X_PROPERTY);
804
805         xstr = icalproperty_get_x (prop);
806         g_assert (xstr != NULL);
807
808         return xstr;
809 }
810
811 /* Sets our alarm UID extension property on an alarm component.  Returns a
812  * pointer to the UID string inside the property itself.
813  */
814 static const char *
815 set_alarm_uid (icalcomponent *alarm, const char *auid)
816 {
817         icalproperty *prop;
818         const char *inprop_auid;
819
820         /* Create the new property */
821
822         prop = icalproperty_new_x ((char *) auid);
823         icalproperty_set_x_name (prop, EVOLUTION_ALARM_UID_PROPERTY);
824
825         icalcomponent_add_property (alarm, prop);
826
827         inprop_auid = alarm_uid_from_prop (prop);
828         return inprop_auid;
829 }
830
831 /* Removes any alarm UID extension properties from an alarm subcomponent */
832 static void
833 remove_alarm_uid (icalcomponent *alarm)
834 {
835         icalproperty *prop;
836         GSList *list, *l;
837
838         list = NULL;
839
840         for (prop = icalcomponent_get_first_property (alarm, ICAL_X_PROPERTY);
841              prop;
842              prop = icalcomponent_get_next_property (alarm, ICAL_X_PROPERTY)) {
843                 const char *xname;
844
845                 xname = icalproperty_get_x_name (prop);
846                 g_assert (xname != NULL);
847
848                 if (strcmp (xname, EVOLUTION_ALARM_UID_PROPERTY) == 0)
849                         list = g_slist_prepend (list, prop);
850         }
851
852         for (l = list; l; l = l->next) {
853                 prop = l->data;
854                 icalcomponent_remove_property (alarm, prop);
855                 icalproperty_free (prop);
856         }
857
858         g_slist_free (list);
859 }
860
861 /* Adds an alarm subcomponent to the calendar component's mapping table.  The
862  * actual UID with which it gets added may not be the same as the specified one;
863  * this function will change it if the table already had an alarm subcomponent
864  * with the specified UID.  Returns the actual UID used.
865  */
866 static const char *
867 add_alarm (ECalComponent *comp, icalcomponent *alarm, const char *auid)
868 {
869         ECalComponentPrivate *priv;
870         icalcomponent *old_alarm;
871
872         priv = comp->priv;
873
874         /* First we see if we already have an alarm with the requested UID.  In
875          * that case, we need to change the new UID to something else.  This
876          * should never happen, but who knows.
877          */
878
879         old_alarm = g_hash_table_lookup (priv->alarm_uid_hash, auid);
880         if (old_alarm != NULL) {
881                 char *new_auid;
882
883                 g_message ("add_alarm(): Got alarm with duplicated UID `%s', changing it...", auid);
884
885                 remove_alarm_uid (alarm);
886
887                 new_auid = e_cal_component_gen_uid ();
888                 auid = set_alarm_uid (alarm, new_auid);
889                 g_free (new_auid);
890         }
891
892         g_hash_table_insert (priv->alarm_uid_hash, (char *) auid, alarm);
893         return auid;
894 }
895
896 /* Scans an alarm subcomponent, adds an UID extension property to it (so that we
897  * can reference alarms by unique IDs), and adds its mapping to the component.  */
898 static void
899 scan_alarm (ECalComponent *comp, icalcomponent *alarm)
900 {
901         ECalComponentPrivate *priv;
902         icalproperty *prop;
903         const char *auid;
904         char *new_auid;
905
906         priv = comp->priv;
907
908         for (prop = icalcomponent_get_first_property (alarm, ICAL_X_PROPERTY);
909              prop;
910              prop = icalcomponent_get_next_property (alarm, ICAL_X_PROPERTY)) {
911                 const char *xname;
912
913                 xname = icalproperty_get_x_name (prop);
914                 g_assert (xname != NULL);
915
916                 if (strcmp (xname, EVOLUTION_ALARM_UID_PROPERTY) == 0) {
917                         auid = alarm_uid_from_prop (prop);
918                         add_alarm (comp, alarm, auid);
919                         return;
920                 }
921         }
922
923         /* The component has no alarm UID property, so we create one. */
924
925         new_auid = e_cal_component_gen_uid ();
926         auid = set_alarm_uid (alarm, new_auid);
927         g_free (new_auid);
928
929         add_alarm (comp, alarm, auid);
930 }
931
932 /* Scans an icalcomponent for its properties so that we can provide
933  * random-access to them.  It also builds a hash table of the component's alarm
934  * subcomponents.
935  */
936 static void
937 scan_icalcomponent (ECalComponent *comp)
938 {
939         ECalComponentPrivate *priv;
940         icalproperty *prop;
941         icalcompiter iter;
942
943         priv = comp->priv;
944
945         g_assert (priv->icalcomp != NULL);
946
947         /* Scan properties */
948
949         for (prop = icalcomponent_get_first_property (priv->icalcomp, ICAL_ANY_PROPERTY);
950              prop;
951              prop = icalcomponent_get_next_property (priv->icalcomp, ICAL_ANY_PROPERTY))
952                 scan_property (comp, prop);
953
954         /* Scan subcomponents */
955
956         for (iter = icalcomponent_begin_component (priv->icalcomp, ICAL_VALARM_COMPONENT);
957              icalcompiter_deref (&iter) != NULL;
958              icalcompiter_next (&iter)) {
959                 icalcomponent *subcomp;
960
961                 subcomp = icalcompiter_deref (&iter);
962                 scan_alarm (comp, subcomp);
963         }
964 }
965
966 /* Ensures that the mandatory calendar component properties (uid, dtstamp) do
967  * exist.  If they don't exist, it creates them automatically.
968  */
969 static void
970 ensure_mandatory_properties (ECalComponent *comp)
971 {
972         ECalComponentPrivate *priv;
973
974         priv = comp->priv;
975         g_assert (priv->icalcomp != NULL);
976
977         if (!priv->uid) {
978                 char *uid;
979
980                 uid = e_cal_component_gen_uid ();
981                 priv->uid = icalproperty_new_uid (uid);
982                 g_free (uid);
983
984                 icalcomponent_add_property (priv->icalcomp, priv->uid);
985         }
986
987         if (!priv->dtstamp) {
988                 struct icaltimetype t;
989
990                 t = icaltime_current_time_with_zone (icaltimezone_get_utc_timezone ());
991
992                 priv->dtstamp = icalproperty_new_dtstamp (t);
993                 icalcomponent_add_property (priv->icalcomp, priv->dtstamp);
994         }
995 }
996
997 /**
998  * e_cal_component_set_new_vtype:
999  * @comp: A calendar component object.
1000  * @type: Type of calendar component to create.
1001  *
1002  * Clears any existing component data from a calendar component object and
1003  * creates a new #icalcomponent of the specified type for it.  The only property
1004  * that will be set in the new component will be its unique identifier.
1005  **/
1006 void
1007 e_cal_component_set_new_vtype (ECalComponent *comp, ECalComponentVType type)
1008 {
1009         ECalComponentPrivate *priv;
1010         icalcomponent *icalcomp;
1011         icalcomponent_kind kind;
1012
1013         g_return_if_fail (comp != NULL);
1014         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
1015
1016         priv = comp->priv;
1017
1018         free_icalcomponent (comp, TRUE);
1019
1020         if (type == E_CAL_COMPONENT_NO_TYPE)
1021                 return;
1022
1023         /* Figure out the kind and create the icalcomponent */
1024
1025         switch (type) {
1026         case E_CAL_COMPONENT_EVENT:
1027                 kind = ICAL_VEVENT_COMPONENT;
1028                 break;
1029
1030         case E_CAL_COMPONENT_TODO:
1031                 kind = ICAL_VTODO_COMPONENT;
1032                 break;
1033
1034         case E_CAL_COMPONENT_JOURNAL:
1035                 kind = ICAL_VJOURNAL_COMPONENT;
1036                 break;
1037
1038         case E_CAL_COMPONENT_FREEBUSY:
1039                 kind = ICAL_VFREEBUSY_COMPONENT;
1040                 break;
1041
1042         case E_CAL_COMPONENT_TIMEZONE:
1043                 kind = ICAL_VTIMEZONE_COMPONENT;
1044                 break;
1045
1046         default:
1047                 g_assert_not_reached ();
1048                 kind = ICAL_NO_COMPONENT;
1049         }
1050
1051         icalcomp = icalcomponent_new (kind);
1052         if (!icalcomp) {
1053                 g_message ("e_cal_component_set_new_vtype(): Could not create the icalcomponent!");
1054                 return;
1055         }
1056
1057         /* Scan the component to build our mapping table */
1058
1059         priv->icalcomp = icalcomp;
1060         scan_icalcomponent (comp);
1061
1062         /* Add missing stuff */
1063
1064         ensure_mandatory_properties (comp);
1065 }
1066
1067 /**
1068  * e_cal_component_set_icalcomponent:
1069  * @comp: A calendar component object.
1070  * @icalcomp: An #icalcomponent.
1071  *
1072  * Sets the contents of a calendar component object from an #icalcomponent
1073  * structure.  If the @comp already had an #icalcomponent set into it, it will
1074  * will be freed automatically if the #icalcomponent does not have a parent
1075  * component itself.
1076  *
1077  * Supported component types are VEVENT, VTODO, VJOURNAL, VFREEBUSY, and VTIMEZONE.
1078  *
1079  * Return value: TRUE on success, FALSE if @icalcomp is an unsupported component
1080  * type.
1081  **/
1082 gboolean
1083 e_cal_component_set_icalcomponent (ECalComponent *comp, icalcomponent *icalcomp)
1084 {
1085         ECalComponentPrivate *priv;
1086         icalcomponent_kind kind;
1087
1088         g_return_val_if_fail (comp != NULL, FALSE);
1089         g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), FALSE);
1090
1091         priv = comp->priv;
1092
1093         if (priv->icalcomp == icalcomp)
1094                 return TRUE;
1095
1096         free_icalcomponent (comp, TRUE);
1097
1098         if (!icalcomp) {
1099                 priv->icalcomp = NULL;
1100                 return TRUE;
1101         }
1102
1103         kind = icalcomponent_isa (icalcomp);
1104
1105         if (!(kind == ICAL_VEVENT_COMPONENT
1106               || kind == ICAL_VTODO_COMPONENT
1107               || kind == ICAL_VJOURNAL_COMPONENT
1108               || kind == ICAL_VFREEBUSY_COMPONENT
1109               || kind == ICAL_VTIMEZONE_COMPONENT))
1110                 return FALSE;
1111
1112         priv->icalcomp = icalcomp;
1113
1114         scan_icalcomponent (comp);
1115         ensure_mandatory_properties (comp);
1116
1117         return TRUE;
1118 }
1119
1120 /**
1121  * e_cal_component_get_icalcomponent:
1122  * @comp: A calendar component object.
1123  *
1124  * Queries the #icalcomponent structure that a calendar component object is
1125  * wrapping.
1126  *
1127  * Return value: An #icalcomponent structure, or NULL if the @comp has no
1128  * #icalcomponent set to it.
1129  **/
1130 icalcomponent *
1131 e_cal_component_get_icalcomponent (ECalComponent *comp)
1132 {
1133         ECalComponentPrivate *priv;
1134
1135         g_return_val_if_fail (comp != NULL, NULL);
1136         g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
1137
1138         priv = comp->priv;
1139
1140         return priv->icalcomp;
1141 }
1142
1143 /**
1144  * e_cal_component_rescan:
1145  * @comp: A calendar component object.
1146  *
1147  * Rescans the #icalcomponent being wrapped by the given calendar component. This
1148  * would replace any value that was changed in the wrapped #icalcomponent.
1149  */
1150 void
1151 e_cal_component_rescan (ECalComponent *comp)
1152 {
1153         ECalComponentPrivate *priv;
1154
1155         g_return_if_fail (comp != NULL);
1156         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
1157
1158         priv = comp->priv;
1159
1160         /* Clear everything out */
1161         free_icalcomponent (comp, FALSE);
1162
1163         /* Rescan */
1164         scan_icalcomponent (comp);
1165         ensure_mandatory_properties (comp);
1166 }
1167
1168 /**
1169  * e_cal_component_strip_errors:
1170  * @comp: A calendar component object.
1171  *
1172  * Strips all error messages from the calendar component. Those error messages are
1173  * added to the iCalendar string representation whenever an invalid is used for
1174  * one of its fields.
1175  */
1176 void
1177 e_cal_component_strip_errors (ECalComponent *comp)
1178 {
1179         ECalComponentPrivate *priv;
1180         
1181         g_return_if_fail (comp != NULL);
1182         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
1183
1184         priv = comp->priv;
1185
1186         icalcomponent_strip_errors (priv->icalcomp);
1187 }
1188
1189 /**
1190  * e_cal_component_get_vtype:
1191  * @comp: A calendar component object.
1192  *
1193  * Queries the type of a calendar component object.
1194  *
1195  * Return value: The type of the component, as defined by RFC 2445.
1196  **/
1197 ECalComponentVType
1198 e_cal_component_get_vtype (ECalComponent *comp)
1199 {
1200         ECalComponentPrivate *priv;
1201         icalcomponent_kind kind;
1202
1203         g_return_val_if_fail (comp != NULL, E_CAL_COMPONENT_NO_TYPE);
1204         g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), E_CAL_COMPONENT_NO_TYPE);
1205
1206         priv = comp->priv;
1207         g_return_val_if_fail (priv->icalcomp != NULL, E_CAL_COMPONENT_NO_TYPE);
1208
1209         kind = icalcomponent_isa (priv->icalcomp);
1210         switch (kind) {
1211         case ICAL_VEVENT_COMPONENT:
1212                 return E_CAL_COMPONENT_EVENT;
1213
1214         case ICAL_VTODO_COMPONENT:
1215                 return E_CAL_COMPONENT_TODO;
1216
1217         case ICAL_VJOURNAL_COMPONENT:
1218                 return E_CAL_COMPONENT_JOURNAL;
1219
1220         case ICAL_VFREEBUSY_COMPONENT:
1221                 return E_CAL_COMPONENT_FREEBUSY;
1222
1223         case ICAL_VTIMEZONE_COMPONENT:
1224                 return E_CAL_COMPONENT_TIMEZONE;
1225
1226         default:
1227                 /* We should have been loaded with a supported type! */
1228                 g_assert_not_reached ();
1229                 return E_CAL_COMPONENT_NO_TYPE;
1230         }
1231 }
1232
1233 /**
1234  * e_cal_component_get_as_string:
1235  * @comp: A calendar component.
1236  *
1237  * Gets the iCalendar string representation of a calendar component.  You should
1238  * call e_cal_component_commit_sequence() before this function to ensure that the
1239  * component's sequence number is consistent with the state of the object.
1240  *
1241  * Return value: String representation of the calendar component according to
1242  * RFC 2445.
1243  **/
1244 char *
1245 e_cal_component_get_as_string (ECalComponent *comp)
1246 {
1247         ECalComponentPrivate *priv;
1248         char *str, *buf;
1249
1250         g_return_val_if_fail (comp != NULL, NULL);
1251         g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
1252
1253         priv = comp->priv;
1254         g_return_val_if_fail (priv->icalcomp != NULL, NULL);
1255
1256         /* Ensure that the user has committed the new SEQUENCE */
1257         g_return_val_if_fail (priv->need_sequence_inc == FALSE, NULL);
1258
1259         /* We dup the string; libical owns that memory */
1260
1261         str = icalcomponent_as_ical_string (priv->icalcomp);
1262
1263         if (str)
1264                 buf = g_strdup (str);
1265         else
1266                 buf = NULL;
1267
1268         return buf;
1269 }
1270
1271 /* Used from g_hash_table_foreach(); ensures that an alarm subcomponent
1272  * has the mandatory properties it needs.
1273  */
1274 static void
1275 ensure_alarm_properties_cb (gpointer key, gpointer value, gpointer data)
1276 {
1277         ECalComponent *comp;
1278         ECalComponentPrivate *priv;
1279         icalcomponent *alarm;
1280         icalproperty *prop;
1281         enum icalproperty_action action;
1282         const char *str;
1283
1284         alarm = value;
1285
1286         comp = E_CAL_COMPONENT (data);
1287         priv = comp->priv;
1288
1289         prop = icalcomponent_get_first_property (alarm, ICAL_ACTION_PROPERTY);
1290         if (!prop)
1291                 return;
1292
1293         action = icalproperty_get_action (prop);
1294
1295         switch (action) {
1296         case ICAL_ACTION_DISPLAY:
1297                 /* Ensure we have a DESCRIPTION property */
1298                 prop = icalcomponent_get_first_property (alarm, ICAL_DESCRIPTION_PROPERTY);
1299                 if (prop) {
1300                         if (priv->summary.prop) {
1301                                 icalproperty *xprop;
1302
1303                                 xprop = icalcomponent_get_first_property (alarm, ICAL_X_PROPERTY);
1304                                 while (xprop) {
1305                                         str = icalproperty_get_x_name (xprop);
1306                                         if (!strcmp (str, "X-EVOLUTION-NEEDS-DESCRIPTION")) {
1307                                                 icalproperty_set_description (prop, icalproperty_get_summary(priv->summary.prop));
1308
1309                                                 icalcomponent_remove_property (alarm, xprop);
1310                                                 icalproperty_free (xprop);
1311                                                 break;
1312                                         }
1313
1314                                         xprop = icalcomponent_get_next_property (alarm, ICAL_X_PROPERTY);
1315                                 }
1316
1317                                 break;
1318                         }
1319                 }
1320
1321                 if (!priv->summary.prop) {
1322                         str = _("Untitled appointment");
1323
1324                         /* add the X-EVOLUTION-NEEDS-DESCRIPTION property */
1325                         prop = icalproperty_new_x ("1");
1326                         icalproperty_set_x_name (prop, "X-EVOLUTION-NEEDS-DESCRIPTION");
1327                         icalcomponent_add_property (alarm, prop);
1328                 } else
1329                         str = icalproperty_get_summary (priv->summary.prop);
1330
1331                 prop = icalproperty_new_description (str);
1332                 icalcomponent_add_property (alarm, prop);
1333
1334                 break;
1335
1336         default:
1337                 break;
1338                 /* FIXME: add other action types here */
1339         }
1340 }
1341
1342 /* Ensures that alarm subcomponents have the mandatory properties they need,
1343  * even when clients may not have set them properly.
1344  */
1345 static void
1346 ensure_alarm_properties (ECalComponent *comp)
1347 {
1348         ECalComponentPrivate *priv;
1349
1350         priv = comp->priv;
1351
1352         g_hash_table_foreach (priv->alarm_uid_hash, ensure_alarm_properties_cb, comp);
1353 }
1354
1355 /**
1356  * e_cal_component_commit_sequence:
1357  * @comp: A calendar component object.
1358  *
1359  * Increments the sequence number property in a calendar component object if it
1360  * needs it.  This needs to be done when any of a number of properties listed in
1361  * RFC 2445 change values, such as the start and end dates of a component.
1362  *
1363  * This function must be called before calling e_cal_component_get_as_string() to
1364  * ensure that the component is fully consistent.
1365  **/
1366 void
1367 e_cal_component_commit_sequence (ECalComponent *comp)
1368 {
1369         ECalComponentPrivate *priv;
1370
1371         g_return_if_fail (comp != NULL);
1372         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
1373
1374         priv = comp->priv;
1375         g_return_if_fail (priv->icalcomp != NULL);
1376
1377         ensure_alarm_properties (comp);
1378
1379         if (!priv->need_sequence_inc)
1380                 return;
1381
1382         if (priv->sequence) {
1383                 int seq;
1384
1385                 seq = icalproperty_get_sequence (priv->sequence);
1386                 icalproperty_set_sequence (priv->sequence, seq + 1);
1387         } else {
1388                 /* The component had no SEQUENCE property, so assume that the
1389                  * default would have been zero.  Since it needed incrementing
1390                  * anyways, we use a value of 1 here.
1391                  */
1392                 priv->sequence = icalproperty_new_sequence (1);
1393                 icalcomponent_add_property (priv->icalcomp, priv->sequence);
1394         }
1395
1396         priv->need_sequence_inc = FALSE;
1397 }
1398
1399 /**
1400  * e_cal_component_abort_sequence:
1401  * @comp: A calendar component object.
1402  *
1403  * Aborts the sequence change needed in the given calendar component, which
1404  * means it will not require a sequence commit (via #e_cal_component_commit_sequence)
1405  * even if the changes done require a sequence increment.
1406  */
1407 void
1408 e_cal_component_abort_sequence (ECalComponent *comp)
1409 {
1410         ECalComponentPrivate *priv;
1411
1412         g_return_if_fail (comp != NULL);
1413         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
1414
1415         priv = comp->priv;
1416
1417         priv->need_sequence_inc = FALSE;
1418 }
1419
1420 /**
1421  * e_cal_component_get_id:
1422  * @comp: A calendar component object.
1423  *
1424  * Get the ID of the component as a #ECalComponentId.  The return value should
1425  * be freed with e_cal_component_free_id() when you have finished with it.
1426  *
1427  * Return value: the id of the component
1428  */
1429 ECalComponentId *
1430 e_cal_component_get_id (ECalComponent *comp)
1431 {
1432         ECalComponentPrivate *priv;
1433         ECalComponentId *id = NULL;
1434
1435         g_return_val_if_fail (comp != NULL, NULL);
1436         g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
1437
1438         priv = comp->priv;
1439         g_return_val_if_fail (priv->icalcomp != NULL, NULL);
1440         
1441         id = g_new0 (ECalComponentId, 1);
1442         id->uid = g_strdup (icalproperty_get_uid (priv->uid));
1443         id->rid = g_strdup (e_cal_component_get_recurid_as_string (comp));
1444
1445         return id;
1446
1447
1448 /**
1449  * e_cal_component_get_uid:
1450  * @comp: A calendar component object.
1451  * @uid: Return value for the UID string.
1452  *
1453  * Queries the unique identifier of a calendar component object.
1454  **/
1455 void
1456 e_cal_component_get_uid (ECalComponent *comp, const char **uid)
1457 {
1458         ECalComponentPrivate *priv;
1459
1460         g_return_if_fail (comp != NULL);
1461         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
1462         g_return_if_fail (uid != NULL);
1463
1464         priv = comp->priv;
1465         g_return_if_fail (priv->icalcomp != NULL);
1466
1467         /* This MUST exist, since we ensured that it did */
1468         g_assert (priv->uid != NULL);
1469
1470         *uid = icalproperty_get_uid (priv->uid);
1471 }
1472
1473 /**
1474  * e_cal_component_set_uid:
1475  * @comp: A calendar component object.
1476  * @uid: Unique identifier.
1477  *
1478  * Sets the unique identifier string of a calendar component object.
1479  **/
1480 void
1481 e_cal_component_set_uid (ECalComponent *comp, const char *uid)
1482 {
1483         ECalComponentPrivate *priv;
1484
1485         g_return_if_fail (comp != NULL);
1486         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
1487         g_return_if_fail (uid != NULL);
1488
1489         priv = comp->priv;
1490         g_return_if_fail (priv->icalcomp != NULL);
1491
1492         /* This MUST exist, since we ensured that it did */
1493         g_assert (priv->uid != NULL);
1494
1495         icalproperty_set_uid (priv->uid, (char *) uid);
1496 }
1497
1498 /* Gets a text list value */
1499 static void
1500 get_attachment_list (GSList *attachment_list, GSList **al)
1501 {
1502         GSList *l;
1503
1504         *al = NULL;
1505
1506         if (!attachment_list)
1507                 return;
1508
1509         for (l = attachment_list; l; l = l->next) {
1510                 struct attachment *attachment;
1511                 const char *data;
1512                 size_t buf_size;
1513                 char *buf = NULL;
1514
1515                 attachment = l->data;
1516                 g_assert (attachment->attach != NULL);
1517
1518                 if (icalattach_get_is_url (attachment->attach)) {
1519                         /* FIXME : this ref count is screwed up
1520                          * These structures are being leaked.
1521                          */   
1522                         icalattach_ref (attachment->attach);
1523                         data = icalattach_get_url (attachment->attach);
1524                         buf_size = strlen (data);
1525                         buf = g_malloc0 (buf_size+1);
1526                         icalvalue_decode_ical_string (data, buf, buf_size);     
1527                 }
1528                 else
1529                         data = NULL;
1530                 *al = g_slist_prepend (*al, (char *)buf);
1531         }
1532
1533         *al = g_slist_reverse (*al);
1534 }
1535
1536
1537 static void
1538 set_attachment_list (icalcomponent *icalcomp,
1539                    GSList **attachment_list,
1540                    GSList *al)
1541 {
1542         GSList *l;
1543
1544         /* Remove old attachments */
1545
1546         if (*attachment_list) {
1547                 for (l = *attachment_list; l; l = l->next) {
1548                         struct attachment *attachment;
1549
1550                         attachment = l->data;
1551                         g_assert (attachment->prop != NULL);
1552                         g_assert (attachment->attach != NULL);
1553
1554                         icalcomponent_remove_property (icalcomp, attachment->prop);
1555                         icalproperty_free (attachment->prop);
1556                         g_free (attachment);
1557                 }
1558
1559                 g_slist_free (*attachment_list);
1560                 *attachment_list = NULL;
1561         }
1562         /* Add in new attachments */
1563
1564         for (l = al; l; l = l->next) {
1565                 struct attachment *attachment;
1566                 size_t buf_size;
1567                 char *buf;
1568
1569                 attachment = g_new0 (struct attachment, 1);
1570                 buf_size = 2 * strlen ((char *)l->data);
1571                 buf = g_malloc0 (buf_size);
1572                 icalvalue_encode_ical_string (l->data, buf, buf_size);
1573                 attachment->attach = icalattach_new_from_url ((char *) buf);    
1574                 attachment->prop = icalproperty_new_attach (attachment->attach);
1575                 icalcomponent_add_property (icalcomp, attachment->prop);
1576                 g_free (buf);
1577                 *attachment_list = g_slist_prepend (*attachment_list, attachment);
1578         }
1579
1580         *attachment_list = g_slist_reverse (*attachment_list);
1581 }
1582
1583
1584 /**
1585  * e_cal_component_get_attachment_list: 
1586  * @comp: A calendar component object. 
1587  * @attachment_list: Return list of URLS to attachments.
1588  * 
1589  * Queries the attachment properties of the calendar component object. When done,
1590  * the @attachment_list should be freed by calling #g_slist_free.
1591  **/
1592 void
1593 e_cal_component_get_attachment_list (ECalComponent *comp, GSList **attachment_list)
1594 {
1595         ECalComponentPrivate *priv;
1596         
1597         g_return_if_fail (comp != NULL);
1598         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
1599         g_return_if_fail (attachment_list != NULL);
1600
1601         priv = comp->priv;
1602         g_return_if_fail (priv->icalcomp != NULL);
1603
1604         get_attachment_list (priv->attachment_list, attachment_list);
1605 }
1606
1607 /**
1608  * e_cal_component_set_attachment_list:
1609  * @comp: A calendar component object. 
1610  * @attachment_list: list of urls to attachment pointers.
1611  *
1612  * This currently handles only attachments that are urls
1613  * in the file system - not inline binaries.
1614  *
1615  * Sets the attachments of a calendar component object
1616  **/
1617 void
1618 e_cal_component_set_attachment_list (ECalComponent *comp, GSList *attachment_list)
1619 {
1620         ECalComponentPrivate *priv;
1621
1622         g_return_if_fail (comp != NULL);
1623         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
1624
1625         priv = comp->priv;
1626         g_return_if_fail (priv->icalcomp != NULL);
1627
1628         set_attachment_list (priv->icalcomp, &priv->attachment_list, attachment_list);
1629 }
1630
1631 /**
1632  * e_cal_component_has_attachments:
1633  * @comp: A calendar component object.
1634  *
1635  * Queries the component to see if it has attachments.
1636  *
1637  * Return value: TRUE if there are attachments, FALSE otherwise.
1638  */
1639 gboolean
1640 e_cal_component_has_attachments (ECalComponent *comp)
1641 {
1642         ECalComponentPrivate *priv;
1643
1644         g_return_val_if_fail (comp != NULL, FALSE);
1645         g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), FALSE);
1646
1647         priv = comp->priv;
1648
1649         if (g_slist_length (priv->attachment_list) > 0)
1650                 return TRUE;
1651         
1652         return FALSE;
1653 }
1654
1655 /**
1656  * e_cal_component_get_num_attachments:
1657  * @comp: A calendar component object.
1658  *
1659  * Get the number of attachments to this calendar component object.
1660  *
1661  * Return value: the number of attachments.
1662  */
1663 int 
1664 e_cal_component_get_num_attachments (ECalComponent *comp)
1665 {
1666         ECalComponentPrivate *priv;
1667
1668         g_return_val_if_fail (comp != NULL, 0);
1669         g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), 0);
1670
1671         priv = comp->priv;
1672
1673         return g_slist_length (priv->attachment_list) > 0;
1674         
1675 }
1676
1677 /**
1678  * e_cal_component_get_categories:
1679  * @comp: A calendar component object.
1680  * @categories: Return holder for the categories.
1681  *
1682  * Queries the categories of the given calendar component. The categories
1683  * are returned in the @categories argument, which, on success, will contain
1684  * a comma-separated list of all categories set in the component.
1685  **/
1686 void
1687 e_cal_component_get_categories (ECalComponent *comp, const char **categories)
1688 {
1689         ECalComponentPrivate *priv;
1690
1691         g_return_if_fail (comp != NULL);
1692         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
1693         g_return_if_fail (categories != NULL);
1694
1695         priv = comp->priv;
1696         g_return_if_fail (priv->icalcomp != NULL);
1697
1698         if (priv->categories)
1699                 *categories = icalproperty_get_categories (priv->categories);
1700         else
1701                 *categories = NULL;
1702 }
1703
1704 /**
1705  * e_cal_component_set_categories:
1706  * @comp: A calendar component object.
1707  * @categories: Comma-separated list of categories.
1708  *
1709  * Sets the list of categories for a calendar component.
1710  **/
1711 void
1712 e_cal_component_set_categories (ECalComponent *comp, const char *categories)
1713 {
1714         ECalComponentPrivate *priv;
1715
1716         g_return_if_fail (comp != NULL);
1717         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
1718
1719         priv = comp->priv;
1720         g_return_if_fail (priv->icalcomp != NULL);
1721
1722         if (!categories || !(*categories)) {
1723                 if (priv->categories) {
1724                         icalcomponent_remove_property (priv->icalcomp, priv->categories);
1725                         icalproperty_free (priv->categories);
1726                         priv->url = NULL;
1727                 }
1728
1729                 return;
1730         }
1731
1732         if (priv->categories)
1733                 icalproperty_set_categories (priv->categories, (char *) categories);
1734         else {
1735                 priv->categories = icalproperty_new_categories ((char *) categories);
1736                 icalcomponent_add_property (priv->icalcomp, priv->categories);
1737         }
1738 }
1739
1740
1741 /**
1742  * e_cal_component_get_categories_list:
1743  * @comp: A calendar component object.
1744  * @categ_list: Return value for the list of strings, where each string is a
1745  * category. This should be freed using e_cal_component_free_categories_list().
1746  *
1747  * Queries the list of categories of a calendar component object.  Each element
1748  * in the returned categ_list is a string with the corresponding category.
1749  **/
1750 void
1751 e_cal_component_get_categories_list (ECalComponent *comp, GSList **categ_list)
1752 {
1753         ECalComponentPrivate *priv;
1754         const char *categories;
1755         const char *p;
1756         const char *cat_start;
1757         char *str;
1758
1759         g_return_if_fail (comp != NULL);
1760         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
1761         g_return_if_fail (categ_list != NULL);
1762
1763         priv = comp->priv;
1764         g_return_if_fail (priv->icalcomp != NULL);
1765
1766         if (!priv->categories) {
1767                 *categ_list = NULL;
1768                 return;
1769         }
1770
1771         categories = icalproperty_get_categories (priv->categories);
1772         g_assert (categories != NULL);
1773
1774         cat_start = categories;
1775         *categ_list = NULL;
1776
1777         for (p = categories; *p; p++)
1778                 if (*p == ',') {
1779                         str = g_strndup (cat_start, p - cat_start);
1780                         *categ_list = g_slist_prepend (*categ_list, str);
1781
1782                         cat_start = p + 1;
1783                 }
1784
1785         str = g_strndup (cat_start, p - cat_start);
1786         *categ_list = g_slist_prepend (*categ_list, str);
1787
1788         *categ_list = g_slist_reverse (*categ_list);
1789 }
1790
1791 /* Creates a comma-delimited string of categories */
1792 static char *
1793 stringify_categories (GSList *categ_list)
1794 {
1795         GString *s;
1796         GSList *l;
1797         char *str;
1798
1799         s = g_string_new (NULL);
1800
1801         for (l = categ_list; l; l = l->next) {
1802                 g_string_append (s, l->data);
1803
1804                 if (l->next != NULL)
1805                         g_string_append (s, ",");
1806         }
1807
1808         str = s->str;
1809         g_string_free (s, FALSE);
1810
1811         return str;
1812 }
1813
1814 /**
1815  * e_cal_component_set_categories_list:
1816  * @comp: A calendar component object.
1817  * @categ_list: List of strings, one for each category.
1818  *
1819  * Sets the list of categories of a calendar component object.
1820  **/
1821 void
1822 e_cal_component_set_categories_list (ECalComponent *comp, GSList *categ_list)
1823 {
1824         ECalComponentPrivate *priv;
1825         char *categories_str;
1826
1827         g_return_if_fail (comp != NULL);
1828         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
1829
1830         priv = comp->priv;
1831         g_return_if_fail (priv->icalcomp != NULL);
1832
1833         if (!categ_list) {
1834                 if (priv->categories) {
1835                         icalcomponent_remove_property (priv->icalcomp, priv->categories);
1836                         icalproperty_free (priv->categories);
1837                 }
1838
1839                 return;
1840         }
1841
1842         /* Create a single string of categories */
1843         categories_str = stringify_categories (categ_list);
1844
1845         /* Set the categories */
1846         priv->categories = icalproperty_new_categories (categories_str);
1847         g_free (categories_str);
1848
1849         icalcomponent_add_property (priv->icalcomp, priv->categories);
1850 }
1851
1852 /**
1853  * e_cal_component_get_classification:
1854  * @comp: A calendar component object.
1855  * @classif: Return value for the classification.
1856  *
1857  * Queries the classification of a calendar component object.  If the
1858  * classification property is not set on this component, this function returns
1859  * #E_CAL_COMPONENT_CLASS_NONE.
1860  **/
1861 void
1862 e_cal_component_get_classification (ECalComponent *comp, ECalComponentClassification *classif)
1863 {
1864         ECalComponentPrivate *priv;
1865         icalproperty_class class;
1866
1867         g_return_if_fail (comp != NULL);
1868         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
1869         g_return_if_fail (classif != NULL);
1870
1871         priv = comp->priv;
1872         g_return_if_fail (priv->icalcomp != NULL);
1873
1874         if (!priv->classification) {
1875                 *classif = E_CAL_COMPONENT_CLASS_NONE;
1876                 return;
1877         }
1878
1879         class = icalproperty_get_class (priv->classification);
1880
1881         switch (class)
1882         {
1883         case ICAL_CLASS_PUBLIC:
1884           *classif = E_CAL_COMPONENT_CLASS_PUBLIC;
1885           break;
1886         case ICAL_CLASS_PRIVATE:
1887           *classif = E_CAL_COMPONENT_CLASS_PRIVATE;
1888           break;
1889         case ICAL_CLASS_CONFIDENTIAL:
1890           *classif = E_CAL_COMPONENT_CLASS_CONFIDENTIAL;
1891           break;
1892         default:
1893           *classif = E_CAL_COMPONENT_CLASS_UNKNOWN;
1894           break;
1895         }
1896 }
1897
1898 /**
1899  * e_cal_component_set_classification:
1900  * @comp: A calendar component object.
1901  * @classif: Classification to use.
1902  *
1903  * Sets the classification property of a calendar component object.  To unset
1904  * the property, specify E_CAL_COMPONENT_CLASS_NONE for @classif.
1905  **/
1906 void
1907 e_cal_component_set_classification (ECalComponent *comp, ECalComponentClassification classif)
1908 {
1909         ECalComponentPrivate *priv;
1910         icalproperty_class class;
1911
1912         g_return_if_fail (comp != NULL);
1913         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
1914         g_return_if_fail (classif != E_CAL_COMPONENT_CLASS_UNKNOWN);
1915
1916         priv = comp->priv;
1917         g_return_if_fail (priv->icalcomp != NULL);
1918
1919         if (classif == E_CAL_COMPONENT_CLASS_NONE) {
1920                 if (priv->classification) {
1921                         icalcomponent_remove_property (priv->icalcomp, priv->classification);
1922                         icalproperty_free (priv->classification);
1923                         priv->classification = NULL;
1924                 }
1925
1926                 return;
1927         }
1928
1929         switch (classif) {
1930         case E_CAL_COMPONENT_CLASS_PUBLIC:
1931           class = ICAL_CLASS_PUBLIC;
1932                 break;
1933
1934         case E_CAL_COMPONENT_CLASS_PRIVATE:
1935           class = ICAL_CLASS_PRIVATE;
1936                 break;
1937
1938         case E_CAL_COMPONENT_CLASS_CONFIDENTIAL:
1939           class = ICAL_CLASS_CONFIDENTIAL;
1940                 break;
1941
1942         default:
1943                 g_assert_not_reached ();
1944                 class = ICAL_CLASS_NONE;
1945         }
1946
1947         if (priv->classification)
1948                 icalproperty_set_class (priv->classification, class);
1949         else {
1950                 priv->classification = icalproperty_new_class (class);
1951                 icalcomponent_add_property (priv->icalcomp, priv->classification);
1952         }
1953 }
1954
1955 /* Gets a text list value */
1956 static void
1957 get_text_list (GSList *text_list,
1958                const char *(* get_prop_func) (const icalproperty *prop),
1959                GSList **tl)
1960 {
1961         GSList *l;
1962
1963         *tl = NULL;
1964
1965         if (!text_list)
1966                 return;
1967
1968         for (l = text_list; l; l = l->next) {
1969                 struct text *text;
1970                 ECalComponentText *t;
1971
1972                 text = l->data;
1973                 g_assert (text->prop != NULL);
1974
1975                 t = g_new (ECalComponentText, 1);
1976                 t->value = (* get_prop_func) (text->prop);
1977
1978                 if (text->altrep_param)
1979                         t->altrep = icalparameter_get_altrep (text->altrep_param);
1980                 else
1981                         t->altrep = NULL;
1982
1983                 *tl = g_slist_prepend (*tl, t);
1984         }
1985
1986         *tl = g_slist_reverse (*tl);
1987 }
1988
1989 /* Sets a text list value */
1990 static void
1991 set_text_list (ECalComponent *comp,
1992                icalproperty *(* new_prop_func) (const char *value),
1993                GSList **text_list,
1994                GSList *tl)
1995 {
1996         ECalComponentPrivate *priv;
1997         GSList *l;
1998
1999         priv = comp->priv;
2000
2001         /* Remove old texts */
2002
2003         for (l = *text_list; l; l = l->next) {
2004                 struct text *text;
2005
2006                 text = l->data;
2007                 g_assert (text->prop != NULL);
2008
2009                 icalcomponent_remove_property (priv->icalcomp, text->prop);
2010                 icalproperty_free (text->prop);
2011                 g_free (text);
2012         }
2013
2014         g_slist_free (*text_list);
2015         *text_list = NULL;
2016
2017         /* Add in new texts */
2018
2019         for (l = tl; l; l = l->next) {
2020                 ECalComponentText *t;
2021                 struct text *text;
2022
2023                 t = l->data;
2024                 g_return_if_fail (t->value != NULL);
2025
2026                 text = g_new (struct text, 1);
2027
2028                 text->prop = (* new_prop_func) ((char *) t->value);
2029                 icalcomponent_add_property (priv->icalcomp, text->prop);
2030
2031                 if (t->altrep) {
2032                         text->altrep_param = icalparameter_new_altrep ((char *) t->altrep);
2033                         icalproperty_add_parameter (text->prop, text->altrep_param);
2034                 } else
2035                         text->altrep_param = NULL;
2036
2037                 *text_list = g_slist_prepend (*text_list, text);
2038         }
2039
2040         *text_list = g_slist_reverse (*text_list);
2041 }
2042
2043 /**
2044  * e_cal_component_get_comment_list:
2045  * @comp: A calendar component object.
2046  * @text_list: Return value for the comment properties and their parameters, as
2047  * a list of #ECalComponentText structures.  This should be freed using the
2048  * e_cal_component_free_text_list() function.
2049  *
2050  * Queries the comments of a calendar component object.  The comment property can
2051  * appear several times inside a calendar component, and so a list of
2052  * #ECalComponentText is returned.
2053  **/
2054 void
2055 e_cal_component_get_comment_list (ECalComponent *comp, GSList **text_list)
2056 {
2057         ECalComponentPrivate *priv;
2058
2059         g_return_if_fail (comp != NULL);
2060         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
2061         g_return_if_fail (text_list != NULL);
2062
2063         priv = comp->priv;
2064         g_return_if_fail (priv->icalcomp != NULL);
2065
2066         get_text_list (priv->comment_list, icalproperty_get_comment, text_list);
2067 }
2068
2069 /**
2070  * e_cal_component_set_comment_list:
2071  * @comp: A calendar component object.
2072  * @text_list: List of #ECalComponentText structures.
2073  *
2074  * Sets the comments of a calendar component object.  The comment property can
2075  * appear several times inside a calendar component, and so a list of
2076  * #ECalComponentText structures is used.
2077  **/
2078 void
2079 e_cal_component_set_comment_list (ECalComponent *comp, GSList *text_list)
2080 {
2081         ECalComponentPrivate *priv;
2082
2083         g_return_if_fail (comp != NULL);
2084         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
2085
2086         priv = comp->priv;
2087         g_return_if_fail (priv->icalcomp != NULL);
2088
2089         set_text_list (comp, icalproperty_new_comment, &priv->comment_list, text_list);
2090 }
2091
2092 /**
2093  * e_cal_component_get_contact_list:
2094  * @comp: A calendar component object.
2095  * @text_list: Return value for the contact properties and their parameters, as
2096  * a list of #ECalComponentText structures.  This should be freed using the
2097  * e_cal_component_free_text_list() function.
2098  *
2099  * Queries the contact of a calendar component object.  The contact property can
2100  * appear several times inside a calendar component, and so a list of
2101  * #ECalComponentText is returned.
2102  **/
2103 void
2104 e_cal_component_get_contact_list (ECalComponent *comp, GSList **text_list)
2105 {
2106         ECalComponentPrivate *priv;
2107
2108         g_return_if_fail (comp != NULL);
2109         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
2110         g_return_if_fail (text_list != NULL);
2111
2112         priv = comp->priv;
2113         g_return_if_fail (priv->icalcomp != NULL);
2114
2115         get_text_list (priv->contact_list, icalproperty_get_contact, text_list);
2116 }
2117
2118 /**
2119  * e_cal_component_set_contact_list:
2120  * @comp: A calendar component object.
2121  * @text_list: List of #ECalComponentText structures.
2122  *
2123  * Sets the contact of a calendar component object.  The contact property can
2124  * appear several times inside a calendar component, and so a list of
2125  * #ECalComponentText structures is used.
2126  **/
2127 void
2128 e_cal_component_set_contact_list (ECalComponent *comp, GSList *text_list)
2129 {
2130         ECalComponentPrivate *priv;
2131
2132         g_return_if_fail (comp != NULL);
2133         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
2134
2135         priv = comp->priv;
2136         g_return_if_fail (priv->icalcomp != NULL);
2137
2138         set_text_list (comp, icalproperty_new_contact, &priv->contact_list, text_list);
2139 }
2140
2141 /* Gets a struct icaltimetype value */
2142 static void
2143 get_icaltimetype (icalproperty *prop,
2144                   struct icaltimetype (* get_prop_func) (const icalproperty *prop),
2145                   struct icaltimetype **t)
2146 {
2147         if (!prop) {
2148                 *t = NULL;
2149                 return;
2150         }
2151
2152         *t = g_new (struct icaltimetype, 1);
2153         **t = (* get_prop_func) (prop);
2154 }
2155
2156 /* Sets a struct icaltimetype value */
2157 static void
2158 set_icaltimetype (ECalComponent *comp, icalproperty **prop,
2159                   icalproperty *(* prop_new_func) (struct icaltimetype v),
2160                   void (* prop_set_func) (icalproperty *prop, struct icaltimetype v),
2161                   struct icaltimetype *t)
2162 {
2163         ECalComponentPrivate *priv;
2164
2165         priv = comp->priv;
2166
2167         if (!t) {
2168                 if (*prop) {
2169                         icalcomponent_remove_property (priv->icalcomp, *prop);
2170                         icalproperty_free (*prop);
2171                         *prop = NULL;
2172                 }
2173
2174                 return;
2175         }
2176
2177         if (*prop)
2178                 (* prop_set_func) (*prop, *t);
2179         else {
2180                 *prop = (* prop_new_func) (*t);
2181                 icalcomponent_add_property (priv->icalcomp, *prop);
2182         }
2183 }
2184
2185 /**
2186  * e_cal_component_get_completed:
2187  * @comp: A calendar component object.
2188  * @t: Return value for the completion date.  This should be freed using the
2189  * e_cal_component_free_icaltimetype() function.
2190  *
2191  * Queries the date at which a calendar compoment object was completed.
2192  **/
2193 void
2194 e_cal_component_get_completed (ECalComponent *comp, struct icaltimetype **t)
2195 {
2196         ECalComponentPrivate *priv;
2197
2198         g_return_if_fail (comp != NULL);
2199         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
2200         g_return_if_fail (t != NULL);
2201
2202         priv = comp->priv;
2203         g_return_if_fail (priv->icalcomp != NULL);
2204
2205         get_icaltimetype (priv->completed, icalproperty_get_completed, t);
2206 }
2207
2208 /**
2209  * e_cal_component_set_completed:
2210  * @comp: A calendar component object.
2211  * @t: Value for the completion date.
2212  *
2213  * Sets the date at which a calendar component object was completed.
2214  **/
2215 void
2216 e_cal_component_set_completed (ECalComponent *comp, struct icaltimetype *t)
2217 {
2218         ECalComponentPrivate *priv;
2219
2220         g_return_if_fail (comp != NULL);
2221         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
2222
2223         priv = comp->priv;
2224         g_return_if_fail (priv->icalcomp != NULL);
2225
2226         set_icaltimetype (comp, &priv->completed,
2227                           icalproperty_new_completed,
2228                           icalproperty_set_completed,
2229                           t);
2230 }
2231
2232
2233 /**
2234  * e_cal_component_get_created:
2235  * @comp: A calendar component object.
2236  * @t: Return value for the creation date.  This should be freed using the
2237  * e_cal_component_free_icaltimetype() function.
2238  *
2239  * Queries the date in which a calendar component object was created in the
2240  * calendar store.
2241  **/
2242 void
2243 e_cal_component_get_created (ECalComponent *comp, struct icaltimetype **t)
2244 {
2245         ECalComponentPrivate *priv;
2246
2247         g_return_if_fail (comp != NULL);
2248         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
2249         g_return_if_fail (t != NULL);
2250
2251         priv = comp->priv;
2252         g_return_if_fail (priv->icalcomp != NULL);
2253
2254         get_icaltimetype (priv->created, icalproperty_get_created, t);
2255 }
2256
2257 /**
2258  * e_cal_component_set_created:
2259  * @comp: A calendar component object.
2260  * @t: Value for the creation date.
2261  *
2262  * Sets the date in which a calendar component object is created in the calendar
2263  * store.  This should only be used inside a calendar store application, i.e.
2264  * not by calendar user agents.
2265  **/
2266 void
2267 e_cal_component_set_created (ECalComponent *comp, struct icaltimetype *t)
2268 {
2269         ECalComponentPrivate *priv;
2270
2271         g_return_if_fail (comp != NULL);
2272         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
2273
2274         priv = comp->priv;
2275         g_return_if_fail (priv->icalcomp != NULL);
2276
2277         set_icaltimetype (comp, &priv->created,
2278                           icalproperty_new_created,
2279                           icalproperty_set_created,
2280                           t);
2281 }
2282
2283 /**
2284  * e_cal_component_get_description_list:
2285  * @comp: A calendar component object.
2286  * @text_list: Return value for the description properties and their parameters,
2287  * as a list of #ECalComponentText structures.  This should be freed using the
2288  * e_cal_component_free_text_list() function.
2289  *
2290  * Queries the description of a calendar component object.  Journal components
2291  * may have more than one description, and as such this function returns a list
2292  * of #ECalComponentText structures.  All other types of components can have at
2293  * most one description.
2294  **/
2295 void
2296 e_cal_component_get_description_list (ECalComponent *comp, GSList **text_list)
2297 {
2298         ECalComponentPrivate *priv;
2299
2300         g_return_if_fail (comp != NULL);
2301         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
2302         g_return_if_fail (text_list != NULL);
2303
2304         priv = comp->priv;
2305         g_return_if_fail (priv->icalcomp != NULL);
2306
2307         get_text_list (priv->description_list, icalproperty_get_description, text_list);
2308 }
2309
2310 /**
2311  * e_cal_component_set_description_list:
2312  * @comp: A calendar component object.
2313  * @text_list: List of #ECalComponentSummary structures.
2314  *
2315  * Sets the description of a calendar component object.  Journal components may
2316  * have more than one description, and as such this function takes in a list of
2317  * #ECalComponentDescription structures.  All other types of components can have
2318  * at most one description.
2319  **/
2320 void
2321 e_cal_component_set_description_list (ECalComponent *comp, GSList *text_list)
2322 {
2323         ECalComponentPrivate *priv;
2324
2325         g_return_if_fail (comp != NULL);
2326         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
2327
2328         priv = comp->priv;
2329         g_return_if_fail (priv->icalcomp != NULL);
2330
2331         set_text_list (comp, icalproperty_new_description, &priv->description_list, text_list);
2332 }
2333
2334 /* Gets a date/time and timezone pair */
2335 static void
2336 get_datetime (struct datetime *datetime,
2337               struct icaltimetype (* get_prop_func) (const icalproperty *prop),
2338               ECalComponentDateTime *dt)
2339 {
2340         if (datetime->prop) {
2341                 dt->value = g_new (struct icaltimetype, 1);
2342                 *dt->value = (* get_prop_func) (datetime->prop);
2343         } else
2344                 dt->value = NULL;
2345
2346         /* If the icaltimetype has is_utc set, we set "UTC" as the TZID.
2347            This makes the timezone code simpler. */
2348         if (datetime->tzid_param)
2349                 dt->tzid = g_strdup (icalparameter_get_tzid (datetime->tzid_param));
2350         else if (dt->value && dt->value->is_utc)
2351                 dt->tzid = g_strdup ("UTC");
2352         else
2353                 dt->tzid = NULL;
2354 }
2355
2356 /* Sets a date/time and timezone pair */
2357 static void
2358 set_datetime (ECalComponent *comp, struct datetime *datetime,
2359               icalproperty *(* prop_new_func) (struct icaltimetype v),
2360               void (* prop_set_func) (icalproperty * prop, struct icaltimetype v),
2361               ECalComponentDateTime *dt)
2362 {
2363         ECalComponentPrivate *priv;
2364
2365         priv = comp->priv;
2366
2367         /* If we are setting the property to NULL (i.e. removing it), then
2368            we remove it if it exists. */
2369         if (!dt) {
2370                 if (datetime->prop) {
2371                         icalcomponent_remove_property (priv->icalcomp, datetime->prop);
2372                         icalproperty_free (datetime->prop);
2373
2374                         datetime->prop = NULL;
2375                         datetime->tzid_param = NULL;
2376                 }
2377
2378                 return;
2379         }
2380
2381         g_return_if_fail (dt->value != NULL);
2382
2383         /* If the TZID is set to "UTC", we set the is_utc flag. */
2384         if (dt->tzid && !strcmp (dt->tzid, "UTC"))
2385                 dt->value->is_utc = 1;
2386         else
2387                 dt->value->is_utc = 0;
2388
2389         if (datetime->prop) {
2390                 (* prop_set_func) (datetime->prop, *dt->value);
2391         } else {
2392                 datetime->prop = (* prop_new_func) (*dt->value);
2393                 icalcomponent_add_property (priv->icalcomp, datetime->prop);
2394         }
2395
2396         /* If the TZID is set to "UTC", we don't want to save the TZID. */
2397         if (dt->tzid && strcmp (dt->tzid, "UTC")) {
2398                 g_assert (datetime->prop != NULL);
2399
2400                 if (datetime->tzid_param) {
2401                         icalparameter_set_tzid (datetime->tzid_param, (char *) dt->tzid);
2402                 } else {
2403                         datetime->tzid_param = icalparameter_new_tzid ((char *) dt->tzid);
2404                         icalproperty_add_parameter (datetime->prop, datetime->tzid_param);
2405                 }
2406         } else if (datetime->tzid_param) {
2407                 icalproperty_remove_parameter (datetime->prop, ICAL_TZID_PARAMETER);
2408                 datetime->tzid_param = NULL;
2409         }
2410 }
2411
2412
2413 /* This tries to get the DTSTART + DURATION for a VEVENT or VTODO. In a
2414    VEVENT this is used for the DTEND if no DTEND exists, In a VTOTO it is
2415    used for the DUE date if DUE doesn't exist. */
2416 static void
2417 e_cal_component_get_start_plus_duration (ECalComponent *comp,
2418                                          ECalComponentDateTime *dt)
2419 {
2420         ECalComponentPrivate *priv;
2421         struct icaldurationtype duration;
2422
2423         priv = comp->priv;
2424
2425         if (!priv->duration)
2426                 return;
2427
2428         /* Get the DTSTART time. */
2429         get_datetime (&priv->dtstart, icalproperty_get_dtstart, dt);
2430         if (!dt->value)
2431                 return;
2432
2433         duration = icalproperty_get_duration (priv->duration);
2434
2435         /* The DURATION shouldn't be negative, but just return DTSTART if it
2436            is, i.e. assume it is 0. */
2437         if (duration.is_neg)
2438                 return;
2439
2440         /* If DTSTART is a DATE value, then we need to check if the DURATION
2441            includes any hours, minutes or seconds. If it does, we need to
2442            make the DTEND/DUE a DATE-TIME value. */
2443         duration.days += duration.weeks * 7;
2444         if (dt->value->is_date) {
2445                 if (duration.hours != 0 || duration.minutes != 0
2446                     || duration.seconds != 0) {
2447                         dt->value->is_date = 0;
2448                 }
2449         }
2450
2451         /* Add on the DURATION. */
2452         icaltime_adjust (dt->value, duration.days, duration.hours,
2453                          duration.minutes, duration.seconds);
2454 }
2455
2456
2457 /**
2458  * e_cal_component_get_dtend:
2459  * @comp: A calendar component object.
2460  * @dt: Return value for the date/time end.  This should be freed with the
2461  * e_cal_component_free_datetime() function.
2462  *
2463  * Queries the date/time end of a calendar component object.
2464  **/
2465 void
2466 e_cal_component_get_dtend (ECalComponent *comp, ECalComponentDateTime *dt)
2467 {
2468         ECalComponentPrivate *priv;
2469
2470         g_return_if_fail (dt != NULL);
2471
2472         dt->tzid = NULL;
2473         dt->value = NULL;
2474         
2475         g_return_if_fail (comp != NULL);
2476         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
2477
2478         priv = comp->priv;
2479         g_return_if_fail (priv->icalcomp != NULL);
2480
2481         get_datetime (&priv->dtend, icalproperty_get_dtend, dt);
2482
2483         /* If we don't have a DTEND property, then we try to get DTSTART
2484            + DURATION. */
2485         if (!dt->value)
2486                 e_cal_component_get_start_plus_duration (comp, dt);
2487 }
2488
2489 /**
2490  * e_cal_component_set_dtend:
2491  * @comp: A calendar component object.
2492  * @dt: End date/time.
2493  *
2494  * Sets the date/time end property of a calendar component object.
2495  **/
2496 void
2497 e_cal_component_set_dtend (ECalComponent *comp, ECalComponentDateTime *dt)
2498 {
2499         ECalComponentPrivate *priv;
2500
2501         g_return_if_fail (comp != NULL);
2502         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
2503
2504         priv = comp->priv;
2505         g_return_if_fail (priv->icalcomp != NULL);
2506
2507         set_datetime (comp, &priv->dtend,
2508                       icalproperty_new_dtend,
2509                       icalproperty_set_dtend,
2510                       dt);
2511
2512         /* Make sure we remove any existing DURATION property, as it can't be
2513            used with a DTEND. If DTEND is set to NULL, i.e. removed, we also
2514            want to remove any DURATION. */
2515         if (priv->duration) {
2516                 icalcomponent_remove_property (priv->icalcomp, priv->duration);
2517                 icalproperty_free (priv->duration);
2518                 priv->duration = NULL;
2519         }
2520
2521         priv->need_sequence_inc = TRUE;
2522 }
2523
2524 /**
2525  * e_cal_component_get_dtstamp:
2526  * @comp: A calendar component object.
2527  * @t: A value for the date/timestamp.
2528  *
2529  * Queries the date/timestamp property of a calendar component object, which is
2530  * the last time at which the object was modified by a calendar user agent.
2531  **/
2532 void
2533 e_cal_component_get_dtstamp (ECalComponent *comp, struct icaltimetype *t)
2534 {
2535         ECalComponentPrivate *priv;
2536
2537         g_return_if_fail (comp != NULL);
2538         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
2539         g_return_if_fail (t != NULL);
2540
2541         priv = comp->priv;
2542         g_return_if_fail (priv->icalcomp != NULL);
2543
2544         /* This MUST exist, since we ensured that it did */
2545         g_assert (priv->dtstamp != NULL);
2546
2547         *t = icalproperty_get_dtstamp (priv->dtstamp);
2548 }
2549
2550 /**
2551  * e_cal_component_set_dtstamp:
2552  * @comp: A calendar component object.
2553  * @t: Date/timestamp value.
2554  *
2555  * Sets the date/timestamp of a calendar component object.  This should be
2556  * called whenever a calendar user agent makes a change to a component's
2557  * properties.
2558  **/
2559 void
2560 e_cal_component_set_dtstamp (ECalComponent *comp, struct icaltimetype *t)
2561 {
2562         ECalComponentPrivate *priv;
2563
2564         g_return_if_fail (comp != NULL);
2565         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
2566         g_return_if_fail (t != NULL);
2567
2568         priv = comp->priv;
2569         g_return_if_fail (priv->icalcomp != NULL);
2570
2571         /* This MUST exist, since we ensured that it did */
2572         g_assert (priv->dtstamp != NULL);
2573
2574         icalproperty_set_dtstamp (priv->dtstamp, *t);
2575 }
2576
2577 /**
2578  * e_cal_component_get_dtstart:
2579  * @comp: A calendar component object.
2580  * @dt: Return value for the date/time start.  This should be freed with the
2581  * e_cal_component_free_datetime() function.
2582  *
2583  * Queries the date/time start of a calendar component object.
2584  **/
2585 void
2586 e_cal_component_get_dtstart (ECalComponent *comp, ECalComponentDateTime *dt)
2587 {
2588         ECalComponentPrivate *priv;
2589
2590         g_return_if_fail (dt != NULL);
2591
2592         dt->tzid = NULL;
2593         dt->value = NULL;
2594         
2595         g_return_if_fail (comp != NULL);
2596         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
2597
2598         priv = comp->priv;
2599         g_return_if_fail (priv->icalcomp != NULL);
2600
2601         get_datetime (&priv->dtstart, icalproperty_get_dtstart, dt);
2602 }
2603
2604 /**
2605  * e_cal_component_set_dtstart:
2606  * @comp: A calendar component object.
2607  * @dt: Start date/time.
2608  *
2609  * Sets the date/time start property of a calendar component object.
2610  **/
2611 void
2612 e_cal_component_set_dtstart (ECalComponent *comp, ECalComponentDateTime *dt)
2613 {
2614         ECalComponentPrivate *priv;
2615
2616         g_return_if_fail (comp != NULL);
2617         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
2618
2619         priv = comp->priv;
2620         g_return_if_fail (priv->icalcomp != NULL);
2621
2622         set_datetime (comp, &priv->dtstart,
2623                       icalproperty_new_dtstart,
2624                       icalproperty_set_dtstart,
2625                       dt);
2626
2627         priv->need_sequence_inc = TRUE;
2628 }
2629
2630 /**
2631  * e_cal_component_get_due:
2632  * @comp: A calendar component object.
2633  * @dt: Return value for the due date/time.  This should be freed with the
2634  * e_cal_component_free_datetime() function.
2635  *
2636  * Queries the due date/time of a calendar component object.
2637  **/
2638 void
2639 e_cal_component_get_due (ECalComponent *comp, ECalComponentDateTime *dt)
2640 {
2641         ECalComponentPrivate *priv;
2642
2643         g_return_if_fail (dt != NULL);
2644
2645         dt->tzid = NULL;
2646         dt->value = NULL;
2647         
2648         g_return_if_fail (comp != NULL);
2649         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
2650
2651         priv = comp->priv;
2652         g_return_if_fail (priv->icalcomp != NULL);
2653
2654         get_datetime (&priv->due, icalproperty_get_due, dt);
2655
2656         /* If we don't have a DTEND property, then we try to get DTSTART
2657            + DURATION. */
2658         if (!dt->value)
2659                 e_cal_component_get_start_plus_duration (comp, dt);
2660 }
2661
2662 /**
2663  * e_cal_component_set_due:
2664  * @comp: A calendar component object.
2665  * @dt: End date/time.
2666  *
2667  * Sets the due date/time property of a calendar component object.
2668  **/
2669 void
2670 e_cal_component_set_due (ECalComponent *comp, ECalComponentDateTime *dt)
2671 {
2672         ECalComponentPrivate *priv;
2673
2674         g_return_if_fail (comp != NULL);
2675         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
2676
2677         priv = comp->priv;
2678         g_return_if_fail (priv->icalcomp != NULL);
2679
2680         set_datetime (comp, &priv->due,
2681                       icalproperty_new_due,
2682                       icalproperty_set_due,
2683                       dt);
2684
2685         /* Make sure we remove any existing DURATION property, as it can't be
2686            used with a DTEND. If DTEND is set to NULL, i.e. removed, we also
2687            want to remove any DURATION. */
2688         if (priv->duration) {
2689                 icalcomponent_remove_property (priv->icalcomp, priv->duration);
2690                 icalproperty_free (priv->duration);
2691                 priv->duration = NULL;
2692         }
2693
2694         priv->need_sequence_inc = TRUE;
2695 }
2696
2697 /* Builds a list of ECalComponentPeriod structures based on a list of icalproperties */
2698 static void
2699 get_period_list (GSList *period_list,
2700                  struct icaldatetimeperiodtype (* get_prop_func) (const icalproperty *prop),
2701                  GSList **list)
2702 {
2703         GSList *l;
2704
2705         *list = NULL;
2706
2707         if (!period_list)
2708                 return;
2709
2710         for (l = period_list; l; l = l->next) {
2711                 struct period *period;
2712                 ECalComponentPeriod *p;
2713                 struct icaldatetimeperiodtype ip;
2714
2715                 period = l->data;
2716                 g_assert (period->prop != NULL);
2717
2718                 p = g_new (ECalComponentPeriod, 1);
2719
2720                 /* Get value parameter */
2721
2722                 if (period->value_param) {
2723                         icalparameter_value value_type;
2724
2725                         value_type = icalparameter_get_value (period->value_param);
2726
2727                         if (value_type == ICAL_VALUE_DATE || value_type == ICAL_VALUE_DATETIME)
2728                                 p->type = E_CAL_COMPONENT_PERIOD_DATETIME;
2729                         else if (value_type == ICAL_VALUE_DURATION)
2730                                 p->type = E_CAL_COMPONENT_PERIOD_DURATION;
2731                         else {
2732                                 g_message ("get_period_list(): Unknown value for period %d; "
2733                                            "using DATETIME", value_type);
2734                                 p->type = E_CAL_COMPONENT_PERIOD_DATETIME;
2735                         }
2736                 } else
2737                         p->type = E_CAL_COMPONENT_PERIOD_DATETIME;
2738
2739                 /* Get start and end/duration */
2740
2741                 ip = (* get_prop_func) (period->prop);
2742
2743                 p->start = ip.period.start;
2744
2745                 if (p->type == E_CAL_COMPONENT_PERIOD_DATETIME)
2746                         p->u.end = ip.period.end;
2747                 else if (p->type == E_CAL_COMPONENT_PERIOD_DURATION)
2748                         p->u.duration = ip.period.duration;
2749                 else
2750                         g_assert_not_reached ();
2751
2752                 /* Put in list */
2753
2754                 *list = g_slist_prepend (*list, p);
2755         }
2756
2757         *list = g_slist_reverse (*list);
2758 }
2759
2760 /* Sets a period list value */
2761 static void
2762 set_period_list (ECalComponent *comp,
2763                  icalproperty *(* new_prop_func) (struct icaldatetimeperiodtype period),
2764                  GSList **period_list,
2765                  GSList *pl)
2766 {
2767         ECalComponentPrivate *priv;
2768         GSList *l;
2769
2770         priv = comp->priv;
2771
2772         /* Remove old periods */
2773
2774         for (l = *period_list; l; l = l->next) {
2775                 struct period *period;
2776
2777                 period = l->data;
2778                 g_assert (period->prop != NULL);
2779
2780                 icalcomponent_remove_property (priv->icalcomp, period->prop);
2781                 icalproperty_free (period->prop);
2782                 g_free (period);
2783         }
2784
2785         g_slist_free (*period_list);
2786         *period_list = NULL;
2787
2788         /* Add in new periods */
2789
2790         for (l = pl; l; l = l->next) {
2791                 ECalComponentPeriod *p;
2792                 struct period *period;
2793                 struct icaldatetimeperiodtype ip = {};
2794                 icalparameter_value value_type;
2795
2796                 g_assert (l->data != NULL);
2797                 p = l->data;
2798
2799                 /* Create libical value */
2800
2801                 ip.period.start = p->start;
2802
2803                 if (p->type == E_CAL_COMPONENT_PERIOD_DATETIME) {
2804                         value_type = ICAL_VALUE_DATETIME;
2805                         ip.period.end = p->u.end;
2806                 } else if (p->type == E_CAL_COMPONENT_PERIOD_DURATION) {
2807                         value_type = ICAL_VALUE_DURATION;
2808                         ip.period.duration = p->u.duration;
2809                 } else {
2810                         g_assert_not_reached ();
2811                         return;
2812                 }
2813
2814                 /* Create property */
2815
2816                 period = g_new (struct period, 1);
2817
2818                 period->prop = (* new_prop_func) (ip);
2819                 period->value_param = icalparameter_new_value (value_type);
2820                 icalproperty_add_parameter (period->prop, period->value_param);
2821
2822                 /* Add to list */
2823
2824                 *period_list = g_slist_prepend (*period_list, period);
2825         }
2826
2827         *period_list = g_slist_reverse (*period_list);
2828 }
2829
2830 /**
2831  * e_cal_component_get_exdate_list:
2832  * @comp: A calendar component object.
2833  * @exdate_list: Return value for the list of exception dates, as a list of
2834  * #ECalComponentDateTime structures.  This should be freed using the
2835  * e_cal_component_free_exdate_list() function.
2836  *
2837  * Queries the list of exception date properties in a calendar component object.
2838  **/
2839 void
2840 e_cal_component_get_exdate_list (ECalComponent *comp, GSList **exdate_list)
2841 {
2842         ECalComponentPrivate *priv;
2843         GSList *l;
2844
2845         g_return_if_fail (comp != NULL);
2846         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
2847         g_return_if_fail (exdate_list != NULL);
2848
2849         priv = comp->priv;
2850         g_return_if_fail (priv->icalcomp != NULL);
2851
2852         *exdate_list = NULL;
2853
2854         for (l = priv->exdate_list; l; l = l->next) {
2855                 struct datetime *dt;
2856                 ECalComponentDateTime *cdt;
2857
2858                 dt = l->data;
2859
2860                 cdt = g_new (ECalComponentDateTime, 1);
2861                 cdt->value = g_new (struct icaltimetype, 1);
2862
2863                 *cdt->value = icalproperty_get_exdate (dt->prop);
2864
2865                 if (dt->tzid_param)
2866                         cdt->tzid = g_strdup (icalparameter_get_tzid (dt->tzid_param));
2867                 else
2868                         cdt->tzid = NULL;
2869
2870                 *exdate_list = g_slist_prepend (*exdate_list, cdt);
2871         }
2872
2873         *exdate_list = g_slist_reverse (*exdate_list);
2874 }
2875
2876 /**
2877  * e_cal_component_set_exdate_list:
2878  * @comp: A calendar component object.
2879  * @exdate_list: List of #ECalComponentDateTime structures.
2880  *
2881  * Sets the list of exception dates in a calendar component object.
2882  **/
2883 void
2884 e_cal_component_set_exdate_list (ECalComponent *comp, GSList *exdate_list)
2885 {
2886         ECalComponentPrivate *priv;
2887         GSList *l;
2888
2889         g_return_if_fail (comp != NULL);
2890         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
2891
2892         priv = comp->priv;
2893         g_return_if_fail (priv->icalcomp != NULL);
2894
2895         /* Remove old exception dates */
2896
2897         for (l = priv->exdate_list; l; l = l->next) {
2898                 struct datetime *dt;
2899
2900                 dt = l->data;
2901
2902                 /* Removing the DATE or DATE-TIME property will also remove
2903                    any TZID parameter. */
2904                 icalcomponent_remove_property (priv->icalcomp, dt->prop);
2905                 icalproperty_free (dt->prop);
2906                 g_free (dt);
2907         }
2908
2909         g_slist_free (priv->exdate_list);
2910         priv->exdate_list = NULL;
2911
2912         /* Add in new exception dates */
2913
2914         for (l = exdate_list; l; l = l->next) {
2915                 ECalComponentDateTime *cdt;
2916                 struct datetime *dt;
2917
2918                 g_assert (l->data != NULL);
2919                 cdt = l->data;
2920
2921                 g_assert (cdt->value != NULL);
2922
2923                 dt = g_new (struct datetime, 1);
2924                 dt->prop = icalproperty_new_exdate (*cdt->value);
2925
2926                 if (cdt->tzid) {
2927                         dt->tzid_param = icalparameter_new_tzid ((char *) cdt->tzid);
2928                         icalproperty_add_parameter (dt->prop, dt->tzid_param);
2929                 } else
2930                         dt->tzid_param = NULL;
2931
2932                 icalcomponent_add_property (priv->icalcomp, dt->prop);
2933                 priv->exdate_list = g_slist_prepend (priv->exdate_list, dt);
2934         }
2935
2936         priv->exdate_list = g_slist_reverse (priv->exdate_list);
2937
2938         priv->need_sequence_inc = TRUE;
2939 }
2940
2941 /**
2942  * e_cal_component_has_exdates:
2943  * @comp: A calendar component object.
2944  *
2945  * Queries whether a calendar component object has any exception dates defined
2946  * for it.
2947  *
2948  * Return value: TRUE if the component has exception dates, FALSE otherwise.
2949  **/
2950 gboolean
2951 e_cal_component_has_exdates (ECalComponent *comp)
2952 {
2953         ECalComponentPrivate *priv;
2954
2955         g_return_val_if_fail (comp != NULL, FALSE);
2956         g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), FALSE);
2957
2958         priv = comp->priv;
2959         g_return_val_if_fail (priv->icalcomp != NULL, FALSE);
2960
2961         return (priv->exdate_list != NULL);
2962 }
2963
2964 /* Gets a list of recurrence rules */
2965 static void
2966 get_recur_list (GSList *recur_list,
2967                 struct icalrecurrencetype (* get_prop_func) (const icalproperty *prop),
2968                 GSList **list)
2969 {
2970         GSList *l;
2971
2972         *list = NULL;
2973
2974         for (l = recur_list; l; l = l->next) {
2975                 icalproperty *prop;
2976                 struct icalrecurrencetype *r;
2977
2978                 prop = l->data;
2979
2980                 r = g_new (struct icalrecurrencetype, 1);
2981                 *r = (* get_prop_func) (prop);
2982
2983                 *list = g_slist_prepend (*list, r);
2984         }
2985
2986         *list = g_slist_reverse (*list);
2987 }
2988
2989 /* Sets a list of recurrence rules */
2990 static void
2991 set_recur_list (ECalComponent *comp,
2992                 icalproperty *(* new_prop_func) (struct icalrecurrencetype recur),
2993                 GSList **recur_list,
2994                 GSList *rl)
2995 {
2996         ECalComponentPrivate *priv;
2997         GSList *l;
2998
2999         priv = comp->priv;
3000
3001         /* Remove old recurrences */
3002
3003         for (l = *recur_list; l; l = l->next) {
3004                 icalproperty *prop;
3005
3006                 prop = l->data;
3007                 icalcomponent_remove_property (priv->icalcomp, prop);
3008                 icalproperty_free (prop);
3009         }
3010
3011         g_slist_free (*recur_list);
3012         *recur_list = NULL;
3013
3014         /* Add in new recurrences */
3015
3016         for (l = rl; l; l = l->next) {
3017                 icalproperty *prop;
3018                 struct icalrecurrencetype *recur;
3019
3020                 g_assert (l->data != NULL);
3021                 recur = l->data;
3022
3023                 prop = (* new_prop_func) (*recur);
3024                 icalcomponent_add_property (priv->icalcomp, prop);
3025
3026                 *recur_list = g_slist_prepend (*recur_list, prop);
3027         }
3028
3029         *recur_list = g_slist_reverse (*recur_list);
3030 }
3031
3032 /**
3033  * e_cal_component_get_exrule_list:
3034  * @comp: A calendar component object.
3035  * @recur_list: List of exception rules as struct #icalrecurrencetype
3036  * structures.  This should be freed using the e_cal_component_free_recur_list()
3037  * function.
3038  *
3039  * Queries the list of exception rule properties of a calendar component
3040  * object.
3041  **/
3042 void
3043 e_cal_component_get_exrule_list (ECalComponent *comp, GSList **recur_list)
3044 {
3045         ECalComponentPrivate *priv;
3046
3047         g_return_if_fail (comp != NULL);
3048         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
3049         g_return_if_fail (recur_list != NULL);
3050
3051         priv = comp->priv;
3052         g_return_if_fail (priv->icalcomp != NULL);
3053
3054         get_recur_list (priv->exrule_list, icalproperty_get_exrule, recur_list);
3055 }
3056
3057 /**
3058  * e_cal_component_get_exrule_property_list:
3059  * @comp: A calendar component object.
3060  * @recur_list: Returns a list of exception rule properties.
3061  *
3062  * Queries the list of exception rule properties of a calendar component object.
3063  **/
3064 void
3065 e_cal_component_get_exrule_property_list (ECalComponent *comp, GSList **recur_list)
3066 {
3067         ECalComponentPrivate *priv;
3068
3069         g_return_if_fail (comp != NULL);
3070         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
3071         g_return_if_fail (recur_list != NULL);
3072
3073         priv = comp->priv;
3074         g_return_if_fail (priv->icalcomp != NULL);
3075
3076         *recur_list = priv->exrule_list;
3077 }
3078
3079 /**
3080  * e_cal_component_set_exrule_list:
3081  * @comp: A calendar component object.
3082  * @recur_list: List of struct #icalrecurrencetype structures.
3083  *
3084  * Sets the list of exception rules in a calendar component object.
3085  **/
3086 void
3087 e_cal_component_set_exrule_list (ECalComponent *comp, GSList *recur_list)
3088 {
3089         ECalComponentPrivate *priv;
3090
3091         g_return_if_fail (comp != NULL);
3092         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
3093
3094         priv = comp->priv;
3095         g_return_if_fail (priv->icalcomp != NULL);
3096
3097         set_recur_list (comp, icalproperty_new_exrule, &priv->exrule_list, recur_list);
3098
3099         priv->need_sequence_inc = TRUE;
3100 }
3101
3102 /**
3103  * e_cal_component_has_exrules:
3104  * @comp: A calendar component object.
3105  *
3106  * Queries whether a calendar component object has any exception rules defined
3107  * for it.
3108  *
3109  * Return value: TRUE if the component has exception rules, FALSE otherwise.
3110  **/
3111 gboolean
3112 e_cal_component_has_exrules (ECalComponent *comp)
3113 {
3114         ECalComponentPrivate *priv;
3115
3116         g_return_val_if_fail (comp != NULL, FALSE);
3117         g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), FALSE);
3118
3119         priv = comp->priv;
3120         g_return_val_if_fail (priv->icalcomp != NULL, FALSE);
3121
3122         return (priv->exrule_list != NULL);
3123 }
3124
3125 /**
3126  * e_cal_component_has_exceptions:
3127  * @comp: A calendar component object
3128  *
3129  * Queries whether a calendar component object has any exception dates
3130  * or exception rules.
3131  *
3132  * Return value: TRUE if the component has exceptions, FALSE otherwise.
3133  **/
3134 gboolean
3135 e_cal_component_has_exceptions (ECalComponent *comp)
3136 {
3137         return e_cal_component_has_exdates (comp) || e_cal_component_has_exrules (comp);
3138 }
3139
3140 /**
3141  * e_cal_component_get_geo:
3142  * @comp: A calendar component object.
3143  * @geo: Return value for the geographic position property.  This should be
3144  * freed using the e_cal_component_free_geo() function.
3145  *
3146  * Gets the geographic position property of a calendar component object.
3147  **/
3148 void
3149 e_cal_component_get_geo (ECalComponent *comp, struct icalgeotype **geo)
3150 {
3151         ECalComponentPrivate *priv;
3152
3153         g_return_if_fail (comp != NULL);
3154         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
3155         g_return_if_fail (geo != NULL);
3156
3157         priv = comp->priv;
3158         g_return_if_fail (priv->icalcomp != NULL);
3159
3160         if (priv->geo) {
3161                 *geo = g_new (struct icalgeotype, 1);
3162                 **geo = icalproperty_get_geo (priv->geo);
3163         } else
3164                 *geo = NULL;
3165 }
3166
3167 /**
3168  * e_cal_component_set_geo:
3169  * @comp: A calendar component object.
3170  * @geo: Value for the geographic position property.
3171  *
3172  * Sets the geographic position property on a calendar component object.
3173  **/
3174 void
3175 e_cal_component_set_geo (ECalComponent *comp, struct icalgeotype *geo)
3176 {
3177         ECalComponentPrivate *priv;
3178
3179         g_return_if_fail (comp != NULL);
3180         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
3181
3182         priv = comp->priv;
3183         g_return_if_fail (priv->icalcomp != NULL);
3184
3185         if (!geo) {
3186                 if (priv->geo) {
3187                         icalcomponent_remove_property (priv->icalcomp, priv->geo);
3188                         icalproperty_free (priv->geo);
3189                         priv->geo = NULL;
3190                 }
3191
3192                 return;
3193         }
3194
3195         if (priv->geo)
3196                 icalproperty_set_geo (priv->geo, *geo);
3197         else {
3198                 priv->geo = icalproperty_new_geo (*geo);
3199                 icalcomponent_add_property (priv->icalcomp, priv->geo);
3200         }
3201 }
3202
3203 /**
3204  * e_cal_component_get_last_modified:
3205  * @comp: A calendar component object.
3206  * @t: Return value for the last modified time value.
3207  *
3208  * Queries the time at which a calendar component object was last modified in
3209  * the calendar store.
3210  **/
3211 void
3212 e_cal_component_get_last_modified (ECalComponent *comp, struct icaltimetype **t)
3213 {
3214         ECalComponentPrivate *priv;
3215
3216         g_return_if_fail (comp != NULL);
3217         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
3218         g_return_if_fail (t != NULL);
3219
3220         priv = comp->priv;
3221         g_return_if_fail (priv->icalcomp != NULL);
3222
3223         get_icaltimetype (priv->last_modified, icalproperty_get_lastmodified, t);
3224 }
3225
3226 /**
3227  * e_cal_component_set_last_modified:
3228  * @comp: A calendar component object.
3229  * @t: Value for the last time modified.
3230  *
3231  * Sets the time at which a calendar component object was last stored in the
3232  * calendar store.  This should not be called by plain calendar user agents.
3233  **/
3234 void
3235 e_cal_component_set_last_modified (ECalComponent *comp, struct icaltimetype *t)
3236 {
3237         ECalComponentPrivate *priv;
3238
3239         g_return_if_fail (comp != NULL);
3240         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
3241
3242         priv = comp->priv;
3243         g_return_if_fail (priv->icalcomp != NULL);
3244
3245         set_icaltimetype (comp, &priv->last_modified,
3246                           icalproperty_new_lastmodified,
3247                           icalproperty_set_lastmodified,
3248                           t);
3249 }
3250
3251 /**
3252  * e_cal_component_get_organizer:
3253  * @comp:  A calendar component object
3254  * @organizer: A value for the organizer
3255  * 
3256  * Queries the organizer property of a calendar component object
3257  **/
3258 void
3259 e_cal_component_get_organizer (ECalComponent *comp, ECalComponentOrganizer *organizer)
3260 {
3261         ECalComponentPrivate *priv;
3262
3263         g_return_if_fail (comp != NULL);
3264         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
3265         g_return_if_fail (organizer != NULL);
3266
3267         priv = comp->priv;
3268         g_return_if_fail (priv->icalcomp != NULL);
3269
3270         if (priv->organizer.prop)
3271                 organizer->value = icalproperty_get_organizer (priv->organizer.prop);
3272         else
3273                 organizer->value = NULL;
3274
3275         if (priv->organizer.sentby_param)
3276                 organizer->sentby = icalparameter_get_sentby (priv->organizer.sentby_param);
3277         else
3278                 organizer->sentby = NULL;
3279
3280         if (priv->organizer.cn_param)
3281                 organizer->cn = icalparameter_get_sentby (priv->organizer.cn_param);
3282         else
3283                 organizer->cn = NULL;
3284
3285         if (priv->organizer.language_param)
3286                 organizer->language = icalparameter_get_sentby (priv->organizer.language_param);
3287         else
3288                 organizer->language = NULL;
3289
3290 }
3291
3292 /**
3293  * e_cal_component_set_organizer:
3294  * @comp:  A calendar component object.
3295  * @organizer: Value for the organizer property
3296  * 
3297  * Sets the organizer of a calendar component object
3298  **/
3299 void
3300 e_cal_component_set_organizer (ECalComponent *comp, ECalComponentOrganizer *organizer)
3301 {
3302         ECalComponentPrivate *priv;
3303
3304         g_return_if_fail (comp != NULL);
3305         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
3306
3307         priv = comp->priv;
3308         g_return_if_fail (priv->icalcomp != NULL);
3309
3310         if (!organizer) {
3311                 if (priv->organizer.prop) {
3312                         icalcomponent_remove_property (priv->icalcomp, priv->organizer.prop);
3313                         icalproperty_free (priv->organizer.prop);
3314
3315                         priv->organizer.prop = NULL;
3316                         priv->organizer.sentby_param = NULL;
3317                         priv->organizer.cn_param = NULL;
3318                         priv->organizer.language_param = NULL;
3319                 }
3320
3321                 return;
3322         }
3323
3324         g_return_if_fail (organizer->value != NULL);
3325
3326         if (priv->organizer.prop)
3327                 icalproperty_set_organizer (priv->organizer.prop, (char *) organizer->value);
3328         else {
3329                 priv->organizer.prop = icalproperty_new_organizer ((char *) organizer->value);
3330                 icalcomponent_add_property (priv->icalcomp, priv->organizer.prop);
3331         }
3332
3333         if (organizer->sentby) {
3334                 g_assert (priv->organizer.prop != NULL);
3335
3336                 if (priv->organizer.sentby_param)
3337                         icalparameter_set_sentby (priv->organizer.sentby_param,
3338                                                   (char *) organizer->sentby);
3339                 else {
3340                         priv->organizer.sentby_param = icalparameter_new_sentby (
3341                                 (char *) organizer->sentby);
3342                         icalproperty_add_parameter (priv->organizer.prop,
3343                                                     priv->organizer.sentby_param);
3344                 }
3345         } else if (priv->organizer.sentby_param) {
3346                 icalproperty_remove_parameter (priv->organizer.prop, ICAL_SENTBY_PARAMETER);
3347                 priv->organizer.sentby_param = NULL;
3348         }
3349
3350         if (organizer->cn) {
3351                 g_assert (priv->organizer.prop != NULL);
3352
3353                 if (priv->organizer.cn_param)
3354                         icalparameter_set_cn (priv->organizer.cn_param,
3355                                                   (char *) organizer->cn);
3356                 else {
3357                         priv->organizer.cn_param = icalparameter_new_cn (
3358                                 (char *) organizer->cn);
3359                         icalproperty_add_parameter (priv->organizer.prop,
3360                                                     priv->organizer.cn_param);
3361                 }
3362         } else if (priv->organizer.cn_param) {
3363                 icalproperty_remove_parameter (priv->organizer.prop, ICAL_CN_PARAMETER);
3364                 priv->organizer.cn_param = NULL;
3365         }
3366
3367         if (organizer->language) {
3368                 g_assert (priv->organizer.prop != NULL);
3369
3370                 if (priv->organizer.language_param)
3371                         icalparameter_set_language (priv->organizer.language_param,
3372                                                   (char *) organizer->language);
3373                 else {
3374                         priv->organizer.language_param = icalparameter_new_language (
3375                                 (char *) organizer->language);
3376                         icalproperty_add_parameter (priv->organizer.prop,
3377                                                     priv->organizer.language_param);
3378                 }
3379         } else if (priv->organizer.language_param) {
3380                 icalproperty_remove_parameter (priv->organizer.prop, ICAL_LANGUAGE_PARAMETER);
3381                 priv->organizer.language_param = NULL;
3382         }
3383
3384
3385 }
3386
3387
3388 /**
3389  * e_cal_component_has_organizer:
3390  * @comp: A calendar component object.
3391  * 
3392  * Check whether a calendar component object has an organizer or not.
3393  * 
3394  * Return value: TRUE if there is an organizer, FALSE otherwise.
3395  **/
3396 gboolean
3397 e_cal_component_has_organizer (ECalComponent *comp)
3398 {
3399         ECalComponentPrivate *priv;
3400
3401         g_return_val_if_fail (comp != NULL, FALSE);
3402         g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), FALSE);
3403
3404         priv = comp->priv;
3405
3406         return priv->organizer.prop != NULL;
3407 }
3408                 
3409 /**
3410  * e_cal_component_get_percent:
3411  * @comp: A calendar component object.
3412  * @percent: Return value for the percent-complete property.  This should be
3413  * freed using the e_cal_component_free_percent() function.
3414  *
3415  * Queries the percent-complete property of a calendar component object.
3416  **/
3417 void
3418 e_cal_component_get_percent (ECalComponent *comp, int **percent)
3419 {
3420         ECalComponentPrivate *priv;
3421
3422         g_return_if_fail (comp != NULL);
3423         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
3424         g_return_if_fail (percent != NULL);
3425
3426         priv = comp->priv;
3427         g_return_if_fail (priv->icalcomp != NULL);
3428
3429         if (priv->percent) {
3430                 *percent = g_new (int, 1);
3431                 **percent = icalproperty_get_percentcomplete (priv->percent);
3432         } else
3433                 *percent = NULL;
3434 }
3435
3436 /**
3437  * e_cal_component_set_percent:
3438  * @comp: A calendar component object.
3439  * @percent: Value for the percent-complete property.
3440  *
3441  * Sets the percent-complete property of a calendar component object.
3442  **/
3443 void
3444 e_cal_component_set_percent (ECalComponent *comp, int *percent)
3445 {
3446         ECalComponentPrivate *priv;
3447
3448         g_return_if_fail (comp != NULL);
3449         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
3450
3451         priv = comp->priv;
3452         g_return_if_fail (priv->icalcomp != NULL);
3453
3454         if (!percent) {
3455                 if (priv->percent) {
3456                         icalcomponent_remove_property (priv->icalcomp, priv->percent);
3457                         icalproperty_free (priv->percent);
3458                         priv->percent = NULL;
3459                 }
3460
3461                 return;
3462         }
3463
3464         g_return_if_fail (*percent >= 0 && *percent <= 100);
3465
3466         if (priv->percent)
3467                 icalproperty_set_percentcomplete (priv->percent, *percent);
3468         else {
3469                 priv->percent = icalproperty_new_percentcomplete (*percent);
3470                 icalcomponent_add_property (priv->icalcomp, priv->percent);
3471         }
3472 }
3473
3474 /**
3475  * e_cal_component_get_priority:
3476  * @comp: A calendar component object.
3477  * @priority: Return value for the priority property.  This should be freed using
3478  * the e_cal_component_free_priority() function.
3479  *
3480  * Queries the priority property of a calendar component object.
3481  **/
3482 void
3483 e_cal_component_get_priority (ECalComponent *comp, int **priority)
3484 {
3485         ECalComponentPrivate *priv;
3486
3487         g_return_if_fail (comp != NULL);
3488         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
3489         g_return_if_fail (priority != NULL);
3490
3491         priv = comp->priv;
3492         g_return_if_fail (priv->icalcomp != NULL);
3493
3494         if (priv->priority) {
3495                 *priority = g_new (int, 1);
3496                 **priority = icalproperty_get_priority (priv->priority);
3497         } else
3498                 *priority = NULL;
3499 }
3500
3501 /**
3502  * e_cal_component_set_priority:
3503  * @comp: A calendar component object.
3504  * @priority: Value for the priority property.
3505  *
3506  * Sets the priority property of a calendar component object.
3507  **/
3508 void
3509 e_cal_component_set_priority (ECalComponent *comp, int *priority)
3510 {
3511         ECalComponentPrivate *priv;
3512
3513         g_return_if_fail (comp != NULL);
3514         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
3515
3516         priv = comp->priv;
3517         g_return_if_fail (priv->icalcomp != NULL);
3518
3519         if (!priority) {
3520                 if (priv->priority) {
3521                         icalcomponent_remove_property (priv->icalcomp, priv->priority);
3522                         icalproperty_free (priv->priority);
3523                         priv->priority = NULL;
3524                 }
3525
3526                 return;
3527         }
3528
3529         g_return_if_fail (*priority >= 0 && *priority <= 9);
3530
3531         if (priv->priority)
3532                 icalproperty_set_priority (priv->priority, *priority);
3533         else {
3534                 priv->priority = icalproperty_new_priority (*priority);
3535                 icalcomponent_add_property (priv->icalcomp, priv->priority);
3536         }
3537 }
3538
3539 /**
3540  * e_cal_component_get_recurid:
3541  * @comp: A calendar component object.
3542  * @recur_id: Return value for the recurrence id property
3543  * 
3544  * Queries the recurrence id property of a calendar component object.
3545  **/
3546 void 
3547 e_cal_component_get_recurid (ECalComponent *comp, ECalComponentRange *recur_id)
3548 {
3549         ECalComponentPrivate *priv;
3550
3551         g_return_if_fail (comp != NULL);
3552         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
3553         g_return_if_fail (recur_id != NULL);
3554
3555         priv = comp->priv;
3556         g_return_if_fail (priv->icalcomp != NULL);
3557
3558         get_datetime (&priv->recur_id.recur_time, 
3559                       icalproperty_get_recurrenceid, 
3560                       &recur_id->datetime);
3561 }
3562
3563 /**
3564  * e_cal_component_get_recurid_as_string:
3565  * @comp: A calendar component object.
3566  *
3567  * Gets the recurrence ID property as a string.
3568  *
3569  * Return value: the recurrence ID as a string.
3570  */
3571 const char *
3572 e_cal_component_get_recurid_as_string (ECalComponent *comp)
3573 {
3574         ECalComponentRange range;
3575         struct icaltimetype tt;
3576
3577         if (!e_cal_component_is_instance (comp))
3578                 return NULL;
3579
3580         e_cal_component_get_recurid (comp, &range);
3581         if (!range.datetime.value)
3582                 return "0";
3583         tt = *range.datetime.value;
3584         e_cal_component_free_range (&range);
3585                                                                                    
3586         return icaltime_is_valid_time (tt) && !icaltime_is_null_time (tt) ?
3587                 icaltime_as_ical_string (tt) : "0";
3588 }
3589
3590 /**
3591  * e_cal_component_set_recurid:
3592  * @comp: A calendar component object.
3593  * @recur_id: Value for the recurrence id property.
3594  * 
3595  * Sets the recurrence id property of a calendar component object.
3596  **/
3597 void
3598 e_cal_component_set_recurid (ECalComponent *comp, ECalComponentRange *recur_id)
3599 {
3600         ECalComponentPrivate *priv;
3601
3602         g_return_if_fail (comp != NULL);
3603         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
3604
3605         priv = comp->priv;
3606         g_return_if_fail (priv->icalcomp != NULL);
3607         
3608         set_datetime (comp, &priv->recur_id.recur_time,
3609                       icalproperty_new_recurrenceid,
3610                       icalproperty_set_recurrenceid,
3611                       recur_id ? &recur_id->datetime : NULL);
3612 }
3613
3614 /**
3615  * e_cal_component_get_rdate_list:
3616  * @comp: A calendar component object.
3617  * @period_list: Return value for the list of recurrence dates, as a list of
3618  * #ECalComponentPeriod structures.  This should be freed using the
3619  * e_cal_component_free_period_list() function.
3620  *
3621  * Queries the list of recurrence date properties in a calendar component
3622  * object.
3623  **/
3624 void
3625 e_cal_component_get_rdate_list (ECalComponent *comp, GSList **period_list)
3626 {
3627         ECalComponentPrivate *priv;
3628
3629         g_return_if_fail (comp != NULL);
3630         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
3631         g_return_if_fail (period_list != NULL);
3632
3633         priv = comp->priv;
3634         g_return_if_fail (priv->icalcomp != NULL);
3635
3636         get_period_list (priv->rdate_list, icalproperty_get_rdate, period_list);
3637 }
3638
3639 /**
3640  * e_cal_component_set_rdate_list:
3641  * @comp: A calendar component object.
3642  * @period_list: List of #ECalComponentPeriod structures.
3643  *
3644  * Sets the list of recurrence dates in a calendar component object.
3645  **/
3646 void
3647 e_cal_component_set_rdate_list (ECalComponent *comp, GSList *period_list)
3648 {
3649         ECalComponentPrivate *priv;
3650
3651         g_return_if_fail (comp != NULL);
3652         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
3653
3654         priv = comp->priv;
3655         g_return_if_fail (priv->icalcomp != NULL);
3656
3657         set_period_list (comp, icalproperty_new_rdate, &priv->rdate_list, period_list);
3658
3659         priv->need_sequence_inc = TRUE;
3660 }
3661
3662 /**
3663  * e_cal_component_has_rdates:
3664  * @comp: A calendar component object.
3665  *
3666  * Queries whether a calendar component object has any recurrence dates defined
3667  * for it.
3668  *
3669  * Return value: TRUE if the component has recurrence dates, FALSE otherwise.
3670  **/
3671 gboolean
3672 e_cal_component_has_rdates (ECalComponent *comp)
3673 {
3674         ECalComponentPrivate *priv;
3675
3676         g_return_val_if_fail (comp != NULL, FALSE);
3677         g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), FALSE);
3678
3679         priv = comp->priv;
3680         g_return_val_if_fail (priv->icalcomp != NULL, FALSE);
3681
3682         return (priv->rdate_list != NULL);
3683 }
3684
3685 /**
3686  * e_cal_component_get_rrule_list:
3687  * @comp: A calendar component object.
3688  * @recur_list: List of recurrence rules as struct #icalrecurrencetype
3689  * structures.  This should be freed using the e_cal_component_free_recur_list()
3690  * function.
3691  *
3692  * Queries the list of recurrence rule properties of a calendar component
3693  * object.
3694  **/
3695 void
3696 e_cal_component_get_rrule_list (ECalComponent *comp, GSList **recur_list)
3697 {
3698         ECalComponentPrivate *priv;
3699
3700         g_return_if_fail (comp != NULL);
3701         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
3702         g_return_if_fail (recur_list != NULL);
3703
3704         priv = comp->priv;
3705         g_return_if_fail (priv->icalcomp != NULL);
3706
3707         get_recur_list (priv->rrule_list, icalproperty_get_rrule, recur_list);
3708 }
3709
3710 /**
3711  * e_cal_component_get_rrule_property_list:
3712  * @comp: A calendar component object.
3713  * @recur_list: Returns a list of recurrence rule properties.
3714  *
3715  * Queries a list of recurrence rule properties of a calendar component object.
3716  **/
3717 void
3718 e_cal_component_get_rrule_property_list (ECalComponent *comp, GSList **recur_list)
3719 {
3720         ECalComponentPrivate *priv;
3721
3722         g_return_if_fail (comp != NULL);
3723         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
3724         g_return_if_fail (recur_list != NULL);
3725
3726         priv = comp->priv;
3727         g_return_if_fail (priv->icalcomp != NULL);
3728
3729         *recur_list = priv->rrule_list;
3730 }
3731
3732 /**
3733  * e_cal_component_set_rrule_list:
3734  * @comp: A calendar component object.
3735  * @recur_list: List of struct #icalrecurrencetype structures.
3736  *
3737  * Sets the list of recurrence rules in a calendar component object.
3738  **/
3739 void
3740 e_cal_component_set_rrule_list (ECalComponent *comp, GSList *recur_list)
3741 {
3742         ECalComponentPrivate *priv;
3743
3744         g_return_if_fail (comp != NULL);
3745         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
3746
3747         priv = comp->priv;
3748         g_return_if_fail (priv->icalcomp != NULL);
3749
3750         set_recur_list (comp, icalproperty_new_rrule, &priv->rrule_list, recur_list);
3751
3752         priv->need_sequence_inc = TRUE;
3753 }
3754
3755 /**
3756  * e_cal_component_has_rrules:
3757  * @comp: A calendar component object.
3758  *
3759  * Queries whether a calendar component object has any recurrence rules defined
3760  * for it.
3761  *
3762  * Return value: TRUE if the component has recurrence rules, FALSE otherwise.
3763  **/
3764 gboolean
3765 e_cal_component_has_rrules (ECalComponent *comp)
3766 {
3767         ECalComponentPrivate *priv;
3768
3769         g_return_val_if_fail (comp != NULL, FALSE);
3770         g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), FALSE);
3771
3772         priv = comp->priv;
3773         g_return_val_if_fail (priv->icalcomp != NULL, FALSE);
3774
3775         return (priv->rrule_list != NULL);
3776 }
3777
3778 /**
3779  * e_cal_component_has_recurrences:
3780  * @comp: A calendar component object
3781  *
3782  * Queries whether a calendar component object has any recurrence dates or
3783  * recurrence rules.
3784  *
3785  * Return value: TRUE if the component has recurrences, FALSE otherwise.
3786  **/
3787 gboolean
3788 e_cal_component_has_recurrences (ECalComponent *comp)
3789 {
3790         return e_cal_component_has_rdates (comp) || e_cal_component_has_rrules (comp);
3791 }
3792
3793 /* Counts the elements in the by_xxx fields of an icalrecurrencetype */
3794 static int
3795 count_by_xxx (short *field, int max_elements)
3796 {
3797         int i;
3798
3799         for (i = 0; i < max_elements; i++)
3800                 if (field[i] == ICAL_RECURRENCE_ARRAY_MAX)
3801                         break;
3802
3803         return i;
3804 }
3805
3806 /**
3807  * e_cal_component_has_simple_recurrence:
3808  * @comp: A calendar component object.
3809  *
3810  * Checks whether the given calendar component object has simple recurrence
3811  * rules or more complicated ones.
3812  *
3813  * Return value: TRUE if it has a simple recurrence rule, FALSE otherwise.
3814  */
3815 gboolean
3816 e_cal_component_has_simple_recurrence (ECalComponent *comp)
3817 {
3818         GSList *rrule_list;
3819         struct icalrecurrencetype *r;
3820         int n_by_second, n_by_minute, n_by_hour;
3821         int n_by_day, n_by_month_day, n_by_year_day;
3822         int n_by_week_no, n_by_month, n_by_set_pos;
3823         int len, i;
3824         gboolean simple = FALSE;
3825
3826         if (!e_cal_component_has_recurrences (comp))
3827                 return TRUE;
3828         
3829         e_cal_component_get_rrule_list (comp, &rrule_list);
3830         len = g_slist_length (rrule_list);
3831         if (len > 1
3832             || e_cal_component_has_rdates (comp)
3833             || e_cal_component_has_exrules (comp))
3834                 goto cleanup;
3835
3836         /* Down to one rule, so test that one */
3837         r = rrule_list->data;
3838
3839         /* Any funky frequency? */
3840         if (r->freq == ICAL_SECONDLY_RECURRENCE
3841             || r->freq == ICAL_MINUTELY_RECURRENCE
3842             || r->freq == ICAL_HOURLY_RECURRENCE)
3843                 goto cleanup;
3844
3845         /* Any funky BY_* */
3846 #define N_HAS_BY(field) (count_by_xxx (field, sizeof (field) / sizeof (field[0])))
3847
3848         n_by_second = N_HAS_BY (r->by_second);
3849         n_by_minute = N_HAS_BY (r->by_minute);
3850         n_by_hour = N_HAS_BY (r->by_hour);
3851         n_by_day = N_HAS_BY (r->by_day);
3852         n_by_month_day = N_HAS_BY (r->by_month_day);
3853         n_by_year_day = N_HAS_BY (r->by_year_day);
3854         n_by_week_no = N_HAS_BY (r->by_week_no);
3855         n_by_month = N_HAS_BY (r->by_month);
3856         n_by_set_pos = N_HAS_BY (r->by_set_pos);
3857
3858         if (n_by_second != 0
3859             || n_by_minute != 0
3860             || n_by_hour != 0)
3861                 goto cleanup;   
3862
3863         switch (r->freq) {
3864         case ICAL_DAILY_RECURRENCE:
3865                 if (n_by_day != 0
3866                     || n_by_month_day != 0
3867                     || n_by_year_day != 0
3868                     || n_by_week_no != 0
3869                     || n_by_month != 0
3870                     || n_by_set_pos != 0)
3871                         goto cleanup;
3872
3873                 simple = TRUE;
3874                 break;
3875
3876         case ICAL_WEEKLY_RECURRENCE:
3877                 if (n_by_month_day != 0
3878                     || n_by_year_day != 0
3879                     || n_by_week_no != 0
3880                     || n_by_month != 0
3881                     || n_by_set_pos != 0)
3882                         goto cleanup;
3883
3884                 for (i = 0; i < 8 && r->by_day[i] != ICAL_RECURRENCE_ARRAY_MAX; i++) {
3885                         int pos;
3886                         pos = icalrecurrencetype_day_position (r->by_day[i]);
3887
3888                         if (pos != 0)
3889                                 goto cleanup;
3890                 }
3891                 
3892                 simple = TRUE;
3893                 break;
3894
3895         case ICAL_MONTHLY_RECURRENCE:
3896                 if (n_by_year_day != 0
3897                     || n_by_week_no != 0
3898                     || n_by_month != 0
3899                     || n_by_set_pos > 1)
3900                         goto cleanup;
3901
3902                 if (n_by_month_day == 1) {
3903                         int nth;
3904
3905                         if (n_by_set_pos != 0)
3906                                 goto cleanup;
3907
3908                         nth = r->by_month_day[0];
3909                         if (nth < 1 && nth != -1)
3910                                 goto cleanup;
3911                         
3912                         simple = TRUE;
3913                         
3914                 } else if (n_by_day == 1) {
3915                         enum icalrecurrencetype_weekday weekday;
3916                         int pos;
3917
3918                         /* Outlook 2000 uses BYDAY=TU;BYSETPOS=2, and will not
3919                            accept BYDAY=2TU. So we now use the same as Outlook
3920                            by default. */
3921
3922                         weekday = icalrecurrencetype_day_day_of_week (r->by_day[0]);
3923                         pos = icalrecurrencetype_day_position (r->by_day[0]);
3924
3925                         if (pos == 0) {
3926                                 if (n_by_set_pos != 1)
3927                                         goto cleanup;
3928                                 pos = r->by_set_pos[0];
3929                         } else if (pos < 0) {
3930                                 goto cleanup;
3931                         }
3932
3933                         switch (weekday) {
3934                         case ICAL_MONDAY_WEEKDAY:
3935                         case ICAL_TUESDAY_WEEKDAY:
3936                         case ICAL_WEDNESDAY_WEEKDAY:
3937                         case ICAL_THURSDAY_WEEKDAY:
3938                         case ICAL_FRIDAY_WEEKDAY:
3939                         case ICAL_SATURDAY_WEEKDAY:
3940                         case ICAL_SUNDAY_WEEKDAY:
3941                                 break;
3942
3943                         default:
3944                                 goto cleanup;
3945                         }
3946                 } else {
3947                         goto cleanup;
3948                 }
3949                 
3950                 simple = TRUE;
3951                 break;
3952
3953         case ICAL_YEARLY_RECURRENCE:
3954                 if (n_by_day != 0
3955                     || n_by_month_day != 0
3956                     || n_by_year_day != 0
3957                     || n_by_week_no != 0
3958                     || n_by_month != 0
3959                     || n_by_set_pos != 0)
3960                         goto cleanup;
3961                 
3962                 simple = TRUE;
3963                 break;
3964
3965         default:
3966                 goto cleanup;
3967         }
3968
3969  cleanup:
3970         e_cal_component_free_recur_list (rrule_list);
3971
3972         return simple;
3973 }
3974
3975 /**
3976  * e_cal_component_is_instance:
3977  * @comp: A calendar component object.
3978  *
3979  * Checks whether a calendar component object is an instance of a recurring
3980  * event.
3981  *
3982  * Return value: TRUE if it is an instance, FALSE if not.
3983  */
3984 gboolean 
3985 e_cal_component_is_instance (ECalComponent *comp)
3986 {
3987         ECalComponentPrivate *priv;
3988
3989         g_return_val_if_fail (comp != NULL, FALSE);
3990         g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), FALSE);
3991
3992         priv = comp->priv;
3993
3994         return !(priv->recur_id.recur_time.prop == NULL);
3995 }
3996
3997 /**
3998  * e_cal_component_get_sequence:
3999  * @comp: A calendar component object.
4000  * @sequence: Return value for the sequence number.  This should be freed using
4001  * e_cal_component_free_sequence().
4002  *
4003  * Queries the sequence number of a calendar component object.
4004  **/
4005 void
4006 e_cal_component_get_sequence (ECalComponent *comp, int **sequence)
4007 {
4008         ECalComponentPrivate *priv;
4009
4010         g_return_if_fail (comp != NULL);
4011         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
4012         g_return_if_fail (sequence != NULL);
4013
4014         priv = comp->priv;
4015         g_return_if_fail (priv->icalcomp != NULL);
4016
4017         if (!priv->sequence) {
4018                 *sequence = NULL;
4019                 return;
4020         }
4021
4022         *sequence = g_new (int, 1);
4023         **sequence = icalproperty_get_sequence (priv->sequence);
4024 }
4025
4026 /**
4027  * e_cal_component_set_sequence:
4028  * @comp: A calendar component object.
4029  * @sequence: Sequence number value.
4030  *
4031  * Sets the sequence number of a calendar component object.  Normally this
4032  * function should not be called, since the sequence number is incremented
4033  * automatically at the proper times.
4034  **/
4035 void
4036 e_cal_component_set_sequence (ECalComponent *comp, int *sequence)
4037 {
4038         ECalComponentPrivate *priv;
4039
4040         g_return_if_fail (comp != NULL);
4041         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
4042
4043         priv = comp->priv;
4044         g_return_if_fail (priv->icalcomp != NULL);
4045
4046         priv->need_sequence_inc = FALSE;
4047
4048         if (!sequence) {
4049                 if (priv->sequence) {
4050                         icalcomponent_remove_property (priv->icalcomp, priv->sequence);
4051                         icalproperty_free (priv->sequence);
4052                         priv->sequence = NULL;
4053                 }
4054
4055                 return;
4056         }
4057
4058         if (priv->sequence)
4059                 icalproperty_set_sequence (priv->sequence, *sequence);
4060         else {
4061                 priv->sequence = icalproperty_new_sequence (*sequence);
4062                 icalcomponent_add_property (priv->icalcomp, priv->sequence);
4063         }
4064 }
4065
4066 /**
4067  * e_cal_component_get_status:
4068  * @comp: A calendar component object.
4069  * @status: Return value for the status value.  It is set to #ICAL_STATUS_NONE
4070  * if the component has no status property.
4071  *
4072  * Queries the status property of a calendar component object.
4073  **/
4074 void
4075 e_cal_component_get_status (ECalComponent *comp, icalproperty_status *status)
4076 {
4077         ECalComponentPrivate *priv;
4078
4079         g_return_if_fail (comp != NULL);
4080         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
4081         g_return_if_fail (status != NULL);
4082
4083         priv = comp->priv;
4084         g_return_if_fail (priv->icalcomp != NULL);
4085
4086         if (!priv->status) {
4087                 *status = ICAL_STATUS_NONE;
4088                 return;
4089         }
4090
4091         *status = icalproperty_get_status (priv->status);
4092 }
4093
4094 /**
4095  * e_cal_component_set_status:
4096  * @comp: A calendar component object.
4097  * @status: Status value.  You should use #ICAL_STATUS_NONE if you want to unset
4098  * this property.
4099  *
4100  * Sets the status property of a calendar component object.
4101  **/
4102 void
4103 e_cal_component_set_status (ECalComponent *comp, icalproperty_status status)
4104 {
4105         ECalComponentPrivate *priv;
4106
4107         g_return_if_fail (comp != NULL);
4108         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
4109
4110         priv = comp->priv;
4111         g_return_if_fail (priv->icalcomp != NULL);
4112
4113         priv->need_sequence_inc = TRUE;
4114
4115         if (status == ICAL_STATUS_NONE) {
4116                 if (priv->status) {
4117                         icalcomponent_remove_property (priv->icalcomp, priv->status);
4118                         icalproperty_free (priv->status);
4119                         priv->status = NULL;
4120                 }
4121
4122                 return;
4123         }
4124
4125         if (priv->status) {
4126                 icalproperty_set_status (priv->status, status);
4127         } else {
4128                 priv->status = icalproperty_new_status (status);
4129                 icalcomponent_add_property (priv->icalcomp, priv->status);
4130         }
4131 }
4132
4133 /**
4134  * e_cal_component_get_summary:
4135  * @comp: A calendar component object.
4136  * @summary: Return value for the summary property and its parameters.
4137  *
4138  * Queries the summary of a calendar component object.
4139  **/
4140 void
4141 e_cal_component_get_summary (ECalComponent *comp, ECalComponentText *summary)
4142 {
4143         ECalComponentPrivate *priv;
4144
4145         g_return_if_fail (comp != NULL);
4146         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
4147         g_return_if_fail (summary != NULL);
4148
4149         priv = comp->priv;
4150         g_return_if_fail (priv->icalcomp != NULL);
4151
4152         if (priv->summary.prop)
4153                 summary->value = icalproperty_get_summary (priv->summary.prop);
4154         else
4155                 summary->value = NULL;
4156
4157         if (priv->summary.altrep_param)
4158                 summary->altrep = icalparameter_get_altrep (priv->summary.altrep_param);
4159         else
4160                 summary->altrep = NULL;
4161 }
4162
4163 typedef struct {
4164         const char *old_summary;
4165         const char *new_summary;
4166 } SetAlarmDescriptionData;
4167
4168 static void
4169 set_alarm_description_cb (gpointer key, gpointer value, gpointer user_data)
4170 {
4171         icalcomponent *alarm;
4172         icalproperty *icalprop, *desc_prop;
4173         SetAlarmDescriptionData *sadd;
4174         gboolean changed = FALSE;
4175         const char *old_summary = NULL;
4176
4177         alarm = value;
4178         sadd = user_data;
4179
4180         /* set the new description on the alarm */
4181         desc_prop = icalcomponent_get_first_property (alarm, ICAL_DESCRIPTION_PROPERTY);
4182         if (desc_prop)
4183                 old_summary = icalproperty_get_description (desc_prop);
4184         else
4185                 desc_prop = icalproperty_new_description (sadd->new_summary);
4186
4187         /* remove the X-EVOLUTION-NEEDS_DESCRIPTION property */
4188         icalprop = icalcomponent_get_first_property (alarm, ICAL_X_PROPERTY);
4189         while (icalprop) {
4190                 const char *x_name;
4191
4192                 x_name = icalproperty_get_x_name (icalprop);
4193                 if (!strcmp (x_name, "X-EVOLUTION-NEEDS-DESCRIPTION")) {
4194                         icalcomponent_remove_property (alarm, icalprop);
4195                         icalproperty_free (icalprop);
4196
4197                         icalproperty_set_description (desc_prop, sadd->new_summary);
4198                         changed = TRUE;
4199                         break;
4200                 }
4201
4202                 icalprop = icalcomponent_get_next_property (alarm, ICAL_X_PROPERTY);
4203         }
4204
4205         if (!changed) {
4206                 if (!strcmp (old_summary ? old_summary : "", sadd->old_summary ? sadd->old_summary : "")) {
4207                         icalproperty_set_description (desc_prop, sadd->new_summary);
4208                 }
4209         }
4210 }
4211
4212 /**
4213  * e_cal_component_set_summary:
4214  * @comp: A calendar component object.
4215  * @summary: Summary property and its parameters.
4216  *
4217  * Sets the summary of a calendar component object.
4218  **/
4219 void
4220 e_cal_component_set_summary (ECalComponent *comp, ECalComponentText *summary)
4221 {
4222         ECalComponentPrivate *priv;
4223         SetAlarmDescriptionData sadd;
4224
4225         g_return_if_fail (comp != NULL);
4226         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
4227
4228         priv = comp->priv;
4229         g_return_if_fail (priv->icalcomp != NULL);
4230
4231         if (!summary) {
4232                 if (priv->summary.prop) {
4233                         icalcomponent_remove_property (priv->icalcomp, priv->summary.prop);
4234                         icalproperty_free (priv->summary.prop);
4235
4236                         priv->summary.prop = NULL;
4237                         priv->summary.altrep_param = NULL;
4238                 }
4239
4240                 return;
4241         }
4242
4243         g_return_if_fail (summary->value != NULL);
4244
4245         if (priv->summary.prop) {
4246                 sadd.old_summary = icalproperty_get_summary (priv->summary.prop);
4247                 icalproperty_set_summary (priv->summary.prop, (char *) summary->value);
4248         } else {
4249                 sadd.old_summary = NULL;
4250                 priv->summary.prop = icalproperty_new_summary ((char *) summary->value);
4251                 icalcomponent_add_property (priv->icalcomp, priv->summary.prop);
4252         }
4253
4254         if (summary->altrep) {
4255                 g_assert (priv->summary.prop != NULL);
4256
4257                 if (priv->summary.altrep_param)
4258                         icalparameter_set_altrep (priv->summary.altrep_param,
4259                                                   (char *) summary->altrep);
4260                 else {
4261                         priv->summary.altrep_param = icalparameter_new_altrep (
4262                                 (char *) summary->altrep);
4263                         icalproperty_add_parameter (priv->summary.prop,
4264                                                     priv->summary.altrep_param);
4265                 }
4266         } else if (priv->summary.altrep_param) {
4267                 icalproperty_remove_parameter (priv->summary.prop, ICAL_ALTREP_PARAMETER);
4268                 priv->summary.altrep_param = NULL; 
4269         }
4270
4271         /* look for alarms that need a description */
4272         sadd.new_summary = summary->value;
4273         g_hash_table_foreach (priv->alarm_uid_hash, set_alarm_description_cb, &sadd);
4274 }
4275
4276 /**
4277  * e_cal_component_get_transparency:
4278  * @comp: A calendar component object.
4279  * @transp: Return value for the time transparency.
4280  *
4281  * Queries the time transparency of a calendar component object.
4282  **/
4283 void
4284 e_cal_component_get_transparency (ECalComponent *comp, ECalComponentTransparency *transp)
4285 {
4286         ECalComponentPrivate *priv;
4287         icalproperty_transp ical_transp;
4288
4289         g_return_if_fail (comp != NULL);
4290         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
4291         g_return_if_fail (transp != NULL);
4292
4293         priv = comp->priv;
4294         g_return_if_fail (priv->icalcomp != NULL);
4295
4296         if (!priv->transparency) {
4297                 *transp = E_CAL_COMPONENT_TRANSP_NONE;
4298                 return;
4299         }
4300
4301         ical_transp = icalproperty_get_transp (priv->transparency);
4302
4303         switch (ical_transp)
4304         {
4305         case ICAL_TRANSP_TRANSPARENT:
4306         case ICAL_TRANSP_TRANSPARENTNOCONFLICT:
4307           *transp = E_CAL_COMPONENT_TRANSP_TRANSPARENT;
4308           break;
4309
4310         case ICAL_TRANSP_OPAQUE:
4311         case ICAL_TRANSP_OPAQUENOCONFLICT:
4312           *transp = E_CAL_COMPONENT_TRANSP_OPAQUE;
4313           break;
4314
4315         default:
4316           *transp = E_CAL_COMPONENT_TRANSP_UNKNOWN;
4317           break;
4318         }
4319 }
4320
4321 /**
4322  * e_cal_component_set_transparency:
4323  * @comp: A calendar component object.
4324  * @transp: Time transparency value.
4325  *
4326  * Sets the time transparency of a calendar component object.
4327  **/
4328 void
4329 e_cal_component_set_transparency (ECalComponent *comp, ECalComponentTransparency transp)
4330 {
4331         ECalComponentPrivate *priv;
4332         icalproperty_transp ical_transp;
4333
4334         g_return_if_fail (comp != NULL);
4335         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
4336         g_return_if_fail (transp != E_CAL_COMPONENT_TRANSP_UNKNOWN);
4337
4338         priv = comp->priv;
4339         g_return_if_fail (priv->icalcomp != NULL);
4340
4341
4342         if (transp == E_CAL_COMPONENT_TRANSP_NONE) {
4343                 if (priv->transparency) {
4344                         icalcomponent_remove_property (priv->icalcomp, priv->transparency);
4345                         icalproperty_free (priv->transparency);
4346                         priv->transparency = NULL;
4347                 }
4348
4349                 return;
4350         }
4351
4352         switch (transp) {
4353         case E_CAL_COMPONENT_TRANSP_TRANSPARENT:
4354           ical_transp = ICAL_TRANSP_TRANSPARENT;
4355                 break;
4356
4357         case E_CAL_COMPONENT_TRANSP_OPAQUE:
4358           ical_transp = ICAL_TRANSP_OPAQUE;
4359                 break;
4360
4361         default:
4362                 g_assert_not_reached ();
4363                 ical_transp = ICAL_TRANSP_NONE;
4364         }
4365
4366         if (priv->transparency)
4367                 icalproperty_set_transp (priv->transparency, ical_transp);
4368         else {
4369                 priv->transparency = icalproperty_new_transp (ical_transp);
4370                 icalcomponent_add_property (priv->icalcomp, priv->transparency);
4371         }
4372 }
4373
4374 /**
4375  * e_cal_component_get_url:
4376  * @comp: A calendar component object.
4377  * @url: Return value for the URL.
4378  *
4379  * Queries the uniform resource locator property of a calendar component object.
4380  **/
4381 void
4382 e_cal_component_get_url (ECalComponent *comp, const char **url)
4383 {
4384         ECalComponentPrivate *priv;
4385
4386         g_return_if_fail (comp != NULL);
4387         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
4388         g_return_if_fail (url != NULL);
4389
4390         priv = comp->priv;
4391         g_return_if_fail (priv->icalcomp != NULL);
4392
4393         if (priv->url)
4394                 *url = icalproperty_get_url (priv->url);
4395         else
4396                 *url = NULL;
4397 }
4398
4399 /**
4400  * e_cal_component_set_url:
4401  * @comp: A calendar component object.
4402  * @url: URL value.
4403  *
4404  * Sets the uniform resource locator property of a calendar component object.
4405  **/
4406 void
4407 e_cal_component_set_url (ECalComponent *comp, const char *url)
4408 {
4409         ECalComponentPrivate *priv;
4410
4411         g_return_if_fail (comp != NULL);
4412         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
4413
4414         priv = comp->priv;
4415         g_return_if_fail (priv->icalcomp != NULL);
4416
4417         if (!url || !(*url)) {
4418                 if (priv->url) {
4419                         icalcomponent_remove_property (priv->icalcomp, priv->url);
4420                         icalproperty_free (priv->url);
4421                         priv->url = NULL;
4422                 }
4423
4424                 return;
4425         }
4426
4427         if (priv->url)
4428                 icalproperty_set_url (priv->url, (char *) url);
4429         else {
4430                 priv->url = icalproperty_new_url ((char *) url);
4431                 icalcomponent_add_property (priv->icalcomp, priv->url);
4432         }
4433 }
4434
4435 /* Gets a text list value */
4436 static void
4437 get_attendee_list (GSList *attendee_list, GSList **al)
4438 {
4439         GSList *l;
4440
4441         *al = NULL;
4442
4443         if (!attendee_list)
4444                 return;
4445
4446         for (l = attendee_list; l; l = l->next) {
4447                 struct attendee *attendee;
4448                 ECalComponentAttendee *a;
4449
4450                 attendee = l->data;
4451                 g_assert (attendee->prop != NULL);
4452
4453                 a = g_new0 (ECalComponentAttendee, 1);
4454                 a->value = icalproperty_get_attendee (attendee->prop);
4455
4456                 if (attendee->member_param)
4457                         a->member = icalparameter_get_member (attendee->member_param);          
4458                 if (attendee->cutype_param)
4459                         a->cutype = icalparameter_get_cutype (attendee->cutype_param);
4460                 else
4461                         a->cutype = ICAL_CUTYPE_UNKNOWN;
4462                 if (attendee->role_param)
4463                         a->role = icalparameter_get_role (attendee->role_param);
4464                 else
4465                         a->role = ICAL_ROLE_REQPARTICIPANT;
4466                 if (attendee->partstat_param)
4467                         a->status = icalparameter_get_partstat (attendee->partstat_param);
4468                 else
4469                         a->status = ICAL_PARTSTAT_NEEDSACTION;
4470                 if (attendee->rsvp_param && icalparameter_get_rsvp (attendee->rsvp_param) == ICAL_RSVP_TRUE)
4471                         a->rsvp = TRUE;
4472                 else
4473                         a->rsvp = FALSE;
4474                 if (attendee->delfrom_param)
4475                         a->delfrom = icalparameter_get_delegatedfrom (attendee->delfrom_param);
4476                 if (attendee->delto_param)
4477                         a->delto = icalparameter_get_delegatedto (attendee->delto_param);
4478                 if (attendee->sentby_param)
4479                         a->sentby = icalparameter_get_sentby (attendee->sentby_param);
4480                 if (attendee->cn_param)
4481                         a->cn = icalparameter_get_cn (attendee->cn_param);
4482                 if (attendee->language_param)
4483                         a->language = icalparameter_get_language (attendee->language_param);
4484
4485                 *al = g_slist_prepend (*al, a);
4486         }
4487
4488         *al = g_slist_reverse (*al);
4489 }
4490
4491
4492 /* Sets a text list value */
4493 static void
4494 set_attendee_list (icalcomponent *icalcomp,
4495                    GSList **attendee_list,
4496                    GSList *al)
4497 {
4498         GSList *l;
4499
4500         /* Remove old attendees */
4501
4502         for (l = *attendee_list; l; l = l->next) {
4503                 struct attendee *attendee;
4504
4505                 attendee = l->data;
4506                 g_assert (attendee->prop != NULL);
4507
4508                 icalcomponent_remove_property (icalcomp, attendee->prop);
4509                 icalproperty_free (attendee->prop);
4510                 g_free (attendee);
4511         }
4512
4513         g_slist_free (*attendee_list);
4514         *attendee_list = NULL;
4515
4516         /* Add in new attendees */
4517
4518         for (l = al; l; l = l->next) {
4519                 ECalComponentAttendee *a;
4520                 struct attendee *attendee;
4521
4522                 a = l->data;
4523                 g_return_if_fail (a->value != NULL);
4524
4525                 attendee = g_new0 (struct attendee, 1);
4526
4527                 attendee->prop = icalproperty_new_attendee (a->value);
4528                 icalcomponent_add_property (icalcomp, attendee->prop);
4529
4530                 if (a->member) {
4531                         attendee->member_param = icalparameter_new_member (a->member);
4532                         icalproperty_add_parameter (attendee->prop, attendee->member_param);
4533                 }
4534
4535                 attendee->cutype_param = icalparameter_new_cutype (a->cutype);
4536                 icalproperty_add_parameter (attendee->prop, attendee->cutype_param);
4537
4538                 attendee->role_param = icalparameter_new_role (a->role);
4539                 icalproperty_add_parameter (attendee->prop, attendee->role_param);
4540
4541                 attendee->partstat_param = icalparameter_new_partstat (a->status);
4542                 icalproperty_add_parameter (attendee->prop, attendee->partstat_param);
4543
4544                 if (a->rsvp)
4545                         attendee->rsvp_param = icalparameter_new_rsvp (ICAL_RSVP_TRUE);
4546                 else
4547                         attendee->rsvp_param = icalparameter_new_rsvp (ICAL_RSVP_FALSE);
4548                 icalproperty_add_parameter (attendee->prop, attendee->rsvp_param);
4549         
4550                 if (a->delfrom) {
4551                         attendee->delfrom_param = icalparameter_new_delegatedfrom (a->delfrom);
4552                         icalproperty_add_parameter (attendee->prop, attendee->delfrom_param);
4553                 }
4554                 if (a->delto) {
4555                         attendee->delto_param = icalparameter_new_delegatedto (a->delto);
4556                         icalproperty_add_parameter (attendee->prop, attendee->delto_param);
4557                 }
4558                 if (a->sentby) {
4559                         attendee->sentby_param = icalparameter_new_sentby (a->sentby);
4560                         icalproperty_add_parameter (attendee->prop, attendee->sentby_param);
4561                 }
4562                 if (a->cn) {
4563                         attendee->cn_param = icalparameter_new_cn (a->cn);
4564                         icalproperty_add_parameter (attendee->prop, attendee->cn_param);
4565                 }
4566                 if (a->language) {
4567                         attendee->language_param = icalparameter_new_language (a->language);
4568                         icalproperty_add_parameter (attendee->prop, attendee->language_param);
4569                 }
4570
4571                 *attendee_list = g_slist_prepend (*attendee_list, attendee);
4572         }
4573
4574         *attendee_list = g_slist_reverse (*attendee_list);
4575 }
4576
4577 /**
4578  * e_cal_component_get_attendee_list: 
4579  * @comp: A calendar component object. 
4580  * @attendee_list: Return value for the attendee property.
4581  * This should be freed using the e_cal_component_free_attendee_list ()
4582  * function.
4583  * 
4584  * Queries the attendee properties of the calendar component object
4585  **/
4586 void
4587 e_cal_component_get_attendee_list (ECalComponent *comp, GSList **attendee_list)
4588 {
4589         ECalComponentPrivate *priv;
4590         
4591         g_return_if_fail (comp != NULL);
4592         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
4593         g_return_if_fail (attendee_list != NULL);
4594
4595         priv = comp->priv;
4596         g_return_if_fail (priv->icalcomp != NULL);
4597
4598         get_attendee_list (priv->attendee_list, attendee_list);
4599 }
4600
4601 /**
4602  * e_cal_component_set_attendee_list:
4603  * @comp: A calendar component object. 
4604  * @attendee_list: Values for attendee properties
4605  * 
4606  * Sets the attendees of a calendar component object
4607  **/
4608 void
4609 e_cal_component_set_attendee_list (ECalComponent *comp, GSList *attendee_list)
4610 {
4611         ECalComponentPrivate *priv;
4612
4613         g_return_if_fail (comp != NULL);
4614         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
4615
4616         priv = comp->priv;
4617         g_return_if_fail (priv->icalcomp != NULL);
4618
4619         set_attendee_list (priv->icalcomp, &priv->attendee_list, attendee_list);
4620 }
4621
4622 /**
4623  * e_cal_component_has_attendees:
4624  * @comp: A calendar component object.
4625  *
4626  * Queries a calendar component object for the existence of attendees.
4627  *
4628  * Return value: TRUE if there are attendees, FALSE if not.
4629  */
4630 gboolean
4631 e_cal_component_has_attendees (ECalComponent *comp)
4632 {
4633         ECalComponentPrivate *priv;
4634
4635         g_return_val_if_fail (comp != NULL, FALSE);
4636         g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), FALSE);
4637
4638         priv = comp->priv;
4639
4640         if (g_slist_length (priv->attendee_list) > 0)
4641                 return TRUE;
4642         
4643         return FALSE;
4644 }
4645
4646 /**
4647  * e_cal_component_get_location:
4648  * @comp: A calendar component object
4649  * @location: Return value for the location.
4650  * 
4651  * Queries the location property of a calendar component object.
4652  **/
4653 void
4654 e_cal_component_get_location (ECalComponent *comp, const char **location)
4655 {
4656         ECalComponentPrivate *priv;
4657
4658         g_return_if_fail (comp != NULL);
4659         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
4660         g_return_if_fail (location != NULL);
4661
4662         priv = comp->priv;
4663         g_return_if_fail (priv->icalcomp != NULL);
4664
4665         if (priv->location)
4666                 *location = icalproperty_get_location (priv->location);
4667         else
4668                 *location = NULL;
4669 }
4670
4671 /**
4672  * e_cal_component_set_location:
4673  * @comp: A calendar component object.
4674  * @location: Location value.
4675  * 
4676  * Sets the location property of a calendar component object.
4677  **/
4678 void
4679 e_cal_component_set_location (ECalComponent *comp, const char *location)
4680 {
4681         ECalComponentPrivate *priv;
4682
4683         g_return_if_fail (comp != NULL);
4684         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
4685
4686         priv = comp->priv;
4687         g_return_if_fail (priv->icalcomp != NULL);
4688
4689         if (!location || !(*location)) {
4690                 if (priv->location) {
4691                         icalcomponent_remove_property (priv->icalcomp, priv->location);
4692                         icalproperty_free (priv->location);
4693                         priv->location = NULL;
4694                 }
4695
4696                 return;
4697         }
4698
4699         if (priv->location)
4700                 icalproperty_set_location (priv->location, (char *) location);
4701         else {
4702                 priv->location = icalproperty_new_location ((char *) location);
4703                 icalcomponent_add_property (priv->icalcomp, priv->location);
4704         }
4705 }
4706
4707 \f
4708
4709 /**
4710  * e_cal_component_free_categories_list:
4711  * @categ_list: List of category strings.
4712  *
4713  * Frees a list of category strings.
4714  **/
4715 void
4716 e_cal_component_free_categories_list (GSList *categ_list)
4717 {
4718         GSList *l;
4719
4720         for (l = categ_list; l; l = l->next)
4721                 g_free (l->data);
4722
4723         g_slist_free (categ_list);
4724 }
4725
4726 /**
4727  * e_cal_component_free_datetime:
4728  * @dt: A date/time structure.
4729  *
4730  * Frees a date/time structure.
4731  **/
4732 void
4733 e_cal_component_free_datetime (ECalComponentDateTime *dt)
4734 {
4735         g_return_if_fail (dt != NULL);
4736
4737         g_free (dt->value);
4738         g_free ((char*)dt->tzid);
4739 }
4740
4741 /**
4742  * e_cal_component_free_range:
4743  * @range: A #ECalComponentRange.
4744  *
4745  * Frees an #ECalComponentRange structure.
4746  */
4747 void 
4748 e_cal_component_free_range (ECalComponentRange *range)
4749 {
4750         g_return_if_fail (range != NULL);
4751
4752         e_cal_component_free_datetime (&range->datetime);
4753 }
4754
4755 /**
4756  * e_cal_component_free_exdate_list:
4757  * @exdate_list: List of #ECalComponentDateTime structures.
4758  *
4759  * Frees a list of #ECalComponentDateTime structures as returned by the
4760  * e_cal_component_get_exdate_list() function.
4761  **/
4762 void
4763 e_cal_component_free_exdate_list (GSList *exdate_list)
4764 {
4765         GSList *l;
4766
4767         for (l = exdate_list; l; l = l->next) {
4768                 ECalComponentDateTime *cdt;
4769
4770                 g_assert (l->data != NULL);
4771                 cdt = l->data;
4772
4773                 g_assert (cdt->value != NULL);
4774                 g_free (cdt->value);
4775                 g_free ((char*)cdt->tzid);
4776
4777                 g_free (cdt);
4778         }
4779
4780         g_slist_free (exdate_list);
4781 }
4782
4783 /**
4784  * e_cal_component_free_geo:
4785  * @geo: An #icalgeotype structure.
4786  *
4787  * Frees a struct #icalgeotype structure as returned by the calendar component
4788  * functions.
4789  **/
4790 void
4791 e_cal_component_free_geo (struct icalgeotype *geo)
4792 {
4793         g_return_if_fail (geo != NULL);
4794
4795         g_free (geo);
4796 }
4797
4798 /**
4799  * e_cal_component_free_icaltimetype:
4800  * @t: An #icaltimetype structure.
4801  *
4802  * Frees a struct #icaltimetype value as returned by the calendar component
4803  * functions.
4804  **/
4805 void
4806 e_cal_component_free_icaltimetype (struct icaltimetype *t)
4807 {
4808         g_return_if_fail (t != NULL);
4809
4810         g_free (t);
4811 }
4812
4813 /**
4814  * e_cal_component_free_percent:
4815  * @percent: Percent value.
4816  *
4817  * Frees a percent value as returned by the e_cal_component_get_percent()
4818  * function.
4819  **/
4820 void
4821 e_cal_component_free_percent (int *percent)
4822 {
4823         g_return_if_fail (percent != NULL);
4824
4825         g_free (percent);
4826 }
4827
4828 /**
4829  * e_cal_component_free_priority:
4830  * @priority: Priority value.
4831  *
4832  * Frees a priority value as returned by the e_cal_component_get_priority()
4833  * function.
4834  **/
4835 void
4836 e_cal_component_free_priority (int *priority)
4837 {
4838         g_return_if_fail (priority != NULL);
4839
4840         g_free (priority);
4841 }
4842
4843 /**
4844  * e_cal_component_free_period_list:
4845  * @period_list: List of #ECalComponentPeriod structures.
4846  *
4847  * Frees a list of #ECalComponentPeriod structures.
4848  **/
4849 void
4850 e_cal_component_free_period_list (GSList *period_list)
4851 {
4852         GSList *l;
4853
4854         for (l = period_list; l; l = l->next) {
4855                 ECalComponentPeriod *period;
4856
4857                 g_assert (l->data != NULL);
4858
4859                 period = l->data;
4860                 g_free (period);
4861         }
4862
4863         g_slist_free (period_list);
4864 }
4865
4866 /**
4867  * e_cal_component_free_recur_list:
4868  * @recur_list: List of struct #icalrecurrencetype structures.
4869  *
4870  * Frees a list of struct #icalrecurrencetype structures.
4871  **/
4872 void
4873 e_cal_component_free_recur_list (GSList *recur_list)
4874 {
4875         GSList *l;
4876
4877         for (l = recur_list; l; l = l->next) {
4878                 struct icalrecurrencetype *r;
4879
4880                 g_assert (l->data != NULL);
4881                 r = l->data;
4882
4883                 g_free (r);
4884         }
4885
4886         g_slist_free (recur_list);
4887 }
4888
4889 /**
4890  * e_cal_component_free_sequence:
4891  * @sequence: Sequence number value.
4892  *
4893  * Frees a sequence number value.
4894  **/
4895 void
4896 e_cal_component_free_sequence (int *sequence)
4897 {
4898         g_return_if_fail (sequence != NULL);
4899
4900         g_free (sequence);
4901 }
4902
4903 /**
4904  * e_cal_component_free_id:
4905  * @id: Component ID
4906  *
4907  * Frees the id.
4908  **/
4909 void
4910 e_cal_component_free_id (ECalComponentId *id)
4911 {
4912         g_return_if_fail (id != NULL);
4913
4914         if (id->uid) {
4915                 g_free (id->uid);
4916                 id->uid = NULL;
4917         }
4918         
4919         if (id->rid) {
4920                 g_free (id->rid);
4921                 id->rid = NULL;
4922         }
4923
4924         g_free (id);
4925 }
4926
4927 /**
4928  * e_cal_component_free_text_list:
4929  * @text_list: List of #ECalComponentText structures.
4930  *
4931  * Frees a list of #ECalComponentText structures.  This function should only be
4932  * used to free lists of text values as returned by the other getter functions
4933  * of #ECalComponent.
4934  **/
4935 void
4936 e_cal_component_free_text_list (GSList *text_list)
4937 {
4938         GSList *l;
4939
4940         for (l = text_list; l; l = l->next) {
4941                 ECalComponentText *text;
4942
4943                 g_assert (l->data != NULL);
4944
4945                 text = l->data;
4946                 g_return_if_fail (text != NULL);
4947                 g_free (text);
4948         }
4949
4950         g_slist_free (text_list);
4951 }
4952
4953 /**
4954  * e_cal_component_free_attendee_list:
4955  * @attendee_list:  List of attendees.
4956  * 
4957  * Frees a list of #ECalComponentAttendee structures.
4958  * 
4959  **/
4960 void
4961 e_cal_component_free_attendee_list (GSList *attendee_list)
4962 {
4963         GSList *l;
4964
4965         for (l = attendee_list; l; l = l->next) {
4966                 ECalComponentAttendee *attendee;
4967
4968                 g_assert (l->data != NULL);
4969
4970                 attendee = l->data;
4971                 g_return_if_fail (attendee != NULL);
4972                 g_free (attendee);
4973         }
4974
4975         g_slist_free (attendee_list);
4976 }
4977
4978 \f
4979
4980 /**
4981  * e_cal_component_has_alarms:
4982  * @comp: A calendar component object.
4983  *
4984  * Checks whether the component has any alarms.
4985  *
4986  * Return value: TRUE if the component has any alarms.
4987  **/
4988 gboolean
4989 e_cal_component_has_alarms (ECalComponent *comp)
4990 {
4991         ECalComponentPrivate *priv;
4992
4993         g_return_val_if_fail (comp != NULL, FALSE);
4994         g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), FALSE);
4995
4996         priv = comp->priv;
4997         g_return_val_if_fail (priv->icalcomp != NULL, FALSE);
4998
4999         return g_hash_table_size (priv->alarm_uid_hash) != 0;
5000 }
5001
5002 /**
5003  * e_cal_component_add_alarm:
5004  * @comp: A calendar component.
5005  * @alarm: An alarm.
5006  * 
5007  * Adds an alarm subcomponent to a calendar component.  You should have created
5008  * the @alarm by using e_cal_component_alarm_new(); it is invalid to use a
5009  * #ECalComponentAlarm structure that came from e_cal_component_get_alarm().  After
5010  * adding the alarm, the @alarm structure is no longer valid because the
5011  * internal structures may change and you should get rid of it by using
5012  * e_cal_component_alarm_free().
5013  **/
5014 void
5015 e_cal_component_add_alarm (ECalComponent *comp, ECalComponentAlarm *alarm)
5016 {
5017         ECalComponentPrivate *priv;
5018
5019         g_return_if_fail (comp != NULL);
5020         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
5021         g_return_if_fail (alarm != NULL);
5022
5023         priv = comp->priv;
5024
5025         add_alarm (comp, alarm->icalcomp, icalproperty_get_x (alarm->uid));
5026         icalcomponent_add_component (priv->icalcomp, alarm->icalcomp);
5027 }
5028
5029 /**
5030  * e_cal_component_remove_alarm:
5031  * @comp: A calendar component.
5032  * @auid: UID of the alarm to remove.
5033  * 
5034  * Removes an alarm subcomponent from a calendar component.  If the alarm that
5035  * corresponds to the specified @auid had been fetched with
5036  * e_cal_component_get_alarm(), then those alarm structures will be invalid; you
5037  * should get rid of them with e_cal_component_alarm_free() before using this
5038  * function.
5039  **/
5040 void
5041 e_cal_component_remove_alarm (ECalComponent *comp, const char *auid)
5042 {
5043         ECalComponentPrivate *priv;
5044         icalcomponent *alarm;
5045
5046         g_return_if_fail (comp != NULL);
5047         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
5048         g_return_if_fail (auid != NULL);
5049
5050         priv = comp->priv;
5051         g_return_if_fail (priv->icalcomp != NULL);
5052
5053         alarm = g_hash_table_lookup (priv->alarm_uid_hash, auid);
5054         if (!alarm)
5055                 return;
5056
5057         g_hash_table_remove (priv->alarm_uid_hash, auid);
5058         icalcomponent_remove_component (priv->icalcomp, alarm);
5059         icalcomponent_free (alarm);
5060 }
5061
5062 static gboolean
5063 for_each_remove_all_alarms (gpointer key, gpointer value, gpointer data)
5064 {
5065         ECalComponent *comp = E_CAL_COMPONENT (data);
5066         ECalComponentPrivate *priv;
5067         icalcomponent *alarm = value;
5068         
5069         priv = comp->priv;
5070         
5071         icalcomponent_remove_component (priv->icalcomp, alarm);
5072         icalcomponent_free (alarm);
5073
5074         return TRUE;    
5075 }
5076
5077 /**
5078  * e_cal_component_remove_all_alarms:
5079  * @comp: A calendar component
5080  * 
5081  * Remove all alarms from the calendar component
5082  **/
5083 void
5084 e_cal_component_remove_all_alarms (ECalComponent *comp)
5085 {
5086         ECalComponentPrivate *priv;
5087
5088         g_return_if_fail (comp != NULL);
5089         g_return_if_fail (E_IS_CAL_COMPONENT (comp));
5090
5091         priv = comp->priv;
5092         g_return_if_fail (priv->icalcomp != NULL);
5093
5094         g_hash_table_foreach_remove (priv->alarm_uid_hash, for_each_remove_all_alarms, comp);
5095 }
5096
5097
5098 /* Scans an icalproperty from a calendar component and adds its mapping to our
5099  * own alarm structure.
5100  */
5101 static void
5102 scan_alarm_property (ECalComponentAlarm *alarm, icalproperty *prop)
5103 {
5104         icalproperty_kind kind;
5105         const char *xname;
5106
5107         kind = icalproperty_isa (prop);
5108
5109         switch (kind) {
5110         case ICAL_ACTION_PROPERTY:
5111                 alarm->action = prop;
5112                 break;
5113
5114         case ICAL_ATTACH_PROPERTY:
5115                 /* FIXME: mail alarms may have any number of these, not just one */
5116                 alarm->attach = prop;
5117                 break;
5118
5119         case ICAL_DESCRIPTION_PROPERTY:
5120                 alarm->description.prop = prop;
5121                 alarm->description.altrep_param = icalproperty_get_first_parameter (
5122                         prop, ICAL_ALTREP_PARAMETER);
5123                 break;
5124
5125         case ICAL_DURATION_PROPERTY:
5126                 alarm->duration = prop;
5127                 break;
5128
5129         case ICAL_REPEAT_PROPERTY:
5130                 alarm->repeat = prop;
5131                 break;
5132
5133         case ICAL_TRIGGER_PROPERTY:
5134                 alarm->trigger = prop;
5135                 break;
5136
5137         case ICAL_ATTENDEE_PROPERTY:
5138                 scan_attendee (&alarm->attendee_list, prop);
5139                 break;
5140                 
5141         case ICAL_X_PROPERTY:
5142                 xname = icalproperty_get_x_name (prop);
5143                 g_assert (xname != NULL);
5144
5145                 if (strcmp (xname, EVOLUTION_ALARM_UID_PROPERTY) == 0)
5146                         alarm->uid = prop;
5147
5148                 break;
5149
5150         default:
5151                 break;
5152         }
5153 }
5154
5155 /* Creates a ECalComponentAlarm from a libical alarm subcomponent */
5156 static ECalComponentAlarm *
5157 make_alarm (icalcomponent *subcomp)
5158 {
5159         ECalComponentAlarm *alarm;
5160         icalproperty *prop;
5161
5162         alarm = g_new (ECalComponentAlarm, 1);
5163
5164         alarm->icalcomp = subcomp;
5165         alarm->uid = NULL;
5166
5167         alarm->action = NULL;
5168         alarm->attach = NULL;
5169         alarm->description.prop = NULL;
5170         alarm->description.altrep_param = NULL;
5171         alarm->duration = NULL;
5172         alarm->repeat = NULL;
5173         alarm->trigger = NULL;
5174         alarm->attendee_list = NULL;
5175         
5176         for (prop = icalcomponent_get_first_property (subcomp, ICAL_ANY_PROPERTY);
5177              prop;
5178              prop = icalcomponent_get_next_property (subcomp, ICAL_ANY_PROPERTY))
5179                 scan_alarm_property (alarm, prop);
5180
5181         g_assert (alarm->uid != NULL);
5182
5183         return alarm;
5184 }
5185
5186 /**
5187  * e_cal_component_get_alarm_uids:
5188  * @comp: A calendar component.
5189  *
5190  * Builds a list of the unique identifiers of the alarm subcomponents inside a
5191  * calendar component.
5192  *
5193  * Return value: List of unique identifiers for alarms.  This should be freed
5194  * using cal_obj_uid_list_free().
5195  **/
5196 GList *
5197 e_cal_component_get_alarm_uids (ECalComponent *comp)
5198 {
5199         ECalComponentPrivate *priv;
5200         icalcompiter iter;
5201         GList *l;
5202
5203         g_return_val_if_fail (comp != NULL, NULL);
5204         g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
5205
5206         priv = comp->priv;
5207         g_return_val_if_fail (priv->icalcomp != NULL, NULL);
5208
5209         l = NULL;
5210         for (iter = icalcomponent_begin_component (priv->icalcomp, ICAL_VALARM_COMPONENT);
5211              icalcompiter_deref (&iter) != NULL;
5212              icalcompiter_next (&iter)) {
5213                 icalcomponent *subcomp;
5214                 icalproperty *prop;
5215                 
5216                 subcomp = icalcompiter_deref (&iter);
5217                 for (prop = icalcomponent_get_first_property (subcomp, ICAL_X_PROPERTY);
5218                      prop;
5219                      prop = icalcomponent_get_next_property (subcomp, ICAL_X_PROPERTY)) {
5220                         const char *xname;
5221                         
5222                         xname = icalproperty_get_x_name (prop);
5223                         g_assert (xname != NULL);
5224                         
5225                         if (strcmp (xname, EVOLUTION_ALARM_UID_PROPERTY) == 0) {
5226                                 const char *auid;
5227                                 
5228                                 auid = alarm_uid_from_prop (prop);
5229                                 l = g_list_append (l, g_strdup (auid));
5230                         }
5231                 }
5232         }
5233
5234         return l;
5235 }
5236
5237 /**
5238  * e_cal_component_get_alarm:
5239  * @comp: A calendar component.
5240  * @auid: Unique identifier for the sought alarm subcomponent.
5241  *
5242  * Queries a particular alarm subcomponent of a calendar component.
5243  *
5244  * Return value: The alarm subcomponent that corresponds to the specified @auid,
5245  * or #NULL if no alarm exists with that UID.  This should be freed using
5246  * e_cal_component_alarm_free().
5247  **/
5248 ECalComponentAlarm *
5249 e_cal_component_get_alarm (ECalComponent *comp, const char *auid)
5250 {
5251         ECalComponentPrivate *priv;
5252         icalcomponent *alarm;
5253
5254         g_return_val_if_fail (comp != NULL, NULL);
5255         g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL);
5256
5257         priv = comp->priv;
5258         g_return_val_if_fail (priv->icalcomp != NULL, NULL);
5259
5260         g_return_val_if_fail (auid != NULL, NULL);
5261
5262         alarm = g_hash_table_lookup (priv->alarm_uid_hash, auid);
5263
5264         if (alarm)
5265                 return make_alarm (alarm);
5266         else
5267                 return NULL;
5268 }
5269
5270 /**
5271  * e_cal_component_alarms_free:
5272  * @alarms: Component alarms structure.
5273  *
5274  * Frees a #ECalComponentAlarms structure.
5275  **/
5276 void
5277 e_cal_component_alarms_free (ECalComponentAlarms *alarms)
5278 {
5279         GSList *l;
5280
5281         g_return_if_fail (alarms != NULL);
5282
5283         g_assert (alarms->comp != NULL);
5284         g_object_unref (G_OBJECT (alarms->comp));
5285
5286         for (l = alarms->alarms; l; l = l->next) {
5287                 ECalComponentAlarmInstance *instance;
5288
5289                 instance = l->data;
5290                 g_assert (instance != NULL);
5291                 g_free (instance);
5292         }
5293
5294         g_slist_free (alarms->alarms);
5295         g_free (alarms);
5296 }
5297
5298 /**
5299  * e_cal_component_alarm_new:
5300  *
5301  * Create a new alarm object.
5302  *
5303  * Return value: a new alarm component
5304  **/
5305 ECalComponentAlarm *
5306 e_cal_component_alarm_new (void)
5307 {
5308         ECalComponentAlarm *alarm;
5309         char *new_auid ;
5310
5311         alarm = g_new (ECalComponentAlarm, 1);
5312
5313         alarm->icalcomp = icalcomponent_new (ICAL_VALARM_COMPONENT);
5314
5315         new_auid = e_cal_component_gen_uid ();
5316         alarm->uid = icalproperty_new_x (new_auid);
5317         icalproperty_set_x_name (alarm->uid, EVOLUTION_ALARM_UID_PROPERTY);
5318         icalcomponent_add_property (alarm->icalcomp, alarm->uid);
5319         g_free (new_auid);
5320
5321         alarm->action = NULL;
5322         alarm->attach = NULL;
5323         alarm->description.prop = NULL;
5324         alarm->description.altrep_param = NULL;
5325         alarm->duration = NULL;
5326         alarm->repeat = NULL;
5327         alarm->trigger = NULL;
5328         alarm->attendee_list = NULL;
5329         
5330         return alarm;
5331 }
5332
5333 /**
5334  * e_cal_component_alarm_clone:
5335  * @alarm: An alarm subcomponent.
5336  * 
5337  * Creates a new alarm subcomponent by copying the information from another one.
5338  * 
5339  * Return value: A newly-created alarm subcomponent with the same values as the
5340  * original one.  Should be freed with e_cal_component_alarm_free().
5341  **/
5342 ECalComponentAlarm *
5343 e_cal_component_alarm_clone (ECalComponentAlarm *alarm)
5344 {
5345         icalcomponent *icalcomp;
5346
5347         g_return_val_if_fail (alarm != NULL, NULL);
5348
5349         icalcomp = icalcomponent_new_clone (alarm->icalcomp);
5350         return make_alarm (icalcomp);
5351 }
5352
5353 /**
5354  * e_cal_component_alarm_free:
5355  * @alarm: A calendar alarm.
5356  *
5357  * Frees an alarm structure.
5358  **/
5359 void
5360 e_cal_component_alarm_free (ECalComponentAlarm *alarm)
5361 {
5362         GSList *l;
5363         
5364         g_return_if_fail (alarm != NULL);
5365
5366         g_assert (alarm->icalcomp != NULL);
5367
5368         if (icalcomponent_get_parent (alarm->icalcomp) == NULL)
5369                 icalcomponent_free (alarm->icalcomp);
5370
5371         alarm->icalcomp = NULL;
5372         alarm->uid = NULL;
5373         alarm->action = NULL;
5374         alarm->attach = NULL;
5375         alarm->description.prop = NULL;
5376         alarm->description.altrep_param = NULL;
5377         alarm->duration = NULL;
5378         alarm->repeat = NULL;
5379         alarm->trigger = NULL;
5380
5381         for (l = alarm->attendee_list; l != NULL; l = l->next)
5382                 g_free (l->data);
5383         g_slist_free (alarm->attendee_list);
5384         alarm->attendee_list = NULL;
5385         
5386         g_free (alarm);
5387 }
5388
5389 /**
5390  * e_cal_component_alarm_get_uid:
5391  * @alarm: An alarm subcomponent.
5392  *
5393  * Queries the unique identifier of an alarm subcomponent.
5394  *
5395  * Return value: UID of the alarm.
5396  **/
5397 const char *
5398 e_cal_component_alarm_get_uid (ECalComponentAlarm *alarm)
5399 {
5400         g_return_val_if_fail (alarm != NULL, NULL);
5401
5402         return alarm_uid_from_prop (alarm->uid);
5403 }
5404
5405 /**
5406  * e_cal_component_alarm_get_action:
5407  * @alarm: An alarm.
5408  * @action: Return value for the alarm's action type.
5409  *
5410  * Queries the action type of an alarm.
5411  **/
5412 void
5413 e_cal_component_alarm_get_action (ECalComponentAlarm *alarm, ECalComponentAlarmAction *action)
5414 {
5415         enum icalproperty_action ipa;
5416
5417         g_return_if_fail (alarm != NULL);
5418         g_return_if_fail (action != NULL);
5419
5420         g_assert (alarm->icalcomp != NULL);
5421
5422         if (!alarm->action) {
5423                 *action = E_CAL_COMPONENT_ALARM_NONE;
5424                 return;
5425         }
5426
5427         ipa = icalproperty_get_action (alarm->action);
5428
5429         switch (ipa) {
5430         case ICAL_ACTION_AUDIO:
5431                 *action = E_CAL_COMPONENT_ALARM_AUDIO;
5432                 break;
5433
5434         case ICAL_ACTION_DISPLAY:
5435                 *action = E_CAL_COMPONENT_ALARM_DISPLAY;
5436                 break;
5437
5438         case ICAL_ACTION_EMAIL:
5439                 *action = E_CAL_COMPONENT_ALARM_EMAIL;
5440                 break;
5441
5442         case ICAL_ACTION_PROCEDURE:
5443                 *action = E_CAL_COMPONENT_ALARM_PROCEDURE;
5444                 break;
5445
5446         case ICAL_ACTION_NONE:
5447                 *action = E_CAL_COMPONENT_ALARM_NONE;
5448                 break;
5449
5450         default:
5451                 *action = E_CAL_COMPONENT_ALARM_UNKNOWN;
5452         }
5453 }
5454
5455 /**
5456  * e_cal_component_alarm_set_action:
5457  * @alarm: An alarm.
5458  * @action: Action type.
5459  *
5460  * Sets the action type for an alarm.
5461  **/
5462 void
5463 e_cal_component_alarm_set_action (ECalComponentAlarm *alarm, ECalComponentAlarmAction action)
5464 {
5465         enum icalproperty_action ipa;
5466
5467         g_return_if_fail (alarm != NULL);
5468         g_return_if_fail (action != E_CAL_COMPONENT_ALARM_NONE);
5469         g_return_if_fail (action != E_CAL_COMPONENT_ALARM_UNKNOWN);
5470
5471         g_assert (alarm->icalcomp != NULL);
5472
5473         switch (action) {
5474         case E_CAL_COMPONENT_ALARM_AUDIO:
5475                 ipa = ICAL_ACTION_AUDIO;
5476                 break;
5477
5478         case E_CAL_COMPONENT_ALARM_DISPLAY:
5479                 ipa = ICAL_ACTION_DISPLAY;
5480                 break;
5481
5482         case E_CAL_COMPONENT_ALARM_EMAIL:
5483                 ipa = ICAL_ACTION_EMAIL;
5484                 break;
5485
5486         case E_CAL_COMPONENT_ALARM_PROCEDURE:
5487                 ipa = ICAL_ACTION_PROCEDURE;
5488                 break;
5489
5490         default:
5491                 g_assert_not_reached ();
5492                 ipa = ICAL_ACTION_NONE;
5493         }
5494
5495         if (alarm->action)
5496                 icalproperty_set_action (alarm->action, ipa);
5497         else {
5498                 alarm->action = icalproperty_new_action (ipa);
5499                 icalcomponent_add_property (alarm->icalcomp, alarm->action);
5500         }
5501 }
5502
5503 /**
5504  * e_cal_component_alarm_get_attach:
5505  * @alarm: An alarm.
5506  * @attach: Return value for the attachment; should be freed using icalattach_unref().
5507  * 
5508  * Queries the attachment property of an alarm.
5509  **/
5510 void
5511 e_cal_component_alarm_get_attach (ECalComponentAlarm *alarm, icalattach **attach)
5512 {
5513         g_return_if_fail (alarm != NULL);
5514         g_return_if_fail (attach != NULL);
5515
5516         g_assert (alarm->icalcomp != NULL);
5517
5518         if (alarm->attach) {
5519                 *attach = icalproperty_get_attach (alarm->attach);
5520                 icalattach_ref (*attach);
5521         } else
5522                 *attach = NULL;
5523 }
5524
5525 /**
5526  * e_cal_component_alarm_set_attach:
5527  * @alarm: An alarm.
5528  * @attach: Attachment property or NULL to remove an existing property.
5529  * 
5530  * Sets the attachment property of an alarm.
5531  **/
5532 void
5533 e_cal_component_alarm_set_attach (ECalComponentAlarm *alarm, icalattach *attach)
5534 {
5535         g_return_if_fail (alarm != NULL);
5536
5537         g_assert (alarm->icalcomp != NULL);
5538
5539         if (alarm->attach) {
5540                 icalcomponent_remove_property (alarm->icalcomp, alarm->attach);
5541                 icalproperty_free (alarm->attach);
5542                 alarm->attach = NULL;
5543         }
5544
5545         if (attach) {
5546                 alarm->attach = icalproperty_new_attach (attach);
5547                 icalcomponent_add_property (alarm->icalcomp, alarm->attach);
5548         }
5549 }
5550
5551 /**
5552  * e_cal_component_alarm_get_description:
5553  * @alarm: An alarm.
5554  * @description: Return value for the description property and its parameters.
5555  * 
5556  * Queries the description property of an alarm.
5557  **/
5558 void
5559 e_cal_component_alarm_get_description (ECalComponentAlarm *alarm, ECalComponentText *description)
5560 {
5561         g_return_if_fail (alarm != NULL);
5562         g_return_if_fail (description != NULL);
5563
5564         g_assert (alarm->icalcomp != NULL);
5565
5566         if (alarm->description.prop)
5567                 description->value = icalproperty_get_description (alarm->description.prop);
5568         else
5569                 description->value = NULL;
5570
5571         if (alarm->description.altrep_param)
5572                 description->altrep = icalparameter_get_altrep (alarm->description.altrep_param);
5573         else
5574                 description->altrep = NULL;
5575 }
5576
5577 /**
5578  * e_cal_component_alarm_set_description:
5579  * @alarm: An alarm.
5580  * @description: Description property and its parameters, or NULL for no description.
5581  * 
5582  * Sets the description property of an alarm.
5583  **/
5584 void
5585 e_cal_component_alarm_set_description (ECalComponentAlarm *alarm, ECalComponentText *description)
5586 {
5587         g_return_if_fail (alarm != NULL);
5588
5589         g_assert (alarm->icalcomp != NULL);
5590
5591         if (alarm->description.prop) {
5592                 icalcomponent_remove_property (alarm->icalcomp, alarm->description.prop);
5593                 icalproperty_free (alarm->description.prop);
5594
5595                 alarm->description.prop = NULL;
5596                 alarm->description.altrep_param = NULL;
5597         }
5598
5599         if (!description)
5600                 return;
5601
5602         g_return_if_fail (description->value != NULL);
5603
5604         alarm->description.prop = icalproperty_new_description (description->value);
5605         icalcomponent_add_property (alarm->icalcomp, alarm->description.prop);
5606
5607         if (description->altrep) {
5608                 alarm->description.altrep_param = icalparameter_new_altrep (
5609                         (char *) description->altrep);
5610                 icalproperty_add_parameter (alarm->description.prop,
5611                                             alarm->description.altrep_param);
5612         }
5613 }
5614
5615 /**
5616  * e_cal_component_alarm_get_repeat:
5617  * @alarm: An alarm.
5618  * @repeat: Return value for the repeat/duration properties.
5619  * 
5620  * Queries the repeat/duration properties of an alarm.
5621  **/
5622 void
5623 e_cal_component_alarm_get_repeat (ECalComponentAlarm *alarm, ECalComponentAlarmRepeat *repeat)
5624 {
5625         g_return_if_fail (alarm != NULL);
5626         g_return_if_fail (repeat != NULL);
5627
5628         g_assert (alarm->icalcomp != NULL);
5629
5630         if (!(alarm->repeat && alarm->duration)) {
5631                 repeat->repetitions = 0;
5632                 memset (&repeat->duration, 0, sizeof (repeat->duration));
5633                 return;
5634         }
5635
5636         repeat->repetitions = icalproperty_get_repeat (alarm->repeat);
5637         repeat->duration = icalproperty_get_duration (alarm->duration);
5638 }
5639
5640 /**
5641  * e_cal_component_alarm_set_repeat:
5642  * @alarm: An alarm.
5643  * @repeat: Repeat/duration values.  To remove any repetitions from the alarm,
5644  * set the @repeat.repetitions to 0.
5645  * 
5646  * Sets the repeat/duration values for an alarm.
5647  **/
5648 void
5649 e_cal_component_alarm_set_repeat (ECalComponentAlarm *alarm, ECalComponentAlarmRepeat repeat)
5650 {
5651         g_return_if_fail (alarm != NULL);
5652         g_return_if_fail (repeat.repetitions >= 0);
5653
5654         g_assert (alarm->icalcomp != NULL);
5655
5656         /* Delete old properties */
5657
5658         if (alarm->repeat) {
5659                 icalcomponent_remove_property (alarm->icalcomp, alarm->repeat);
5660                 icalproperty_free (alarm->repeat);
5661                 alarm->repeat = NULL;
5662         }
5663
5664         if (alarm->duration) {
5665                 icalcomponent_remove_property (alarm->icalcomp, alarm->duration);
5666                 icalproperty_free (alarm->duration);
5667                 alarm->duration = NULL;
5668         }
5669
5670         /* Set the new properties */
5671
5672         if (repeat.repetitions == 0)
5673                 return; /* For zero extra repetitions the properties should not exist */
5674
5675         alarm->repeat = icalproperty_new_repeat (repeat.repetitions);
5676         icalcomponent_add_property (alarm->icalcomp, alarm->repeat);
5677
5678         alarm->duration = icalproperty_new_duration (repeat.duration);
5679         icalcomponent_add_property (alarm->icalcomp, alarm->duration);
5680 }
5681
5682 /**
5683  * e_cal_component_alarm_get_trigger:
5684  * @alarm: An alarm.
5685  * @trigger: Return value for the trigger time.
5686  *
5687  * Queries the trigger time for an alarm.
5688  **/
5689 void
5690 e_cal_component_alarm_get_trigger (ECalComponentAlarm *alarm, ECalComponentAlarmTrigger *trigger)
5691 {
5692         icalparameter *param;
5693         struct icaltriggertype t;
5694         gboolean relative;
5695
5696         g_return_if_fail (alarm != NULL);
5697         g_return_if_fail (trigger != NULL);
5698
5699         g_assert (alarm->icalcomp != NULL);
5700
5701         if (!alarm->trigger) {
5702                 trigger->type = E_CAL_COMPONENT_ALARM_TRIGGER_NONE;
5703                 return;
5704         }
5705
5706         /* Get trigger type */
5707
5708         param = icalproperty_get_first_parameter (alarm->trigger, ICAL_VALUE_PARAMETER);
5709         if (param) {
5710                 icalparameter_value value;
5711
5712                 value = icalparameter_get_value (param);
5713
5714                 switch (value) {
5715                 case ICAL_VALUE_DURATION:
5716                         relative = TRUE;
5717                         break;
5718
5719                 case ICAL_VALUE_DATETIME:
5720                         relative = FALSE;
5721                         break;
5722
5723                 default:
5724                         g_message ("e_cal_component_alarm_get_trigger(): Unknown value for trigger "
5725                                    "value %d; using RELATIVE", value);
5726
5727                         relative = TRUE;
5728                         break;
5729                 }
5730         } else
5731                 relative = TRUE;
5732
5733         /* Get trigger value and the RELATED parameter */
5734
5735         t = icalproperty_get_trigger (alarm->trigger);
5736
5737         if (relative) {
5738                 trigger->u.rel_duration = t.duration;
5739
5740                 param = icalproperty_get_first_parameter (alarm->trigger, ICAL_RELATED_PARAMETER);
5741                 if (param) {
5742                         icalparameter_related rel;
5743
5744                         rel = icalparameter_get_related (param);
5745
5746                         switch (rel) {
5747                         case ICAL_RELATED_START:
5748                                 trigger->type = E_CAL_COMPONENT_ALARM_TRIGGER_RELATIVE_START;
5749                                 break;
5750
5751                         case ICAL_RELATED_END:
5752                                 trigger->type = E_CAL_COMPONENT_ALARM_TRIGGER_RELATIVE_END;
5753                                 break;
5754
5755                         default:
5756                                 g_assert_not_reached ();
5757                         }
5758                 } else
5759                         trigger->type = E_CAL_COMPONENT_ALARM_TRIGGER_RELATIVE_START;
5760         } else {
5761                 trigger->u.abs_time = t.time;
5762                 trigger->type = E_CAL_COMPONENT_ALARM_TRIGGER_ABSOLUTE;
5763         }
5764 }
5765
5766 /**
5767  * e_cal_component_alarm_set_trigger:
5768  * @alarm: An alarm.
5769  * @trigger: Trigger time structure.
5770  *
5771  * Sets the trigger time of an alarm.
5772  **/
5773 void
5774 e_cal_component_alarm_set_trigger (ECalComponentAlarm *alarm, ECalComponentAlarmTrigger trigger)
5775 {
5776         struct icaltriggertype t;
5777         icalparameter *param;
5778         icalparameter_value value_type;
5779         icalparameter_related related;
5780
5781         g_return_if_fail (alarm != NULL);
5782         g_return_if_fail (trigger.type != E_CAL_COMPONENT_ALARM_TRIGGER_NONE);
5783
5784         g_assert (alarm->icalcomp != NULL);
5785
5786         /* Delete old trigger */
5787
5788         if (alarm->trigger) {
5789                 icalcomponent_remove_property (alarm->icalcomp, alarm->trigger);
5790                 icalproperty_free (alarm->trigger);
5791                 alarm->trigger = NULL;
5792         }
5793
5794         /* Set the value */
5795
5796         related = ICAL_RELATED_START; /* Keep GCC happy */
5797
5798         t.time = icaltime_null_time ();
5799         t.duration = icaldurationtype_null_duration ();
5800         switch (trigger.type) {
5801         case E_CAL_COMPONENT_ALARM_TRIGGER_RELATIVE_START:
5802                 t.duration = trigger.u.rel_duration;
5803                 value_type = ICAL_VALUE_DURATION;
5804                 related = ICAL_RELATED_START;
5805                 break;
5806
5807         case E_CAL_COMPONENT_ALARM_TRIGGER_RELATIVE_END:
5808                 t.duration = trigger.u.rel_duration;
5809                 value_type = ICAL_VALUE_DURATION;
5810                 related = ICAL_RELATED_END;
5811                 break;
5812
5813         case E_CAL_COMPONENT_ALARM_TRIGGER_ABSOLUTE:
5814                 t.time = trigger.u.abs_time;
5815                 value_type = ICAL_VALUE_DATETIME;
5816                 break;
5817
5818         default:
5819                 g_assert_not_reached ();
5820                 return;
5821         }
5822
5823         alarm->trigger = icalproperty_new_trigger (t);
5824         icalcomponent_add_property (alarm->icalcomp, alarm->trigger);
5825
5826         /* Value parameters */
5827
5828         param = icalproperty_get_first_parameter (alarm->trigger, ICAL_VALUE_PARAMETER);
5829         if (param)
5830                 icalparameter_set_value (param, value_type);
5831         else {
5832                 param = icalparameter_new_value (value_type);
5833                 icalproperty_add_parameter (alarm->trigger, param);
5834         }
5835
5836         /* Related parameter */
5837
5838         if (trigger.type != E_CAL_COMPONENT_ALARM_TRIGGER_ABSOLUTE) {
5839                 param = icalproperty_get_first_parameter (alarm->trigger, ICAL_RELATED_PARAMETER);
5840
5841                 if (param)
5842                         icalparameter_set_related (param, related);
5843                 else {
5844                         param = icalparameter_new_related (related);
5845                         icalproperty_add_parameter (alarm->trigger, param);
5846                 }
5847         }
5848 }
5849
5850 /**
5851  * e_cal_component_alarm_get_attendee_list:
5852  * @alarm: An alarm.
5853  * @attendee_list: Return value for the list of attendees.
5854  *
5855  * Gets the list of attendees associated with an alarm.
5856  */
5857 void 
5858 e_cal_component_alarm_get_attendee_list (ECalComponentAlarm *alarm, GSList **attendee_list)
5859 {
5860         g_return_if_fail (alarm != NULL);
5861         
5862         get_attendee_list (alarm->attendee_list, attendee_list);
5863 }
5864
5865 /**
5866  * e_cal_component_alarm_set_attendee_list:
5867  * @alarm: An alarm.
5868  * @attendee_list: List of attendees.
5869  *
5870  * Sets the list of attendees for an alarm.
5871  */
5872 void 
5873 e_cal_component_alarm_set_attendee_list (ECalComponentAlarm *alarm, GSList *attendee_list)
5874 {
5875         g_return_if_fail (alarm != NULL);
5876
5877         set_attendee_list (alarm->icalcomp, &alarm->attendee_list, attendee_list);
5878 }
5879
5880 /**
5881  * e_cal_component_alarm_has_attendees:
5882  * @alarm: An alarm.
5883  *
5884  * Queries an alarm to see if it has attendees associated with it.
5885  *
5886  * Return value: TRUE if there are attendees in the alarm, FALSE if not.
5887  */
5888 gboolean 
5889 e_cal_component_alarm_has_attendees (ECalComponentAlarm *alarm)
5890 {
5891
5892         g_return_val_if_fail (alarm != NULL, FALSE);
5893
5894         if (g_slist_length (alarm->attendee_list) > 0)
5895                 return TRUE;
5896         
5897         return FALSE;   
5898 }
5899
5900
5901 /**
5902  * e_cal_component_alarm_get_icalcomponent
5903  * @alarm: An alarm.
5904  *
5905  * Get the icalcomponent associated with the given #ECalComponentAlarm.
5906  *
5907  * Returns: the icalcomponent.
5908  */
5909 icalcomponent *
5910 e_cal_component_alarm_get_icalcomponent (ECalComponentAlarm *alarm)
5911 {
5912         g_return_val_if_fail (alarm != NULL, NULL);
5913         return alarm->icalcomp;
5914 }
5915
5916 /* Returns TRUE if both strings match, i.e. they are both NULL or the
5917    strings are equal. */
5918 static gboolean
5919 e_cal_component_strings_match   (const gchar    *string1,
5920                                  const gchar    *string2)
5921 {
5922         if (string1 == NULL || string2 == NULL)
5923                 return (string1 == string2) ? TRUE : FALSE;
5924
5925         if (!strcmp (string1, string2))
5926                 return TRUE;
5927
5928         return FALSE;
5929 }
5930
5931
5932 /**
5933  * e_cal_component_event_dates_match:
5934  * @comp1: A calendar component object.
5935  * @comp2: A calendar component object.
5936  *
5937  * Checks if the DTSTART and DTEND properties of the 2 components match.
5938  * Note that the events may have different recurrence properties which are not
5939  * taken into account here.
5940  *
5941  * Returns: TRUE if the DTSTART and DTEND properties of the 2 components match.
5942  **/
5943 gboolean
5944 e_cal_component_event_dates_match       (ECalComponent *comp1,
5945                                  ECalComponent *comp2)
5946 {
5947         ECalComponentDateTime comp1_dtstart, comp1_dtend;
5948         ECalComponentDateTime comp2_dtstart, comp2_dtend;
5949         gboolean retval = TRUE;
5950
5951         e_cal_component_get_dtstart (comp1, &comp1_dtstart);
5952         e_cal_component_get_dtend   (comp1, &comp1_dtend);
5953         e_cal_component_get_dtstart (comp2, &comp2_dtstart);
5954         e_cal_component_get_dtend   (comp2, &comp2_dtend);
5955
5956         /* If either value is NULL they must both be NULL to match. */
5957         if (comp1_dtstart.value == NULL || comp2_dtstart.value == NULL) {
5958                 if (comp1_dtstart.value != comp2_dtstart.value) {
5959                         retval = FALSE;
5960                         goto out;
5961                 }
5962         } else {
5963                 if (icaltime_compare (*comp1_dtstart.value,
5964                                       *comp2_dtstart.value)) {
5965                         retval = FALSE;
5966                         goto out;
5967                 }
5968         }
5969
5970         if (comp1_dtend.value == NULL || comp2_dtend.value == NULL) {
5971                 if (comp1_dtend.value != comp2_dtend.value) {
5972                         retval = FALSE;
5973                         goto out;
5974                 }
5975         } else {
5976                 if (icaltime_compare (*comp1_dtend.value,
5977                                       *comp2_dtend.value)) {
5978                         retval = FALSE;
5979                         goto out;
5980                 }
5981         }
5982
5983         /* Now check the timezones. */
5984         if (!e_cal_component_strings_match (comp1_dtstart.tzid,
5985                                           comp2_dtstart.tzid)) {
5986                 retval = FALSE;
5987                 goto out;
5988         }
5989
5990         if (!e_cal_component_strings_match (comp1_dtend.tzid,
5991                                           comp2_dtend.tzid)) {
5992                 retval = FALSE;
5993         }
5994
5995  out:
5996
5997         e_cal_component_free_datetime (&comp1_dtstart);
5998         e_cal_component_free_datetime (&comp1_dtend);
5999         e_cal_component_free_datetime (&comp2_dtstart);
6000         e_cal_component_free_datetime (&comp2_dtend);
6001
6002         return retval;
6003 }
6004
6005