1 /*-*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* Evolution calendar ecal
4 * Copyright (C) 2001 Ximian, Inc.
5 * Copyright (C) 2004 Novell, Inc.
7 * Authors: Federico Mena-Quintero <federico@ximian.com>
8 * Rodrigo Moya <rodrigo@novell.com>
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of version 2 of the GNU Lesser General Public
12 * License as published by the Free Software Foundation.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
30 #include <glib/gi18n-lib.h>
31 #include <bonobo-activation/bonobo-activation.h>
32 #include <bonobo/bonobo-exception.h>
33 #include <bonobo/bonobo-main.h>
35 #include "libedataserver/e-component-listener.h"
36 #include "libedataserver/e-flag.h"
37 #include "libedataserver/e-url.h"
38 #include "e-cal-marshal.h"
39 #include "e-cal-time-util.h"
40 #include "e-cal-listener.h"
41 #include "e-cal-view-listener.h"
42 #include "e-cal-view-private.h"
47 open_calendar (ECal *ecal, gboolean only_if_exists, GError **error, ECalendarStatus *status, gboolean needs_auth);
50 get_read_only (ECal *ecal, gboolean *read_only, GError **error);
55 ECalendarStatus status;
64 ECalViewListener *listener;
67 /* Private part of the ECal structure */
69 /* Load state to avoid multiple loads */
70 ECalLoadState load_state;
72 /* URI of the calendar that is being loaded or is already loaded, or
73 * NULL if we are not loaded.
79 ECalendarOp *current_op;
83 /* Email address associated with this calendar, or NULL */
85 char *alarm_email_address;
95 /* The calendar factories we are contacting */
98 /* Our calendar listener implementation */
99 ECalListener *listener;
101 /* The calendar ecal interface object we are contacting */
102 GNOME_Evolution_Calendar_Cal cal;
104 /* The authentication function */
105 ECalAuthFunc auth_func;
106 gpointer auth_user_data;
108 /* A cache of timezones retrieved from the server, to avoid getting
109 them repeatedly for each get_object() call. */
110 GHashTable *timezones;
112 /* The default timezone to use to resolve DATE and floating DATE-TIME
114 icaltimezone *default_zone;
116 /* The component listener to keep track of the lifetime of backends */
117 EComponentListener *comp_listener;
119 char *local_attachment_store;
133 static guint e_cal_signals[LAST_SIGNAL];
135 static GObjectClass *parent_class;
137 #ifdef __PRETTY_FUNCTION__
138 #define e_return_error_if_fail(expr,error_code) G_STMT_START{ \
139 if G_LIKELY(expr) { } else \
141 g_log (G_LOG_DOMAIN, \
142 G_LOG_LEVEL_CRITICAL, \
143 "file %s: line %d (%s): assertion `%s' failed", \
146 __PRETTY_FUNCTION__, \
148 g_set_error (error, E_CALENDAR_ERROR, (error_code), \
149 "file %s: line %d (%s): assertion `%s' failed", \
152 __PRETTY_FUNCTION__, \
157 #define e_return_error_if_fail(expr,error_code) G_STMT_START{ \
158 if G_LIKELY(expr) { } else \
160 g_log (G_LOG_DOMAIN, \
161 G_LOG_LEVEL_CRITICAL, \
162 "file %s: line %d: assertion `%s' failed", \
166 g_set_error (error, E_CALENDAR_ERROR, (error_code), \
167 "file %s: line %d: assertion `%s' failed", \
175 #define E_CALENDAR_CHECK_STATUS(status,error) G_STMT_START{ \
176 if ((status) == E_CALENDAR_STATUS_OK) { \
181 msg = e_cal_get_error_message ((status)); \
182 g_set_error ((error), E_CALENDAR_ERROR, (status), msg, (status)); \
190 e_calendar_error_quark (void)
194 q = g_quark_from_static_string ("e-calendar-error-quark");
200 * e_cal_source_type_enum_get_type:
202 * Registers the #ECalSourceTypeEnum type with glib.
204 * Return value: the ID of the #ECalSourceTypeEnum type.
207 e_cal_source_type_enum_get_type (void)
209 static GType e_cal_source_type_enum_type = 0;
211 if (!e_cal_source_type_enum_type) {
212 static GEnumValue values [] = {
213 { E_CAL_SOURCE_TYPE_EVENT, "Event", NULL},
214 { E_CAL_SOURCE_TYPE_TODO, "ToDo", NULL},
215 { E_CAL_SOURCE_TYPE_JOURNAL, "Journal", NULL},
216 { E_CAL_SOURCE_TYPE_LAST, "Invalid", NULL},
220 e_cal_source_type_enum_type =
221 g_enum_register_static ("ECalSourceTypeEnum", values);
224 return e_cal_source_type_enum_type;
228 * e_cal_set_mode_status_enum_get_type:
230 * Registers the #ECalSetModeStatusEnum type with glib.
232 * Return value: the ID of the #ECalSetModeStatusEnum type.
235 e_cal_set_mode_status_enum_get_type (void)
237 static GType e_cal_set_mode_status_enum_type = 0;
239 if (!e_cal_set_mode_status_enum_type) {
240 static GEnumValue values [] = {
241 { E_CAL_SET_MODE_SUCCESS, "ECalSetModeSuccess", "success" },
242 { E_CAL_SET_MODE_ERROR, "ECalSetModeError", "error" },
243 { E_CAL_SET_MODE_NOT_SUPPORTED, "ECalSetModeNotSupported", "unsupported" },
247 e_cal_set_mode_status_enum_type =
248 g_enum_register_static ("ECalSetModeStatusEnum", values);
251 return e_cal_set_mode_status_enum_type;
255 * cal_mode_enum_get_type:
257 * Registers the #CalModeEnum type with glib.
259 * Return value: the ID of the #CalModeEnum type.
262 cal_mode_enum_get_type (void)
264 static GType cal_mode_enum_type = 0;
266 if (!cal_mode_enum_type) {
267 static GEnumValue values [] = {
268 { CAL_MODE_INVALID, "CalModeInvalid", "invalid" },
269 { CAL_MODE_LOCAL, "CalModeLocal", "local" },
270 { CAL_MODE_REMOTE, "CalModeRemote", "remote" },
271 { CAL_MODE_ANY, "CalModeAny", "any" },
275 cal_mode_enum_type = g_enum_register_static ("CalModeEnum", values);
278 return cal_mode_enum_type;
283 static GNOME_Evolution_Calendar_CalObjType
284 convert_type (ECalSourceType type)
287 case E_CAL_SOURCE_TYPE_EVENT:
288 return GNOME_Evolution_Calendar_TYPE_EVENT;
289 case E_CAL_SOURCE_TYPE_TODO:
290 return GNOME_Evolution_Calendar_TYPE_TODO;
291 case E_CAL_SOURCE_TYPE_JOURNAL:
292 return GNOME_Evolution_Calendar_TYPE_JOURNAL;
294 return GNOME_Evolution_Calendar_TYPE_ANY;
297 return GNOME_Evolution_Calendar_TYPE_ANY;
303 e_calendar_new_op (ECal *ecal)
305 ECalendarOp *op = g_new0 (ECalendarOp, 1);
307 op->done = e_flag_new ();
309 ecal->priv->current_op = op;
315 e_calendar_get_op (ECal *ecal)
317 if (!ecal->priv->current_op) {
318 g_warning (G_STRLOC ": Unexpected response");
322 return ecal->priv->current_op;
326 e_calendar_free_op (ECalendarOp *op)
328 /* XXX more stuff here */
329 e_flag_free (op->done);
334 e_calendar_remove_op (ECal *ecal, ECalendarOp *op)
336 if (ecal->priv->current_op != op)
337 g_warning (G_STRLOC ": Cannot remove op, it's not current");
339 ecal->priv->current_op = NULL;
342 /* Gets rid of the factories that a ecal knows about */
344 destroy_factories (ECal *ecal)
347 CORBA_Object factory;
348 CORBA_Environment ev;
354 CORBA_exception_init (&ev);
356 for (f = priv->factories; f; f = f->next) {
359 result = CORBA_Object_is_nil (factory, &ev);
360 if (BONOBO_EX (&ev)) {
361 g_message (G_STRLOC ": could not see if a factory was nil");
362 CORBA_exception_free (&ev);
370 CORBA_Object_release (factory, &ev);
371 if (BONOBO_EX (&ev)) {
372 g_message (G_STRLOC ": could not release a factory");
373 CORBA_exception_free (&ev);
377 g_list_free (priv->factories);
378 priv->factories = NULL;
381 /* Gets rid of the calendar ecal interface object that a ecal knows about */
383 destroy_cal (ECal *ecal)
386 CORBA_Environment ev;
391 CORBA_exception_init (&ev);
392 result = CORBA_Object_is_nil (priv->cal, &ev);
393 if (BONOBO_EX (&ev)) {
394 g_message (G_STRLOC ": could not see if the "
395 "calendar ecal interface object was nil");
396 priv->cal = CORBA_OBJECT_NIL;
397 CORBA_exception_free (&ev);
400 CORBA_exception_free (&ev);
405 bonobo_object_release_unref (priv->cal, NULL);
406 priv->cal = CORBA_OBJECT_NIL;
411 free_timezone (gpointer key, gpointer value, gpointer data)
413 /* Note that the key comes from within the icaltimezone value, so we
415 icaltimezone_free (value, TRUE);
421 backend_died_cb (EComponentListener *cl, gpointer user_data)
424 ECal *ecal = (ECal *) user_data;
427 priv->load_state = E_CAL_LOAD_NOT_LOADED;
428 g_signal_emit (G_OBJECT (ecal), e_cal_signals[BACKEND_DIED], 0);
431 /* Signal handlers for the listener's signals */
432 /* Handle the cal_opened notification from the listener */
435 cal_read_only_cb (ECalListener *listener, ECalendarStatus status, gboolean read_only, gpointer data)
440 op = e_calendar_get_op (ecal);
442 if (op == NULL || !op->bool) {
443 ecal->priv->read_only = read_only;
448 op->bool = read_only;
450 e_flag_set (op->done);
454 cal_cal_address_cb (ECalListener *listener, ECalendarStatus status, const char *address, gpointer data)
459 op = e_calendar_get_op (ecal);
461 if (ecal->priv->cal_address) {
462 g_free (ecal->priv->cal_address);
463 ecal->priv->cal_address = NULL;
466 ecal->priv->cal_address = g_strdup (address);
473 op->string = g_strdup (address);
475 e_flag_set (op->done);
479 cal_alarm_address_cb (ECalListener *listener, ECalendarStatus status, const char *address, gpointer data)
484 op = e_calendar_get_op (ecal);
487 g_warning (G_STRLOC ": Cannot find operation ");
492 op->string = g_strdup (address);
494 e_flag_set (op->done);
498 cal_ldap_attribute_cb (ECalListener *listener, ECalendarStatus status, const char *attribute, gpointer data)
503 op = e_calendar_get_op (ecal);
506 g_warning (G_STRLOC ": Cannot find operation ");
511 op->string = g_strdup (attribute);
513 e_flag_set (op->done);
517 cal_static_capabilities_cb (ECalListener *listener, ECalendarStatus status, const char *capabilities, gpointer data)
522 op = e_calendar_get_op (ecal);
525 g_warning (G_STRLOC ": Cannot find operation ");
530 op->string = g_strdup (capabilities);
532 e_flag_set (op->done);
536 cal_opened_cb (ECalListener *listener, ECalendarStatus status, gpointer data)
541 op = e_calendar_get_op (ecal);
544 g_warning (G_STRLOC ": Cannot find operation ");
550 e_flag_set (op->done);
554 cal_removed_cb (ECalListener *listener, ECalendarStatus status, gpointer data)
559 op = e_calendar_get_op (ecal);
562 g_warning (G_STRLOC ": Cannot find operation ");
568 e_flag_set (op->done);
572 cal_object_created_cb (ECalListener *listener, ECalendarStatus status, const char *uid, gpointer data)
577 op = e_calendar_get_op (ecal);
580 g_warning (G_STRLOC ": Cannot find operation ");
585 op->uid = g_strdup (uid);
587 e_flag_set (op->done);
591 cal_object_modified_cb (ECalListener *listener, ECalendarStatus status, gpointer data)
596 op = e_calendar_get_op (ecal);
599 g_warning (G_STRLOC ": Cannot find operation ");
605 e_flag_set (op->done);
609 cal_object_removed_cb (ECalListener *listener, ECalendarStatus status, gpointer data)
614 op = e_calendar_get_op (ecal);
617 g_warning (G_STRLOC ": Cannot find operation ");
623 e_flag_set (op->done);
627 cal_alarm_discarded_cb (ECalListener *listener, ECalendarStatus status, gpointer data)
632 op = e_calendar_get_op (ecal);
635 g_warning (G_STRLOC ": Cannot find operation ");
641 e_flag_set (op->done);
645 cal_objects_received_cb (ECalListener *listener, ECalendarStatus status, gpointer data)
650 op = e_calendar_get_op (ecal);
653 g_warning (G_STRLOC ": Cannot find operation ");
659 e_flag_set (op->done);
663 cal_objects_sent_cb (ECalListener *listener, ECalendarStatus status, GList *users, const char *object, gpointer data)
669 op = e_calendar_get_op (ecal);
672 g_warning (G_STRLOC ": Cannot find operation ");
677 op->list = g_list_copy (users);
678 op->string = g_strdup (object);
680 for (l = op->list; l; l = l->next)
681 l->data = g_strdup (l->data);
683 e_flag_set (op->done);
687 cal_default_object_requested_cb (ECalListener *listener, ECalendarStatus status, const char *object, gpointer data)
692 op = e_calendar_get_op (ecal);
695 g_warning (G_STRLOC ": Cannot find operation ");
700 op->string = g_strdup (object);
702 e_flag_set (op->done);
706 cal_object_requested_cb (ECalListener *listener, ECalendarStatus status, const char *object, gpointer data)
711 op = e_calendar_get_op (ecal);
714 g_warning (G_STRLOC ": Cannot find operation ");
719 op->string = g_strdup (object);
721 e_flag_set (op->done);
725 cal_object_list_cb (ECalListener *listener, ECalendarStatus status, GList *objects, gpointer data)
731 op = e_calendar_get_op (ecal);
734 g_warning (G_STRLOC ": Cannot find operation ");
739 op->list = g_list_copy (objects);
741 for (l = op->list; l; l = l->next)
742 l->data = icalcomponent_new_clone (l->data);
744 e_flag_set (op->done);
748 cal_attachment_list_cb (ECalListener *listener, ECalendarStatus status, GSList *attachments, gpointer data)
753 op = e_calendar_get_op (ecal);
756 g_warning (G_STRLOC ": Cannot find operation ");
761 op->slist = g_slist_copy (attachments);
763 e_flag_set (op->done);
767 cal_get_timezone_cb (ECalListener *listener, ECalendarStatus status, const char *object, gpointer data)
772 op = e_calendar_get_op (ecal);
775 g_warning (G_STRLOC ": Cannot find operation ");
780 op->string = g_strdup (object);
782 e_flag_set (op->done);
786 cal_add_timezone_cb (ECalListener *listener, ECalendarStatus status, const char *tzid, gpointer data)
791 op = e_calendar_get_op (ecal);
794 g_warning (G_STRLOC ": Cannot find operation ");
799 op->uid = g_strdup (tzid);
801 e_flag_set (op->done);
805 cal_set_default_timezone_cb (ECalListener *listener, ECalendarStatus status, gpointer data)
810 op = e_calendar_get_op (ecal);
813 g_warning (G_STRLOC ": Cannot find operation ");
819 e_flag_set (op->done);
823 cal_get_changes_cb (ECalListener *listener, ECalendarStatus status, GList *changes, gpointer data)
829 op = e_calendar_get_op (ecal);
832 g_warning (G_STRLOC ": Cannot find operation ");
837 op->list = g_list_copy (changes);
839 for (l = op->list; l; l = l->next) {
840 ECalChange *ccc = l->data, *new_ccc;
842 new_ccc = g_new (ECalChange, 1);
843 new_ccc->comp = e_cal_component_clone (ccc->comp);
844 new_ccc->type = ccc->type;
849 e_flag_set (op->done);
853 cal_get_free_busy_cb (ECalListener *listener, ECalendarStatus status, GList *freebusy, gpointer data)
859 op = e_calendar_get_op (ecal);
862 g_warning (G_STRLOC ": Cannot find operation ");
867 op->list = g_list_copy (freebusy);
869 for (l = op->list; l; l = l->next)
870 l->data = e_cal_component_clone (l->data);
872 e_flag_set (op->done);
876 cal_query_cb (ECalListener *listener, ECalendarStatus status, GNOME_Evolution_Calendar_CalView query, gpointer data)
881 op = e_calendar_get_op (ecal);
884 g_warning (G_STRLOC ": Cannot find operation ");
889 op->query = e_cal_view_new (query, op->listener, ecal);
891 e_flag_set (op->done);
895 reopen_with_auth (gpointer data)
897 ECalendarStatus status;
899 open_calendar (E_CAL (data), TRUE, NULL, &status, TRUE);
904 auth_required_cb (ECalListener *listener, gpointer data)
906 g_idle_add (reopen_with_auth, data);
910 /* Handle the cal_set_mode notification from the listener */
912 cal_set_mode_cb (ECalListener *listener,
913 GNOME_Evolution_Calendar_CalListener_SetModeStatus status,
914 GNOME_Evolution_Calendar_CalMode mode,
919 ECalSetModeStatus ecal_status;
924 ecal_status = E_CAL_SET_MODE_ERROR;
927 case GNOME_Evolution_Calendar_CalListener_MODE_SET:
928 ecal_status = E_CAL_SET_MODE_SUCCESS;
930 case GNOME_Evolution_Calendar_CalListener_MODE_NOT_SET:
931 ecal_status = E_CAL_SET_MODE_ERROR;
933 case GNOME_Evolution_Calendar_CalListener_MODE_NOT_SUPPORTED:
934 ecal_status = E_CAL_SET_MODE_NOT_SUPPORTED;
937 g_assert_not_reached ();
940 /* We are *not* inside a signal handler (this is just a simple callback
941 * called from the listener), so there is not a temporary reference to
942 * the ecal object. We ref() so that we can safely emit our own
943 * signal and clean up.
946 g_object_ref (G_OBJECT (ecal));
948 g_signal_emit (G_OBJECT (ecal), e_cal_signals[CAL_SET_MODE],
949 0, ecal_status, mode);
951 g_object_unref (G_OBJECT (ecal));
961 backend_error_idle_cb (gpointer data)
963 ECalErrorData *error_data = data;
965 g_signal_emit (G_OBJECT (error_data->ecal), e_cal_signals[BACKEND_ERROR], 0, error_data->message);
967 g_object_unref (error_data->ecal);
968 g_free (error_data->message);
974 /* Handle the error_occurred signal from the listener */
976 backend_error_cb (ECalListener *listener, const char *message, gpointer data)
978 ECalErrorData *error_data;
980 error_data = g_new0 (ECalErrorData, 1);
982 error_data->ecal = g_object_ref (data);
983 error_data->message = g_strdup (message);
985 g_idle_add (backend_error_idle_cb, error_data);
991 get_factories (const char *str_uri, GList **factories)
993 GNOME_Evolution_Calendar_CalFactory factory;
994 Bonobo_ServerInfoList *servers;
1000 /* Determine the protocol and query for factory supporting that */
1001 uri = e_uri_new (str_uri);
1003 g_warning (G_STRLOC ": Invalid uri string");
1008 query = "repo_ids.has ('IDL:GNOME/Evolution/DataServer/CalFactory:" API_VERSION "')";
1011 servers = bonobo_activation_query (query, NULL, NULL);
1016 g_warning (G_STRLOC ": Unable to query for calendar factories");
1021 /* Try to activate the servers for the protocol */
1022 for (i = 0; i < servers->_length; i++) {
1023 const Bonobo_ServerInfo *info;
1025 info = servers->_buffer + i;
1028 g_message (G_STRLOC ": Activating calendar factory (%s)", info->iid);
1030 factory = bonobo_activation_activate_from_id (info->iid, 0, NULL, NULL);
1032 if (factory == CORBA_OBJECT_NIL)
1033 g_warning (G_STRLOC ": Could not activate calendar factory (%s)", info->iid);
1035 *factories = g_list_append (*factories, factory);
1038 CORBA_free (servers);
1043 /* Object initialization function for the calendar ecal */
1045 e_cal_init (ECal *ecal, ECalClass *klass)
1049 priv = g_new0 (ECalPrivate, 1);
1052 priv->load_state = E_CAL_LOAD_NOT_LOADED;
1054 priv->local_attachment_store = NULL;
1055 priv->mutex = g_mutex_new ();
1056 priv->listener = e_cal_listener_new (cal_set_mode_cb, ecal);
1058 priv->cal_address = NULL;
1059 priv->alarm_email_address = NULL;
1060 priv->ldap_attribute = NULL;
1061 priv->capabilities = FALSE;
1062 priv->factories = NULL;
1063 priv->timezones = g_hash_table_new (g_str_hash, g_str_equal);
1064 priv->default_zone = icaltimezone_get_utc_timezone ();
1065 priv->comp_listener = NULL;
1067 g_signal_connect (G_OBJECT (priv->listener), "read_only", G_CALLBACK (cal_read_only_cb), ecal);
1068 g_signal_connect (G_OBJECT (priv->listener), "cal_address", G_CALLBACK (cal_cal_address_cb), ecal);
1069 g_signal_connect (G_OBJECT (priv->listener), "alarm_address", G_CALLBACK (cal_alarm_address_cb), ecal);
1070 g_signal_connect (G_OBJECT (priv->listener), "ldap_attribute", G_CALLBACK (cal_ldap_attribute_cb), ecal);
1071 g_signal_connect (G_OBJECT (priv->listener), "static_capabilities", G_CALLBACK (cal_static_capabilities_cb), ecal);
1072 g_signal_connect (G_OBJECT (priv->listener), "open", G_CALLBACK (cal_opened_cb), ecal);
1073 g_signal_connect (G_OBJECT (priv->listener), "remove", G_CALLBACK (cal_removed_cb), ecal);
1074 g_signal_connect (G_OBJECT (priv->listener), "create_object", G_CALLBACK (cal_object_created_cb), ecal);
1075 g_signal_connect (G_OBJECT (priv->listener), "modify_object", G_CALLBACK (cal_object_modified_cb), ecal);
1076 g_signal_connect (G_OBJECT (priv->listener), "remove_object", G_CALLBACK (cal_object_removed_cb), ecal);
1077 g_signal_connect (G_OBJECT (priv->listener), "discard_alarm", G_CALLBACK (cal_alarm_discarded_cb), ecal);
1078 g_signal_connect (G_OBJECT (priv->listener), "receive_objects", G_CALLBACK (cal_objects_received_cb), ecal);
1079 g_signal_connect (G_OBJECT (priv->listener), "send_objects", G_CALLBACK (cal_objects_sent_cb), ecal);
1080 g_signal_connect (G_OBJECT (priv->listener), "default_object", G_CALLBACK (cal_default_object_requested_cb), ecal);
1081 g_signal_connect (G_OBJECT (priv->listener), "object", G_CALLBACK (cal_object_requested_cb), ecal);
1082 g_signal_connect (G_OBJECT (priv->listener), "object_list", G_CALLBACK (cal_object_list_cb), ecal);
1083 g_signal_connect (G_OBJECT (priv->listener), "attachment_list", G_CALLBACK (cal_attachment_list_cb), ecal);
1084 g_signal_connect (G_OBJECT (priv->listener), "get_timezone", G_CALLBACK (cal_get_timezone_cb), ecal);
1085 g_signal_connect (G_OBJECT (priv->listener), "add_timezone", G_CALLBACK (cal_add_timezone_cb), ecal);
1086 g_signal_connect (G_OBJECT (priv->listener), "set_default_timezone", G_CALLBACK (cal_set_default_timezone_cb), ecal);
1087 g_signal_connect (G_OBJECT (priv->listener), "get_changes", G_CALLBACK (cal_get_changes_cb), ecal);
1088 g_signal_connect (G_OBJECT (priv->listener), "get_free_busy", G_CALLBACK (cal_get_free_busy_cb), ecal);
1089 g_signal_connect (G_OBJECT (priv->listener), "query", G_CALLBACK (cal_query_cb), ecal);
1090 g_signal_connect (G_OBJECT (priv->listener), "backend_error", G_CALLBACK (backend_error_cb), ecal);
1091 g_signal_connect (G_OBJECT (priv->listener), "auth_required", G_CALLBACK (auth_required_cb), ecal);
1094 /* Finalize handler for the calendar ecal */
1096 e_cal_finalize (GObject *object)
1101 g_return_if_fail (object != NULL);
1102 g_return_if_fail (E_IS_CAL (object));
1104 ecal = E_CAL (object);
1107 if (priv->listener) {
1108 e_cal_listener_stop_notification (priv->listener);
1109 bonobo_object_unref (priv->listener);
1110 priv->listener = NULL;
1113 if (priv->comp_listener) {
1114 g_signal_handlers_disconnect_matched (G_OBJECT (priv->comp_listener),
1115 G_SIGNAL_MATCH_DATA,
1118 g_object_unref (G_OBJECT (priv->comp_listener));
1119 priv->comp_listener = NULL;
1122 destroy_factories (ecal);
1125 priv->load_state = E_CAL_LOAD_NOT_LOADED;
1128 g_object_unref (priv->source);
1129 priv->source = NULL;
1137 if (priv->local_attachment_store) {
1138 g_free (priv->local_attachment_store);
1139 priv->local_attachment_store = NULL;
1143 g_mutex_free (priv->mutex);
1147 if (priv->cal_address) {
1148 g_free (priv->cal_address);
1149 priv->cal_address = NULL;
1151 if (priv->alarm_email_address) {
1152 g_free (priv->alarm_email_address);
1153 priv->alarm_email_address = NULL;
1155 if (priv->ldap_attribute) {
1156 g_free (priv->ldap_attribute);
1157 priv->ldap_attribute = NULL;
1159 if (priv->capabilities) {
1160 g_free (priv->capabilities);
1161 priv->capabilities = NULL;
1164 g_hash_table_foreach (priv->timezones, free_timezone, NULL);
1165 g_hash_table_destroy (priv->timezones);
1166 priv->timezones = NULL;
1171 if (G_OBJECT_CLASS (parent_class)->finalize)
1172 (* G_OBJECT_CLASS (parent_class)->finalize) (object);
1175 /* Class initialization function for the calendar ecal */
1177 e_cal_class_init (ECalClass *klass)
1179 GObjectClass *object_class;
1181 object_class = (GObjectClass *) klass;
1183 parent_class = g_type_class_peek_parent (klass);
1185 e_cal_signals[CAL_OPENED] =
1186 g_signal_new ("cal_opened",
1187 G_TYPE_FROM_CLASS (klass),
1189 G_STRUCT_OFFSET (ECalClass, cal_opened),
1191 g_cclosure_marshal_VOID__INT,
1192 G_TYPE_NONE, 1, G_TYPE_INT);
1193 e_cal_signals[CAL_SET_MODE] =
1194 g_signal_new ("cal_set_mode",
1195 G_TYPE_FROM_CLASS (klass),
1197 G_STRUCT_OFFSET (ECalClass, cal_set_mode),
1199 e_cal_marshal_VOID__ENUM_ENUM,
1201 E_CAL_SET_MODE_STATUS_ENUM_TYPE,
1202 CAL_MODE_ENUM_TYPE);
1203 e_cal_signals[BACKEND_ERROR] =
1204 g_signal_new ("backend_error",
1205 G_TYPE_FROM_CLASS (klass),
1207 G_STRUCT_OFFSET (ECalClass, backend_error),
1209 g_cclosure_marshal_VOID__STRING,
1212 e_cal_signals[BACKEND_DIED] =
1213 g_signal_new ("backend_died",
1214 G_TYPE_FROM_CLASS (klass),
1216 G_STRUCT_OFFSET (ECalClass, backend_died),
1218 g_cclosure_marshal_VOID__VOID,
1221 klass->cal_opened = NULL;
1222 klass->backend_died = NULL;
1224 object_class->finalize = e_cal_finalize;
1230 * Registers the #ECal class if necessary, and returns the type ID assigned
1233 * Return value: The type ID of the #ECal class.
1236 e_cal_get_type (void)
1238 static GType e_cal_type = 0;
1241 static GTypeInfo info = {
1243 (GBaseInitFunc) NULL,
1244 (GBaseFinalizeFunc) NULL,
1245 (GClassInitFunc) e_cal_class_init,
1249 (GInstanceInitFunc) e_cal_init
1251 e_cal_type = g_type_register_static (G_TYPE_OBJECT, "ECal", &info, 0);
1259 fetch_corba_cal (ECal *ecal, ESource *source, ECalSourceType type)
1263 CORBA_Environment ev;
1266 gboolean result = FALSE;
1269 g_return_val_if_fail (priv->load_state == E_CAL_LOAD_NOT_LOADED, FALSE);
1270 g_assert (priv->uri == NULL);
1271 g_return_val_if_fail (source != NULL, FALSE);
1273 str_uri = e_source_get_uri (source);
1277 if (!get_factories (str_uri, &priv->factories)) {
1282 g_object_ref (source);
1283 priv->source = source;
1285 priv->uri = g_strdup (str_uri);
1288 source_xml = e_source_to_standalone_xml (source);
1290 for (f = priv->factories; f; f = f->next) {
1291 GNOME_Evolution_Calendar_Cal cal;
1293 CORBA_exception_init (&ev);
1295 cal = GNOME_Evolution_Calendar_CalFactory_getCal (f->data, source_xml, convert_type (priv->type),
1296 BONOBO_OBJREF (priv->listener), &ev);
1297 if (BONOBO_EX (&ev))
1307 g_free (source_xml);
1311 /* one-time start up for libecal */
1315 static GStaticMutex e_cal_lock = G_STATIC_MUTEX_INIT;
1316 static gboolean activated = FALSE;
1318 g_static_mutex_lock (&e_cal_lock);
1322 if (!bonobo_is_initialized ())
1323 bonobo_init (NULL, NULL);
1325 g_static_mutex_unlock (&e_cal_lock);
1329 /* TODO - For now, the policy of where each backend serializes its
1330 * attachment data is hardcoded below. Should this end up as a
1331 * gconf key set during the account creation and fetched
1335 set_local_attachment_store (ECal *ecal)
1342 mangled_uri = g_strdup (priv->uri);
1343 /* mangle the URI to not contain invalid characters */
1344 for (i = 0; i < strlen (mangled_uri); i++) {
1345 switch (mangled_uri[i]) {
1348 mangled_uri[i] = '_';
1352 /* the file backend uses its uri as the attachment store*/
1353 if (g_str_has_prefix (priv->uri, "file://")) {
1354 priv->local_attachment_store = g_strdup (priv->uri);
1355 } else if (g_str_has_prefix (priv->uri, "groupwise://")) {
1356 /* points to the location of the cache*/
1357 gchar *filename = g_build_filename (g_get_home_dir (),
1358 ".evolution/cache/calendar",
1361 priv->local_attachment_store =
1362 g_filename_to_uri (filename, NULL, NULL);
1364 } else if (g_str_has_prefix (priv->uri, "exchange://")) {
1365 gchar *filename = g_build_filename (g_get_home_dir (),
1366 ".evolution/exchange",
1369 priv->local_attachment_store =
1370 g_filename_to_uri (filename, NULL, NULL);
1372 } else if (g_str_has_prefix (priv->uri, "scalix://")) {
1373 gchar *filename = g_build_filename (g_get_home_dir (),
1374 ".evolution/cache/scalix",
1378 priv->local_attachment_store =
1379 g_filename_to_uri (filename, NULL, NULL);
1383 g_free (mangled_uri);
1388 * @source: An #ESource to be used for the client.
1389 * @type: Type of the client.
1391 * Creates a new calendar client. This does not open the calendar itself,
1392 * for that, #e_cal_open or #e_cal_open_async needs to be called.
1394 * Return value: A newly-created calendar client, or NULL if the client could
1395 * not be constructed because it could not contact the calendar server.
1398 e_cal_new (ESource *source, ECalSourceType type)
1404 ecal = g_object_new (E_TYPE_CAL, NULL);
1406 if (!fetch_corba_cal (ecal, source, type)) {
1407 g_object_unref (ecal);
1412 /* Set the local attachment store path for the calendar */
1413 set_local_attachment_store (ecal);
1415 /* initialize component listener */
1416 ecal->priv->comp_listener = e_component_listener_new ((Bonobo_Unknown) ecal->priv->cal);
1417 g_signal_connect (G_OBJECT (ecal->priv->comp_listener), "component_died",
1418 G_CALLBACK (backend_died_cb), ecal);
1424 * e_cal_new_from_uri:
1425 * @uri: The URI pointing to the calendar to open.
1426 * @type: Type of the client.
1428 * Creates a new calendar client. This does not open the calendar itself,
1429 * for that, #e_cal_open or #e_cal_open_async needs to be called.
1431 * Return value: A newly-created calendar client, or NULL if the client could
1432 * not be constructed because it could not contact the calendar server.
1435 e_cal_new_from_uri (const gchar *uri, ECalSourceType type)
1440 source = e_source_new_with_absolute_uri ("", uri);
1441 cal = e_cal_new (source, type);
1443 g_object_unref (source);
1449 * e_cal_new_system_calendar:
1451 * Create a calendar client for the system calendar, which should always be present in
1452 * all Evolution installations. This does not open the calendar itself,
1453 * for that, #e_cal_open or #e_cal_open_async needs to be called.
1455 * Return value: A newly-created calendar client, or NULL if the client could
1456 * not be constructed.
1459 e_cal_new_system_calendar (void)
1465 filename = g_build_filename (g_get_home_dir (),
1466 ".evolution/calendar/local/system",
1468 uri = g_filename_to_uri (filename, NULL, NULL);
1470 ecal = e_cal_new_from_uri (uri, E_CAL_SOURCE_TYPE_EVENT);
1477 * e_cal_new_system_tasks:
1479 * Create a calendar client for the system task list, which should always be present in
1480 * all Evolution installations. This does not open the tasks list itself,
1481 * for that, #e_cal_open or #e_cal_open_async needs to be called.
1483 * Return value: A newly-created calendar client, or NULL if the client could
1484 * not be constructed.
1487 e_cal_new_system_tasks (void)
1493 filename = g_build_filename (g_get_home_dir (),
1494 ".evolution/tasks/local/system",
1496 uri = g_filename_to_uri (filename, NULL, NULL);
1498 ecal = e_cal_new_from_uri (uri, E_CAL_SOURCE_TYPE_TODO);
1505 * e_cal_new_system_memos:
1507 * Create a calendar client for the system memos, which should always be present
1508 * in all Evolution installations. This does not open the memos itself, for
1509 * that, #e_cal_open or #e_cal_open_async needs to be called.
1511 * Return value: A newly-created calendar client, or NULL if the client could
1512 * not be constructed.
1515 e_cal_new_system_memos (void)
1521 filename = g_build_filename (g_get_home_dir (),
1522 ".evolution/memos/local/system",
1524 uri = g_filename_to_uri (filename, NULL, NULL);
1526 ecal = e_cal_new_from_uri (uri, E_CAL_SOURCE_TYPE_JOURNAL);
1533 * e_cal_set_auth_func
1534 * @ecal: A calendar client.
1535 * @func: The authentication function
1536 * @data: User data to be used when calling the authentication function
1538 * Sets the given authentication function on the calendar client. This
1539 * function will be called any time the calendar server needs a
1540 * password for an operation associated with the calendar and should
1541 * be supplied before any calendar is opened.
1543 * When a calendar is opened asynchronously, the open function is
1544 * processed in a concurrent thread. This means that the
1545 * authentication function will also be called from this thread. As
1546 * such, the authentication callback cannot directly call any
1547 * functions that must be called from the main thread. For example
1548 * any Gtk+ related functions, which must be proxied synchronously to
1549 * the main thread by the callback.
1551 * The authentication function has the following signature
1553 * char * auth_func (ECal *ecal,
1554 * const gchar *prompt,
1556 * gpointer user_data)
1559 e_cal_set_auth_func (ECal *ecal, ECalAuthFunc func, gpointer data)
1561 g_return_if_fail (ecal != NULL);
1562 g_return_if_fail (E_IS_CAL (ecal));
1564 ecal->priv->auth_func = func;
1565 ecal->priv->auth_user_data = data;
1569 build_proxy_pass_key (ECal *ecal, const char* parent_user)
1575 uri = e_cal_get_uri (ecal);
1577 euri = e_uri_new (uri);
1578 g_free (euri->user);
1579 euri->user = g_strdup(parent_user);
1581 euri_str = e_uri_to_string (euri, FALSE);
1588 build_pass_key (ECal *ecal)
1594 uri = e_cal_get_uri (ecal);
1596 euri = e_uri_new (uri);
1597 euri_str = e_uri_to_string (euri, FALSE);
1604 open_calendar (ECal *ecal, gboolean only_if_exists, GError **error, ECalendarStatus *status, gboolean needs_auth)
1607 CORBA_Environment ev;
1608 ECalendarOp *our_op;
1609 char *username = NULL, *auth_type = NULL, *password = NULL;
1610 gboolean read_only = FALSE;
1612 e_return_error_if_fail (ecal != NULL, E_CALENDAR_STATUS_INVALID_ARG);
1613 e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
1617 g_mutex_lock (ecal->priv->mutex);
1619 if (!needs_auth && priv->load_state == E_CAL_LOAD_LOADED) {
1620 g_mutex_unlock (ecal->priv->mutex);
1624 if (ecal->priv->current_op != NULL) {
1625 g_mutex_unlock (ecal->priv->mutex);
1626 *status = E_CALENDAR_STATUS_BUSY;
1627 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error);
1629 /* start the open operation */
1630 our_op = e_calendar_new_op (ecal);
1632 g_mutex_unlock (priv->mutex);
1634 /* see if the backend needs authentication */
1635 if ( (priv->mode != CAL_MODE_LOCAL) && e_source_get_property (priv->source, "auth")) {
1639 priv->load_state = E_CAL_LOAD_AUTHENTICATING;
1641 if (priv->auth_func == NULL) {
1642 e_calendar_remove_op (ecal, our_op);
1643 e_calendar_free_op (our_op);
1644 priv->load_state = E_CAL_LOAD_NOT_LOADED;
1645 *status = E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED;
1646 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED, error);
1649 username = e_source_get_duped_property (priv->source, "username");
1651 e_calendar_remove_op (ecal, our_op);
1652 e_calendar_free_op (our_op);
1653 priv->load_state = E_CAL_LOAD_NOT_LOADED;
1654 *status = E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED;
1655 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED, error);
1658 prompt = g_strdup_printf (_("Enter password for %s (user %s)"),
1659 e_source_peek_name (priv->source), username);
1661 auth_type = e_source_get_duped_property (priv->source, "auth-type");
1663 key = build_pass_key (ecal);
1665 parent_user = e_source_get_duped_property (priv->source, "parent_id_name");
1667 key = build_proxy_pass_key (ecal, parent_user);
1669 This password prompt will be prompted rarely. Since the key that is passed to
1670 the auth_func corresponds to the parent user.
1672 prompt = g_strdup_printf (_("Enter password for %s to enable proxy for user %s"), e_source_peek_name (priv->source), parent_user);
1673 g_free (parent_user);
1675 key = g_strdup (e_cal_get_uri (ecal));
1680 e_calendar_remove_op (ecal, our_op);
1681 e_calendar_free_op (our_op);
1682 priv->load_state = E_CAL_LOAD_NOT_LOADED;
1683 *status = E_CALENDAR_STATUS_URI_NOT_LOADED;
1684 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED, error);
1687 password = priv->auth_func (ecal, prompt, key, priv->auth_user_data);
1690 e_calendar_remove_op (ecal, our_op);
1691 e_calendar_free_op (our_op);
1692 priv->load_state = E_CAL_LOAD_NOT_LOADED;
1693 *status = E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED;
1694 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED, error);
1702 CORBA_exception_init (&ev);
1704 priv->load_state = E_CAL_LOAD_LOADING;
1706 GNOME_Evolution_Calendar_Cal_open (priv->cal, only_if_exists,
1707 username ? username : "",
1708 password ? password : "",
1713 if (BONOBO_EX (&ev)) {
1714 e_calendar_remove_op (ecal, our_op);
1715 e_calendar_free_op (our_op);
1717 CORBA_exception_free (&ev);
1719 g_warning (G_STRLOC ": Unable to contact backend");
1721 *status = E_CALENDAR_STATUS_CORBA_EXCEPTION;
1722 priv->load_state = E_CAL_LOAD_NOT_LOADED;
1723 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error);
1726 CORBA_exception_free (&ev);
1728 e_flag_wait (our_op->done);
1730 *status = our_op->status;
1732 e_calendar_remove_op (ecal, our_op);
1733 e_calendar_free_op (our_op);
1734 if (*status == E_CALENDAR_STATUS_OK) {
1735 priv->load_state = E_CAL_LOAD_LOADED;
1736 if (get_read_only (ecal, &read_only, NULL))
1737 priv->read_only = read_only;
1739 priv->load_state = E_CAL_LOAD_NOT_LOADED;
1741 E_CALENDAR_CHECK_STATUS (*status, error);
1746 * @ecal: A calendar client.
1747 * @only_if_exists: FALSE if the calendar should be opened even if there
1748 * was no storage for it, i.e. to create a new calendar or load an existing
1749 * one if it already exists. TRUE if it should only try to load calendars
1750 * that already exist.
1751 * @error: Placeholder for error information.
1753 * Makes a calendar client initiate a request to open a calendar. The calendar
1754 * client will emit the "cal_opened" signal when the response from the server is
1757 * Return value: TRUE on success, FALSE on failure to issue the open request.
1760 e_cal_open (ECal *ecal, gboolean only_if_exists, GError **error)
1762 ECalendarStatus status;
1765 result = open_calendar (ecal, only_if_exists, error, &status, FALSE);
1766 g_signal_emit (G_OBJECT (ecal), e_cal_signals[CAL_OPENED], 0, status);
1775 ECalendarStatus status;
1776 const char *auth_prompt;
1777 const char *auth_key;
1782 async_signal_idle_cb (gpointer data)
1784 ECalAsyncData *ccad = data;
1786 g_signal_emit (G_OBJECT (ccad->ecal), e_cal_signals[CAL_OPENED], 0, ccad->status);
1789 g_object_unref (ccad->ecal);
1796 open_async (gpointer data)
1798 ECalAsyncData *ccad = data;
1800 ccad->result = open_calendar (ccad->ecal, ccad->exists, NULL, &ccad->status, FALSE);
1801 g_idle_add ((GSourceFunc) async_signal_idle_cb, ccad);
1803 return GINT_TO_POINTER (ccad->result);
1808 * @ecal: A calendar client.
1809 * @only_if_exists: If TRUE, then only open the calendar if it already
1810 * exists. If FALSE, then create a new calendar if it doesn't already
1813 * Open the calendar asynchronously. The calendar will emit the
1814 * "cal_opened" signal when the operation has completed.
1816 * Because this operation runs in another thread, any authentication
1817 * callback set on the calendar will be called from this other thread.
1818 * See #e_cal_set_auth_func() for details.
1821 e_cal_open_async (ECal *ecal, gboolean only_if_exists)
1823 ECalAsyncData *ccad;
1825 GError *error = NULL;
1826 g_return_if_fail (ecal != NULL);
1827 g_return_if_fail (E_IS_CAL (ecal));
1829 switch (ecal->priv->load_state) {
1830 case E_CAL_LOAD_AUTHENTICATING :
1831 case E_CAL_LOAD_LOADING :
1832 g_signal_emit (G_OBJECT (ecal), e_cal_signals[CAL_OPENED], 0, E_CALENDAR_STATUS_BUSY);
1834 case E_CAL_LOAD_LOADED :
1835 g_signal_emit (G_OBJECT (ecal), e_cal_signals[CAL_OPENED], 0, E_CALENDAR_STATUS_OK);
1838 /* ignore everything else */
1842 ccad = g_new0 (ECalAsyncData, 1);
1843 ccad->ecal = g_object_ref (ecal);
1844 ccad->exists = only_if_exists;
1846 /* spawn a new thread for opening the calendar */
1847 thread = g_thread_create ((GThreadFunc) open_async, ccad, FALSE, &error);
1849 g_warning (G_STRLOC ": %s", error->message);
1850 g_error_free (error);
1852 /* notify listeners of the error */
1853 g_signal_emit (G_OBJECT (ecal), e_cal_signals[CAL_OPENED], 0, E_CALENDAR_STATUS_OTHER_ERROR);
1859 * @ecal: A calendar client.
1860 * @error: Placeholder for error information.
1862 * Removes a calendar.
1864 * Return value: TRUE if the calendar was removed, FALSE if there was an error.
1867 e_cal_remove (ECal *ecal, GError **error)
1870 CORBA_Environment ev;
1871 ECalendarStatus status;
1872 ECalendarOp *our_op;
1874 g_return_val_if_fail (ecal != NULL, FALSE);
1875 g_return_val_if_fail (E_IS_CAL (ecal), FALSE);
1879 g_mutex_lock (ecal->priv->mutex);
1881 if (ecal->priv->current_op != NULL) {
1882 g_mutex_unlock (ecal->priv->mutex);
1883 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error);
1886 our_op = e_calendar_new_op (ecal);
1888 g_mutex_unlock (ecal->priv->mutex);
1891 CORBA_exception_init (&ev);
1893 GNOME_Evolution_Calendar_Cal_remove (priv->cal, &ev);
1894 if (BONOBO_EX (&ev)) {
1895 e_calendar_remove_op (ecal, our_op);
1896 e_calendar_free_op (our_op);
1898 CORBA_exception_free (&ev);
1900 g_warning (G_STRLOC ": Unable to contact backend");
1902 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error);
1905 CORBA_exception_free (&ev);
1907 e_flag_wait (our_op->done);
1909 status = our_op->status;
1911 e_calendar_remove_op (ecal, our_op);
1912 e_calendar_free_op (our_op);
1914 E_CALENDAR_CHECK_STATUS (status, error);
1918 /* Builds an URI list out of a CORBA string sequence */
1920 build_uri_list (GNOME_Evolution_Calendar_StringSeq *seq)
1925 for (i = 0; i < seq->_length; i++)
1926 uris = g_list_prepend (uris, g_strdup (seq->_buffer[i]));
1934 * @ecal: A calendar client.
1935 * @mode: Mode of the URIs to get.
1937 * Retrieves a list of all calendar clients for the given mode.
1939 * Return value: list of uris.
1942 e_cal_uri_list (ECal *ecal, CalMode mode)
1946 GNOME_Evolution_Calendar_StringSeq *uri_seq;
1948 CORBA_Environment ev;
1951 g_return_val_if_fail (ecal != NULL, FALSE);
1952 g_return_val_if_fail (E_IS_CAL (ecal), FALSE);
1956 for (f = priv->factories; f; f = f->next) {
1957 CORBA_exception_init (&ev);
1958 uri_seq = GNOME_Evolution_Calendar_CalFactory_uriList (f->data, mode, &ev);
1960 if (BONOBO_EX (&ev)) {
1961 g_message ("e_cal_uri_list(): request failed");
1963 /* free memory and return */
1964 g_list_foreach (uris, (GFunc) g_free, NULL);
1970 uris = g_list_concat (uris, build_uri_list (uri_seq));
1971 CORBA_free (uri_seq);
1974 CORBA_exception_free (&ev);
1984 * e_cal_get_source_type:
1985 * @ecal: A calendar client.
1987 * Gets the type of the calendar client.
1989 * Return value: an #ECalSourceType value corresponding to the type
1990 * of the calendar client.
1993 e_cal_get_source_type (ECal *ecal)
1997 g_return_val_if_fail (ecal != NULL, E_CAL_SOURCE_TYPE_LAST);
1998 g_return_val_if_fail (E_IS_CAL (ecal), E_CAL_SOURCE_TYPE_LAST);
2006 * e_cal_get_load_state:
2007 * @ecal: A calendar client.
2009 * Queries the state of loading of a calendar client.
2011 * Return value: A #ECalLoadState value indicating whether the client has
2012 * not been loaded with #e_cal_open yet, whether it is being
2013 * loaded, or whether it is already loaded.
2016 e_cal_get_load_state (ECal *ecal)
2020 g_return_val_if_fail (ecal != NULL, E_CAL_LOAD_NOT_LOADED);
2021 g_return_val_if_fail (E_IS_CAL (ecal), E_CAL_LOAD_NOT_LOADED);
2024 return priv->load_state;
2029 * @ecal: A calendar client.
2031 * Queries the source that is open in a calendar client.
2033 * Return value: The source of the calendar that is already loaded or is being
2034 * loaded, or NULL if the ecal has not started a load request yet.
2037 e_cal_get_source (ECal *ecal)
2041 g_return_val_if_fail (ecal != NULL, NULL);
2042 g_return_val_if_fail (E_IS_CAL (ecal), NULL);
2045 return priv->source;
2050 * @ecal: A calendar client.
2052 * Queries the URI that is open in a calendar client.
2054 * Return value: The URI of the calendar that is already loaded or is being
2055 * loaded, or NULL if the client has not started a load request yet.
2058 e_cal_get_uri (ECal *ecal)
2062 g_return_val_if_fail (ecal != NULL, NULL);
2063 g_return_val_if_fail (E_IS_CAL (ecal), NULL);
2070 * e_cal_get_local_attachment_store
2071 * @ecal: A calendar client.
2073 * Queries the URL where the calendar attachments are
2074 * serialized in the local filesystem. This enable clients
2075 * to operate with the reference to attachments rather than the data itself
2076 * unless it specifically uses the attachments for open/sending
2079 * Return value: The URL where the attachments are serialized in the
2083 e_cal_get_local_attachment_store (ECal *ecal)
2087 g_return_val_if_fail (ecal != NULL, NULL);
2088 g_return_val_if_fail (E_IS_CAL (ecal), NULL);
2091 return (const char *)priv->local_attachment_store;
2095 * e_cal_is_read_only:
2096 * @ecal: A calendar client.
2097 * @read_only: Return value for read only status.
2098 * @error: Placeholder for error information.
2100 * Queries whether the calendar client can perform modifications
2101 * on the calendar or not. Whether the backend is read only or not
2102 * is specified, on exit, in the @read_only argument.
2104 * Return value: TRUE if the call was successful, FALSE if there was an error.
2107 e_cal_is_read_only (ECal *ecal, gboolean *read_only, GError **error)
2111 if (!(ecal && E_IS_CAL (ecal)))
2112 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_INVALID_ARG, error);
2115 *read_only = priv->read_only;
2121 get_read_only (ECal *ecal, gboolean *read_only, GError **error)
2124 CORBA_Environment ev;
2125 ECalendarStatus status;
2126 ECalendarOp *our_op;
2129 g_mutex_lock (ecal->priv->mutex);
2131 if (ecal->priv->load_state != E_CAL_LOAD_LOADED) {
2132 g_mutex_unlock (ecal->priv->mutex);
2133 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
2136 if (ecal->priv->current_op != NULL) {
2137 g_mutex_unlock (ecal->priv->mutex);
2138 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error);
2141 our_op = e_calendar_new_op (ecal);
2143 /* set it to true so that op does not emit cond signals for all notifications
2145 our_op->bool = TRUE;
2147 g_mutex_unlock (ecal->priv->mutex);
2150 CORBA_exception_init (&ev);
2152 GNOME_Evolution_Calendar_Cal_isReadOnly (priv->cal, &ev);
2153 if (BONOBO_EX (&ev)) {
2154 e_calendar_remove_op (ecal, our_op);
2155 e_calendar_free_op (our_op);
2157 CORBA_exception_free (&ev);
2159 g_warning (G_STRLOC ": Unable to contact backend");
2161 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error);
2164 CORBA_exception_free (&ev);
2166 e_flag_wait (our_op->done);
2168 status = our_op->status;
2170 if (status == E_CALENDAR_STATUS_OK)
2171 *read_only = our_op->bool;
2173 e_calendar_remove_op (ecal, our_op);
2174 e_calendar_free_op (our_op);
2175 E_CALENDAR_CHECK_STATUS (status, error);
2179 * e_cal_get_cal_address:
2180 * @ecal: A calendar client.
2181 * @cal_address: Return value for address information.
2182 * @error: Placeholder for error information.
2184 * Queries the calendar address associated with a calendar client.
2186 * Return value: TRUE if the operation was successful, FALSE if there
2190 e_cal_get_cal_address (ECal *ecal, char **cal_address, GError **error)
2193 CORBA_Environment ev;
2194 ECalendarStatus status;
2195 ECalendarOp *our_op;
2198 if (!(ecal && E_IS_CAL (ecal)))
2199 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_INVALID_ARG, error);
2201 if (priv->cal_address == NULL) {
2202 g_mutex_lock (ecal->priv->mutex);
2204 if (ecal->priv->load_state != E_CAL_LOAD_LOADED) {
2205 g_mutex_unlock (ecal->priv->mutex);
2206 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
2209 if (ecal->priv->current_op != NULL) {
2210 g_mutex_unlock (ecal->priv->mutex);
2211 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error);
2214 our_op = e_calendar_new_op (ecal);
2216 g_mutex_unlock (ecal->priv->mutex);
2219 CORBA_exception_init (&ev);
2221 GNOME_Evolution_Calendar_Cal_getCalAddress (priv->cal, &ev);
2222 if (BONOBO_EX (&ev)) {
2223 e_calendar_remove_op (ecal, our_op);
2224 e_calendar_free_op (our_op);
2226 CORBA_exception_free (&ev);
2228 g_warning (G_STRLOC ": Unable to contact backend");
2230 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error);
2233 CORBA_exception_free (&ev);
2235 e_flag_wait (our_op->done);
2237 status = our_op->status;
2238 *cal_address = our_op->string;
2239 e_calendar_remove_op (ecal, our_op);
2240 e_calendar_free_op (our_op);
2242 E_CALENDAR_CHECK_STATUS (status, error);
2244 *cal_address = g_strdup (priv->cal_address);
2251 * e_cal_get_alarm_email_address:
2252 * @ecal: A calendar client.
2253 * @alarm_address: Return value for alarm address.
2254 * @error: Placeholder for error information.
2256 * Queries the address to be used for alarms in a calendar client.
2258 * Return value: TRUE if the operation was successful, FALSE if there was
2259 * an error while contacting the backend.
2262 e_cal_get_alarm_email_address (ECal *ecal, char **alarm_address, GError **error)
2265 CORBA_Environment ev;
2266 ECalendarStatus status;
2267 ECalendarOp *our_op;
2269 e_return_error_if_fail (ecal && E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
2273 g_mutex_lock (ecal->priv->mutex);
2275 if (ecal->priv->load_state != E_CAL_LOAD_LOADED) {
2276 g_mutex_unlock (ecal->priv->mutex);
2277 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
2280 if (ecal->priv->current_op != NULL) {
2281 g_mutex_unlock (ecal->priv->mutex);
2282 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error);
2285 our_op = e_calendar_new_op (ecal);
2287 g_mutex_unlock (ecal->priv->mutex);
2290 CORBA_exception_init (&ev);
2292 GNOME_Evolution_Calendar_Cal_getAlarmEmailAddress (priv->cal, &ev);
2293 if (BONOBO_EX (&ev)) {
2294 e_calendar_remove_op (ecal, our_op);
2295 e_calendar_free_op (our_op);
2297 CORBA_exception_free (&ev);
2299 g_warning (G_STRLOC ": Unable to contact backend");
2301 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error);
2304 CORBA_exception_free (&ev);
2306 e_flag_wait (our_op->done);
2308 status = our_op->status;
2309 *alarm_address = our_op->string;
2311 e_calendar_remove_op (ecal, our_op);
2312 e_calendar_free_op (our_op);
2314 E_CALENDAR_CHECK_STATUS (status, error);
2318 * e_cal_get_ldap_attribute:
2319 * @ecal: A calendar client.
2320 * @ldap_attribute: Return value for the LDAP attribute.
2321 * @error: Placeholder for error information.
2323 * Queries the LDAP attribute for a calendar client.
2325 * Return value: TRUE if the call was successful, FALSE if there was an
2326 * error contacting the backend.
2329 e_cal_get_ldap_attribute (ECal *ecal, char **ldap_attribute, GError **error)
2332 CORBA_Environment ev;
2333 ECalendarStatus status;
2334 ECalendarOp *our_op;
2336 e_return_error_if_fail (ecal && E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
2340 g_mutex_lock (ecal->priv->mutex);
2342 if (ecal->priv->load_state != E_CAL_LOAD_LOADED) {
2343 g_mutex_unlock (ecal->priv->mutex);
2344 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
2347 if (ecal->priv->current_op != NULL) {
2348 g_mutex_unlock (ecal->priv->mutex);
2349 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error);
2352 our_op = e_calendar_new_op (ecal);
2354 g_mutex_unlock (ecal->priv->mutex);
2357 CORBA_exception_init (&ev);
2359 GNOME_Evolution_Calendar_Cal_getLdapAttribute (priv->cal, &ev);
2360 if (BONOBO_EX (&ev)) {
2361 e_calendar_remove_op (ecal, our_op);
2362 e_calendar_free_op (our_op);
2364 CORBA_exception_free (&ev);
2366 g_warning (G_STRLOC ": Unable to contact backend");
2368 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error);
2371 CORBA_exception_free (&ev);
2373 e_flag_wait (our_op->done);
2375 status = our_op->status;
2376 *ldap_attribute = our_op->string;
2378 e_calendar_remove_op (ecal, our_op);
2379 e_calendar_free_op (our_op);
2381 E_CALENDAR_CHECK_STATUS (status, error);
2385 load_static_capabilities (ECal *ecal, GError **error)
2388 CORBA_Environment ev;
2389 ECalendarStatus status;
2390 ECalendarOp *our_op;
2394 if (priv->capabilities)
2395 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
2397 g_mutex_lock (ecal->priv->mutex);
2399 if (ecal->priv->load_state != E_CAL_LOAD_LOADED) {
2400 g_mutex_unlock (ecal->priv->mutex);
2401 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
2404 if (ecal->priv->current_op != NULL) {
2405 g_mutex_unlock (ecal->priv->mutex);
2406 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error);
2409 our_op = e_calendar_new_op (ecal);
2411 g_mutex_unlock (ecal->priv->mutex);
2414 CORBA_exception_init (&ev);
2416 GNOME_Evolution_Calendar_Cal_getStaticCapabilities (priv->cal, &ev);
2417 if (BONOBO_EX (&ev)) {
2418 e_calendar_remove_op (ecal, our_op);
2419 e_calendar_free_op (our_op);
2421 CORBA_exception_free (&ev);
2423 g_warning (G_STRLOC ": Unable to contact backend");
2425 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error);
2428 CORBA_exception_free (&ev);
2430 e_flag_wait (our_op->done);
2432 status = our_op->status;
2433 priv->capabilities = our_op->string;
2435 e_calendar_remove_op (ecal, our_op);
2436 e_calendar_free_op (our_op);
2438 E_CALENDAR_CHECK_STATUS (status, error);
2442 check_capability (ECal *ecal, const char *cap)
2448 /* FIXME Check result */
2449 load_static_capabilities (ecal, NULL);
2450 if (priv->capabilities && strstr (priv->capabilities, cap))
2457 * e_cal_get_one_alarm_only:
2458 * @ecal: A calendar client.
2460 * Checks if a calendar supports only one alarm per component.
2462 * Return value: TRUE if the calendar allows only one alarm, FALSE otherwise.
2465 e_cal_get_one_alarm_only (ECal *ecal)
2467 g_return_val_if_fail (ecal != NULL, FALSE);
2468 g_return_val_if_fail (ecal && E_IS_CAL (ecal), FALSE);
2470 return check_capability (ecal, CAL_STATIC_CAPABILITY_ONE_ALARM_ONLY);
2474 * e_cal_get_organizer_must_attend:
2475 * @ecal: A calendar client.
2477 * Checks if a calendar forces organizers of meetings to be also attendees.
2479 * Return value: TRUE if the calendar forces organizers to attend meetings,
2483 e_cal_get_organizer_must_attend (ECal *ecal)
2485 g_return_val_if_fail (ecal != NULL, FALSE);
2486 g_return_val_if_fail (E_IS_CAL (ecal), FALSE);
2488 return check_capability (ecal, CAL_STATIC_CAPABILITY_ORGANIZER_MUST_ATTEND);
2492 * e_cal_get_recurrences_no_master:
2493 * @ecal: A calendar client.
2495 * Checks if the calendar has a master object for recurrences.
2497 * Return value: TRUE if the calendar has a master object for recurrences,
2501 e_cal_get_recurrences_no_master (ECal *ecal)
2503 g_return_val_if_fail (ecal != NULL, FALSE);
2504 g_return_val_if_fail (E_IS_CAL (ecal), FALSE);
2506 return check_capability (ecal, CAL_STATIC_CAPABILITY_RECURRENCES_NO_MASTER);
2510 * e_cal_get_static_capability:
2511 * @ecal: A calendar client.
2512 * @cap: Name of the static capability to check.
2514 * Queries the calendar for static capabilities.
2516 * Return value: TRUE if the capability is supported, FALSE otherwise.
2519 e_cal_get_static_capability (ECal *ecal, const char *cap)
2521 g_return_val_if_fail (ecal != NULL, FALSE);
2522 g_return_val_if_fail (E_IS_CAL (ecal), FALSE);
2524 return check_capability (ecal, cap);
2528 * e_cal_get_save_schedules:
2529 * @ecal: A calendar client.
2531 * Checks whether the calendar saves schedules.
2533 * Return value: TRUE if it saves schedules, FALSE otherwise.
2536 e_cal_get_save_schedules (ECal *ecal)
2538 g_return_val_if_fail (ecal != NULL, FALSE);
2539 g_return_val_if_fail (E_IS_CAL (ecal), FALSE);
2541 return check_capability (ecal, CAL_STATIC_CAPABILITY_SAVE_SCHEDULES);
2545 * e_cal_get_organizer_must_accept:
2546 * @ecal: A calendar client.
2548 * Checks whether a calendar requires organizer to accept their attendance to
2551 * Return value: TRUE if the calendar requires organizers to accept, FALSE
2555 e_cal_get_organizer_must_accept (ECal *ecal)
2557 g_return_val_if_fail (ecal != NULL, FALSE);
2558 g_return_val_if_fail (E_IS_CAL (ecal), FALSE);
2560 return check_capability (ecal, CAL_STATIC_CAPABILITY_ORGANIZER_MUST_ACCEPT);
2565 * @ecal: A calendar client.
2566 * @mode: Mode to switch to.
2568 * Switches online/offline mode on the calendar.
2570 * Return value: TRUE if the switch was successful, FALSE if there was an error.
2573 e_cal_set_mode (ECal *ecal, CalMode mode)
2576 gboolean retval = TRUE;
2577 CORBA_Environment ev;
2579 g_return_val_if_fail (ecal != NULL, -1);
2580 g_return_val_if_fail (E_IS_CAL (ecal), -1);
2583 g_return_val_if_fail (priv->load_state == E_CAL_LOAD_LOADED, -1);
2585 CORBA_exception_init (&ev);
2586 GNOME_Evolution_Calendar_Cal_setMode (priv->cal, mode, &ev);
2588 if (BONOBO_EX (&ev))
2591 CORBA_exception_free (&ev);
2596 /* This is used in the callback which fetches all the timezones needed for an
2598 typedef struct _ECalGetTimezonesData ECalGetTimezonesData;
2599 struct _ECalGetTimezonesData {
2602 /* This starts out at E_CALENDAR_STATUS_OK. If an error occurs this
2603 contains the last error. */
2604 ECalendarStatus status;
2608 * e_cal_get_default_object:
2609 * @ecal: A calendar client.
2610 * @icalcomp: Return value for the default object.
2611 * @error: Placeholder for error information.
2613 * Retrives an #icalcomponent from the backend that contains the default
2614 * values for properties needed.
2616 * Return value: TRUE if the call was successful, FALSE otherwise.
2619 e_cal_get_default_object (ECal *ecal, icalcomponent **icalcomp, GError **error)
2622 CORBA_Environment ev;
2623 ECalendarStatus status;
2624 ECalendarOp *our_op;
2626 e_return_error_if_fail (ecal && E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
2630 g_mutex_lock (ecal->priv->mutex);
2632 if (ecal->priv->load_state != E_CAL_LOAD_LOADED) {
2633 g_mutex_unlock (ecal->priv->mutex);
2634 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
2637 if (ecal->priv->current_op != NULL) {
2638 g_mutex_unlock (ecal->priv->mutex);
2639 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error);
2642 our_op = e_calendar_new_op (ecal);
2644 g_mutex_unlock (ecal->priv->mutex);
2646 CORBA_exception_init (&ev);
2648 GNOME_Evolution_Calendar_Cal_getDefaultObject (priv->cal, &ev);
2649 if (BONOBO_EX (&ev)) {
2650 e_calendar_remove_op (ecal, our_op);
2651 e_calendar_free_op (our_op);
2653 CORBA_exception_free (&ev);
2655 g_warning (G_STRLOC ": Unable to contact backend");
2657 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error);
2660 CORBA_exception_free (&ev);
2662 e_flag_wait (our_op->done);
2664 status = our_op->status;
2665 if (status != E_CALENDAR_STATUS_OK) {
2668 *icalcomp = icalparser_parse_string (our_op->string);
2670 status = E_CALENDAR_STATUS_INVALID_OBJECT;
2672 g_free (our_op->string);
2674 e_calendar_remove_op (ecal, our_op);
2675 e_calendar_free_op (our_op);
2677 E_CALENDAR_CHECK_STATUS (status, error);
2681 * e_cal_get_attachments_for_comp:
2682 * @ecal: A calendar client.
2683 * @uid: Unique identifier for a calendar component.
2684 * @rid: Recurrence identifier.
2685 * @list: Return the list of attachment uris.
2686 * @error: Placeholder for error information.
2688 * Queries a calendar for a calendar component object based on its unique
2689 * identifier and gets the attachments for the component.
2691 * Return value: TRUE if the call was successful, FALSE otherwise.
2694 e_cal_get_attachments_for_comp (ECal *ecal, const char *uid, const char *rid, GSList **list, GError **error)
2697 CORBA_Environment ev;
2698 ECalendarStatus status;
2699 ECalendarOp *our_op;
2701 e_return_error_if_fail (ecal && E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
2705 g_mutex_lock (ecal->priv->mutex);
2707 if (ecal->priv->load_state != E_CAL_LOAD_LOADED) {
2708 g_mutex_unlock (ecal->priv->mutex);
2709 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
2712 if (ecal->priv->current_op != NULL) {
2713 g_mutex_unlock (ecal->priv->mutex);
2714 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error);
2717 our_op = e_calendar_new_op (ecal);
2719 g_mutex_unlock (ecal->priv->mutex);
2721 CORBA_exception_init (&ev);
2722 GNOME_Evolution_Calendar_Cal_getAttachmentList (priv->cal, uid, rid ? rid : "", &ev);
2723 if (BONOBO_EX (&ev)) {
2724 e_calendar_remove_op (ecal, our_op);
2725 e_calendar_free_op (our_op);
2727 CORBA_exception_free (&ev);
2729 g_warning (G_STRLOC ": Unable to contact backend");
2731 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error);
2734 CORBA_exception_free (&ev);
2736 e_flag_wait (our_op->done);
2738 status = our_op->status;
2739 if (status != E_CALENDAR_STATUS_OK){
2742 *list = our_op->slist;
2745 e_calendar_remove_op (ecal, our_op);
2746 e_calendar_free_op (our_op);
2748 E_CALENDAR_CHECK_STATUS (status, error);
2753 * @ecal: A calendar client.
2754 * @uid: Unique identifier for a calendar component.
2755 * @rid: Recurrence identifier.
2756 * @icalcomp: Return value for the calendar component object.
2757 * @error: Placeholder for error information.
2759 * Queries a calendar for a calendar component object based on its unique
2762 * Return value: TRUE if the call was successful, FALSE otherwise.
2765 e_cal_get_object (ECal *ecal, const char *uid, const char *rid, icalcomponent **icalcomp, GError **error)
2768 CORBA_Environment ev;
2769 ECalendarStatus status;
2770 ECalendarOp *our_op;
2772 e_return_error_if_fail (ecal && E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
2776 g_mutex_lock (ecal->priv->mutex);
2778 if (ecal->priv->load_state != E_CAL_LOAD_LOADED) {
2779 g_mutex_unlock (ecal->priv->mutex);
2780 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
2783 if (ecal->priv->current_op != NULL) {
2784 g_mutex_unlock (ecal->priv->mutex);
2785 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error);
2788 our_op = e_calendar_new_op (ecal);
2790 g_mutex_unlock (ecal->priv->mutex);
2792 CORBA_exception_init (&ev);
2794 GNOME_Evolution_Calendar_Cal_getObject (priv->cal, uid, rid ? rid : "", &ev);
2795 if (BONOBO_EX (&ev)) {
2796 e_calendar_remove_op (ecal, our_op);
2797 e_calendar_free_op (our_op);
2799 CORBA_exception_free (&ev);
2801 g_warning (G_STRLOC ": Unable to contact backend");
2803 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error);
2806 CORBA_exception_free (&ev);
2808 e_flag_wait (our_op->done);
2810 status = our_op->status;
2811 if (status != E_CALENDAR_STATUS_OK){
2814 icalcomponent *tmp_icalcomp;
2815 icalcomponent_kind kind;
2817 tmp_icalcomp = icalparser_parse_string (our_op->string);
2818 if (!tmp_icalcomp) {
2819 status = E_CALENDAR_STATUS_INVALID_OBJECT;
2822 kind = icalcomponent_isa (tmp_icalcomp);
2823 if ((kind == ICAL_VEVENT_COMPONENT && priv->type == E_CAL_SOURCE_TYPE_EVENT) ||
2824 (kind == ICAL_VTODO_COMPONENT && priv->type == E_CAL_SOURCE_TYPE_TODO) ||
2825 (kind == ICAL_VJOURNAL_COMPONENT && priv->type == E_CAL_SOURCE_TYPE_JOURNAL)) {
2826 *icalcomp = icalcomponent_new_clone (tmp_icalcomp);
2827 } else if (kind == ICAL_VCALENDAR_COMPONENT) {
2828 icalcomponent *subcomp = NULL;
2830 switch (priv->type) {
2831 case E_CAL_SOURCE_TYPE_EVENT :
2832 subcomp = icalcomponent_get_first_component (tmp_icalcomp, ICAL_VEVENT_COMPONENT);
2834 case E_CAL_SOURCE_TYPE_TODO :
2835 subcomp = icalcomponent_get_first_component (tmp_icalcomp, ICAL_VTODO_COMPONENT);
2837 case E_CAL_SOURCE_TYPE_JOURNAL :
2838 subcomp = icalcomponent_get_first_component (tmp_icalcomp, ICAL_VJOURNAL_COMPONENT);
2841 /* ignore everything else */
2845 /* we are only interested in the first component */
2847 *icalcomp = icalcomponent_new_clone (subcomp);
2850 icalcomponent_free (tmp_icalcomp);
2853 g_free (our_op->string);
2855 e_calendar_remove_op (ecal, our_op);
2856 e_calendar_free_op (our_op);
2858 E_CALENDAR_CHECK_STATUS (status, error);
2862 * e_cal_get_objects_for_uid:
2863 * @ecal: A calendar client.
2864 * @uid: Unique identifier for a calendar component.
2865 * @objects: Return value for the list of objects obtained from the backend.
2866 * @error: Placeholder for error information.
2868 * Queries a calendar for all calendar components with the given unique
2869 * ID. This will return any recurring event and all its detached recurrences.
2870 * For non-recurring events, it will just return the object with that ID.
2872 * Return value: TRUE if the call was successful, FALSE otherwise.
2875 e_cal_get_objects_for_uid (ECal *ecal, const char *uid, GList **objects, GError **error)
2878 CORBA_Environment ev;
2879 ECalendarStatus status;
2880 ECalendarOp *our_op;
2882 e_return_error_if_fail (ecal && E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
2887 g_mutex_lock (ecal->priv->mutex);
2889 if (ecal->priv->load_state != E_CAL_LOAD_LOADED) {
2890 g_mutex_unlock (ecal->priv->mutex);
2891 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
2894 if (ecal->priv->current_op != NULL) {
2895 g_mutex_unlock (ecal->priv->mutex);
2896 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error);
2899 our_op = e_calendar_new_op (ecal);
2901 g_mutex_unlock (ecal->priv->mutex);
2903 CORBA_exception_init (&ev);
2905 GNOME_Evolution_Calendar_Cal_getObject (priv->cal, uid, "", &ev);
2906 if (BONOBO_EX (&ev)) {
2907 e_calendar_remove_op (ecal, our_op);
2908 e_calendar_free_op (our_op);
2910 CORBA_exception_free (&ev);
2912 g_warning (G_STRLOC ": Unable to contact backend");
2914 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error);
2917 CORBA_exception_free (&ev);
2919 e_flag_wait (our_op->done);
2921 status = our_op->status;
2922 if (status != E_CALENDAR_STATUS_OK){
2925 icalcomponent *icalcomp;
2926 icalcomponent_kind kind;
2928 icalcomp = icalparser_parse_string (our_op->string);
2930 status = E_CALENDAR_STATUS_INVALID_OBJECT;
2933 ECalComponent *comp;
2935 kind = icalcomponent_isa (icalcomp);
2936 if ((kind == ICAL_VEVENT_COMPONENT && priv->type == E_CAL_SOURCE_TYPE_EVENT) ||
2937 (kind == ICAL_VTODO_COMPONENT && priv->type == E_CAL_SOURCE_TYPE_TODO)) {
2938 comp = e_cal_component_new ();
2939 e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (icalcomp));
2940 *objects = g_list_append (NULL, comp);
2941 } else if (kind == ICAL_VCALENDAR_COMPONENT) {
2942 icalcomponent *subcomp;
2943 icalcomponent_kind kind_to_find;
2945 switch (priv->type) {
2946 case E_CAL_SOURCE_TYPE_EVENT :
2947 kind_to_find = ICAL_VEVENT_COMPONENT;
2949 case E_CAL_SOURCE_TYPE_TODO :
2950 kind_to_find = ICAL_VTODO_COMPONENT;
2952 case E_CAL_SOURCE_TYPE_JOURNAL :
2953 kind_to_find = ICAL_VJOURNAL_COMPONENT;
2956 /* ignore everything else */
2957 kind_to_find = ICAL_NO_COMPONENT;
2962 subcomp = icalcomponent_get_first_component (icalcomp, kind_to_find);
2964 comp = e_cal_component_new ();
2965 e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (subcomp));
2966 *objects = g_list_append (*objects, comp);
2967 subcomp = icalcomponent_get_next_component (icalcomp, kind_to_find);
2971 icalcomponent_free (icalcomp);
2974 g_free (our_op->string);
2976 e_calendar_remove_op (ecal, our_op);
2977 e_calendar_free_op (our_op);
2979 E_CALENDAR_CHECK_STATUS (status, error);
2983 * e_cal_resolve_tzid_cb:
2984 * @tzid: ID of the timezone to resolve.
2985 * @data: Closure data for the callback.
2987 * Resolves TZIDs for the recurrence generator.
2989 * Return value: The timezone identified by the @tzid argument, or %NULL if
2990 * it could not be found.
2993 e_cal_resolve_tzid_cb (const char *tzid, gpointer data)
2996 icaltimezone *zone = NULL;
2998 g_return_val_if_fail (data != NULL, NULL);
2999 g_return_val_if_fail (E_IS_CAL (data), NULL);
3001 ecal = E_CAL (data);
3003 /* FIXME: Handle errors. */
3004 e_cal_get_timezone (ecal, tzid, &zone, NULL);
3010 * e_cal_get_changes:
3011 * @ecal: A calendar client.
3012 * @change_id: ID to use for comparing changes.
3013 * @changes: Return value for the list of changes.
3014 * @error: Placeholder for error information.
3016 * Returns a list of changes made to the calendar since a specific time. That time
3017 * is identified by the @change_id argument, which is used by the backend to
3018 * compute the changes done.
3020 * Return value: TRUE if the call was successful, FALSE otherwise.
3023 e_cal_get_changes (ECal *ecal, const char *change_id, GList **changes, GError **error)
3025 CORBA_Environment ev;
3026 ECalendarOp *our_op;
3027 ECalendarStatus status;
3029 e_return_error_if_fail (ecal && E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
3030 e_return_error_if_fail (change_id, E_CALENDAR_STATUS_INVALID_ARG);
3032 g_mutex_lock (ecal->priv->mutex);
3034 if (ecal->priv->load_state != E_CAL_LOAD_LOADED) {
3035 g_mutex_unlock (ecal->priv->mutex);
3036 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
3039 if (ecal->priv->current_op != NULL) {
3040 g_mutex_unlock (ecal->priv->mutex);
3041 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error);
3044 our_op = e_calendar_new_op (ecal);
3046 g_mutex_unlock (ecal->priv->mutex);
3048 CORBA_exception_init (&ev);
3050 GNOME_Evolution_Calendar_Cal_getChanges (ecal->priv->cal, change_id, &ev);
3052 if (BONOBO_EX (&ev)) {
3053 e_calendar_remove_op (ecal, our_op);
3054 e_calendar_free_op (our_op);
3056 CORBA_exception_free (&ev);
3058 g_warning (G_STRLOC ": Unable to contact backend");
3060 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error);
3063 CORBA_exception_free (&ev);
3065 e_flag_wait (our_op->done);
3067 status = our_op->status;
3068 *changes = our_op->list;
3070 e_calendar_remove_op (ecal, our_op);
3071 e_calendar_free_op (our_op);
3073 E_CALENDAR_CHECK_STATUS (status, error);
3077 * e_cal_free_change_list:
3078 * @list: List of changes to be freed.
3080 * Free a list of changes as returned by #e_cal_get_changes.
3083 e_cal_free_change_list (GList *list)
3088 for (l = list; l; l = l->next) {
3091 g_assert (c != NULL);
3092 g_assert (c->comp != NULL);
3094 g_object_unref (G_OBJECT (c->comp));
3102 * e_cal_get_object_list:
3103 * @ecal: A calendar client.
3104 * @query: Query string.
3105 * @objects: Return value for list of objects.
3106 * @error: Placeholder for error information.
3108 * Gets a list of objects from the calendar that match the query specified
3109 * by the @query argument. The objects will be returned in the @objects
3110 * argument, which is a list of #icalcomponent. When done, this list
3111 * should be freed by using the #e_cal_free_object_list function.
3113 * Return value: TRUE if the operation was successful, FALSE otherwise.
3116 e_cal_get_object_list (ECal *ecal, const char *query, GList **objects, GError **error)
3118 CORBA_Environment ev;
3119 ECalendarOp *our_op;
3120 ECalendarStatus status;
3123 e_return_error_if_fail (ecal && E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
3124 e_return_error_if_fail (query, E_CALENDAR_STATUS_INVALID_ARG);
3126 g_mutex_lock (ecal->priv->mutex);
3128 if (ecal->priv->load_state != E_CAL_LOAD_LOADED) {
3129 g_mutex_unlock (ecal->priv->mutex);
3130 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
3133 if (ecal->priv->current_op != NULL) {
3134 g_mutex_unlock (ecal->priv->mutex);
3135 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error);
3138 our_op = e_calendar_new_op (ecal);
3140 g_mutex_unlock (ecal->priv->mutex);
3142 CORBA_exception_init (&ev);
3144 GNOME_Evolution_Calendar_Cal_getObjectList (ecal->priv->cal, query, &ev);
3146 if (BONOBO_EX (&ev)) {
3147 e_calendar_remove_op (ecal, our_op);
3148 e_calendar_free_op (our_op);
3150 CORBA_exception_free (&ev);
3152 g_warning (G_STRLOC ": Unable to contact backend");
3154 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error);
3157 CORBA_exception_free (&ev);
3159 e_flag_wait (our_op->done);
3161 status = our_op->status;
3162 *objects = our_op->list;
3164 e_calendar_remove_op (ecal, our_op);
3165 e_calendar_free_op (our_op);
3167 E_CALENDAR_CHECK_STATUS (status, error);
3171 * e_cal_get_object_list_as_comp:
3172 * @ecal: A calendar client.
3173 * @query: Query string.
3174 * @objects: Return value for list of objects.
3175 * @error: Placeholder for error information.
3177 * Gets a list of objects from the calendar that match the query specified
3178 * by the @query argument. The objects will be returned in the @objects
3179 * argument, which is a list of #ECalComponent.
3181 * Return value: TRUE if the operation was successful, FALSE otherwise.
3184 e_cal_get_object_list_as_comp (ECal *ecal, const char *query, GList **objects, GError **error)
3186 GList *ical_objects = NULL;
3189 e_return_error_if_fail (ecal && E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
3190 e_return_error_if_fail (query, E_CALENDAR_STATUS_INVALID_ARG);
3191 e_return_error_if_fail (objects, E_CALENDAR_STATUS_INVALID_ARG);
3193 if (!e_cal_get_object_list (ecal, query, &ical_objects, error))
3197 for (l = ical_objects; l; l = l->next) {
3198 ECalComponent *comp;
3200 comp = e_cal_component_new ();
3201 e_cal_component_set_icalcomponent (comp, l->data);
3202 *objects = g_list_prepend (*objects, comp);
3205 g_list_free (ical_objects);
3211 * e_cal_free_object_list:
3212 * @objects: List of objects to be freed.
3214 * Frees a list of objects as returned by #e_cal_get_object_list.
3217 e_cal_free_object_list (GList *objects)
3221 for (l = objects; l; l = l->next)
3222 icalcomponent_free (l->data);
3224 g_list_free (objects);
3228 * e_cal_get_free_busy
3229 * @ecal: A calendar client.
3230 * @users: List of users to retrieve free/busy information for.
3231 * @start: Start time for query.
3232 * @end: End time for query.
3233 * @freebusy: Return value for VFREEBUSY objects.
3234 * @error: Placeholder for error information.
3236 * Gets free/busy information from the calendar server.
3238 * Returns: TRUE if the operation was successful, FALSE otherwise.
3241 e_cal_get_free_busy (ECal *ecal, GList *users, time_t start, time_t end,
3242 GList **freebusy, GError **error)
3244 CORBA_Environment ev;
3245 ECalendarOp *our_op;
3246 ECalendarStatus status;
3247 GNOME_Evolution_Calendar_UserList corba_users;
3251 e_return_error_if_fail (ecal && E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
3253 g_mutex_lock (ecal->priv->mutex);
3255 if (ecal->priv->load_state != E_CAL_LOAD_LOADED) {
3256 g_mutex_unlock (ecal->priv->mutex);
3257 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
3260 if (ecal->priv->current_op != NULL) {
3261 g_mutex_unlock (ecal->priv->mutex);
3262 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error);
3265 our_op = e_calendar_new_op (ecal);
3267 g_mutex_unlock (ecal->priv->mutex);
3269 /* create the CORBA user list to be passed to the backend */
3270 len = g_list_length (users);
3272 corba_users._length = len;
3273 corba_users._buffer = CORBA_sequence_GNOME_Evolution_Calendar_User_allocbuf (len);
3275 for (l = users, i = 0; l; l = l->next, i++)
3276 corba_users._buffer[i] = CORBA_string_dup (l->data);
3278 CORBA_exception_init (&ev);
3280 GNOME_Evolution_Calendar_Cal_getFreeBusy (ecal->priv->cal, &corba_users, start, end, &ev);
3282 CORBA_free (corba_users._buffer);
3284 if (BONOBO_EX (&ev)) {
3285 e_calendar_remove_op (ecal, our_op);
3286 e_calendar_free_op (our_op);
3288 CORBA_exception_free (&ev);
3290 g_warning (G_STRLOC ": Unable to contact backend");
3292 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error);
3295 CORBA_exception_free (&ev);
3297 e_flag_wait (our_op->done);
3299 status = our_op->status;
3300 *freebusy = our_op->list;
3302 e_calendar_remove_op (ecal, our_op);
3303 e_calendar_free_op (our_op);
3305 E_CALENDAR_CHECK_STATUS (status, error);
3308 struct comp_instance {
3309 ECalComponent *comp;
3314 struct instances_info {
3316 icaltimezone *start_zone;
3319 /* Called from cal_recur_generate_instances(); adds an instance to the list */
3321 add_instance (ECalComponent *comp, time_t start, time_t end, gpointer data)
3324 struct comp_instance *ci;
3325 struct icaltimetype itt;
3326 icalcomponent *icalcomp;
3327 struct instances_info *instances_hold;
3328 ECalComponentDateTime datetime;
3330 instances_hold = data;
3331 list = instances_hold->instances;
3333 ci = g_new (struct comp_instance, 1);
3335 icalcomp = icalcomponent_new_clone (e_cal_component_get_icalcomponent (comp));
3336 e_cal_component_get_dtstart (comp, &datetime);
3338 /* add the instance to the list */
3339 ci->comp = e_cal_component_new ();
3340 e_cal_component_set_icalcomponent (ci->comp, icalcomp);
3342 /* set the RECUR-ID for the instance */
3343 if (e_cal_util_component_has_recurrences (icalcomp)) {
3344 if (!(icalcomponent_get_first_property (icalcomp, ICAL_RECURRENCEID_PROPERTY))) {
3345 ECalComponentRange *range;
3347 if (instances_hold->start_zone)
3348 itt = icaltime_from_timet_with_zone (start, datetime.value->is_date, instances_hold->start_zone);
3350 itt = icaltime_from_timet (start, datetime.value->is_date);
3352 if (datetime.tzid) {
3353 g_free ((char *) datetime.tzid);
3354 datetime.tzid = NULL;
3358 g_free (datetime.value);
3359 datetime.value = &itt;
3361 range = g_new0 (ECalComponentRange, 1);
3362 range->type = E_CAL_COMPONENT_RANGE_SINGLE;
3363 range->datetime = datetime;
3365 e_cal_component_set_recurid (ci->comp, range);
3368 g_free ((char *) datetime.tzid);
3376 *list = g_list_prepend (*list, ci);
3381 /* Used from g_list_sort(); compares two struct comp_instance structures */
3383 compare_comp_instance (gconstpointer a, gconstpointer b)
3385 const struct comp_instance *cia, *cib;
3391 diff = cia->start - cib->start;
3392 return (diff < 0) ? -1 : (diff > 0) ? 1 : 0;
3396 process_detached_instances (GList *instances, GList *detached_instances)
3398 struct comp_instance *ci, *cid;
3399 GList *dl, *unprocessed_instances = NULL;
3401 for (dl = detached_instances; dl != NULL; dl = dl->next) {
3405 ECalComponentRange recur_id, instance_recur_id;
3410 e_cal_component_get_uid (cid->comp, &uid);
3411 e_cal_component_get_recurid (cid->comp, &recur_id);
3413 /* search for coincident instances already expanded */
3414 for (il = instances; il != NULL; il = il->next) {
3415 const char *instance_uid;
3419 e_cal_component_get_uid (ci->comp, &instance_uid);
3420 e_cal_component_get_recurid (ci->comp, &instance_recur_id);
3421 if (strcmp (uid, instance_uid) == 0) {
3422 const char *i_rid = NULL, *d_rid = NULL;
3424 i_rid = e_cal_component_get_recurid_as_string (ci->comp);
3425 d_rid = e_cal_component_get_recurid_as_string (cid->comp);
3427 if (i_rid && d_rid && strcmp (i_rid, d_rid) == 0) {
3428 g_object_unref (ci->comp);
3429 ci->comp = g_object_ref (cid->comp);
3430 ci->start = cid->start;
3435 if (!instance_recur_id.datetime.value ||
3436 !recur_id.datetime.value) {
3438 * Prevent obvious segfault by ignoring missing
3439 * recurrency ids. Real problem might be elsewhere,
3440 * but anything is better than crashing...
3442 g_log (G_LOG_DOMAIN,
3443 G_LOG_LEVEL_CRITICAL,
3444 "UID %s: instance RECURRENCE-ID %s + detached instance RECURRENCE-ID %s: cannot compare",
3450 cmp = icaltime_compare (*instance_recur_id.datetime.value,
3451 *recur_id.datetime.value);
3452 if ((recur_id.type == E_CAL_COMPONENT_RANGE_THISPRIOR && cmp <= 0) ||
3453 (recur_id.type == E_CAL_COMPONENT_RANGE_THISFUTURE && cmp >= 0)) {
3454 ECalComponent *comp;
3456 comp = e_cal_component_new ();
3457 e_cal_component_set_icalcomponent (
3459 icalcomponent_new_clone (e_cal_component_get_icalcomponent (cid->comp)));
3460 e_cal_component_set_recurid (comp, &instance_recur_id);
3462 /* replace the generated instances */
3463 g_object_unref (ci->comp);
3471 unprocessed_instances = g_list_prepend (unprocessed_instances, cid);
3474 /* add the unprocessed instances (ie, detached instances with no master object */
3475 while (unprocessed_instances != NULL) {
3476 cid = unprocessed_instances->data;
3477 ci = g_new0 (struct comp_instance, 1);
3478 ci->comp = g_object_ref (cid->comp);
3479 ci->start = cid->start;
3481 instances = g_list_append (instances, ci);
3483 unprocessed_instances = g_list_remove (unprocessed_instances, cid);
3490 generate_instances (ECal *ecal, time_t start, time_t end, const char *uid,
3491 ECalRecurInstanceFn cb, gpointer cb_data)
3493 GList *objects = NULL;
3494 GList *instances, *detached_instances = NULL;
3497 char *iso_start, *iso_end;
3502 /* Generate objects */
3504 if (!e_cal_get_objects_for_uid (ecal, uid, &objects, NULL))
3508 iso_start = isodate_from_time_t (start);
3512 iso_end = isodate_from_time_t (end);
3518 query = g_strdup_printf ("(occur-in-time-range? (make-time \"%s\") (make-time \"%s\"))",
3519 iso_start, iso_end);
3522 if (!e_cal_get_object_list_as_comp (ecal, query, &objects, NULL)) {
3531 for (l = objects; l; l = l->next) {
3532 ECalComponent *comp;
3533 icaltimezone *default_zone;
3535 if (priv->default_zone)
3536 default_zone = priv->default_zone;
3538 default_zone = icaltimezone_get_utc_timezone ();
3541 if (e_cal_component_is_instance (comp)) {
3542 struct comp_instance *ci;
3543 ECalComponentDateTime dtstart, dtend;
3544 icaltimezone *start_zone = NULL, *end_zone = NULL;
3546 /* keep the detached instances apart */
3547 ci = g_new0 (struct comp_instance, 1);
3550 e_cal_component_get_dtstart (comp, &dtstart);
3551 e_cal_component_get_dtend (comp, &dtend);
3553 /* For DATE-TIME values with a TZID, we use
3554 e_cal_resolve_tzid_cb to resolve the TZID.
3555 For DATE values and DATE-TIME values without a
3556 TZID (i.e. floating times) we use the default
3558 if (dtstart.tzid && !dtstart.value->is_date) {
3559 start_zone = e_cal_resolve_tzid_cb (dtstart.tzid, ecal);
3561 start_zone = default_zone;
3563 start_zone = default_zone;
3566 if (dtend.tzid && !dtend.value->is_date) {
3567 end_zone = e_cal_resolve_tzid_cb (dtend.tzid, ecal);
3569 end_zone = default_zone;
3571 end_zone = default_zone;
3574 ci->start = icaltime_as_timet_with_zone (*dtstart.value, start_zone);
3577 ci->end = icaltime_as_timet_with_zone (*dtend.value, end_zone);
3578 else if (icaltime_is_date (*dtstart.value))
3579 ci->end = time_day_end (ci->start);
3581 ci->end = ci->start;
3583 e_cal_component_free_datetime (&dtstart);
3584 e_cal_component_free_datetime (&dtend);
3586 detached_instances = g_list_prepend (detached_instances, ci);
3588 ECalComponentDateTime datetime;
3589 icaltimezone *start_zone;
3590 struct instances_info *instances_hold;
3592 /* Get the start timezone */
3593 e_cal_component_get_dtstart (comp, &datetime);
3594 e_cal_get_timezone (ecal, datetime.tzid, &start_zone, NULL);
3595 e_cal_component_free_datetime (&datetime);
3597 instances_hold = g_new0 (struct instances_info, 1);
3598 instances_hold->instances = &instances;
3599 instances_hold->start_zone = start_zone;
3601 e_cal_recur_generate_instances (comp, start, end, add_instance, instances_hold,
3602 e_cal_resolve_tzid_cb, ecal,
3605 g_free (instances_hold);
3606 g_object_unref (comp);
3610 g_list_free (objects);
3612 /* Generate instances and spew them out */
3614 instances = g_list_sort (instances, compare_comp_instance);
3615 instances = process_detached_instances (instances, detached_instances);
3617 for (l = instances; l; l = l->next) {
3618 struct comp_instance *ci;
3623 result = (* cb) (ci->comp, ci->start, ci->end, cb_data);
3631 for (l = instances; l; l = l->next) {
3632 struct comp_instance *ci;
3635 g_object_unref (G_OBJECT (ci->comp));
3639 g_list_free (instances);
3641 for (l = detached_instances; l; l = l->next) {
3642 struct comp_instance *ci;
3645 g_object_unref (G_OBJECT (ci->comp));
3649 g_list_free (detached_instances);
3654 * e_cal_generate_instances:
3655 * @ecal: A calendar client.
3656 * @start: Start time for query.
3657 * @end: End time for query.
3658 * @cb: Callback for each generated instance.
3659 * @cb_data: Closure data for the callback.
3661 * Does a combination of #e_cal_get_object_list () and
3662 * #e_cal_recur_generate_instances().
3664 * The callback function should do a g_object_ref() of the calendar component
3665 * it gets passed if it intends to keep it around, since it will be unref'ed
3666 * as soon as the callback returns.
3669 e_cal_generate_instances (ECal *ecal, time_t start, time_t end,
3670 ECalRecurInstanceFn cb, gpointer cb_data)
3674 g_return_if_fail (ecal != NULL);
3675 g_return_if_fail (E_IS_CAL (ecal));
3678 g_return_if_fail (priv->load_state == E_CAL_LOAD_LOADED);
3680 g_return_if_fail (start >= 0);
3681 g_return_if_fail (end >= 0);
3682 g_return_if_fail (cb != NULL);
3684 generate_instances (ecal, start, end, NULL, cb, cb_data);
3688 * e_cal_generate_instances_for_object:
3689 * @ecal: A calendar client.
3690 * @icalcomp: Object to generate instances from.
3691 * @start: Start time for query.
3692 * @end: End time for query.
3693 * @cb: Callback for each generated instance.
3694 * @cb_data: Closure data for the callback.
3696 * Does a combination of #e_cal_get_object_list () and
3697 * #e_cal_recur_generate_instances(), like #e_cal_generate_instances(), but
3698 * for a single object.
3700 * The callback function should do a g_object_ref() of the calendar component
3701 * it gets passed if it intends to keep it around, since it will be unref'ed
3702 * as soon as the callback returns.
3705 e_cal_generate_instances_for_object (ECal *ecal, icalcomponent *icalcomp,
3706 time_t start, time_t end,
3707 ECalRecurInstanceFn cb, gpointer cb_data)
3710 ECalComponent *comp;
3714 GList *instances = NULL;
3715 ECalComponentDateTime datetime;
3716 icaltimezone *start_zone;
3717 struct instances_info *instances_hold;
3719 g_return_if_fail (E_IS_CAL (ecal));
3720 g_return_if_fail (start >= 0);
3721 g_return_if_fail (end >= 0);
3722 g_return_if_fail (cb != NULL);
3726 comp = e_cal_component_new ();
3727 e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (icalcomp));
3729 /*If the backend stores it as individual instances and does not
3730 * have a master object - do not expand*/
3731 if (e_cal_get_static_capability (ecal, CAL_STATIC_CAPABILITY_RECURRENCES_NO_MASTER)) {
3733 /*return the same instance */
3734 result = (* cb) (comp, icaltime_as_timet_with_zone (icalcomponent_get_dtstart (icalcomp), ecal->priv->default_zone),
3735 icaltime_as_timet_with_zone (icalcomponent_get_dtend (icalcomp), ecal->priv->default_zone), cb_data);
3736 g_object_unref (comp);
3740 e_cal_component_get_uid (comp, &uid);
3741 /* string might be freed at any time, keep a copy */
3742 rid = g_strdup (e_cal_component_get_recurid_as_string (comp));
3744 /* Get the start timezone */
3745 e_cal_component_get_dtstart (comp, &datetime);
3746 e_cal_get_timezone (ecal, datetime.tzid, &start_zone, NULL);
3747 e_cal_component_free_datetime (&datetime);
3749 instances_hold = g_new0 (struct instances_info, 1);
3750 instances_hold->instances = &instances;
3751 instances_hold->start_zone = start_zone;
3753 /* generate all instances in the given time range */
3754 generate_instances (ecal, start, end, uid, add_instance, instances_hold);
3756 instances = *(instances_hold->instances);
3757 /* now only return back the instances for the given object */
3759 while (instances != NULL) {
3760 struct comp_instance *ci;
3761 const char *instance_rid;
3763 ci = instances->data;
3766 instance_rid = e_cal_component_get_recurid_as_string (ci->comp);
3769 if (instance_rid && *instance_rid && strcmp (rid, instance_rid) == 0)
3770 result = (* cb) (ci->comp, ci->start, ci->end, cb_data);
3772 result = (* cb) (ci->comp, ci->start, ci->end, cb_data);
3775 /* remove instance from list */
3776 instances = g_list_remove (instances, ci);
3777 g_object_unref (ci->comp);
3782 g_object_unref (comp);
3783 g_free (instances_hold);
3787 /* Builds a list of ECalComponentAlarms structures */
3789 build_component_alarms_list (ECal *ecal, GList *object_list, time_t start, time_t end)
3791 GSList *comp_alarms;
3796 for (l = object_list; l != NULL; l = l->next) {
3797 ECalComponent *comp;
3798 ECalComponentAlarms *alarms;
3799 ECalComponentAlarmAction omit[] = {-1};
3801 comp = e_cal_component_new ();
3802 if (!e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (l->data))) {
3803 g_object_unref (G_OBJECT (comp));
3807 alarms = e_cal_util_generate_alarms_for_comp (comp, start, end, omit, e_cal_resolve_tzid_cb,
3808 ecal, ecal->priv->default_zone);
3810 comp_alarms = g_slist_prepend (comp_alarms, alarms);
3817 * e_cal_get_alarms_in_range:
3818 * @ecal: A calendar client.
3819 * @start: Start time for query.
3820 * @end: End time for query.
3822 * Queries a calendar for the alarms that trigger in the specified range of
3825 * Return value: A list of #ECalComponentAlarms structures. This should be freed
3826 * using the #e_cal_free_alarms() function, or by freeing each element
3827 * separately with #e_cal_component_alarms_free() and then freeing the list with
3831 e_cal_get_alarms_in_range (ECal *ecal, time_t start, time_t end)
3835 char *sexp, *iso_start, *iso_end;
3836 GList *object_list = NULL;
3838 g_return_val_if_fail (ecal != NULL, NULL);
3839 g_return_val_if_fail (E_IS_CAL (ecal), NULL);
3842 g_return_val_if_fail (priv->load_state == E_CAL_LOAD_LOADED, NULL);
3844 g_return_val_if_fail (start >= 0 && end >= 0, NULL);
3845 g_return_val_if_fail (start <= end, NULL);
3847 iso_start = isodate_from_time_t (start);
3851 iso_end = isodate_from_time_t (end);
3857 /* build the query string */
3858 sexp = g_strdup_printf ("(has-alarms-in-range? (make-time \"%s\") (make-time \"%s\"))",
3859 iso_start, iso_end);
3863 /* execute the query on the server */
3864 if (!e_cal_get_object_list (ecal, sexp, &object_list, NULL)) {
3869 alarms = build_component_alarms_list (ecal, object_list, start, end);
3871 g_list_foreach (object_list, (GFunc) icalcomponent_free, NULL);
3872 g_list_free (object_list);
3879 * e_cal_free_alarms:
3880 * @comp_alarms: A list of #ECalComponentAlarms structures.
3882 * Frees a list of #ECalComponentAlarms structures as returned by
3883 * e_cal_get_alarms_in_range().
3886 e_cal_free_alarms (GSList *comp_alarms)
3890 for (l = comp_alarms; l; l = l->next) {
3891 ECalComponentAlarms *alarms;
3894 g_assert (alarms != NULL);
3896 e_cal_component_alarms_free (alarms);
3899 g_slist_free (comp_alarms);
3903 * e_cal_get_alarms_for_object:
3904 * @ecal: A calendar client.
3905 * @id: Unique identifier for a calendar component.
3906 * @start: Start time for query.
3907 * @end: End time for query.
3908 * @alarms: Return value for the component's alarm instances. Will return NULL
3909 * if no instances occur within the specified time range. This should be freed
3910 * using the e_cal_component_alarms_free() function.
3912 * Queries a calendar for the alarms of a particular object that trigger in the
3913 * specified range of time.
3915 * Return value: TRUE on success, FALSE if the object was not found.
3918 e_cal_get_alarms_for_object (ECal *ecal, const ECalComponentId *id,
3919 time_t start, time_t end,
3920 ECalComponentAlarms **alarms)
3923 icalcomponent *icalcomp;
3924 ECalComponent *comp;
3925 ECalComponentAlarmAction omit[] = {-1};
3927 g_return_val_if_fail (ecal != NULL, FALSE);
3928 g_return_val_if_fail (E_IS_CAL (ecal), FALSE);
3931 g_return_val_if_fail (priv->load_state == E_CAL_LOAD_LOADED, FALSE);
3933 g_return_val_if_fail (id != NULL, FALSE);
3934 g_return_val_if_fail (start >= 0 && end >= 0, FALSE);
3935 g_return_val_if_fail (start <= end, FALSE);
3936 g_return_val_if_fail (alarms != NULL, FALSE);
3940 if (!e_cal_get_object (ecal, id->uid, id->rid, &icalcomp, NULL))
3945 comp = e_cal_component_new ();
3946 if (!e_cal_component_set_icalcomponent (comp, icalcomp)) {
3947 icalcomponent_free (icalcomp);
3948 g_object_unref (G_OBJECT (comp));
3952 *alarms = e_cal_util_generate_alarms_for_comp (comp, start, end, omit, e_cal_resolve_tzid_cb,
3953 ecal, priv->default_zone);
3959 * e_cal_discard_alarm
3960 * @ecal: A calendar ecal.
3961 * @comp: The component to discard the alarm from.
3962 * @auid: Unique identifier of the alarm to be discarded.
3963 * @error: Placeholder for error information.
3965 * Tells the calendar backend to get rid of the alarm identified by the
3966 * @auid argument in @comp. Some backends might remove the alarm or
3967 * update internal information about the alarm be discarded, or, like
3968 * the file backend does, ignore the operation.
3970 * Return value: TRUE if the operation was successful, FALSE otherwise.
3973 e_cal_discard_alarm (ECal *ecal, ECalComponent *comp, const char *auid, GError **error)
3976 CORBA_Environment ev;
3977 ECalendarStatus status;
3978 ECalendarOp *our_op;
3981 g_return_val_if_fail (ecal != NULL, FALSE);
3982 g_return_val_if_fail (E_IS_CAL (ecal), FALSE);
3986 g_mutex_lock (ecal->priv->mutex);
3988 if (ecal->priv->load_state != E_CAL_LOAD_LOADED) {
3989 g_mutex_unlock (ecal->priv->mutex);
3990 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
3993 if (ecal->priv->current_op != NULL) {
3994 g_mutex_unlock (ecal->priv->mutex);
3995 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error);
3998 our_op = e_calendar_new_op (ecal);
4000 g_mutex_unlock (ecal->priv->mutex);
4002 e_cal_component_get_uid (comp, &uid);
4004 CORBA_exception_init (&ev);
4006 GNOME_Evolution_Calendar_Cal_discardAlarm (priv->cal, uid, auid, &ev);
4007 if (BONOBO_EX (&ev)) {
4008 e_calendar_remove_op (ecal, our_op);
4009 e_calendar_free_op (our_op);
4011 CORBA_exception_free (&ev);
4013 g_warning (G_STRLOC ": Unable to contact backend");
4015 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error);
4018 CORBA_exception_free (&ev);
4020 e_flag_wait (our_op->done);
4022 status = our_op->status;
4024 e_calendar_remove_op (ecal, our_op);
4025 e_calendar_free_op (our_op);
4027 E_CALENDAR_CHECK_STATUS (status, error);
4030 typedef struct _ForeachTZIDCallbackData ForeachTZIDCallbackData;
4031 struct _ForeachTZIDCallbackData {
4033 GHashTable *timezone_hash;
4034 gboolean include_all_timezones;
4038 /* This adds the VTIMEZONE given by the TZID parameter to the GHashTable in
4041 foreach_tzid_callback (icalparameter *param, void *cbdata)
4043 ForeachTZIDCallbackData *data = cbdata;
4047 icalcomponent *vtimezone_comp;
4048 char *vtimezone_as_string;
4050 priv = data->ecal->priv;
4052 /* Get the TZID string from the parameter. */
4053 tzid = icalparameter_get_tzid (param);
4057 /* Check if we've already added it to the GHashTable. */
4058 if (g_hash_table_lookup (data->timezone_hash, tzid))
4061 if (data->include_all_timezones) {
4062 if (!e_cal_get_timezone (data->ecal, tzid, &zone, NULL)) {
4063 data->success = FALSE;
4067 /* Check if it is in our cache. If it is, it must already be
4068 on the server so return. */
4069 if (g_hash_table_lookup (priv->timezones, tzid))
4072 /* Check if it is a builtin timezone. If it isn't, return. */
4073 zone = icaltimezone_get_builtin_timezone_from_tzid (tzid);
4078 /* Convert it to a string and add it to the hash. */
4079 vtimezone_comp = icaltimezone_get_component (zone);
4080 if (!vtimezone_comp)
4083 vtimezone_as_string = icalcomponent_as_ical_string (vtimezone_comp);
4085 g_hash_table_insert (data->timezone_hash, (char*) tzid,
4086 g_strdup (vtimezone_as_string));
4089 /* This appends the value string to the GString given in data. */
4091 append_timezone_string (gpointer key, gpointer value, gpointer data)
4093 GString *vcal_string = data;
4095 g_string_append (vcal_string, value);
4100 /* This simply frees the hash values. */
4102 free_timezone_string (gpointer key, gpointer value, gpointer data)
4108 /* This converts the VEVENT/VTODO to a string. If include_all_timezones is
4109 TRUE, it includes all the VTIMEZONE components needed for the VEVENT/VTODO.
4110 If not, it only includes builtin timezones that may not be on the server.
4112 To do that we check every TZID in the component to see if it is a builtin
4113 timezone. If it is, we see if it it in our cache. If it is in our cache,
4114 then we know the server already has it and we don't need to send it.
4115 If it isn't in our cache, then we need to send it to the server.
4116 If we need to send any timezones to the server, then we have to create a
4117 complete VCALENDAR object, otherwise we can just send a single VEVENT/VTODO
4120 e_cal_get_component_as_string_internal (ECal *ecal,
4121 icalcomponent *icalcomp,
4122 gboolean include_all_timezones)
4124 GHashTable *timezone_hash;
4125 GString *vcal_string;
4126 int initial_vcal_string_len;
4127 ForeachTZIDCallbackData cbdata;
4133 timezone_hash = g_hash_table_new (g_str_hash, g_str_equal);
4135 /* Add any timezones needed to the hash. We use a hash since we only
4136 want to add each timezone once at most. */
4138 cbdata.timezone_hash = timezone_hash;
4139 cbdata.include_all_timezones = include_all_timezones;
4140 cbdata.success = TRUE;
4141 icalcomponent_foreach_tzid (icalcomp, foreach_tzid_callback, &cbdata);
4142 if (!cbdata.success) {
4143 g_hash_table_foreach (timezone_hash, free_timezone_string,
4148 /* Create the start of a VCALENDAR, to add the VTIMEZONES to,
4149 and remember its length so we know if any VTIMEZONEs get added. */
4150 vcal_string = g_string_new (NULL);
4151 g_string_append (vcal_string,
4153 "PRODID:-//Ximian//NONSGML Evolution Calendar//EN\n"
4155 "METHOD:PUBLISH\n");
4156 initial_vcal_string_len = vcal_string->len;
4158 /* Now concatenate all the timezone strings. This also frees the
4159 timezone strings as it goes. */
4160 g_hash_table_foreach (timezone_hash, append_timezone_string,
4163 /* Get the string for the VEVENT/VTODO. */
4164 obj_string = g_strdup (icalcomponent_as_ical_string (icalcomp));
4166 /* If there were any timezones to send, create a complete VCALENDAR,
4167 else just send the VEVENT/VTODO string. */
4168 if (!include_all_timezones
4169 && vcal_string->len == initial_vcal_string_len) {
4170 g_string_free (vcal_string, TRUE);
4172 g_string_append (vcal_string, obj_string);
4173 g_string_append (vcal_string, "END:VCALENDAR\n");
4174 g_free (obj_string);
4175 obj_string = vcal_string->str;
4176 g_string_free (vcal_string, FALSE);
4179 g_hash_table_destroy (timezone_hash);
4185 * e_cal_get_component_as_string:
4186 * @ecal: A calendar client.
4187 * @icalcomp: A calendar component object.
4189 * Gets a calendar component as an iCalendar string, with a toplevel
4190 * VCALENDAR component and all VTIMEZONEs needed for the component.
4192 * Return value: the component as a complete iCalendar string, or NULL on
4193 * failure. The string should be freed after use.
4196 e_cal_get_component_as_string (ECal *ecal, icalcomponent *icalcomp)
4198 return e_cal_get_component_as_string_internal (ecal, icalcomp, TRUE);
4202 * e_cal_create_object:
4203 * @ecal: A calendar client.
4204 * @icalcomp: The component to create.
4205 * @uid: Return value for the UID assigned to the new component by the calendar backend.
4206 * @error: Placeholder for error information.
4208 * Requests the calendar backend to create the object specified by the @icalcomp
4209 * argument. Some backends would assign a specific UID to the newly created object,
4210 * in those cases that UID would be returned in the @uid argument.
4212 * Return value: TRUE if the operation was successful, FALSE otherwise.
4215 e_cal_create_object (ECal *ecal, icalcomponent *icalcomp, char **uid, GError **error)
4218 CORBA_Environment ev;
4219 ECalendarStatus status;
4220 ECalendarOp *our_op;
4222 e_return_error_if_fail (ecal && E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
4226 g_mutex_lock (ecal->priv->mutex);
4228 if (ecal->priv->load_state != E_CAL_LOAD_LOADED) {
4229 g_mutex_unlock (ecal->priv->mutex);
4230 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
4233 if (ecal->priv->current_op != NULL) {
4234 g_mutex_unlock (ecal->priv->mutex);
4235 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error);
4238 our_op = e_calendar_new_op (ecal);
4240 g_mutex_unlock (ecal->priv->mutex);
4242 CORBA_exception_init (&ev);
4244 GNOME_Evolution_Calendar_Cal_createObject (priv->cal, icalcomponent_as_ical_string (icalcomp), &ev);
4245 if (BONOBO_EX (&ev)) {
4246 e_calendar_remove_op (ecal, our_op);
4247 e_calendar_free_op (our_op);
4249 CORBA_exception_free (&ev);
4251 g_warning (G_STRLOC ": Unable to contact backend");
4253 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error);
4256 CORBA_exception_free (&ev);
4258 e_flag_wait (our_op->done);
4260 status = our_op->status;
4264 icalcomponent_set_uid (icalcomp, *uid);
4267 e_calendar_remove_op (ecal, our_op);
4268 e_calendar_free_op (our_op);
4270 E_CALENDAR_CHECK_STATUS (status, error);
4274 * e_cal_modify_object:
4275 * @ecal: A calendar client.
4276 * @icalcomp: Component to modify.
4277 * @mod: Type of modification.
4278 * @error: Placeholder for error information.
4280 * Requests the calendar backend to modify an existing object. If the object
4281 * does not exist on the calendar, an error will be returned.
4283 * For recurrent appointments, the @mod argument specifies what to modify,
4284 * if all instances (CALOBJ_MOD_ALL), a single instance (CALOBJ_MOD_THIS),
4285 * or a specific set of instances (CALOBJ_MOD_THISNADPRIOR and
4286 * CALOBJ_MOD_THISANDFUTURE).
4288 * Return value: TRUE if the operation was successful, FALSE otherwise.
4291 e_cal_modify_object (ECal *ecal, icalcomponent *icalcomp, CalObjModType mod, GError **error)
4294 CORBA_Environment ev;
4295 ECalendarStatus status;
4296 ECalendarOp *our_op;
4298 e_return_error_if_fail (ecal && E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
4299 e_return_error_if_fail (icalcomp, E_CALENDAR_STATUS_INVALID_ARG);
4303 g_mutex_lock (ecal->priv->mutex);
4305 if (ecal->priv->load_state != E_CAL_LOAD_LOADED) {
4306 g_mutex_unlock (ecal->priv->mutex);
4307 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
4310 if (ecal->priv->current_op != NULL) {
4311 g_mutex_unlock (ecal->priv->mutex);
4312 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error);
4315 our_op = e_calendar_new_op (ecal);
4317 g_mutex_unlock (ecal->priv->mutex);
4319 CORBA_exception_init (&ev);
4321 GNOME_Evolution_Calendar_Cal_modifyObject (priv->cal, icalcomponent_as_ical_string (icalcomp), mod, &ev);
4322 if (BONOBO_EX (&ev)) {
4323 e_calendar_remove_op (ecal, our_op);
4324 e_calendar_free_op (our_op);
4326 CORBA_exception_free (&ev);
4328 g_warning (G_STRLOC ": Unable to contact backend");
4330 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error);
4333 CORBA_exception_free (&ev);
4335 e_flag_wait (our_op->done);
4337 status = our_op->status;
4339 e_calendar_remove_op (ecal, our_op);
4340 e_calendar_free_op (our_op);
4342 E_CALENDAR_CHECK_STATUS (status, error);
4346 * e_cal_remove_object_with_mod:
4347 * @ecal: A calendar client.
4348 * @uid: UID og the object to remove.
4349 * @rid: Recurrence ID of the specific recurrence to remove.
4350 * @mod: Type of removal.
4351 * @error: Placeholder for error information.
4353 * This function allows the removal of instances of a recurrent
4354 * appointment. By using a combination of the @uid, @rid and @mod
4355 * arguments, you can remove specific instances. If what you want
4356 * is to remove all instances, use e_cal_remove_object instead.
4358 * If not all instances are removed, the client will get a "obj_modified"
4359 * signal, while it will get a "obj_removed" signal when all instances
4362 * Return value: TRUE if the operation was successful, FALSE otherwise.
4365 e_cal_remove_object_with_mod (ECal *ecal, const char *uid,
4366 const char *rid, CalObjModType mod, GError **error)
4369 CORBA_Environment ev;
4370 ECalendarStatus status;
4371 ECalendarOp *our_op;
4373 e_return_error_if_fail (ecal && E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
4374 e_return_error_if_fail (uid, E_CALENDAR_STATUS_INVALID_ARG);
4378 g_mutex_lock (ecal->priv->mutex);
4380 if (ecal->priv->load_state != E_CAL_LOAD_LOADED) {
4381 g_mutex_unlock (ecal->priv->mutex);
4382 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
4385 if (ecal->priv->current_op != NULL) {
4386 g_mutex_unlock (ecal->priv->mutex);
4387 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error);
4390 our_op = e_calendar_new_op (ecal);
4392 g_mutex_unlock (ecal->priv->mutex);
4395 CORBA_exception_init (&ev);
4397 GNOME_Evolution_Calendar_Cal_removeObject (priv->cal, uid, rid ? rid : "", mod, &ev);
4398 if (BONOBO_EX (&ev)) {
4399 e_calendar_remove_op (ecal, our_op);
4400 e_calendar_free_op (our_op);
4402 CORBA_exception_free (&ev);
4404 g_warning (G_STRLOC ": Unable to contact backend");
4406 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error);
4409 CORBA_exception_free (&ev);
4411 e_flag_wait (our_op->done);
4413 status = our_op->status;
4415 e_calendar_remove_op (ecal, our_op);
4416 e_calendar_free_op (our_op);
4418 E_CALENDAR_CHECK_STATUS (status, error);
4422 * e_cal_remove_object:
4423 * @ecal: A calendar client.
4424 * @uid: Unique identifier of the calendar component to remove.
4425 * @error: Placeholder for error information.
4427 * Asks a calendar to remove a component. If the server is able to remove the
4428 * component, all clients will be notified and they will emit the "obj_removed"
4431 * Return value: %TRUE if successful, %FALSE otherwise.
4434 e_cal_remove_object (ECal *ecal, const char *uid, GError **error)
4436 e_return_error_if_fail (ecal && E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
4437 e_return_error_if_fail (uid, E_CALENDAR_STATUS_INVALID_ARG);
4439 return e_cal_remove_object_with_mod (ecal, uid, NULL, CALOBJ_MOD_THIS, error);
4443 * e_cal_receive_objects:
4444 * @ecal: A calendar client.
4445 * @icalcomp: An icalcomponent.
4446 * @error: Placeholder for error information.
4448 * Makes the backend receive the set of iCalendar objects specified in the
4449 * @icalcomp argument. This is used for iTIP confirmation/cancellation
4450 * messages for scheduled meetings.
4452 * Return value: %TRUE if successful, %FALSE otherwise.
4455 e_cal_receive_objects (ECal *ecal, icalcomponent *icalcomp, GError **error)
4458 CORBA_Environment ev;
4459 ECalendarStatus status;
4460 ECalendarOp *our_op;
4462 e_return_error_if_fail (ecal && E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
4466 g_mutex_lock (ecal->priv->mutex);
4468 if (ecal->priv->load_state != E_CAL_LOAD_LOADED) {
4469 g_mutex_unlock (ecal->priv->mutex);
4470 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
4473 if (ecal->priv->current_op != NULL) {
4474 g_mutex_unlock (ecal->priv->mutex);
4475 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error);
4478 our_op = e_calendar_new_op (ecal);
4480 g_mutex_unlock (ecal->priv->mutex);
4482 CORBA_exception_init (&ev);
4484 GNOME_Evolution_Calendar_Cal_receiveObjects (priv->cal, icalcomponent_as_ical_string (icalcomp), &ev);
4485 if (BONOBO_EX (&ev)) {
4486 e_calendar_remove_op (ecal, our_op);
4487 e_calendar_free_op (our_op);
4489 CORBA_exception_free (&ev);
4491 g_warning (G_STRLOC ": Unable to contact backend");
4493 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error);
4496 CORBA_exception_free (&ev);
4498 e_flag_wait (our_op->done);
4500 status = our_op->status;
4502 e_calendar_remove_op (ecal, our_op);
4503 e_calendar_free_op (our_op);
4505 E_CALENDAR_CHECK_STATUS (status, error);
4509 * e_cal_send_objects:
4510 * @ecal: A calendar client.
4511 * @icalcomp: An icalcomponent.
4512 * @users: List of users to send the objects to.
4513 * @modified_icalcomp: Return value for the icalcomponent after all the operations
4515 * @error: Placeholder for error information.
4517 * Requests a calendar backend to send meeting information to the specified list
4520 * Return value: TRUE if the operation was successful, FALSE otherwise.
4523 e_cal_send_objects (ECal *ecal, icalcomponent *icalcomp, GList **users, icalcomponent **modified_icalcomp, GError **error)
4526 CORBA_Environment ev;
4527 ECalendarStatus status;
4528 ECalendarOp *our_op;
4530 e_return_error_if_fail (ecal && E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
4534 g_mutex_lock (ecal->priv->mutex);
4536 if (ecal->priv->load_state != E_CAL_LOAD_LOADED) {
4537 g_mutex_unlock (ecal->priv->mutex);
4538 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
4541 if (ecal->priv->current_op != NULL) {
4542 g_mutex_unlock (ecal->priv->mutex);
4543 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error);
4546 our_op = e_calendar_new_op (ecal);
4548 g_mutex_unlock (ecal->priv->mutex);
4550 CORBA_exception_init (&ev);
4552 GNOME_Evolution_Calendar_Cal_sendObjects (priv->cal, icalcomponent_as_ical_string (icalcomp), &ev);
4553 if (BONOBO_EX (&ev)) {
4554 e_calendar_remove_op (ecal, our_op);
4555 e_calendar_free_op (our_op);
4557 CORBA_exception_free (&ev);
4559 g_warning (G_STRLOC ": Unable to contact backend");
4561 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error);
4564 CORBA_exception_free (&ev);
4566 e_flag_wait (our_op->done);
4568 status = our_op->status;
4569 *users = our_op->list;
4570 if (status != E_CALENDAR_STATUS_OK) {
4571 *modified_icalcomp = NULL;
4572 g_list_foreach (*users, (GFunc) g_free, NULL);
4573 g_list_free (*users);
4576 *modified_icalcomp = icalparser_parse_string (our_op->string);
4577 if (!(*modified_icalcomp)) {
4578 status = E_CALENDAR_STATUS_INVALID_OBJECT;
4579 g_list_foreach (*users, (GFunc) g_free, NULL);
4580 g_list_free (*users);
4584 g_free (our_op->string);
4586 e_calendar_remove_op (ecal, our_op);
4587 e_calendar_free_op (our_op);
4589 E_CALENDAR_CHECK_STATUS (status, error);
4593 * e_cal_get_timezone:
4594 * @ecal: A calendar client.
4595 * @tzid: ID of the timezone to retrieve.
4596 * @zone: Return value for the timezone.
4597 * @error: Placeholder for error information.
4599 * Retrieves a timezone object from the calendar backend.
4601 * Return value: TRUE if the operation was successful, FALSE otherwise.
4604 e_cal_get_timezone (ECal *ecal, const char *tzid, icaltimezone **zone, GError **error)
4607 CORBA_Environment ev;
4608 ECalendarStatus status;
4609 ECalendarOp *our_op;
4610 icalcomponent *icalcomp;
4612 e_return_error_if_fail (ecal && E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
4613 e_return_error_if_fail (zone, E_CALENDAR_STATUS_INVALID_ARG);
4617 g_mutex_lock (priv->mutex);
4619 if (ecal->priv->load_state != E_CAL_LOAD_LOADED) {
4620 g_mutex_unlock (ecal->priv->mutex);
4621 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
4624 if (ecal->priv->current_op != NULL) {
4625 g_mutex_unlock (ecal->priv->mutex);
4626 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error);
4629 our_op = e_calendar_new_op (ecal);
4631 g_mutex_unlock (priv->mutex);
4633 /* Check for well known zones and in the cache */
4636 /* If tzid is NULL or "" we return NULL, since it is a 'local time'. */
4637 if (!tzid || !tzid[0]) {
4638 e_calendar_remove_op (ecal, our_op);
4639 e_calendar_free_op (our_op);
4643 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
4646 /* If it is UTC, we return the special UTC timezone. */
4647 if (!strcmp (tzid, "UTC")) {
4648 *zone = icaltimezone_get_utc_timezone ();
4650 /* See if we already have it in the cache. */
4651 *zone = g_hash_table_lookup (priv->timezones, tzid);
4655 e_calendar_remove_op (ecal, our_op);
4656 e_calendar_free_op (our_op);
4658 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
4661 /* call the backend */
4662 CORBA_exception_init (&ev);
4664 GNOME_Evolution_Calendar_Cal_getTimezone (priv->cal, tzid, &ev);
4665 if (BONOBO_EX (&ev)) {
4666 e_calendar_remove_op (ecal, our_op);
4667 e_calendar_free_op (our_op);
4669 CORBA_exception_free (&ev);
4671 g_warning (G_STRLOC ": Unable to contact backend");
4673 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error);
4676 CORBA_exception_free (&ev);
4678 e_flag_wait (our_op->done);
4680 status = our_op->status;
4681 if (status != E_CALENDAR_STATUS_OK){
4684 icalcomp = icalparser_parse_string (our_op->string);
4686 status = E_CALENDAR_STATUS_INVALID_OBJECT;
4688 g_free (our_op->string);
4691 e_calendar_remove_op (ecal, our_op);
4692 e_calendar_free_op (our_op);
4694 E_CALENDAR_CHECK_STATUS (status, error);
4697 *zone = icaltimezone_new ();
4698 if (!icaltimezone_set_component (*zone, icalcomp)) {
4699 icaltimezone_free (*zone, 1);
4701 e_calendar_remove_op (ecal, our_op);
4702 e_calendar_free_op (our_op);
4704 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OBJECT_NOT_FOUND, error);
4707 /* Now add it to the cache, to avoid the server call in future. */
4708 g_hash_table_insert (priv->timezones, icaltimezone_get_tzid (*zone), *zone);
4710 e_calendar_remove_op (ecal, our_op);
4711 e_calendar_free_op (our_op);
4713 E_CALENDAR_CHECK_STATUS (status, error);
4717 * e_cal_add_timezone
4718 * @ecal: A calendar client.
4719 * @izone: The timezone to add.
4720 * @error: Placeholder for error information.
4722 * Add a VTIMEZONE object to the given calendar.
4724 * Returns: TRUE if successful, FALSE otherwise.
4727 e_cal_add_timezone (ECal *ecal, icaltimezone *izone, GError **error)
4730 CORBA_Environment ev;
4731 ECalendarStatus status;
4732 ECalendarOp *our_op;
4734 icalcomponent *icalcomp;
4736 e_return_error_if_fail (ecal && E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
4737 e_return_error_if_fail (izone, E_CALENDAR_STATUS_INVALID_ARG);
4741 g_mutex_lock (priv->mutex);
4743 if (ecal->priv->load_state != E_CAL_LOAD_LOADED) {
4744 g_mutex_unlock (ecal->priv->mutex);
4745 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
4748 if (ecal->priv->current_op != NULL) {
4749 g_mutex_unlock (ecal->priv->mutex);
4750 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error);
4753 our_op = e_calendar_new_op (ecal);
4755 g_mutex_unlock (priv->mutex);
4757 /* Make sure we have a valid component - UTC doesn't, nor do
4758 * we really have to add it */
4759 if (izone == icaltimezone_get_utc_timezone ()) {
4760 e_calendar_remove_op (ecal, our_op);
4761 e_calendar_free_op (our_op);
4763 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
4766 icalcomp = icaltimezone_get_component (izone);
4768 e_calendar_remove_op (ecal, our_op);
4769 e_calendar_free_op (our_op);
4771 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_INVALID_ARG, error);
4774 /* convert icaltimezone into a string */
4775 tzobj = icalcomponent_as_ical_string (icalcomp);
4777 /* call the backend */
4778 CORBA_exception_init (&ev);
4780 GNOME_Evolution_Calendar_Cal_addTimezone (priv->cal, tzobj, &ev);
4781 if (BONOBO_EX (&ev)) {
4782 e_calendar_remove_op (ecal, our_op);
4783 e_calendar_free_op (our_op);
4785 CORBA_exception_free (&ev);
4787 g_warning (G_STRLOC ": Unable to contact backend");
4789 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error);
4792 CORBA_exception_free (&ev);
4794 e_flag_wait (our_op->done);
4796 status = our_op->status;
4798 e_calendar_remove_op (ecal, our_op);
4799 e_calendar_free_op (our_op);
4801 E_CALENDAR_CHECK_STATUS (status, error);
4806 * @ecal: A calendar client.
4807 * @sexp: S-expression representing the query.
4808 * @query: Return value for the new query.
4809 * @error: Placeholder for error information.
4811 * Creates a live query object from a loaded calendar.
4813 * Return value: A query object that will emit notification signals as calendar
4814 * components are added and removed from the query in the server.
4817 e_cal_get_query (ECal *ecal, const char *sexp, ECalView **query, GError **error)
4819 CORBA_Environment ev;
4820 ECalendarOp *our_op;
4821 ECalendarStatus status;
4823 e_return_error_if_fail (ecal && E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
4824 e_return_error_if_fail (query, E_CALENDAR_STATUS_INVALID_ARG);
4826 g_mutex_lock (ecal->priv->mutex);
4828 if (ecal->priv->load_state != E_CAL_LOAD_LOADED) {
4829 g_mutex_unlock (ecal->priv->mutex);
4830 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
4833 if (ecal->priv->current_op != NULL) {
4834 g_mutex_unlock (ecal->priv->mutex);
4835 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error);
4838 our_op = e_calendar_new_op (ecal);
4840 g_mutex_unlock (ecal->priv->mutex);
4842 CORBA_exception_init (&ev);
4844 our_op->listener = e_cal_view_listener_new ();
4845 GNOME_Evolution_Calendar_Cal_getQuery (ecal->priv->cal, sexp, BONOBO_OBJREF (our_op->listener), &ev);
4847 if (BONOBO_EX (&ev)) {
4848 e_calendar_remove_op (ecal, our_op);
4849 e_calendar_free_op (our_op);
4851 CORBA_exception_free (&ev);
4853 g_warning (G_STRLOC ": Unable to contact backend");
4855 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error);
4858 CORBA_exception_free (&ev);
4860 e_flag_wait (our_op->done);
4862 status = our_op->status;
4863 *query = our_op->query;
4865 bonobo_object_unref (BONOBO_OBJECT (our_op->listener));
4867 e_calendar_remove_op (ecal, our_op);
4868 e_calendar_free_op (our_op);
4870 E_CALENDAR_CHECK_STATUS (status, error);
4874 * e_cal_set_default_timezone:
4875 * @ecal: A calendar client.
4876 * @zone: A timezone object.
4877 * @error: Placeholder for error information.
4879 * Sets the default timezone on the calendar. This should be called before opening
4882 * Return value: TRUE if the operation was successful, FALSE otherwise.
4885 e_cal_set_default_timezone (ECal *ecal, icaltimezone *zone, GError **error)
4888 CORBA_Environment ev;
4889 ECalendarStatus status;
4890 ECalendarOp *our_op;
4891 icalcomponent *icalcomp = NULL;
4894 e_return_error_if_fail (ecal && E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
4895 e_return_error_if_fail (zone, E_CALENDAR_STATUS_INVALID_ARG);
4899 /* Don't set the same timezone multiple times */
4900 if (priv->default_zone == zone)
4903 g_mutex_lock (priv->mutex);
4905 if (ecal->priv->current_op != NULL) {
4906 g_mutex_unlock (ecal->priv->mutex);
4907 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_BUSY, error);
4910 our_op = e_calendar_new_op (ecal);
4912 g_mutex_unlock (priv->mutex);
4914 /* FIXME Adding it to the server to change the tzid */
4915 icalcomp = icaltimezone_get_component (zone);
4917 e_calendar_remove_op (ecal, our_op);
4918 e_calendar_free_op (our_op);
4920 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_INVALID_ARG, error);
4923 /* convert icaltimezone into a string */
4924 tzobj = icalcomponent_as_ical_string (icalcomp);
4926 /* call the backend */
4927 CORBA_exception_init (&ev);
4929 GNOME_Evolution_Calendar_Cal_setDefaultTimezone (priv->cal, tzobj, &ev);
4930 if (BONOBO_EX (&ev)) {
4931 e_calendar_remove_op (ecal, our_op);
4932 e_calendar_free_op (our_op);
4934 CORBA_exception_free (&ev);
4936 g_warning (G_STRLOC ": Unable to contact backend");
4938 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_CORBA_EXCEPTION, error);
4941 CORBA_exception_free (&ev);
4943 e_flag_wait (our_op->done);
4945 status = our_op->status;
4947 /* set the default timezone internally if successful */
4948 if (our_op->status == E_CALENDAR_STATUS_OK) {
4949 g_mutex_lock (priv->mutex);
4950 priv->default_zone = zone;
4951 g_mutex_unlock (priv->mutex);
4954 e_calendar_remove_op (ecal, our_op);
4955 e_calendar_free_op (our_op);
4957 E_CALENDAR_CHECK_STATUS (status, error);
4961 * e_cal_get_error_message
4962 * @status: A status code.
4964 * Gets an error message for the given status code.
4966 * Returns: the error message.
4969 e_cal_get_error_message (ECalendarStatus status)
4972 case E_CALENDAR_STATUS_INVALID_ARG :
4973 return _("Invalid argument");
4974 case E_CALENDAR_STATUS_BUSY :
4975 return _("Backend is busy");
4976 case E_CALENDAR_STATUS_REPOSITORY_OFFLINE :
4977 return _("Repository is offline");
4978 case E_CALENDAR_STATUS_NO_SUCH_CALENDAR :
4979 return _("No such calendar");
4980 case E_CALENDAR_STATUS_OBJECT_NOT_FOUND :
4981 return _("Object not found");
4982 case E_CALENDAR_STATUS_INVALID_OBJECT :
4983 return _("Invalid object");
4984 case E_CALENDAR_STATUS_URI_NOT_LOADED :
4985 return _("URI not loaded");
4986 case E_CALENDAR_STATUS_URI_ALREADY_LOADED :
4987 return _("URI already loaded");
4988 case E_CALENDAR_STATUS_PERMISSION_DENIED :
4989 return _("Permission denied");
4990 case E_CALENDAR_STATUS_UNKNOWN_USER :
4991 return _("Unknown User");
4992 case E_CALENDAR_STATUS_OBJECT_ID_ALREADY_EXISTS :
4993 return _("Object ID already exists");
4994 case E_CALENDAR_STATUS_PROTOCOL_NOT_SUPPORTED :
4995 return _("Protocol not supported");
4996 case E_CALENDAR_STATUS_CANCELLED :
4997 return _("Operation has been canceled");
4998 case E_CALENDAR_STATUS_COULD_NOT_CANCEL :
4999 return _("Could not cancel operation");
5000 case E_CALENDAR_STATUS_AUTHENTICATION_FAILED :
5001 return _("Authentication failed");
5002 case E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED :
5003 return _("Authentication required");
5004 case E_CALENDAR_STATUS_CORBA_EXCEPTION :
5005 return _("A CORBA exception has occurred");
5006 case E_CALENDAR_STATUS_OTHER_ERROR :
5007 return _("Unknown error");
5008 case E_CALENDAR_STATUS_OK :
5009 return _("No error");
5011 /* ignore everything else */
5019 get_default (ECal **ecal, ESourceList *sources, ECalSourceType type, ECalAuthFunc func, gpointer data, GError **error)
5023 ESource *default_source = NULL;
5026 for (g = e_source_list_peek_groups (sources); g; g = g->next) {
5027 ESourceGroup *group = E_SOURCE_GROUP (g->data);
5029 for (s = e_source_group_peek_sources (group); s; s = s->next) {
5030 ESource *source = E_SOURCE (s->data);
5032 if (e_source_get_property (source, "default")) {
5033 default_source = source;
5042 if (default_source) {
5043 *ecal = e_cal_new (default_source, type);
5045 g_propagate_error (error, err);
5050 e_cal_set_auth_func (*ecal, func, data);
5051 if (!e_cal_open (*ecal, TRUE, &err)) {
5052 g_propagate_error (error, err);
5058 case E_CAL_SOURCE_TYPE_EVENT:
5059 *ecal = e_cal_new_system_calendar ();
5061 case E_CAL_SOURCE_TYPE_TODO:
5062 *ecal = e_cal_new_system_tasks ();
5064 case E_CAL_SOURCE_TYPE_JOURNAL:
5065 *ecal = e_cal_new_system_memos ();
5072 g_propagate_error (error, err);
5077 e_cal_set_auth_func (*ecal, func, data);
5078 if (!e_cal_open (*ecal, TRUE, &err)) {
5079 g_propagate_error (error, err);
5087 g_object_unref (*ecal);
5090 g_object_unref (sources);
5096 * e_cal_open_default:
5097 * @ecal: A calendar client.
5098 * @type: Type of the calendar.
5099 * @func: Authentication function.
5100 * @data: Closure data for the authentication function.
5101 * @error: Placeholder for error information.
5103 * Opens the default calendar.
5105 * Return value: TRUE if it opened correctly, FALSE otherwise.
5108 e_cal_open_default (ECal **ecal, ECalSourceType type, ECalAuthFunc func, gpointer data, GError **error)
5110 ESourceList *sources;
5113 if (!e_cal_get_sources (&sources, type, &err)) {
5114 g_propagate_error (error, err);
5118 return get_default (ecal, sources, type, func, data, error);
5122 * e_cal_set_default:
5123 * @ecal: A calendar client.
5124 * @error: Placeholder for error information.
5126 * Sets a calendar as the default one.
5128 * Return value: TRUE if the operation was successful, FALSE otherwise.
5131 e_cal_set_default (ECal *ecal, GError **error)
5135 e_return_error_if_fail (ecal && E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
5137 source = e_cal_get_source (ecal);
5143 return e_cal_set_default_source (source, ecal->priv->type, error);
5147 set_default_source (ESourceList *sources, ESource *source, GError **error)
5153 uid = e_source_peek_uid (source);
5155 /* make sure the source is actually in the ESourceList. if
5156 it's not we don't bother adding it, just return an error */
5157 source = e_source_list_peek_source_by_uid (sources, uid);
5160 g_object_unref (sources);
5164 /* loop over all the sources clearing out any "default"
5165 properties we find */
5166 for (g = e_source_list_peek_groups (sources); g; g = g->next) {
5168 for (s = e_source_group_peek_sources (E_SOURCE_GROUP (g->data));
5170 e_source_set_property (E_SOURCE (s->data), "default", NULL);
5174 /* set the "default" property on the source */
5175 e_source_set_property (source, "default", "true");
5177 if (!e_source_list_sync (sources, &err)) {
5178 g_propagate_error (error, err);
5186 * e_cal_set_default_source:
5187 * @source: An #ESource.
5188 * @type: Type of the source.
5189 * @error: Placeholder for error information.
5191 * Sets the default source for the specified @type.
5193 * Return value: TRUE if the operation was successful, FALSE otherwise.
5196 e_cal_set_default_source (ESource *source, ECalSourceType type, GError **error)
5198 ESourceList *sources;
5201 if (!e_cal_get_sources (&sources, type, &err)) {
5202 g_propagate_error (error, err);
5206 return set_default_source (sources, source, error);
5210 get_sources (ESourceList **sources, const char *key, GError **error)
5212 GConfClient *gconf = gconf_client_get_default();
5214 *sources = e_source_list_new_for_gconf (gconf, key);
5215 g_object_unref (gconf);
5221 * e_cal_get_sources:
5222 * @sources: Return value for list of sources.
5223 * @type: Type of the sources to get.
5224 * @error: Placeholder for error information.
5226 * Gets the list of sources defined in the configuration for the given @type.
5228 * Return value: TRUE if the operation was successful, FALSE otherwise.
5231 e_cal_get_sources (ESourceList **sources, ECalSourceType type, GError **error)
5234 case E_CAL_SOURCE_TYPE_EVENT:
5235 return get_sources (sources, "/apps/evolution/calendar/sources", error);
5237 case E_CAL_SOURCE_TYPE_TODO:
5238 return get_sources (sources, "/apps/evolution/tasks/sources", error);
5240 case E_CAL_SOURCE_TYPE_JOURNAL:
5241 return get_sources (sources, "/apps/evolution/memos/sources", error);
5244 /* FIXME Fill in error */
5248 /* FIXME Fill in error */