2
* Copyright (C) 2004 Free Software Foundation, Inc.
4
* This program is free software; you can redistribute it and/or
5
* modify it under the terms of the GNU General Public License as
6
* published by the Free Software Foundation; either version 2 of the
7
* License, or (at your option) any later version.
9
* This program is distributed in the hope that it will be useful, but
10
* WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
* General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program; if not, write to the Free Software
16
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20
* Mark McLoughlin <mark@skynet.ie>
21
* William Jon McCann <mccann@jhu.edu>
22
* Martin Grimme <martin@pycage.de>
23
* Christian Kellner <gicmo@xatom.net>
28
#include "calendar-client.h"
32
#include <libecal/e-cal.h>
33
#include <libecal/e-cal-time-util.h>
34
#include <libecal/e-cal-recur.h>
36
#include "calendar-sources.h"
38
#undef CALENDAR_ENABLE_DEBUG
39
#include "calendar-debug.h"
41
#define CALENDAR_CONFIG_PREFIX "/apps/evolution/calendar"
42
#define CALENDAR_CONFIG_TIMEZONE CALENDAR_CONFIG_PREFIX "/display/timezone"
45
#define _(x) gettext(x)
52
#define CALENDAR_CLIENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CALENDAR_TYPE_CLIENT, CalendarClientPrivate))
54
typedef struct _CalendarClientQuery CalendarClientQuery;
55
typedef struct _CalendarClientSource CalendarClientSource;
57
struct _CalendarClientQuery
63
struct _CalendarClientSource
65
CalendarClient *client;
68
CalendarClientQuery completed_query;
69
CalendarClientQuery in_progress_query;
71
guint changed_signal_id;
73
guint query_completed : 1;
74
guint query_in_progress : 1;
77
struct _CalendarClientPrivate
79
CalendarSources *calendar_sources;
81
GSList *appointment_sources;
87
GConfClient *gconf_client;
94
static void calendar_client_class_init (CalendarClientClass *klass);
95
static void calendar_client_init (CalendarClient *client);
96
static void calendar_client_finalize (GObject *object);
97
static void calendar_client_set_property (GObject *object,
101
static void calendar_client_get_property (GObject *object,
106
static GSList *calendar_client_update_sources_list (CalendarClient *client,
109
guint changed_signal_id);
110
static void calendar_client_appointment_sources_changed (CalendarClient *client);
111
static void calendar_client_task_sources_changed (CalendarClient *client);
113
static void calendar_client_stop_query (CalendarClient *client,
114
CalendarClientSource *source,
115
CalendarClientQuery *query);
116
static void calendar_client_start_query (CalendarClient *client,
117
CalendarClientSource *source,
120
static void calendar_client_source_finalize (CalendarClientSource *source);
121
static void calendar_client_query_finalize (CalendarClientQuery *query);
133
APPOINTMENTS_CHANGED,
138
static GObjectClass *parent_class = NULL;
139
static guint signals [LAST_SIGNAL] = { 0, };
142
calendar_client_get_type (void)
144
static GType client_type = 0;
148
static const GTypeInfo client_info =
150
sizeof (CalendarClientClass),
151
NULL, /* base_init */
152
NULL, /* base_finalize */
153
(GClassInitFunc) calendar_client_class_init,
154
NULL, /* class_finalize */
155
NULL, /* class_data */
156
sizeof (CalendarClient),
158
(GInstanceInitFunc) calendar_client_init,
161
client_type = g_type_register_static (G_TYPE_OBJECT,
170
calendar_client_class_init (CalendarClientClass *klass)
172
GObjectClass *gobject_class = (GObjectClass *) klass;
174
parent_class = g_type_class_peek_parent (klass);
176
gobject_class->finalize = calendar_client_finalize;
177
gobject_class->set_property = calendar_client_set_property;
178
gobject_class->get_property = calendar_client_get_property;
180
g_type_class_add_private (klass, sizeof (CalendarClientPrivate));
182
g_object_class_install_property (gobject_class,
184
g_param_spec_uint ("day",
186
"The currently monitored day between 1 and 31 (0 denotes unset)",
190
g_object_class_install_property (gobject_class,
192
g_param_spec_uint ("month",
194
"The currently monitored month between 0 and 11",
198
g_object_class_install_property (gobject_class,
200
g_param_spec_uint ("year",
202
"The currently monitored year",
206
signals [APPOINTMENTS_CHANGED] =
207
g_signal_new ("appointments-changed",
208
G_TYPE_FROM_CLASS (gobject_class),
210
G_STRUCT_OFFSET (CalendarClientClass, tasks_changed),
213
g_cclosure_marshal_VOID__VOID,
217
signals [TASKS_CHANGED] =
218
g_signal_new ("tasks-changed",
219
G_TYPE_FROM_CLASS (gobject_class),
221
G_STRUCT_OFFSET (CalendarClientClass, tasks_changed),
224
g_cclosure_marshal_VOID__VOID,
229
/* Timezone code adapted from evolution/calendar/gui/calendar-config.c */
230
/* The current timezone, e.g. "Europe/London". It may be NULL, in which case
231
you should assume UTC. */
233
calendar_client_config_get_timezone (GConfClient *gconf_client)
237
location = gconf_client_get_string (gconf_client,
238
CALENDAR_CONFIG_TIMEZONE,
244
static icaltimezone *
245
calendar_client_config_get_icaltimezone (GConfClient *gconf_client)
248
icaltimezone *zone = NULL;
250
location = calendar_client_config_get_timezone (gconf_client);
252
return icaltimezone_get_utc_timezone ();
254
zone = icaltimezone_get_builtin_timezone (location);
261
calendar_client_set_timezone (CalendarClient *client)
266
client->priv->zone = calendar_client_config_get_icaltimezone (client->priv->gconf_client);
268
esources = calendar_sources_get_appointment_sources (client->priv->calendar_sources);
269
for (l = esources; l; l = l->next) {
270
ECal *source = l->data;
272
if (e_cal_get_load_state (source) != E_CAL_LOAD_LOADED)
275
e_cal_set_default_timezone (source, client->priv->zone, NULL);
280
calendar_client_timezone_changed_cb (GConfClient *gconf_client,
283
CalendarClient *client)
285
calendar_client_set_timezone (client);
290
calendar_client_init (CalendarClient *client)
294
client->priv = CALENDAR_CLIENT_GET_PRIVATE (client);
296
client->priv->calendar_sources = calendar_sources_get ();
298
esources = calendar_sources_get_appointment_sources (client->priv->calendar_sources);
299
client->priv->appointment_sources =
300
calendar_client_update_sources_list (client, NULL, esources, signals [APPOINTMENTS_CHANGED]);
302
esources = calendar_sources_get_task_sources (client->priv->calendar_sources);
303
client->priv->task_sources =
304
calendar_client_update_sources_list (client, NULL, esources, signals [TASKS_CHANGED]);
306
g_signal_connect_swapped (client->priv->calendar_sources,
307
"appointment-sources-changed",
308
G_CALLBACK (calendar_client_appointment_sources_changed),
310
g_signal_connect_swapped (client->priv->calendar_sources,
311
"task-sources-changed",
312
G_CALLBACK (calendar_client_task_sources_changed),
315
client->priv->gconf_client = gconf_client_get_default ();
317
gconf_client_add_dir (client->priv->gconf_client,
318
CALENDAR_CONFIG_PREFIX,
319
GCONF_CLIENT_PRELOAD_NONE,
322
calendar_client_set_timezone (client);
323
client->priv->zone_listener = gconf_client_notify_add (client->priv->gconf_client,
324
CALENDAR_CONFIG_TIMEZONE,
325
(GConfClientNotifyFunc) calendar_client_timezone_changed_cb,
328
client->priv->day = -1;
329
client->priv->month = -1;
330
client->priv->year = -1;
334
calendar_client_finalize (GObject *object)
336
CalendarClient *client = CALENDAR_CLIENT (object);
339
if (client->priv->zone_listener)
341
gconf_client_notify_remove (client->priv->gconf_client,
342
client->priv->zone_listener);
343
client->priv->zone_listener = 0;
346
gconf_client_remove_dir (client->priv->gconf_client,
347
CALENDAR_CONFIG_PREFIX,
350
if (client->priv->gconf_client)
351
g_object_unref (client->priv->gconf_client);
352
client->priv->gconf_client = NULL;
354
for (l = client->priv->appointment_sources; l; l = l->next)
356
calendar_client_source_finalize (l->data);
359
g_slist_free (client->priv->appointment_sources);
360
client->priv->appointment_sources = NULL;
362
for (l = client->priv->task_sources; l; l = l->next)
364
calendar_client_source_finalize (l->data);
367
g_slist_free (client->priv->task_sources);
368
client->priv->task_sources = NULL;
370
if (client->priv->calendar_sources)
371
g_object_unref (client->priv->calendar_sources);
372
client->priv->calendar_sources = NULL;
374
if (G_OBJECT_CLASS (parent_class)->finalize)
375
G_OBJECT_CLASS (parent_class)->finalize (object);
379
calendar_client_set_property (GObject *object,
384
CalendarClient *client = CALENDAR_CLIENT (object);
389
calendar_client_select_day (client, g_value_get_uint (value));
392
calendar_client_select_month (client,
393
g_value_get_uint (value),
397
calendar_client_select_month (client,
399
g_value_get_uint (value));
402
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
408
calendar_client_get_property (GObject *object,
413
CalendarClient *client = CALENDAR_CLIENT (object);
418
g_value_set_uint (value, client->priv->day);
421
g_value_set_uint (value, client->priv->month);
424
g_value_set_uint (value, client->priv->year);
427
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
433
calendar_client_new (void)
435
return g_object_new (CALENDAR_TYPE_CLIENT, NULL);
438
/* @day and @month can happily be out of range as
439
* mktime() will normalize them correctly. From mktime(3):
441
* "If structure members are outside their legal interval,
442
* they will be normalized (so that, e.g., 40 October is
443
* changed into 9 November)."
445
* "What?", you say, "Something useful in libc?"
448
make_time_for_day_begin (int day,
452
struct tm localtime_tm = { 0, };
454
localtime_tm.tm_mday = day;
455
localtime_tm.tm_mon = month;
456
localtime_tm.tm_year = year - 1900;
457
localtime_tm.tm_isdst = -1;
459
return mktime (&localtime_tm);
463
make_isodate_for_day_begin (int day,
469
utctime = make_time_for_day_begin (day, month, year);
471
return utctime != -1 ? isodate_from_time_t (utctime) : NULL;
475
get_time_from_property (icalcomponent *ical,
476
icalproperty_kind prop_kind,
477
struct icaltimetype (* get_prop_func) (const icalproperty *prop),
478
icaltimezone *default_zone)
481
struct icaltimetype ical_time;
482
icalparameter *param;
483
icaltimezone *timezone = NULL;
485
prop = icalcomponent_get_first_property (ical, prop_kind);
489
ical_time = get_prop_func (prop);
491
param = icalproperty_get_first_parameter (prop, ICAL_TZID_PARAMETER);
493
timezone = icaltimezone_get_builtin_timezone_from_tzid (icalparameter_get_tzid (param));
494
else if (icaltime_is_utc (ical_time))
495
timezone = icaltimezone_get_utc_timezone ();
497
timezone = default_zone;
499
return icaltime_as_timet_with_zone (ical_time, timezone);
503
get_ical_uid (icalcomponent *ical)
505
return g_strdup (icalcomponent_get_uid (ical));
509
get_ical_rid (icalcomponent *ical)
512
struct icaltimetype ical_time;
514
prop = icalcomponent_get_first_property (ical, ICAL_RECURRENCEID_PROPERTY);
518
ical_time = icalproperty_get_recurrenceid (prop);
520
return icaltime_is_valid_time (ical_time) && !icaltime_is_null_time (ical_time) ?
521
g_strdup (icaltime_as_ical_string (ical_time)) : NULL;
525
get_ical_summary (icalcomponent *ical)
529
prop = icalcomponent_get_first_property (ical, ICAL_SUMMARY_PROPERTY);
533
return g_strdup (icalproperty_get_summary (prop));
537
get_ical_description (icalcomponent *ical)
541
prop = icalcomponent_get_first_property (ical, ICAL_DESCRIPTION_PROPERTY);
545
return g_strdup (icalproperty_get_description (prop));
549
get_ical_url (icalcomponent *ical)
553
prop = icalcomponent_get_first_property (ical, ICAL_URL_PROPERTY);
557
return g_strdup (icalproperty_get_url (prop));
561
get_ical_start_time (icalcomponent *ical,
562
icaltimezone *default_zone)
564
return get_time_from_property (ical,
565
ICAL_DTSTART_PROPERTY,
566
icalproperty_get_dtstart,
571
get_ical_end_time (icalcomponent *ical,
572
icaltimezone *default_zone)
574
return get_time_from_property (ical,
576
icalproperty_get_dtend,
581
get_ical_is_all_day (icalcomponent *ical,
583
icaltimezone *default_zone)
589
struct icaldurationtype duration;
590
struct icaltimetype start_icaltime;
592
start_icaltime = icalcomponent_get_dtstart (ical);
593
if (start_icaltime.is_date)
596
start_time = (time_t) start_gtime;
597
start_tm = gmtime (&start_time);
598
if (start_tm->tm_sec != 0 ||
599
start_tm->tm_min != 0 ||
600
start_tm->tm_hour != 0)
603
if ((end_time = get_ical_end_time (ical, default_zone)))
604
return (end_time - start_time) % 86400 == 0;
606
prop = icalcomponent_get_first_property (ical, ICAL_DURATION_PROPERTY);
610
duration = icalproperty_get_duration (prop);
612
return icaldurationtype_as_int (duration) % 86400 == 0;
616
get_ical_due_time (icalcomponent *ical,
617
icaltimezone *default_zone)
619
return get_time_from_property (ical,
621
icalproperty_get_due,
626
get_ical_percent_complete (icalcomponent *ical)
629
int percent_complete;
631
prop = icalcomponent_get_first_property (ical, ICAL_COMPLETED_PROPERTY);
635
prop = icalcomponent_get_first_property (ical, ICAL_PERCENTCOMPLETE_PROPERTY);
639
percent_complete = icalproperty_get_percentcomplete (prop);
641
return CLAMP (percent_complete, 0, 100);
645
get_ical_completed_time (icalcomponent *ical,
646
icaltimezone *default_zone)
648
return get_time_from_property (ical,
649
ICAL_COMPLETED_PROPERTY,
650
icalproperty_get_completed,
655
get_ical_priority (icalcomponent *ical)
659
prop = icalcomponent_get_first_property (ical, ICAL_PRIORITY_PROPERTY);
663
return icalproperty_get_priority (prop);
667
get_source_color (ECal *esource)
672
g_return_val_if_fail (E_IS_CAL (esource), NULL);
674
source = e_cal_get_source (esource);
675
if (e_source_get_color (source, &color)) {
676
return g_strdup_printf ("%06x", color);
683
null_safe_strcmp (const char *a,
686
return (!a && !b) ? 0 : (a && !b) || (!a && b) ? 1 : strcmp (a, b);
689
static inline gboolean
690
calendar_appointment_equal (CalendarAppointment *a,
691
CalendarAppointment *b)
695
if (g_slist_length (a->occurrences) != g_slist_length (b->occurrences))
698
for (la = a->occurrences, lb = b->occurrences; la && lb; la = la->next, lb = lb->next)
700
CalendarOccurrence *oa = la->data;
701
CalendarOccurrence *ob = lb->data;
703
if (oa->start_time != ob->start_time ||
704
oa->end_time != ob->end_time)
709
null_safe_strcmp (a->uid, b->uid) == 0 &&
710
null_safe_strcmp (a->summary, b->summary) == 0 &&
711
null_safe_strcmp (a->description, b->description) == 0 &&
712
null_safe_strcmp (a->color_string, b->color_string) == 0 &&
713
a->start_time == b->start_time &&
714
a->end_time == b->end_time &&
715
a->is_all_day == b->is_all_day;
719
calendar_appointment_copy (CalendarAppointment *appointment,
720
CalendarAppointment *appointment_copy)
724
g_assert (appointment != NULL);
725
g_assert (appointment_copy != NULL);
727
appointment_copy->occurrences = g_slist_copy (appointment->occurrences);
728
for (l = appointment_copy->occurrences; l; l = l->next)
730
CalendarOccurrence *occurrence = l->data;
731
CalendarOccurrence *occurrence_copy;
733
occurrence_copy = g_new0 (CalendarOccurrence, 1);
734
occurrence_copy->start_time = occurrence->start_time;
735
occurrence_copy->end_time = occurrence->end_time;
737
l->data = occurrence_copy;
740
appointment_copy->uid = g_strdup (appointment->uid);
741
appointment_copy->summary = g_strdup (appointment->summary);
742
appointment_copy->description = g_strdup (appointment->description);
743
appointment_copy->color_string = g_strdup (appointment->color_string);
744
appointment_copy->start_time = appointment->start_time;
745
appointment_copy->end_time = appointment->end_time;
746
appointment_copy->is_all_day = appointment->is_all_day;
750
calendar_appointment_finalize (CalendarAppointment *appointment)
754
for (l = appointment->occurrences; l; l = l->next)
756
g_slist_free (appointment->occurrences);
757
appointment->occurrences = NULL;
759
g_free (appointment->uid);
760
appointment->uid = NULL;
762
g_free (appointment->summary);
763
appointment->summary = NULL;
765
g_free (appointment->description);
766
appointment->description = NULL;
768
g_free (appointment->color_string);
769
appointment->color_string = NULL;
771
appointment->start_time = 0;
772
appointment->is_all_day = FALSE;
776
calendar_appointment_init (CalendarAppointment *appointment,
778
CalendarClientSource *source,
779
icaltimezone *default_zone)
781
appointment->uid = get_ical_uid (ical);
782
appointment->rid = get_ical_rid (ical);
783
appointment->summary = get_ical_summary (ical);
784
appointment->description = get_ical_description (ical);
785
appointment->color_string = get_source_color (source->source);
786
appointment->start_time = get_ical_start_time (ical, default_zone);
787
appointment->end_time = get_ical_end_time (ical, default_zone);
788
appointment->is_all_day = get_ical_is_all_day (ical,
789
appointment->start_time,
793
static icaltimezone *
794
resolve_timezone_id (const char *tzid,
797
icaltimezone *retval;
799
retval = icaltimezone_get_builtin_timezone_from_tzid (tzid);
802
e_cal_get_timezone (source, tzid, &retval, NULL);
809
calendar_appointment_collect_occurrence (ECalComponent *component,
810
GTime occurrence_start,
811
GTime occurrence_end,
812
GSList **collect_loc)
814
CalendarOccurrence *occurrence;
816
occurrence = g_new0 (CalendarOccurrence, 1);
817
occurrence->start_time = occurrence_start;
818
occurrence->end_time = occurrence_end;
820
*collect_loc = g_slist_prepend (*collect_loc, occurrence);
826
calendar_appointment_generate_ocurrences (CalendarAppointment *appointment,
831
icaltimezone *default_zone)
835
g_assert (appointment->occurrences == NULL);
837
ecal = e_cal_component_new ();
838
e_cal_component_set_icalcomponent (ecal,
839
icalcomponent_new_clone (ical));
841
e_cal_recur_generate_instances (ecal,
844
(ECalRecurInstanceFn) calendar_appointment_collect_occurrence,
845
&appointment->occurrences,
846
(ECalRecurResolveTimezoneFn) resolve_timezone_id,
850
g_object_unref (ecal);
852
appointment->occurrences = g_slist_reverse (appointment->occurrences);
855
static inline gboolean
856
calendar_task_equal (CalendarTask *a,
860
null_safe_strcmp (a->uid, b->uid) == 0 &&
861
null_safe_strcmp (a->summary, b->summary) == 0 &&
862
null_safe_strcmp (a->description, b->description) == 0 &&
863
null_safe_strcmp (a->color_string, b->color_string) == 0 &&
864
null_safe_strcmp (a->url, b->url) == 0 &&
865
a->start_time == b->start_time &&
866
a->due_time == b->due_time &&
867
a->percent_complete == b->percent_complete &&
868
a->completed_time == b->completed_time &&
869
a->priority == b->priority;
873
calendar_task_copy (CalendarTask *task,
874
CalendarTask *task_copy)
876
g_assert (task != NULL);
877
g_assert (task_copy != NULL);
879
task_copy->uid = g_strdup (task->uid);
880
task_copy->summary = g_strdup (task->summary);
881
task_copy->description = g_strdup (task->description);
882
task_copy->color_string = g_strdup (task->color_string);
883
task_copy->url = g_strdup (task->url);
884
task_copy->start_time = task->start_time;
885
task_copy->due_time = task->due_time;
886
task_copy->percent_complete = task->percent_complete;
887
task_copy->completed_time = task->completed_time;
888
task_copy->priority = task->priority;
892
calendar_task_finalize (CalendarTask *task)
897
g_free (task->summary);
898
task->summary = NULL;
900
g_free (task->description);
901
task->description = NULL;
903
g_free (task->color_string);
904
task->color_string = NULL;
909
task->percent_complete = 0;
913
calendar_task_init (CalendarTask *task,
915
CalendarClientSource *source,
916
icaltimezone *default_zone)
918
task->uid = get_ical_uid (ical);
919
task->summary = get_ical_summary (ical);
920
task->description = get_ical_description (ical);
921
task->color_string = get_source_color (source->source);
922
task->url = get_ical_url (ical);
923
task->start_time = get_ical_start_time (ical, default_zone);
924
task->due_time = get_ical_due_time (ical, default_zone);
925
task->percent_complete = get_ical_percent_complete (ical);
926
task->completed_time = get_ical_completed_time (ical, default_zone);
927
task->priority = get_ical_priority (ical);
931
calendar_event_free (CalendarEvent *event)
935
case CALENDAR_EVENT_APPOINTMENT:
936
calendar_appointment_finalize (CALENDAR_APPOINTMENT (event));
938
case CALENDAR_EVENT_TASK:
939
calendar_task_finalize (CALENDAR_TASK (event));
942
g_assert_not_reached ();
949
static CalendarEvent *
950
calendar_event_new (icalcomponent *ical,
951
CalendarClientSource *source,
952
icaltimezone *default_zone)
954
CalendarEvent *event;
956
event = g_new0 (CalendarEvent, 1);
958
switch (icalcomponent_isa (ical))
960
case ICAL_VEVENT_COMPONENT:
961
event->type = CALENDAR_EVENT_APPOINTMENT;
962
calendar_appointment_init (CALENDAR_APPOINTMENT (event),
967
case ICAL_VTODO_COMPONENT:
968
event->type = CALENDAR_EVENT_TASK;
969
calendar_task_init (CALENDAR_TASK (event),
975
g_warning ("Unknown calendar component type: %d\n",
976
icalcomponent_isa (ical));
984
static CalendarEvent *
985
calendar_event_copy (CalendarEvent *event)
987
CalendarEvent *retval;
992
retval = g_new0 (CalendarEvent, 1);
994
retval->type = event->type;
998
case CALENDAR_EVENT_APPOINTMENT:
999
calendar_appointment_copy (CALENDAR_APPOINTMENT (event),
1000
CALENDAR_APPOINTMENT (retval));
1002
case CALENDAR_EVENT_TASK:
1003
calendar_task_copy (CALENDAR_TASK (event),
1004
CALENDAR_TASK (retval));
1007
g_assert_not_reached ();
1015
calendar_event_get_uid (CalendarEvent *event)
1017
switch (event->type)
1019
case CALENDAR_EVENT_APPOINTMENT:
1020
return g_strdup_printf ("%s%s", CALENDAR_APPOINTMENT (event)->uid, CALENDAR_APPOINTMENT (event)->rid ? CALENDAR_APPOINTMENT (event)->rid : "");
1022
case CALENDAR_EVENT_TASK:
1023
return g_strdup (CALENDAR_TASK (event)->uid);
1026
g_assert_not_reached ();
1034
calendar_event_equal (CalendarEvent *a,
1040
if ((a && !b) || (!a && b))
1043
if (a->type != b->type)
1048
case CALENDAR_EVENT_APPOINTMENT:
1049
return calendar_appointment_equal (CALENDAR_APPOINTMENT (a),
1050
CALENDAR_APPOINTMENT (b));
1051
case CALENDAR_EVENT_TASK:
1052
return calendar_task_equal (CALENDAR_TASK (a),
1058
g_assert_not_reached ();
1064
calendar_event_generate_ocurrences (CalendarEvent *event,
1065
icalcomponent *ical,
1069
icaltimezone *default_zone)
1071
if (event->type != CALENDAR_EVENT_APPOINTMENT)
1074
calendar_appointment_generate_ocurrences (CALENDAR_APPOINTMENT (event),
1083
calendar_event_debug_dump (CalendarEvent *event)
1085
#ifdef CALENDAR_ENABLE_DEBUG
1086
switch (event->type)
1088
case CALENDAR_EVENT_APPOINTMENT:
1094
start_str = CALENDAR_APPOINTMENT (event)->start_time ?
1095
isodate_from_time_t (CALENDAR_APPOINTMENT (event)->start_time) :
1096
g_strdup ("(undefined)");
1097
end_str = CALENDAR_APPOINTMENT (event)->end_time ?
1098
isodate_from_time_t (CALENDAR_APPOINTMENT (event)->end_time) :
1099
g_strdup ("(undefined)");
1101
dprintf ("Appointment: uid '%s', summary '%s', description '%s', "
1102
"start_time '%s', end_time '%s', is_all_day %s\n",
1103
CALENDAR_APPOINTMENT (event)->uid,
1104
CALENDAR_APPOINTMENT (event)->summary,
1105
CALENDAR_APPOINTMENT (event)->description,
1108
CALENDAR_APPOINTMENT (event)->is_all_day ? "(true)" : "(false)");
1113
dprintf (" Occurrences:\n");
1114
for (l = CALENDAR_APPOINTMENT (event)->occurrences; l; l = l->next)
1116
CalendarOccurrence *occurrence = l->data;
1118
start_str = occurrence->start_time ?
1119
isodate_from_time_t (occurrence->start_time) :
1120
g_strdup ("(undefined)");
1122
end_str = occurrence->end_time ?
1123
isodate_from_time_t (occurrence->end_time) :
1124
g_strdup ("(undefined)");
1126
dprintf (" start_time '%s', end_time '%s'\n",
1127
start_str, end_str);
1134
case CALENDAR_EVENT_TASK:
1138
char *completed_str;
1140
start_str = CALENDAR_TASK (event)->start_time ?
1141
isodate_from_time_t (CALENDAR_TASK (event)->start_time) :
1142
g_strdup ("(undefined)");
1143
due_str = CALENDAR_TASK (event)->due_time ?
1144
isodate_from_time_t (CALENDAR_TASK (event)->due_time) :
1145
g_strdup ("(undefined)");
1146
completed_str = CALENDAR_TASK (event)->completed_time ?
1147
isodate_from_time_t (CALENDAR_TASK (event)->completed_time) :
1148
g_strdup ("(undefined)");
1150
dprintf ("Task: uid '%s', summary '%s', description '%s', "
1151
"start_time '%s', due_time '%s', percent_complete %d, completed_time '%s'\n",
1152
CALENDAR_TASK (event)->uid,
1153
CALENDAR_TASK (event)->summary,
1154
CALENDAR_TASK (event)->description,
1157
CALENDAR_TASK (event)->percent_complete,
1160
g_free (completed_str);
1164
g_assert_not_reached ();
1170
static inline CalendarClientQuery *
1171
goddamn_this_is_crack (CalendarClientSource *source,
1173
gboolean *emit_signal)
1175
g_assert (view != NULL);
1177
if (source->completed_query.view == view)
1180
*emit_signal = TRUE;
1181
return &source->completed_query;
1183
else if (source->in_progress_query.view == view)
1186
*emit_signal = FALSE;
1187
return &source->in_progress_query;
1190
g_assert_not_reached ();
1196
calendar_client_handle_query_completed (CalendarClientSource *source,
1197
ECalendarStatus status,
1200
CalendarClientQuery *query;
1202
query = goddamn_this_is_crack (source, view, NULL);
1204
dprintf ("Query %p completed: %s\n", query, e_cal_get_error_message (status));
1206
if (status != E_CALENDAR_STATUS_OK)
1208
g_warning ("Calendar query failed: %s\n",
1209
e_cal_get_error_message (status));
1210
calendar_client_stop_query (source->client, source, query);
1214
g_assert (source->query_in_progress != FALSE);
1215
g_assert (query == &source->in_progress_query);
1217
calendar_client_query_finalize (&source->completed_query);
1219
source->completed_query = source->in_progress_query;
1220
source->query_completed = TRUE;
1222
source->query_in_progress = FALSE;
1223
source->in_progress_query.view = NULL;
1224
source->in_progress_query.events = NULL;
1226
g_signal_emit (source->client, source->changed_signal_id, 0);
1230
calendar_client_handle_query_result (CalendarClientSource *source,
1234
CalendarClientQuery *query;
1235
CalendarClient *client;
1236
gboolean emit_signal;
1237
gboolean events_changed;
1242
client = source->client;
1244
query = goddamn_this_is_crack (source, view, &emit_signal);
1246
dprintf ("Query %p result: %d objects:\n",
1247
query, g_list_length (objects));
1249
month_begin = make_time_for_day_begin (1,
1250
client->priv->month,
1251
client->priv->year);
1253
month_end = make_time_for_day_begin (1,
1254
client->priv->month + 1,
1255
client->priv->year);
1257
events_changed = FALSE;
1258
for (l = objects; l; l = l->next)
1260
CalendarEvent *event;
1261
CalendarEvent *old_event;
1262
icalcomponent *ical = l->data;
1265
event = calendar_event_new (ical, source, client->priv->zone);
1269
calendar_event_generate_ocurrences (event,
1274
client->priv->zone);
1276
uid = calendar_event_get_uid (event);
1278
old_event = g_hash_table_lookup (query->events, uid);
1280
if (!calendar_event_equal (event, old_event))
1282
dprintf ("Event %s: ", old_event ? "modified" : "added");
1284
calendar_event_debug_dump (event);
1286
g_hash_table_replace (query->events, uid, event);
1288
events_changed = TRUE;
1296
if (emit_signal && events_changed)
1298
g_signal_emit (source->client, source->changed_signal_id, 0);
1303
check_object_remove (gpointer key,
1312
if (len <= strlen (key) && strncmp (uid, key, len) == 0)
1314
dprintf ("Event removed: ");
1316
calendar_event_debug_dump (value);
1325
calendar_client_handle_objects_removed (CalendarClientSource *source,
1329
CalendarClientQuery *query;
1330
gboolean emit_signal;
1331
gboolean events_changed;
1334
query = goddamn_this_is_crack (source, view, &emit_signal);
1336
events_changed = FALSE;
1337
for (l = ids; l; l = l->next)
1339
CalendarEvent *event;
1340
ECalComponentId *id = l->data;
1341
char *uid = g_strdup_printf ("%s%s", id->uid, id->rid ? id->rid : "");
1343
if (!id->rid || !(*id->rid))
1345
int size = g_hash_table_size (query->events);
1347
g_hash_table_foreach_remove (query->events, check_object_remove, id->uid);
1349
if (size != g_hash_table_size (query->events))
1350
events_changed = TRUE;
1352
else if ((event = g_hash_table_lookup (query->events, uid)))
1354
dprintf ("Event removed: ");
1356
calendar_event_debug_dump (event);
1358
g_assert (g_hash_table_remove (query->events, uid));
1360
events_changed = TRUE;
1365
if (emit_signal && events_changed)
1367
g_signal_emit (source->client, source->changed_signal_id, 0);
1372
calendar_client_query_finalize (CalendarClientQuery *query)
1375
g_object_unref (query->view);
1379
g_hash_table_destroy (query->events);
1380
query->events = NULL;
1384
calendar_client_stop_query (CalendarClient *client,
1385
CalendarClientSource *source,
1386
CalendarClientQuery *query)
1388
if (query == &source->in_progress_query)
1390
dprintf ("Stopping in progress query %p\n", query);
1392
g_assert (source->query_in_progress != FALSE);
1394
source->query_in_progress = FALSE;
1396
else if (query == &source->completed_query)
1398
dprintf ("Stopping completed query %p\n", query);
1400
g_assert (source->query_completed != FALSE);
1402
source->query_completed = FALSE;
1405
g_assert_not_reached ();
1407
calendar_client_query_finalize (query);
1411
calendar_client_start_query (CalendarClient *client,
1412
CalendarClientSource *source,
1415
ECalView *view = NULL;
1416
GError *error = NULL;
1418
if (!e_cal_get_query (source->source, query, &view, &error))
1420
g_warning ("Error preparing the query: '%s': %s\n",
1421
query, error->message);
1422
g_error_free (error);
1426
g_assert (view != NULL);
1428
if (source->query_in_progress)
1429
calendar_client_stop_query (client, source, &source->in_progress_query);
1431
dprintf ("Starting query %p: '%s'\n", &source->in_progress_query, query);
1433
source->query_in_progress = TRUE;
1434
source->in_progress_query.view = view;
1435
source->in_progress_query.events =
1436
g_hash_table_new_full (g_str_hash,
1439
(GDestroyNotify) calendar_event_free);
1441
g_signal_connect_swapped (view, "objects-added",
1442
G_CALLBACK (calendar_client_handle_query_result),
1444
g_signal_connect_swapped (view, "objects-modified",
1445
G_CALLBACK (calendar_client_handle_query_result),
1447
g_signal_connect_swapped (view, "objects-removed",
1448
G_CALLBACK (calendar_client_handle_objects_removed),
1450
g_signal_connect_swapped (view, "view-done",
1451
G_CALLBACK (calendar_client_handle_query_completed),
1454
e_cal_view_start (view);
1458
calendar_client_update_appointments (CalendarClient *client)
1465
if (client->priv->month == -1 ||
1466
client->priv->year == -1)
1469
month_begin = make_isodate_for_day_begin (1,
1470
client->priv->month,
1471
client->priv->year);
1473
month_end = make_isodate_for_day_begin (1,
1474
client->priv->month + 1,
1475
client->priv->year);
1477
query = g_strdup_printf ("occur-in-time-range? (make-time \"%s\") "
1478
"(make-time \"%s\")",
1479
month_begin, month_end);
1481
for (l = client->priv->appointment_sources; l; l = l->next)
1482
calendar_client_start_query (client, l->data, query);
1484
g_free (month_begin);
1490
* perhaps we should use evo's "hide_completed_tasks" pref?
1493
calendar_client_update_tasks (CalendarClient *client)
1498
#ifdef FIX_BROKEN_TASKS_QUERY
1499
/* FIXME: this doesn't work for tasks without a start or
1501
* Look at filter_task() to see the behaviour we
1508
if (client->priv->day == -1 ||
1509
client->priv->month == -1 ||
1510
client->priv->year == -1)
1513
day_begin = make_isodate_for_day_begin (client->priv->day,
1514
client->priv->month,
1515
client->priv->year);
1517
day_end = make_isodate_for_day_begin (client->priv->day + 1,
1518
client->priv->month,
1519
client->priv->year);
1520
if (!day_begin || !day_end)
1522
g_warning ("Cannot run query with invalid date: %dd %dy %dm\n",
1524
client->priv->month,
1525
client->priv->year);
1531
query = g_strdup_printf ("(and (occur-in-time-range? (make-time \"%s\") "
1532
"(make-time \"%s\")) "
1533
"(or (not is-completed?) "
1534
"(and (is-completed?) "
1535
"(not (completed-before? (make-time \"%s\"))))))",
1536
day_begin, day_end, day_begin);
1538
query = g_strdup ("#t");
1539
#endif /* FIX_BROKEN_TASKS_QUERY */
1541
for (l = client->priv->task_sources; l; l = l->next)
1542
calendar_client_start_query (client, l->data, query);
1544
#ifdef FIX_BROKEN_TASKS_QUERY
1552
calendar_client_source_finalize (CalendarClientSource *source)
1554
source->client = NULL;
1557
g_object_unref (source->source);
1558
source->source = NULL;
1560
calendar_client_query_finalize (&source->completed_query);
1561
calendar_client_query_finalize (&source->in_progress_query);
1563
source->query_completed = FALSE;
1564
source->query_in_progress = FALSE;
1568
compare_calendar_sources (CalendarClientSource *s1,
1569
CalendarClientSource *s2)
1571
return (s1->source == s2->source) ? 0 : 1;
1575
calendar_client_update_sources_list (CalendarClient *client,
1578
guint changed_signal_id)
1584
for (l = esources; l; l = l->next)
1586
CalendarClientSource dummy_source;
1587
CalendarClientSource *new_source;
1589
ECal *esource = l->data;
1591
dummy_source.source = esource;
1593
dprintf ("update_sources_list: adding client %s: ",
1594
e_source_peek_uid (e_cal_get_source (esource)));
1596
if ((s = g_slist_find_custom (sources,
1598
(GCompareFunc) compare_calendar_sources)))
1600
dprintf ("already on list\n");
1601
new_source = s->data;
1602
sources = g_slist_delete_link (sources, s);
1606
dprintf ("added\n");
1607
new_source = g_new0 (CalendarClientSource, 1);
1608
new_source->client = client;
1609
new_source->source = g_object_ref (esource);
1610
new_source->changed_signal_id = changed_signal_id;
1613
retval = g_slist_prepend (retval, new_source);
1616
for (l = sources; l; l = l->next)
1618
CalendarClientSource *source = l->data;
1620
dprintf ("Removing client %s from list\n",
1621
e_source_peek_uid (e_cal_get_source (source->source)));
1623
calendar_client_source_finalize (source);
1626
g_slist_free (sources);
1632
calendar_client_appointment_sources_changed (CalendarClient *client)
1636
dprintf ("appointment_sources_changed: updating ...\n");
1638
esources = calendar_sources_get_appointment_sources (client->priv->calendar_sources);
1640
client->priv->appointment_sources =
1641
calendar_client_update_sources_list (client,
1642
client->priv->appointment_sources,
1644
signals [APPOINTMENTS_CHANGED]);
1646
calendar_client_update_appointments (client);
1650
calendar_client_task_sources_changed (CalendarClient *client)
1654
dprintf ("task_sources_changed: updating ...\n");
1656
esources = calendar_sources_get_task_sources (client->priv->calendar_sources);
1658
client->priv->task_sources =
1659
calendar_client_update_sources_list (client,
1660
client->priv->task_sources,
1662
signals [TASKS_CHANGED]);
1664
calendar_client_update_tasks (client);
1668
calendar_client_get_date (CalendarClient *client,
1673
g_return_if_fail (CALENDAR_IS_CLIENT (client));
1676
*year = client->priv->year;
1679
*month = client->priv->month;
1682
*day = client->priv->day;
1686
calendar_client_select_month (CalendarClient *client,
1690
g_return_if_fail (CALENDAR_IS_CLIENT (client));
1691
g_return_if_fail (month >= 0 && month <= 11);
1693
if (client->priv->year != year || client->priv->month != month)
1695
client->priv->month = month;
1696
client->priv->year = year;
1698
calendar_client_update_appointments (client);
1699
calendar_client_update_tasks (client);
1701
g_object_freeze_notify (G_OBJECT (client));
1702
g_object_notify (G_OBJECT (client), "month");
1703
g_object_notify (G_OBJECT (client), "year");
1704
g_object_thaw_notify (G_OBJECT (client));
1709
calendar_client_select_day (CalendarClient *client,
1712
g_return_if_fail (CALENDAR_IS_CLIENT (client));
1713
g_return_if_fail (day <= 31);
1715
if (client->priv->day != day)
1717
client->priv->day = day;
1719
/* don't need to update appointments unless
1720
* the selected month changes
1722
#ifdef FIX_BROKEN_TASKS_QUERY
1723
calendar_client_update_tasks (client);
1726
g_object_notify (G_OBJECT (client), "day");
1732
CalendarClient *client;
1738
typedef void (* CalendarEventFilterFunc) (const char *uid,
1739
CalendarEvent *event,
1740
FilterData *filter_data);
1743
filter_appointment (const char *uid,
1744
CalendarEvent *event,
1745
FilterData *filter_data)
1747
GSList *occurrences, *l;
1749
if (event->type != CALENDAR_EVENT_APPOINTMENT)
1752
occurrences = CALENDAR_APPOINTMENT (event)->occurrences;
1753
CALENDAR_APPOINTMENT (event)->occurrences = NULL;
1755
for (l = occurrences; l; l = l->next)
1757
CalendarOccurrence *occurrence = l->data;
1758
GTime start_time = occurrence->start_time;
1759
GTime end_time = occurrence->end_time;
1761
if ((start_time >= filter_data->start_time &&
1762
start_time < filter_data->end_time) ||
1763
(start_time <= filter_data->start_time &&
1764
(end_time - 1) > filter_data->start_time))
1766
CalendarEvent *new_event;
1768
new_event = calendar_event_copy (event);
1770
CALENDAR_APPOINTMENT (new_event)->start_time = occurrence->start_time;
1771
CALENDAR_APPOINTMENT (new_event)->end_time = occurrence->end_time;
1773
filter_data->events = g_slist_prepend (filter_data->events, new_event);
1777
CALENDAR_APPOINTMENT (event)->occurrences = occurrences;
1781
filter_task (const char *uid,
1782
CalendarEvent *event,
1783
FilterData *filter_data)
1787
if (event->type != CALENDAR_EVENT_TASK)
1790
task = CALENDAR_TASK (event);
1792
#ifdef FIX_BROKEN_TASKS_QUERY
1793
if (task->start_time && task->start_time > filter_data->start_time)
1796
if (task->completed_time &&
1797
(task->completed_time < filter_data->start_time ||
1798
task->completed_time > filter_data->end_time))
1800
#endif /* FIX_BROKEN_TASKS_QUERY */
1802
filter_data->events = g_slist_prepend (filter_data->events,
1803
calendar_event_copy (event));
1807
calendar_client_filter_events (CalendarClient *client,
1809
CalendarEventFilterFunc filter_func,
1813
FilterData filter_data;
1820
filter_data.client = client;
1821
filter_data.events = NULL;
1822
filter_data.start_time = start_time;
1823
filter_data.end_time = end_time;
1826
for (l = sources; l; l = l->next)
1828
CalendarClientSource *source = l->data;
1830
if (source->query_completed)
1832
filter_data.events = NULL;
1833
g_hash_table_foreach (source->completed_query.events,
1834
(GHFunc) filter_func,
1837
filter_data.events = g_slist_reverse (filter_data.events);
1839
retval = g_slist_concat (retval, filter_data.events);
1847
calendar_client_get_events (CalendarClient *client,
1848
CalendarEventType event_mask)
1850
GSList *appointments;
1855
g_return_val_if_fail (CALENDAR_IS_CLIENT (client), NULL);
1856
g_return_val_if_fail (client->priv->day != -1 &&
1857
client->priv->month != -1 &&
1858
client->priv->year != -1, NULL);
1860
day_begin = make_time_for_day_begin (client->priv->day,
1861
client->priv->month,
1862
client->priv->year);
1863
day_end = make_time_for_day_begin (client->priv->day + 1,
1864
client->priv->month,
1865
client->priv->year);
1867
appointments = NULL;
1868
if (event_mask & CALENDAR_EVENT_APPOINTMENT)
1870
appointments = calendar_client_filter_events (client,
1871
client->priv->appointment_sources,
1878
if (event_mask & CALENDAR_EVENT_TASK)
1880
tasks = calendar_client_filter_events (client,
1881
client->priv->task_sources,
1887
return g_slist_concat (appointments, tasks);
1891
day_from_time_t (time_t t)
1893
struct tm *tm = localtime (&t);
1895
g_assert (tm == NULL || (tm->tm_mday >=1 && tm->tm_mday <= 31));
1897
return tm ? tm->tm_mday : 0;
1901
calendar_client_foreach_appointment_day (CalendarClient *client,
1902
CalendarDayIter iter_func,
1905
GSList *appointments, *l;
1906
gboolean marked_days [32] = { FALSE, };
1911
g_return_if_fail (CALENDAR_IS_CLIENT (client));
1912
g_return_if_fail (iter_func != NULL);
1913
g_return_if_fail (client->priv->month != -1 &&
1914
client->priv->year != -1);
1916
month_begin = make_time_for_day_begin (1,
1917
client->priv->month,
1918
client->priv->year);
1919
month_end = make_time_for_day_begin (1,
1920
client->priv->month + 1,
1921
client->priv->year);
1923
appointments = calendar_client_filter_events (client,
1924
client->priv->appointment_sources,
1928
for (l = appointments; l; l = l->next)
1930
CalendarAppointment *appointment = l->data;
1932
if (appointment->start_time)
1934
GTime day_time = appointment->start_time;
1936
if (day_time >= month_begin)
1937
marked_days [day_from_time_t (day_time)] = TRUE;
1939
if (appointment->end_time)
1942
int duration = appointment->end_time - appointment->start_time;
1943
for (day_offset = 1; day_offset < duration / 86400; day_offset++)
1945
GTime day_time = appointment->start_time + day_offset * 86400;
1947
if (day_time > month_end)
1949
if (day_time >= month_begin)
1950
marked_days [day_from_time_t (day_time)] = TRUE;
1954
calendar_event_free (CALENDAR_EVENT (appointment));
1957
g_slist_free (appointments);
1959
for (i = 1; i < 32; i++)
1961
if (marked_days [i])
1962
iter_func (client, i, user_data);
1967
calendar_client_set_task_completed (CalendarClient *client,
1969
gboolean task_completed,
1970
guint percent_complete)
1974
icalcomponent *ical;
1976
icalproperty_status status;
1978
g_return_if_fail (CALENDAR_IS_CLIENT (client));
1979
g_return_if_fail (task_uid != NULL);
1980
g_return_if_fail (task_completed == FALSE || percent_complete == 100);
1984
for (l = client->priv->task_sources; l; l = l->next)
1986
CalendarClientSource *source = l->data;
1988
esource = source->source;
1989
e_cal_get_object (esource, task_uid, NULL, &ical, NULL);
1996
g_warning ("Cannot locate task with uid = '%s'\n", task_uid);
2000
g_assert (esource != NULL);
2002
/* Completed time */
2003
prop = icalcomponent_get_first_property (ical,
2004
ICAL_COMPLETED_PROPERTY);
2007
struct icaltimetype completed_time;
2009
completed_time = icaltime_current_time_with_zone (client->priv->zone);
2012
icalcomponent_add_property (ical,
2013
icalproperty_new_completed (completed_time));
2017
icalproperty_set_completed (prop, completed_time);
2022
icalcomponent_remove_property (ical, prop);
2025
/* Percent complete */
2026
prop = icalcomponent_get_first_property (ical,
2027
ICAL_PERCENTCOMPLETE_PROPERTY);
2030
icalcomponent_add_property (ical,
2031
icalproperty_new_percentcomplete (percent_complete));
2035
icalproperty_set_percentcomplete (prop, percent_complete);
2039
status = task_completed ? ICAL_STATUS_COMPLETED : ICAL_STATUS_NEEDSACTION;
2040
prop = icalcomponent_get_first_property (ical, ICAL_STATUS_PROPERTY);
2043
icalproperty_set_status (prop, status);
2047
icalcomponent_add_property (ical,
2048
icalproperty_new_status (status));
2051
e_cal_modify_object (esource, ical, CALOBJ_MOD_ALL, NULL);