1 /*-*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* Evolution calendar ecal
4 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
5 * Copyright (C) 2009 Intel Corporation
7 * Authors: Federico Mena-Quintero <federico@ximian.com>
8 * Rodrigo Moya <rodrigo@novell.com>
9 * Ross Burton <ross@linux.intel.com>
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of version 2 of the GNU Lesser General Public
13 * License as published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
28 * The old signal "cal-opened" is deprecated since 3.0 and is replaced with
29 * its equivalent "cal_opened_ex", which has a detailed #GError structure
30 * as a parameter, instead of a status code only.
32 * Deprecated: 3.2: Use #ECalClient instead.
41 #include <glib/gi18n-lib.h>
43 #include <libical/ical.h>
44 #include <libedataserver/e-url.h>
45 #include <libedataserver/e-credentials.h>
46 #include <libedataserver/e-data-server-util.h>
48 #include "libedata-cal/e-data-cal-types.h"
50 #include "e-cal-check-timezones.h"
51 #include "e-cal-marshal.h"
52 #include "e-cal-time-util.h"
53 #include "e-cal-view-private.h"
56 #include "e-gdbus-cal.h"
57 #include "e-gdbus-cal-view.h"
58 #include "e-gdbus-cal-factory.h"
60 #define E_CAL_GET_PRIVATE(obj) \
61 (G_TYPE_INSTANCE_GET_PRIVATE \
62 ((obj), E_TYPE_CAL, ECalPrivate))
64 #define CLIENT_BACKEND_PROPERTY_CACHE_DIR "cache-dir"
65 #define CLIENT_BACKEND_PROPERTY_CAPABILITIES "capabilities"
66 #define CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS "cal-email-address"
67 #define CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS "alarm-email-address"
68 #define CAL_BACKEND_PROPERTY_DEFAULT_OBJECT "default-object"
70 static guint active_cals = 0, cal_connection_closed_id = 0;
71 static EGdbusCalFactory *cal_factory_proxy = NULL;
72 static GStaticRecMutex cal_factory_proxy_lock = G_STATIC_REC_MUTEX_INIT;
73 #define LOCK_FACTORY() g_static_rec_mutex_lock (&cal_factory_proxy_lock)
74 #define UNLOCK_FACTORY() g_static_rec_mutex_unlock (&cal_factory_proxy_lock)
76 #define LOCK_CACHE() g_static_rec_mutex_lock (&priv->cache_lock)
77 #define UNLOCK_CACHE() g_static_rec_mutex_unlock (&priv->cache_lock)
79 G_DEFINE_TYPE (ECal, e_cal, G_TYPE_OBJECT)
81 static gboolean open_calendar (ECal *ecal, gboolean only_if_exists, GError **error,
82 ECalendarStatus *status,
83 gboolean needs_auth, gboolean async);
84 static void e_cal_dispose (GObject *object);
85 static void e_cal_finalize (GObject *object);
87 /* Private part of the ECal structure */
89 GDBusProxy *gdbus_cal;
92 /* Load state to avoid multiple loads */
93 ECalLoadState load_state;
95 /* URI of the calendar that is being loaded or is already loaded, or
96 * NULL if we are not loaded.
102 /* Email address associated with this calendar, or NULL */
104 gchar *alarm_email_address;
105 gchar *ldap_attribute;
107 /* Scheduling info */
111 gboolean requires_auth;
115 /* The authentication function */
116 ECalAuthFunc auth_func;
117 gpointer auth_user_data;
119 /* A cache of timezones retrieved from the server, to avoid getting
120 * them repeatedly for each get_object () call. */
121 GHashTable *timezones;
123 /* The default timezone to use to resolve DATE and floating DATE-TIME
125 icaltimezone *default_zone;
127 gchar *local_attachment_store;
129 /* For locking the operation while localling cache values like
130 * static capabilities, cal address etc. */
131 GStaticRecMutex cache_lock;
133 GList **free_busy_data;
134 GMutex *free_busy_data_lock;
149 static guint e_cal_signals[LAST_SIGNAL];
151 #ifdef __PRETTY_FUNCTION__
152 #define e_return_error_if_fail(expr,error_code) G_STMT_START{ \
153 if G_LIKELY (expr) { } else \
155 g_log (G_LOG_DOMAIN, \
156 G_LOG_LEVEL_CRITICAL, \
157 "file %s: line %d (%s): assertion `%s' failed", \
160 __PRETTY_FUNCTION__, \
162 g_set_error (error, E_CALENDAR_ERROR, (error_code), \
163 "file %s: line %d (%s): assertion `%s' failed", \
166 __PRETTY_FUNCTION__, \
171 #define e_return_error_if_fail(expr,error_code) G_STMT_START{ \
172 if G_LIKELY (expr) { } else \
174 g_log (G_LOG_DOMAIN, \
175 G_LOG_LEVEL_CRITICAL, \
176 "file %s: line %d: assertion `%s' failed", \
180 g_set_error (error, E_CALENDAR_ERROR, (error_code), \
181 "file %s: line %d: assertion `%s' failed", \
189 #define E_CALENDAR_CHECK_STATUS(status,error) \
191 if ((status) == E_CALENDAR_STATUS_OK) \
195 if (error && *error) \
196 return unwrap_gerror (error); \
197 msg = e_cal_get_error_message ((status)); \
198 g_set_error ((error), E_CALENDAR_ERROR, (status), "%s", msg); \
207 e_calendar_error_quark (void)
211 q = g_quark_from_static_string ("e-calendar-error-quark");
217 * If the GError is a remote error, extract the EBookStatus embedded inside.
218 * Otherwise return CORBA_EXCEPTION (I know this is DBus...).
220 static ECalendarStatus
221 get_status_from_error (const GError *error)
223 #define err(a,b) "org.gnome.evolution.dataserver.Calendar." a, b
226 ECalendarStatus err_code;
228 { err ("Success", E_CALENDAR_STATUS_OK) },
229 { err ("Busy", E_CALENDAR_STATUS_BUSY) },
230 { err ("RepositoryOffline", E_CALENDAR_STATUS_REPOSITORY_OFFLINE) },
231 { err ("PermissionDenied", E_CALENDAR_STATUS_PERMISSION_DENIED) },
232 { err ("InvalidRange", E_CALENDAR_STATUS_OTHER_ERROR) },
233 { err ("ObjectNotFound", E_CALENDAR_STATUS_OBJECT_NOT_FOUND) },
234 { err ("InvalidObject", E_CALENDAR_STATUS_INVALID_OBJECT) },
235 { err ("ObjectIdAlreadyExists", E_CALENDAR_STATUS_OBJECT_ID_ALREADY_EXISTS) },
236 { err ("AuthenticationFailed", E_CALENDAR_STATUS_AUTHENTICATION_FAILED) },
237 { err ("AuthenticationRequired", E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED) },
238 { err ("UnsupportedField", E_CALENDAR_STATUS_OTHER_ERROR) },
239 { err ("UnsupportedMethod", E_CALENDAR_STATUS_OTHER_ERROR) },
240 { err ("UnsupportedAuthenticationMethod", E_CALENDAR_STATUS_OTHER_ERROR) },
241 { err ("TLSNotAvailable", E_CALENDAR_STATUS_OTHER_ERROR) },
242 { err ("NoSuchCal", E_CALENDAR_STATUS_NO_SUCH_CALENDAR) },
243 { err ("UnknownUser", E_CALENDAR_STATUS_UNKNOWN_USER) },
244 { err ("OfflineUnavailable", E_CALENDAR_STATUS_OTHER_ERROR) },
245 { err ("SearchSizeLimitExceeded", E_CALENDAR_STATUS_OTHER_ERROR) },
246 { err ("SearchTimeLimitExceeded", E_CALENDAR_STATUS_OTHER_ERROR) },
247 { err ("InvalidQuery", E_CALENDAR_STATUS_OTHER_ERROR) },
248 { err ("QueryRefused", E_CALENDAR_STATUS_OTHER_ERROR) },
249 { err ("CouldNotCancel", E_CALENDAR_STATUS_COULD_NOT_CANCEL) },
250 { err ("OtherError", E_CALENDAR_STATUS_OTHER_ERROR) },
251 { err ("InvalidServerVersion", E_CALENDAR_STATUS_INVALID_SERVER_VERSION) },
252 { err ("InvalidArg", E_CALENDAR_STATUS_INVALID_ARG) },
253 { err ("NotSupported", E_CALENDAR_STATUS_NOT_SUPPORTED) }
257 if G_LIKELY (error == NULL)
260 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR)) {
264 name = g_dbus_error_get_remote_error (error);
266 for (i = 0; i < G_N_ELEMENTS (errors); i++) {
267 if (g_ascii_strcasecmp (errors[i].name, name) == 0) {
269 return errors[i].err_code;
273 g_warning ("Unmatched error name %s", name);
276 return E_CALENDAR_STATUS_OTHER_ERROR;
277 } else if (error->domain == E_CALENDAR_ERROR) {
280 /* In this case the error was caused by DBus */
281 return E_CALENDAR_STATUS_DBUS_EXCEPTION;
286 * If the specified GError is a remote error, then create a new error
287 * representing the remote error. If the error is anything else, then leave it
291 unwrap_gerror (GError **error)
296 if (g_error_matches (*error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR)) {
297 GError *new_error = NULL;
300 code = get_status_from_error (*error);
301 g_dbus_error_strip_remote_error (*error);
303 new_error = g_error_new_literal (E_CALENDAR_ERROR, code, (*error)->message);
305 g_error_free (*error);
313 * e_cal_source_type_enum_get_type:
315 * Registers the #ECalSourceTypeEnum type with glib.
317 * Returns: the ID of the #ECalSourceTypeEnum type.
319 * Deprecated: 3.2: Use e_cal_client_source_type_enum_get_type() instead.
322 e_cal_source_type_enum_get_type (void)
324 static volatile gsize enum_type__volatile = 0;
326 if (g_once_init_enter (&enum_type__volatile)) {
328 static GEnumValue values[] = {
329 { E_CAL_SOURCE_TYPE_EVENT, "Event", "Event"},
330 { E_CAL_SOURCE_TYPE_TODO, "ToDo", "ToDo"},
331 { E_CAL_SOURCE_TYPE_JOURNAL, "Journal", "Journal"},
332 { E_CAL_SOURCE_TYPE_LAST, "Invalid", "Invalid"},
336 enum_type = g_enum_register_static ("ECalSourceTypeEnum", values);
337 g_once_init_leave (&enum_type__volatile, enum_type);
340 return enum_type__volatile;
344 * e_cal_set_mode_status_enum_get_type:
346 * Registers the #ECalSetModeStatusEnum type with glib.
348 * Returns: the ID of the #ECalSetModeStatusEnum type.
350 * Deprecated: 3.2: This type has been dropped completely.
353 e_cal_set_mode_status_enum_get_type (void)
355 static volatile gsize enum_type__volatile = 0;
357 if (g_once_init_enter (&enum_type__volatile)) {
359 static GEnumValue values[] = {
360 { E_CAL_SET_MODE_SUCCESS, "ECalSetModeSuccess", "success" },
361 { E_CAL_SET_MODE_ERROR, "ECalSetModeError", "error" },
362 { E_CAL_SET_MODE_NOT_SUPPORTED, "ECalSetModeNotSupported", "unsupported" },
366 enum_type = g_enum_register_static ("ECalSetModeStatusEnum", values);
367 g_once_init_leave (&enum_type__volatile, enum_type);
370 return enum_type__volatile;
374 * cal_mode_enum_get_type:
376 * Registers the #CalModeEnum type with glib.
378 * Returns: the ID of the #CalModeEnum type.
380 * Deprecated: 3.2: This type has been dropped completely.
383 cal_mode_enum_get_type (void)
385 static volatile gsize enum_type__volatile = 0;
387 if (g_once_init_enter (&enum_type__volatile)) {
389 static GEnumValue values[] = {
390 { CAL_MODE_INVALID, "CalModeInvalid", "invalid" },
391 { CAL_MODE_LOCAL, "CalModeLocal", "local" },
392 { CAL_MODE_REMOTE, "CalModeRemote", "remote" },
393 { CAL_MODE_ANY, "CalModeAny", "any" },
397 enum_type = g_enum_register_static ("CalModeEnum", values);
398 g_once_init_leave (&enum_type__volatile, enum_type);
401 return enum_type__volatile;
404 static EDataCalObjType
405 convert_type (ECalSourceType type)
408 case E_CAL_SOURCE_TYPE_EVENT:
410 case E_CAL_SOURCE_TYPE_TODO:
412 case E_CAL_SOURCE_TYPE_JOURNAL:
422 e_cal_init (ECal *ecal)
428 ecal->priv = E_CAL_GET_PRIVATE (ecal);
430 ecal->priv->load_state = E_CAL_LOAD_NOT_LOADED;
431 ecal->priv->uri = NULL;
432 ecal->priv->local_attachment_store = NULL;
434 ecal->priv->cal_address = NULL;
435 ecal->priv->alarm_email_address = NULL;
436 ecal->priv->ldap_attribute = NULL;
437 ecal->priv->capabilities = NULL;
438 ecal->priv->gdbus_cal = NULL;
439 ecal->priv->timezones = g_hash_table_new (g_str_hash, g_str_equal);
440 ecal->priv->default_zone = icaltimezone_get_utc_timezone ();
441 ecal->priv->free_busy_data_lock = g_mutex_new ();
442 g_static_rec_mutex_init (&ecal->priv->cache_lock);
446 gdbus_cal_disconnect (ECal *ecal);
449 * Called when the calendar server dies.
452 gdbus_cal_closed_cb (GDBusConnection *connection,
453 gboolean remote_peer_vanished,
459 g_return_if_fail (E_IS_CAL (ecal));
462 err = g_error_copy (error);
463 unwrap_gerror (&err);
467 g_debug (G_STRLOC ": ECal GDBus connection is closed%s: %s", remote_peer_vanished ? ", remote peer vanished" : "", err->message);
470 g_debug (G_STRLOC ": ECal GDBus connection is closed%s", remote_peer_vanished ? ", remote peer vanished" : "");
473 gdbus_cal_disconnect (ecal);
475 g_signal_emit (G_OBJECT (ecal), e_cal_signals[BACKEND_DIED], 0);
479 gdbus_cal_connection_gone_cb (GDBusConnection *connection,
480 const gchar *sender_name,
481 const gchar *object_path,
482 const gchar *interface_name,
483 const gchar *signal_name,
484 GVariant *parameters,
487 /* signal subscription takes care of correct parameters,
488 * thus just do what is to be done here */
489 gdbus_cal_closed_cb (connection, TRUE, NULL, user_data);
493 gdbus_cal_disconnect (ECal *ecal)
495 /* Ensure that everything relevant is NULL */
498 if (ecal->priv->gdbus_cal) {
499 GError *error = NULL;
500 GDBusConnection *connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (ecal->priv->gdbus_cal));
502 g_signal_handlers_disconnect_by_func (connection, gdbus_cal_closed_cb, ecal);
503 g_dbus_connection_signal_unsubscribe (connection, ecal->priv->gone_signal_id);
504 ecal->priv->gone_signal_id = 0;
506 e_gdbus_cal_call_close_sync (ecal->priv->gdbus_cal, NULL, &error);
507 g_object_unref (ecal->priv->gdbus_cal);
508 ecal->priv->gdbus_cal = NULL;
511 unwrap_gerror (&error);
513 g_warning ("%s: Failed to close calendar, %s\n", G_STRFUNC, error->message);
514 g_error_free (error);
520 /* Dispose handler for the calendar ecal */
522 e_cal_dispose (GObject *object)
524 ECal *ecal = E_CAL (object);
526 gdbus_cal_disconnect (ecal);
528 /* Chain up to parent's dispose() method. */
529 G_OBJECT_CLASS (e_cal_parent_class)->dispose (object);
533 free_timezone (gpointer key,
537 /* Note that the key comes from within the icaltimezone value, so we
538 * don't free that. */
539 icaltimezone_free (value, TRUE);
542 /* Finalize handler for the calendar ecal */
544 e_cal_finalize (GObject *object)
549 g_return_if_fail (object != NULL);
550 g_return_if_fail (E_IS_CAL (object));
552 ecal = E_CAL (object);
555 priv->load_state = E_CAL_LOAD_NOT_LOADED;
558 g_object_unref (priv->source);
567 if (priv->local_attachment_store) {
568 g_free (priv->local_attachment_store);
569 priv->local_attachment_store = NULL;
572 if (priv->cal_address) {
573 g_free (priv->cal_address);
574 priv->cal_address = NULL;
576 if (priv->alarm_email_address) {
577 g_free (priv->alarm_email_address);
578 priv->alarm_email_address = NULL;
580 if (priv->ldap_attribute) {
581 g_free (priv->ldap_attribute);
582 priv->ldap_attribute = NULL;
584 if (priv->capabilities) {
585 g_free (priv->capabilities);
586 priv->capabilities = NULL;
589 if (priv->free_busy_data) {
590 g_mutex_lock (priv->free_busy_data_lock);
591 g_list_foreach (*priv->free_busy_data, (GFunc) g_object_unref, NULL);
592 g_list_free (*priv->free_busy_data);
593 *priv->free_busy_data = NULL;
594 priv->free_busy_data = NULL;
595 g_mutex_unlock (priv->free_busy_data_lock);
598 g_hash_table_foreach (priv->timezones, free_timezone, NULL);
599 g_hash_table_destroy (priv->timezones);
600 priv->timezones = NULL;
601 g_static_rec_mutex_free (&priv->cache_lock);
602 g_mutex_free (priv->free_busy_data_lock);
604 /* Chain up to parent's finalize() method. */
605 G_OBJECT_CLASS (e_cal_parent_class)->finalize (object);
612 /* Class initialization function for the calendar ecal */
614 e_cal_class_init (ECalClass *class)
616 GObjectClass *object_class;
618 object_class = (GObjectClass *) class;
620 /* XXX The "cal-opened" signal is deprecated. */
621 e_cal_signals[CAL_OPENED] =
622 g_signal_new ("cal_opened",
623 G_TYPE_FROM_CLASS (class),
625 G_STRUCT_OFFSET (ECalClass, cal_opened),
627 g_cclosure_marshal_VOID__INT,
628 G_TYPE_NONE, 1, G_TYPE_INT);
631 * ECal::cal-opened-ex:
633 * @error: (type glong):
635 e_cal_signals[CAL_OPENED_EX] =
636 g_signal_new ("cal_opened_ex",
637 G_TYPE_FROM_CLASS (class),
639 G_STRUCT_OFFSET (ECalClass, cal_opened_ex),
641 g_cclosure_marshal_VOID__POINTER,
642 G_TYPE_NONE, 1, G_TYPE_POINTER);
644 e_cal_signals[CAL_SET_MODE] =
645 g_signal_new ("cal_set_mode",
646 G_TYPE_FROM_CLASS (class),
648 G_STRUCT_OFFSET (ECalClass, cal_set_mode),
650 e_cal_marshal_VOID__ENUM_ENUM,
652 E_CAL_SET_MODE_STATUS_ENUM_TYPE,
654 e_cal_signals[BACKEND_ERROR] =
655 g_signal_new ("backend_error",
656 G_TYPE_FROM_CLASS (class),
658 G_STRUCT_OFFSET (ECalClass, backend_error),
660 g_cclosure_marshal_VOID__STRING,
663 e_cal_signals[BACKEND_DIED] =
664 g_signal_new ("backend_died",
665 G_TYPE_FROM_CLASS (class),
667 G_STRUCT_OFFSET (ECalClass, backend_died),
669 g_cclosure_marshal_VOID__VOID,
672 class->cal_opened = NULL;
673 class->cal_opened_ex = NULL;
674 class->backend_died = NULL;
676 object_class->dispose = e_cal_dispose;
677 object_class->finalize = e_cal_finalize;
679 g_type_class_add_private (class, sizeof (ECalPrivate));
683 cal_factory_proxy_closed_cb (GDBusConnection *connection,
684 gboolean remote_peer_vanished,
692 if (cal_connection_closed_id) {
693 g_dbus_connection_signal_unsubscribe (connection, cal_connection_closed_id);
694 cal_connection_closed_id = 0;
695 g_signal_handlers_disconnect_by_func (connection, cal_factory_proxy_closed_cb, NULL);
698 if (cal_factory_proxy) {
699 g_object_unref (cal_factory_proxy);
700 cal_factory_proxy = NULL;
704 err = g_error_copy (error);
705 unwrap_gerror (&err);
709 g_debug ("GDBus connection is closed%s: %s", remote_peer_vanished ? ", remote peer vanished" : "", err->message);
711 } else if (active_cals) {
712 g_debug ("GDBus connection is closed%s", remote_peer_vanished ? ", remote peer vanished" : "");
719 cal_factory_connection_gone_cb (GDBusConnection *connection,
720 const gchar *sender_name,
721 const gchar *object_path,
722 const gchar *interface_name,
723 const gchar *signal_name,
724 GVariant *parameters,
727 /* signal subscription takes care of correct parameters,
728 * thus just do what is to be done here */
729 cal_factory_proxy_closed_cb (connection, TRUE, NULL, user_data);
732 /* one-time start up for libecal */
734 e_cal_activate (GError **error)
736 GDBusConnection *connection;
739 if (G_LIKELY (cal_factory_proxy)) {
744 cal_factory_proxy = e_gdbus_cal_factory_proxy_new_for_bus_sync (
746 G_DBUS_PROXY_FLAGS_NONE,
747 CALENDAR_DBUS_SERVICE_NAME,
748 "/org/gnome/evolution/dataserver/CalendarFactory",
752 if (!cal_factory_proxy) {
757 connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (cal_factory_proxy));
758 cal_connection_closed_id = g_dbus_connection_signal_subscribe (connection,
760 "org.freedesktop.DBus", /* interface */
761 "NameOwnerChanged", /* member */
762 "/org/freedesktop/DBus", /* object_path */
763 CALENDAR_DBUS_SERVICE_NAME, /* arg0 */
764 G_DBUS_SIGNAL_FLAGS_NONE,
765 cal_factory_connection_gone_cb, NULL, NULL);
767 g_signal_connect (connection, "closed", G_CALLBACK (cal_factory_proxy_closed_cb), NULL);
775 build_proxy_pass_key (ECal *ecal,
776 const gchar *parent_user)
782 uri = e_cal_get_uri (ecal);
784 euri = e_uri_new (uri);
786 euri->user = g_strdup (parent_user);
788 euri_str = e_uri_to_string (euri, FALSE);
795 build_pass_key (ECal *ecal)
801 uri = e_cal_get_uri (ecal);
803 euri = e_uri_new (uri);
804 euri_str = e_uri_to_string (euri, FALSE);
810 static void async_open_report_result (ECal *ecal, const GError *error);
813 authenticate_user_ready_cb (GObject *source_object,
814 GAsyncResult *result,
817 ECal *cal = user_data;
818 GError *error = NULL;
820 g_return_if_fail (cal != NULL);
822 if (!e_gdbus_cal_call_authenticate_user_finish (G_DBUS_PROXY (source_object), result, &error))
823 cal->priv->load_state = E_CAL_LOAD_NOT_LOADED;
825 cal->priv->load_state = E_CAL_LOAD_LOADED;
827 if (cal->priv->requires_auth && !error) {
828 cal->priv->load_state = E_CAL_LOAD_NOT_LOADED;
829 g_set_error_literal (&error, E_CALENDAR_ERROR, E_CALENDAR_STATUS_AUTHENTICATION_FAILED, e_cal_get_error_message (E_CALENDAR_STATUS_AUTHENTICATION_FAILED));
832 unwrap_gerror (&error);
833 async_open_report_result (cal, error);
836 g_error_free (error);
840 finish_backend_opening_phase (ECal *cal)
842 const gchar *strv[2];
844 g_return_if_fail (cal != NULL);
845 g_return_if_fail (E_IS_CAL (cal));
850 e_gdbus_cal_call_authenticate_user_sync (cal->priv->gdbus_cal, (const gchar * const *) strv, NULL, NULL);
854 call_authenticate_user (ECal *cal,
858 gchar *username = NULL, *password = NULL;
859 ECredentials *credentials = NULL;
862 g_return_val_if_fail (cal != NULL, FALSE);
863 g_return_val_if_fail (E_IS_CAL (cal), FALSE);
867 if (!priv->gdbus_cal) {
868 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
871 /* see if the backend needs authentication */
872 if ((priv->mode != CAL_MODE_LOCAL) && (e_source_get_property (priv->source, "auth") || priv->requires_auth)) {
873 gchar *prompt, *key, *auth_type = NULL;
876 priv->load_state = E_CAL_LOAD_AUTHENTICATING;
878 if (priv->auth_func == NULL) {
879 priv->load_state = E_CAL_LOAD_NOT_LOADED;
880 finish_backend_opening_phase (cal);
881 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED, error);
884 username = e_source_get_duped_property (priv->source, "username");
886 priv->load_state = E_CAL_LOAD_NOT_LOADED;
887 finish_backend_opening_phase (cal);
888 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED, error);
891 prompt = g_strdup_printf (_("Enter password for %s (user %s)"),
892 e_source_get_display_name (priv->source), username);
894 auth_type = e_source_get_duped_property (priv->source, "auth-type");
896 key = build_pass_key (cal);
898 parent_user = e_source_get_duped_property (priv->source, "parent_id_name");
900 key = build_proxy_pass_key (cal, parent_user);
902 * This password prompt will be prompted rarely. Since the key that is passed to
903 * the auth_func corresponds to the parent user.
905 prompt = g_strdup_printf (_("Enter password for %s to enable proxy for user %s"), e_source_get_display_name (priv->source), parent_user);
906 g_free (parent_user);
908 key = g_strdup (e_cal_get_uri (cal));
913 priv->load_state = E_CAL_LOAD_NOT_LOADED;
915 finish_backend_opening_phase (cal);
916 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED, error);
919 password = priv->auth_func (cal, prompt, key, priv->auth_user_data);
922 priv->load_state = E_CAL_LOAD_NOT_LOADED;
924 finish_backend_opening_phase (cal);
925 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED, error);
933 credentials = e_credentials_new_args (
934 E_CREDENTIALS_KEY_USERNAME, username,
935 E_CREDENTIALS_KEY_PASSWORD, password,
938 priv->load_state = E_CAL_LOAD_NOT_LOADED;
941 e_credentials_util_safe_free_string (password);
944 gchar **strv = e_credentials_to_strv (credentials);
947 cal->priv->requires_auth = FALSE;
948 e_gdbus_cal_call_authenticate_user (cal->priv->gdbus_cal, (const gchar * const *) strv, NULL, authenticate_user_ready_cb, cal);
949 } else if (e_gdbus_cal_call_authenticate_user_sync (cal->priv->gdbus_cal, (const gchar * const *) strv, NULL, error))
950 priv->load_state = E_CAL_LOAD_LOADED;
952 priv->load_state = E_CAL_LOAD_NOT_LOADED;
955 e_credentials_free (credentials);
958 unwrap_gerror (error);
959 } else if (priv->requires_auth) {
960 priv->load_state = E_CAL_LOAD_NOT_LOADED;
961 finish_backend_opening_phase (cal);
962 g_set_error_literal (error, E_CALENDAR_ERROR, E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED, e_cal_get_error_message (E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED));
965 return credentials && (!error || !*error);
969 reopen_with_auth (gpointer data)
971 ECalendarStatus status;
972 GError *error = NULL;
974 open_calendar (E_CAL (data), TRUE, &error,
979 g_error_free (error);
985 auth_required_cb (EGdbusCal *gdbus_cal,
986 const gchar * const *credentials_strv,
990 g_return_if_fail (E_IS_CAL (cal));
994 priv->requires_auth = TRUE;
996 if (priv->load_state != E_CAL_LOAD_AUTHENTICATING)
997 g_idle_add (reopen_with_auth, (gpointer) cal);
1001 free_busy_data_cb (EGdbusCal *gdbus_cal,
1002 const gchar * const *free_busy_strv,
1007 g_return_if_fail (E_IS_CAL (cal));
1011 g_mutex_lock (priv->free_busy_data_lock);
1013 if (priv->free_busy_data) {
1015 GList *list = *priv->free_busy_data;
1017 for (ii = 0; free_busy_strv[ii]; ii++) {
1018 ECalComponent *comp;
1019 icalcomponent *icalcomp;
1020 icalcomponent_kind kind;
1022 icalcomp = icalcomponent_new_from_string (free_busy_strv[ii]);
1026 kind = icalcomponent_isa (icalcomp);
1027 if (kind == ICAL_VFREEBUSY_COMPONENT) {
1028 comp = e_cal_component_new ();
1029 if (!e_cal_component_set_icalcomponent (comp, icalcomp)) {
1030 icalcomponent_free (icalcomp);
1031 g_object_unref (G_OBJECT (comp));
1035 list = g_list_append (list, comp);
1037 icalcomponent_free (icalcomp);
1041 *priv->free_busy_data = list;
1044 g_mutex_unlock (priv->free_busy_data_lock);
1054 backend_error_idle_cb (gpointer data)
1056 ECalErrorData *error_data = data;
1058 g_signal_emit (G_OBJECT (error_data->ecal), e_cal_signals[BACKEND_ERROR], 0, error_data->message);
1060 g_object_unref (error_data->ecal);
1061 g_free (error_data->message);
1062 g_free (error_data);
1067 /* Handle the error_occurred signal from the listener */
1069 backend_error_cb (EGdbusCal *gdbus_cal,
1070 const gchar *message,
1073 ECalErrorData *error_data;
1075 g_return_if_fail (E_IS_CAL (ecal));
1077 error_data = g_new0 (ECalErrorData, 1);
1079 error_data->ecal = g_object_ref (ecal);
1080 error_data->message = g_strdup (message);
1082 g_idle_add (backend_error_idle_cb, error_data);
1086 readonly_cb (EGdbusCal *gdbus_cal,
1092 g_return_if_fail (cal && E_IS_CAL (cal));
1095 priv->read_only = read_only;
1099 online_cb (EGdbusCal *gdbus_cal,
1103 g_return_if_fail (E_IS_CAL (cal));
1105 g_signal_emit (G_OBJECT (cal), e_cal_signals[CAL_SET_MODE],
1106 0, E_CALENDAR_STATUS_OK, is_online ? Remote : Local);
1111 backend_died_cb (EComponentListener *cl,
1112 * gpointer user_data)
1115 ECal *ecal = (ECal *) user_data;
1118 priv->load_state = E_CAL_LOAD_NOT_LOADED;
1119 g_signal_emit (G_OBJECT (ecal), e_cal_signals[BACKEND_DIED], 0);
1123 set_local_attachment_store (ECal *ecal)
1125 gchar *cache_dir = NULL;
1126 GError *error = NULL;
1128 e_gdbus_cal_call_get_backend_property_sync (
1129 ecal->priv->gdbus_cal, CLIENT_BACKEND_PROPERTY_CACHE_DIR, &cache_dir, NULL, &error);
1132 ecal->priv->local_attachment_store = cache_dir;
1134 unwrap_gerror (&error);
1135 g_warning ("%s", error->message);
1136 g_error_free (error);
1142 * @source: An #ESource to be used for the client.
1143 * @type: Type of the client.
1145 * Creates a new calendar client. This does not open the calendar itself,
1146 * for that, #e_cal_open or #e_cal_open_async needs to be called.
1148 * Returns: A newly-created calendar client, or NULL if the client could
1149 * not be constructed because it could not contact the calendar server.
1151 * Deprecated: 3.2: Use e_cal_client_new() instead.
1154 e_cal_new (ESource *source,
1155 ECalSourceType type)
1162 GError *error = NULL;
1163 GDBusConnection *connection;
1165 g_return_val_if_fail (source && E_IS_SOURCE (source), NULL);
1166 g_return_val_if_fail (type < E_CAL_SOURCE_TYPE_LAST, NULL);
1168 if (!e_cal_activate (&error)) {
1169 unwrap_gerror (&error);
1170 g_warning("Cannot activate ECal: %s\n", error ? error->message : "Unknown error");
1172 g_error_free (error);
1176 ecal = g_object_new (E_TYPE_CAL, NULL);
1179 priv->source = g_object_ref (source);
1180 priv->uri = e_source_get_uri (source);
1183 xml = e_source_to_standalone_xml (priv->source);
1184 strv = e_gdbus_cal_factory_encode_get_cal (xml, convert_type (priv->type));
1185 if (!e_gdbus_cal_factory_call_get_cal_sync (G_DBUS_PROXY (cal_factory_proxy), (const gchar * const *) strv, &path, NULL, &error)) {
1188 unwrap_gerror (&error);
1189 g_warning ("Cannot get cal from factory: %s", error ? error->message : "Unknown error");
1191 g_error_free (error);
1192 g_object_unref (ecal);
1198 priv->gdbus_cal = G_DBUS_PROXY (e_gdbus_cal_proxy_new_sync (g_dbus_proxy_get_connection (G_DBUS_PROXY (cal_factory_proxy)),
1199 G_DBUS_PROXY_FLAGS_NONE,
1200 CALENDAR_DBUS_SERVICE_NAME,
1205 if (!priv->gdbus_cal) {
1207 unwrap_gerror (&error);
1208 g_warning ("Cannot create cal proxy: %s", error ? error->message : "Unknown error");
1210 g_error_free (error);
1211 g_object_unref (ecal);
1215 connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (priv->gdbus_cal));
1216 priv->gone_signal_id = g_dbus_connection_signal_subscribe (connection,
1217 "org.freedesktop.DBus", /* sender */
1218 "org.freedesktop.DBus", /* interface */
1219 "NameOwnerChanged", /* member */
1220 "/org/freedesktop/DBus", /* object_path */
1221 CALENDAR_DBUS_SERVICE_NAME, /* arg0 */
1222 G_DBUS_SIGNAL_FLAGS_NONE,
1223 gdbus_cal_connection_gone_cb, ecal, NULL);
1224 g_signal_connect (connection, "closed", G_CALLBACK (gdbus_cal_closed_cb), ecal);
1226 g_signal_connect (priv->gdbus_cal, "auth-required", G_CALLBACK (auth_required_cb), ecal);
1227 g_signal_connect (priv->gdbus_cal, "backend-error", G_CALLBACK (backend_error_cb), ecal);
1228 g_signal_connect (priv->gdbus_cal, "readonly", G_CALLBACK (readonly_cb), ecal);
1229 g_signal_connect (priv->gdbus_cal, "online", G_CALLBACK (online_cb), ecal);
1230 g_signal_connect (priv->gdbus_cal, "free-busy-data", G_CALLBACK (free_busy_data_cb), ecal);
1232 /* Set the local attachment store path for the calendar */
1233 set_local_attachment_store (ecal);
1240 /* for each known source calls check_func, which should return TRUE if the required
1241 * source have been found. Function returns NULL or the source on which was returned
1242 * TRUE by the check_func. Non-NULL pointer should be unreffed by g_object_unref.
1244 * 'sources' is an output parameter and cannot be NULL. When returned non-NULL, then
1245 * should be freed with g_object_unref function. */
1247 search_known_sources (ECalSourceType type,
1248 gboolean (*check_func) (ESource *source,
1249 gpointer user_data),
1251 ESourceList **sources,
1254 ESource *res = NULL;
1258 g_return_val_if_fail (sources != NULL, NULL);
1259 g_return_val_if_fail (check_func != NULL, NULL);
1263 if (!e_cal_get_sources (sources, type, &err)) {
1264 g_propagate_error (error, err);
1268 for (g = e_source_list_peek_groups (*sources); g; g = g->next) {
1269 ESourceGroup *group = E_SOURCE_GROUP (g->data);
1272 for (s = e_source_group_peek_sources (group); s; s = s->next) {
1273 ESource *source = E_SOURCE (s->data);
1275 if (check_func (source, user_data)) {
1276 res = g_object_ref (source);
1289 check_uri (ESource *source,
1294 g_return_val_if_fail (source != NULL, FALSE);
1295 g_return_val_if_fail (uri != NULL, FALSE);
1297 suri = e_source_peek_absolute_uri (source);
1299 return !g_ascii_strcasecmp (suri, uri);
1304 suri2 = e_source_get_uri (source);
1305 ret = !g_ascii_strcasecmp (suri2, uri);
1312 * e_cal_new_from_uri:
1313 * @uri: The URI pointing to the calendar to open.
1314 * @type: Type of the client.
1316 * Creates a new calendar client. This does not open the calendar itself,
1317 * for that, #e_cal_open or #e_cal_open_async needs to be called.
1319 * Returns: A newly-created calendar client, or NULL if the client could
1320 * not be constructed because it could not contact the calendar server.
1322 * Deprecated: 3.2: Use e_cal_client_new_from_uri() instead.
1325 e_cal_new_from_uri (const gchar *uri,
1326 ECalSourceType type)
1328 ESourceList *sources = NULL;
1332 source = search_known_sources (type, check_uri, (gpointer) uri, &sources, NULL);
1334 source = e_source_new_with_absolute_uri ("", uri);
1336 cal = e_cal_new (source, type);
1338 g_object_unref (source);
1340 g_object_unref (sources);
1346 get_local_source (ECalSourceType type)
1348 ESourceList *sources;
1349 ESourceGroup *on_this_computer;
1350 GSList *local_sources, *iter;
1351 gchar *source_uri = NULL;
1354 if (!e_cal_get_sources (&sources, type, NULL)) {
1355 g_warning ("Could not get task sources from GConf!");
1359 on_this_computer = e_source_list_ensure_group (sources,
1360 _("On This Computer"),
1362 if (!on_this_computer) {
1363 g_object_unref (sources);
1367 local_sources = e_source_group_peek_sources (on_this_computer);
1368 for (iter = local_sources; !source_uri && iter != NULL; iter = iter->next) {
1369 ESource *source = iter->data;
1372 uri = e_source_get_uri (source);
1373 if (g_strcmp0 (uri, "local:system") == 0)
1380 source = e_source_new (_("Personal"), "system");
1381 e_source_set_color_spec (source, "#BECEDD");
1382 e_source_group_add_source (on_this_computer, source, -1);
1383 g_object_unref (source);
1385 if (!e_source_list_sync (sources, NULL))
1386 g_warning ("Cannot add system source to GConf!");
1388 g_object_unref (on_this_computer);
1389 g_object_unref (sources);
1391 ecal = e_cal_new_from_uri (source_uri?:"local:system", type);
1392 g_free (source_uri);
1396 * e_cal_new_system_calendar:
1398 * Create a calendar client for the system calendar, which should always be
1399 * present in all Evolution installations. This does not open the calendar
1400 * itself -- for that use e_cal_open() or e_cal_open_async().
1402 * Returns: A newly-created calendar client, or %NULL if the client could
1403 * not be constructed.
1405 * Deprecated: 3.2: Use e_cal_client_new_system() instead.
1408 e_cal_new_system_calendar (void)
1410 return get_local_source (E_CAL_SOURCE_TYPE_EVENT);
1414 * e_cal_new_system_tasks:
1416 * Create a calendar client for the system task list, which should always
1417 * be present in all Evolution installations. This does not open the task
1418 * list itself -- for that use e_cal_open() or e_cal_open_async().
1420 * Returns: A newly-created calendar client, or %NULL if the client could
1421 * not be constructed.
1423 * Deprecated: 3.2: Use e_cal_client_new_system() instead.
1426 e_cal_new_system_tasks (void)
1428 return get_local_source (E_CAL_SOURCE_TYPE_TODO);
1432 * e_cal_new_system_memos:
1434 * Create a calendar client for the system memo list, which should always
1435 * be present in all Evolution installations. This does not open the memo
1436 * list itself -- for that use e_cal_open() or e_cal_open_async().
1438 * Returns: A newly-created calendar client, or %NULL if the client could
1439 * not be constructed.
1441 * Deprecated: 3.2: Use e_cal_client_new_system() instead.
1444 e_cal_new_system_memos (void)
1446 return get_local_source (E_CAL_SOURCE_TYPE_JOURNAL);
1450 * e_cal_set_auth_func
1451 * @ecal: A calendar client.
1452 * @func: The authentication function
1453 * @data: User data to be used when calling the authentication function
1455 * Sets the given authentication function on the calendar client. This
1456 * function will be called any time the calendar server needs a
1457 * password for an operation associated with the calendar and should
1458 * be supplied before any calendar is opened.
1460 * When a calendar is opened asynchronously, the open function is
1461 * processed in a concurrent thread. This means that the
1462 * authentication function will also be called from this thread. As
1463 * such, the authentication callback cannot directly call any
1464 * functions that must be called from the main thread. For example
1465 * any Gtk+ related functions, which must be proxied synchronously to
1466 * the main thread by the callback.
1468 * The authentication function has the following signature
1470 * gchar * auth_func (ECal *ecal,
1471 * const gchar *prompt,
1473 * gpointer user_data)
1475 * Deprecated: 3.2: Use EClient::authenticate() signal on an #ECalClient instead.
1478 e_cal_set_auth_func (ECal *ecal,
1482 g_return_if_fail (ecal != NULL);
1483 g_return_if_fail (E_IS_CAL (ecal));
1485 ecal->priv->auth_func = func;
1486 ecal->priv->auth_user_data = data;
1490 async_open_report_result (ECal *ecal,
1491 const GError *error)
1493 ECalendarStatus status;
1495 g_return_if_fail (ecal && E_IS_CAL (ecal));
1498 ecal->priv->load_state = E_CAL_LOAD_LOADED;
1501 status = get_status_from_error (error);
1503 status = E_CALENDAR_STATUS_OK;
1506 g_signal_emit (G_OBJECT (ecal), e_cal_signals[CAL_OPENED], 0, status);
1507 g_signal_emit (G_OBJECT (ecal), e_cal_signals[CAL_OPENED_EX], 0, error);
1511 reschedule_authenticate_cb (gpointer user_data)
1513 GError *error = NULL;
1514 ECal *ecal = user_data;
1516 g_return_val_if_fail (ecal && E_IS_CAL (ecal), FALSE);
1518 if (g_main_depth () > 1)
1521 if (call_authenticate_user (ecal, TRUE, &error))
1524 unwrap_gerror (&error);
1525 async_open_report_result (ecal, error);
1528 g_error_free (error);
1534 async_open_ready_cb (GDBusProxy *gdbus_cal,
1538 GError *error = NULL;
1540 g_return_if_fail (ecal && E_IS_CAL (ecal));
1542 if (e_gdbus_cal_call_open_finish (gdbus_cal, res, &error)) {
1543 if (g_main_depth () > 1) {
1544 g_idle_add (reschedule_authenticate_cb, ecal);
1546 } else if (call_authenticate_user (ecal, TRUE, &error))
1550 unwrap_gerror (&error);
1552 async_open_report_result (ecal, error);
1555 g_error_free (error);
1559 open_calendar (ECal *ecal,
1560 gboolean only_if_exists,
1562 ECalendarStatus *status,
1563 gboolean needs_auth,
1568 g_return_val_if_fail (error != NULL, FALSE);
1570 e_return_error_if_fail (ecal != NULL, E_CALENDAR_STATUS_INVALID_ARG);
1571 e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
1573 e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
1575 if (!needs_auth && priv->load_state == E_CAL_LOAD_LOADED) {
1579 priv->load_state = E_CAL_LOAD_LOADING;
1581 if ((priv->mode != CAL_MODE_LOCAL) && e_source_get_property (priv->source, "auth")) {
1582 priv->load_state = E_CAL_LOAD_AUTHENTICATING;
1584 if (priv->auth_func == NULL) {
1585 priv->load_state = E_CAL_LOAD_NOT_LOADED;
1586 *status = E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED;
1587 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED, error);
1590 if (!e_source_get_property (priv->source, "username")) {
1591 priv->load_state = E_CAL_LOAD_NOT_LOADED;
1592 *status = E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED;
1593 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED, error);
1599 *status = E_CALENDAR_STATUS_OK;
1601 if (!e_gdbus_cal_call_open_sync (priv->gdbus_cal, only_if_exists, NULL, error)) {
1602 *status = E_CALENDAR_STATUS_DBUS_EXCEPTION;
1603 } else if (needs_auth && !call_authenticate_user (ecal, FALSE, error)) {
1604 *status = error && *error ? (*error)->code : E_CALENDAR_STATUS_AUTHENTICATION_FAILED;
1607 priv->load_state = E_CAL_LOAD_LOADED;
1609 e_gdbus_cal_call_open (priv->gdbus_cal, only_if_exists, NULL, (GAsyncReadyCallback) async_open_ready_cb, ecal);
1613 unwrap_gerror (error);
1614 priv->load_state = E_CAL_LOAD_NOT_LOADED;
1617 return *error == NULL;
1622 * @ecal: A calendar client.
1623 * @only_if_exists: FALSE if the calendar should be opened even if there
1624 * was no storage for it, i.e. to create a new calendar or load an existing
1625 * one if it already exists. TRUE if it should only try to load calendars
1626 * that already exist.
1627 * @error: Placeholder for error information.
1629 * Makes a calendar client initiate a request to open a calendar. The calendar
1630 * client will emit the "cal_opened" signal when the response from the server is
1631 * received. Since 3.0 is emitted also "cal_opened_ex" signal, which contains
1632 * a GError pointer from the open operation (NULL when no error occurred).
1633 * New signal deprecates the old "cal_opened" signal.
1635 * Returns: TRUE on success, FALSE on failure to issue the open request.
1637 * Deprecated: 3.2: Use e_client_open_sync() on an #ECalClient object instead.
1640 e_cal_open (ECal *ecal,
1641 gboolean only_if_exists,
1644 ECalendarStatus status;
1648 result = open_calendar (ecal, only_if_exists, &err, &status, FALSE, FALSE);
1649 g_signal_emit (G_OBJECT (ecal), e_cal_signals[CAL_OPENED], 0, status);
1650 g_signal_emit (G_OBJECT (ecal), e_cal_signals[CAL_OPENED_EX], 0, err);
1653 g_propagate_error (error, err);
1658 struct idle_async_error_reply_data
1660 ECal *ecal; /* ref-ed */
1661 GError *error; /* can be NULL */
1665 idle_async_error_reply_cb (gpointer user_data)
1667 struct idle_async_error_reply_data *data = user_data;
1669 g_return_val_if_fail (data != NULL, FALSE);
1670 g_return_val_if_fail (data->ecal != NULL, FALSE);
1672 async_open_report_result (data->ecal, data->error);
1674 g_object_unref (data->ecal);
1676 g_error_free (data->error);
1682 /* takes ownership of error */
1684 async_report_idle (ECal *ecal,
1687 struct idle_async_error_reply_data *data;
1689 g_return_if_fail (ecal != NULL);
1691 data = g_new0 (struct idle_async_error_reply_data, 1);
1692 data->ecal = g_object_ref (ecal);
1693 data->error = error;
1695 g_idle_add (idle_async_error_reply_cb, data);
1700 * @ecal: A calendar client.
1701 * @only_if_exists: If TRUE, then only open the calendar if it already
1702 * exists. If FALSE, then create a new calendar if it doesn't already
1705 * Open the calendar asynchronously. The calendar will emit the
1706 * "cal_opened" signal when the operation has completed.
1707 * Since 3.0 is emitted also "cal_opened_ex" signal, which contains
1708 * a GError pointer from the open operation (NULL when no error occurred).
1709 * New signal deprecates the old "cal_opened" signal.
1711 * Because this operation runs in another thread, any authentication
1712 * callback set on the calendar will be called from this other thread.
1713 * See #e_cal_set_auth_func() for details.
1715 * Deprecated: 3.2: Use e_client_open()/e_client_open_finish()
1716 * on an #ECalClient object instead.
1719 e_cal_open_async (ECal *ecal,
1720 gboolean only_if_exists)
1723 GError *error = NULL;
1724 ECalendarStatus status;
1726 g_return_if_fail (ecal != NULL);
1727 g_return_if_fail (E_IS_CAL (ecal));
1731 switch (priv->load_state) {
1732 case E_CAL_LOAD_AUTHENTICATING :
1733 case E_CAL_LOAD_LOADING :
1734 async_report_idle (ecal, g_error_new_literal (E_CALENDAR_ERROR, E_CALENDAR_STATUS_BUSY, e_cal_get_error_message (E_CALENDAR_STATUS_BUSY)));
1736 case E_CAL_LOAD_LOADED :
1737 async_report_idle (ecal, NULL /* success */);
1740 /* ignore everything else */
1744 open_calendar (ecal, only_if_exists, &error, &status, FALSE, TRUE);
1747 async_report_idle (ecal, error);
1752 * @ecal: A calendar client.
1753 * @error: Placeholder for error information.
1755 * Invokes refresh on a calendar. See @e_cal_get_refresh_supported.
1757 * Returns: TRUE if calendar supports refresh and it was invoked, FALSE otherwise.
1761 * Deprecated: 3.2: Use e_cal_client_refresh_sync() instead.
1764 e_cal_refresh (ECal *ecal,
1769 e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
1771 e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
1773 if (!e_gdbus_cal_call_refresh_sync (priv->gdbus_cal, NULL, error)) {
1774 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
1782 * @ecal: A calendar client.
1783 * @error: Placeholder for error information.
1785 * Removes a calendar.
1787 * Returns: TRUE if the calendar was removed, FALSE if there was an error.
1789 * Deprecated: 3.2: Use e_client_remove_sync() on an #ECalClient object instead.
1792 e_cal_remove (ECal *ecal,
1797 e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
1799 e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
1801 if (!e_gdbus_cal_call_remove_sync (priv->gdbus_cal, NULL, error)) {
1802 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
1809 /* Builds an URI list out of a CORBA string sequence */
1811 build_uri_list (GNOME_Evolution_Calendar_StringSeq *seq)
1816 for (i = 0; i < seq->_length; i++)
1817 uris = g_list_prepend (uris, g_strdup (seq->_buffer[i]));
1825 * @ecal: A calendar client.
1826 * @mode: Mode of the URIs to get.
1828 * Retrieves a list of all calendar clients for the given mode.
1830 * Returns: list of uris.
1832 * Deprecated: 3.2: This function has been dropped completely.
1835 e_cal_uri_list (ECal *ecal,
1840 GNOME_Evolution_Calendar_StringSeq *uri_seq;
1842 CORBA_Environment ev;
1845 g_return_val_if_fail (ecal != NULL, NULL);
1846 g_return_val_if_fail (E_IS_CAL (ecal), NULL);
1850 for (f = priv->factories; f; f = f->next) {
1851 CORBA_exception_init (&ev);
1852 uri_seq = GNOME_Evolution_Calendar_CalFactory_uriList (f->data, mode, &ev);
1854 if (BONOBO_EX (&ev)) {
1855 g_message ("e_cal_uri_list(): request failed");
1857 /* free memory and return */
1858 g_list_foreach (uris, (GFunc) g_free, NULL);
1864 uris = g_list_concat (uris, build_uri_list (uri_seq));
1865 CORBA_free (uri_seq);
1868 CORBA_exception_free (&ev);
1878 * e_cal_get_source_type:
1879 * @ecal: A calendar client.
1881 * Gets the type of the calendar client.
1883 * Returns: an #ECalSourceType value corresponding to the type
1884 * of the calendar client.
1886 * Deprecated: 3.2: Use e_cal_client_get_source_type() instead.
1889 e_cal_get_source_type (ECal *ecal)
1893 g_return_val_if_fail (ecal != NULL, E_CAL_SOURCE_TYPE_LAST);
1894 g_return_val_if_fail (E_IS_CAL (ecal), E_CAL_SOURCE_TYPE_LAST);
1902 * e_cal_get_load_state:
1903 * @ecal: A calendar client.
1905 * Queries the state of loading of a calendar client.
1907 * Returns: A #ECalLoadState value indicating whether the client has
1908 * not been loaded with #e_cal_open yet, whether it is being
1909 * loaded, or whether it is already loaded.
1911 * Deprecated: 3.2: Use e_client_is_opened() on an #ECalClient instead.
1914 e_cal_get_load_state (ECal *ecal)
1918 g_return_val_if_fail (ecal != NULL, E_CAL_LOAD_NOT_LOADED);
1919 g_return_val_if_fail (E_IS_CAL (ecal), E_CAL_LOAD_NOT_LOADED);
1922 return priv->load_state;
1927 * @ecal: A calendar client.
1929 * Queries the source that is open in a calendar client.
1931 * Returns: The source of the calendar that is already loaded or is being
1932 * loaded, or NULL if the ecal has not started a load request yet.
1934 * Deprecated: 3.2: Use e_client_get_source() on an #ECalClient object instead.
1937 e_cal_get_source (ECal *ecal)
1941 g_return_val_if_fail (ecal != NULL, NULL);
1942 g_return_val_if_fail (E_IS_CAL (ecal), NULL);
1945 return priv->source;
1950 * @ecal: A calendar client.
1952 * Queries the URI that is open in a calendar client.
1954 * Returns: The URI of the calendar that is already loaded or is being
1955 * loaded, or NULL if the client has not started a load request yet.
1957 * Deprecated: 3.2: Use e_client_get_uri() on an #ECalClient object instead.
1960 e_cal_get_uri (ECal *ecal)
1964 g_return_val_if_fail (ecal != NULL, NULL);
1965 g_return_val_if_fail (E_IS_CAL (ecal), NULL);
1972 * e_cal_get_local_attachment_store
1973 * @ecal: A calendar client.
1975 * Queries the URL where the calendar attachments are
1976 * serialized in the local filesystem. This enable clients
1977 * to operate with the reference to attachments rather than the data itself
1978 * unless it specifically uses the attachments for open/sending
1981 * Returns: The URL where the attachments are serialized in the
1984 * Deprecated: 3.2: Use e_cal_client_get_local_attachment_store() instead.
1987 e_cal_get_local_attachment_store (ECal *ecal)
1991 g_return_val_if_fail (ecal != NULL, NULL);
1992 g_return_val_if_fail (E_IS_CAL (ecal), NULL);
1995 return (const gchar *) priv->local_attachment_store;
1999 * e_cal_is_read_only:
2000 * @ecal: A calendar client.
2001 * @read_only: Return value for read only status.
2002 * @error: Placeholder for error information.
2004 * Queries whether the calendar client can perform modifications
2005 * on the calendar or not. Whether the backend is read only or not
2006 * is specified, on exit, in the @read_only argument.
2008 * Returns: TRUE if the call was successful, FALSE if there was an error.
2010 * Deprecated: 3.2: Use e_cal_client_is_readonly() on an #ECalClient object instead.
2013 e_cal_is_read_only (ECal *ecal,
2014 gboolean *read_only,
2019 if (!(ecal && E_IS_CAL (ecal)))
2020 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_INVALID_ARG, error);
2023 *read_only = priv->read_only;
2029 * e_cal_get_cal_address:
2030 * @ecal: A calendar client.
2031 * @cal_address: Return value for address information.
2032 * @error: Placeholder for error information.
2034 * Queries the calendar address associated with a calendar client.
2036 * Returns: TRUE if the operation was successful, FALSE if there
2039 * Deprecated: 3.2: Use e_client_get_backend_property_sync()
2040 * with #CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS instead.
2043 e_cal_get_cal_address (ECal *ecal,
2044 gchar **cal_address,
2049 e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
2050 e_return_error_if_fail (cal_address != NULL, E_CALENDAR_STATUS_INVALID_ARG);
2052 e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
2053 *cal_address = NULL;
2056 if (priv->cal_address == NULL) {
2057 e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
2058 if (priv->load_state != E_CAL_LOAD_LOADED) {
2060 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
2063 if (!e_gdbus_cal_call_get_backend_property_sync (priv->gdbus_cal, CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS, &priv->cal_address, NULL, error)) {
2065 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
2069 *cal_address = g_strdup (priv->cal_address);
2076 * e_cal_get_alarm_email_address:
2077 * @ecal: A calendar client.
2078 * @alarm_address: Return value for alarm address.
2079 * @error: Placeholder for error information.
2081 * Queries the address to be used for alarms in a calendar client.
2083 * Returns: TRUE if the operation was successful, FALSE if there was
2084 * an error while contacting the backend.
2086 * Deprecated: 3.2: Use e_client_get_backend_property_sync()
2087 * with #CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS instead.
2090 e_cal_get_alarm_email_address (ECal *ecal,
2091 gchar **alarm_address,
2096 e_return_error_if_fail (alarm_address != NULL, E_CALENDAR_STATUS_INVALID_ARG);
2097 e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
2099 e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
2100 *alarm_address = NULL;
2102 if (priv->load_state != E_CAL_LOAD_LOADED) {
2103 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
2106 if (!e_gdbus_cal_call_get_backend_property_sync (priv->gdbus_cal, CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS, alarm_address, NULL, error)) {
2107 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
2114 * e_cal_get_ldap_attribute:
2115 * @ecal: A calendar client.
2116 * @ldap_attribute: Return value for the LDAP attribute.
2117 * @error: Placeholder for error information.
2119 * Queries the LDAP attribute for a calendar client.
2121 * Returns: TRUE if the call was successful, FALSE if there was an
2122 * error contacting the backend.
2124 * Deprecated: 3.2: This function has been dropped completely.
2127 e_cal_get_ldap_attribute (ECal *ecal,
2128 gchar **ldap_attribute,
2133 e_return_error_if_fail (ldap_attribute != NULL, E_CALENDAR_STATUS_INVALID_ARG);
2134 e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
2136 e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
2137 *ldap_attribute = NULL;
2139 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_NOT_SUPPORTED, error);
2143 load_capabilities (ECal *ecal,
2149 e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
2151 if (priv->load_state != E_CAL_LOAD_LOADED) {
2152 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
2157 if (priv->capabilities) {
2159 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
2162 if (!e_gdbus_cal_call_get_backend_property_sync (priv->gdbus_cal, CLIENT_BACKEND_PROPERTY_CAPABILITIES, &priv->capabilities, NULL, error)) {
2164 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
2173 check_capability (ECal *ecal,
2180 /* FIXME Check result */
2181 load_capabilities (ecal, NULL);
2182 if (priv->capabilities && strstr (priv->capabilities, cap))
2189 * e_cal_get_one_alarm_only:
2190 * @ecal: A calendar client.
2192 * Checks if a calendar supports only one alarm per component.
2194 * Returns: TRUE if the calendar allows only one alarm, FALSE otherwise.
2196 * Deprecated: 3.2: Use e_cal_client_check_one_alarm_only() instead.
2199 e_cal_get_one_alarm_only (ECal *ecal)
2201 g_return_val_if_fail (ecal != NULL, FALSE);
2202 g_return_val_if_fail (ecal && E_IS_CAL (ecal), FALSE);
2204 return check_capability (ecal, CAL_STATIC_CAPABILITY_ONE_ALARM_ONLY);
2208 * e_cal_get_organizer_must_attend:
2209 * @ecal: A calendar client.
2211 * Checks if a calendar forces organizers of meetings to be also attendees.
2213 * Returns: TRUE if the calendar forces organizers to attend meetings,
2216 * Deprecated: 3.2: Use e_cal_client_check_organizer_must_attend() instead.
2219 e_cal_get_organizer_must_attend (ECal *ecal)
2221 g_return_val_if_fail (ecal != NULL, FALSE);
2222 g_return_val_if_fail (E_IS_CAL (ecal), FALSE);
2224 return check_capability (ecal, CAL_STATIC_CAPABILITY_ORGANIZER_MUST_ATTEND);
2228 * e_cal_get_recurrences_no_master:
2229 * @ecal: A calendar client.
2231 * Checks if the calendar has a master object for recurrences.
2233 * Returns: TRUE if the calendar has a master object for recurrences,
2236 * Deprecated: 3.2: Use e_cal_client_check_recurrences_no_master() instead.
2239 e_cal_get_recurrences_no_master (ECal *ecal)
2241 g_return_val_if_fail (ecal != NULL, FALSE);
2242 g_return_val_if_fail (E_IS_CAL (ecal), FALSE);
2244 return check_capability (ecal, CAL_STATIC_CAPABILITY_RECURRENCES_NO_MASTER);
2248 * e_cal_get_static_capability:
2249 * @ecal: A calendar client.
2250 * @cap: Name of the static capability to check.
2252 * Queries the calendar for static capabilities.
2254 * Returns: TRUE if the capability is supported, FALSE otherwise.
2256 * Deprecated: 3.2: Use e_client_check_capability() on an #ECalClient object instead.
2259 e_cal_get_static_capability (ECal *ecal,
2262 g_return_val_if_fail (ecal != NULL, FALSE);
2263 g_return_val_if_fail (E_IS_CAL (ecal), FALSE);
2265 return check_capability (ecal, cap);
2269 * e_cal_get_save_schedules:
2270 * @ecal: A calendar client.
2272 * Checks whether the calendar saves schedules.
2274 * Returns: TRUE if it saves schedules, FALSE otherwise.
2276 * Deprecated: 3.2: Use e_cal_client_check_save_schedules() instead.
2279 e_cal_get_save_schedules (ECal *ecal)
2281 g_return_val_if_fail (ecal != NULL, FALSE);
2282 g_return_val_if_fail (E_IS_CAL (ecal), FALSE);
2284 return check_capability (ecal, CAL_STATIC_CAPABILITY_SAVE_SCHEDULES);
2288 * e_cal_get_organizer_must_accept:
2289 * @ecal: A calendar client.
2291 * Checks whether a calendar requires organizer to accept their attendance to
2294 * Returns: TRUE if the calendar requires organizers to accept, FALSE
2297 * Deprecated: 3.2: Use e_cal_client_check_organizer_must_accept() instead.
2300 e_cal_get_organizer_must_accept (ECal *ecal)
2302 g_return_val_if_fail (ecal != NULL, FALSE);
2303 g_return_val_if_fail (E_IS_CAL (ecal), FALSE);
2305 return check_capability (ecal, CAL_STATIC_CAPABILITY_ORGANIZER_MUST_ACCEPT);
2309 * e_cal_get_refresh_supported:
2310 * @ecal: A calendar client.
2312 * Checks whether a calendar supports explicit refreshing (see @e_cal_refresh).
2314 * Returns: TRUE if the calendar supports refreshing, FALSE otherwise.
2318 * Deprecated: 3.2: Use e_client_check_refresh_supported() instead.
2321 e_cal_get_refresh_supported (ECal *ecal)
2323 g_return_val_if_fail (ecal != NULL, FALSE);
2324 g_return_val_if_fail (E_IS_CAL (ecal), FALSE);
2326 return check_capability (ecal, CAL_STATIC_CAPABILITY_REFRESH_SUPPORTED);
2331 * @ecal: A calendar client.
2332 * @mode: Mode to switch to.
2334 * Switches online/offline mode on the calendar.
2336 * Returns: TRUE if the switch was successful, FALSE if there was an error.
2338 * Deprecated: 3.2: This function has been dropped completely.
2341 e_cal_set_mode (ECal *ecal,
2346 g_return_val_if_fail (ecal != NULL, FALSE);
2347 g_return_val_if_fail (E_IS_CAL (ecal), FALSE);
2348 g_return_val_if_fail (mode & CAL_MODE_ANY, FALSE);
2351 g_return_val_if_fail (priv->gdbus_cal, FALSE);
2352 g_return_val_if_fail (priv->load_state == E_CAL_LOAD_LOADED, FALSE);
2354 g_debug ("%s: This function is not supported since 3.2", G_STRFUNC);
2359 /* This is used in the callback which fetches all the timezones needed for an
2361 typedef struct _ECalGetTimezonesData ECalGetTimezonesData;
2362 struct _ECalGetTimezonesData {
2365 /* This starts out at E_CALENDAR_STATUS_OK. If an error occurs this
2366 * contains the last error. */
2367 ECalendarStatus status;
2371 * e_cal_get_default_object:
2372 * @ecal: A calendar client.
2373 * @icalcomp: Return value for the default object.
2374 * @error: Placeholder for error information.
2376 * Retrives an #icalcomponent from the backend that contains the default
2377 * values for properties needed.
2379 * Returns: TRUE if the call was successful, FALSE otherwise.
2381 * Deprecated: 3.2: Use e_cal_client_get_default_object_sync() instead.
2384 e_cal_get_default_object (ECal *ecal,
2385 icalcomponent **icalcomp,
2389 ECalendarStatus status;
2390 gchar *object = NULL;
2392 e_return_error_if_fail (icalcomp != NULL, E_CALENDAR_STATUS_INVALID_ARG);
2393 e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
2395 e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
2398 if (priv->load_state != E_CAL_LOAD_LOADED) {
2399 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
2402 if (!e_gdbus_cal_call_get_backend_property_sync (priv->gdbus_cal, CAL_BACKEND_PROPERTY_DEFAULT_OBJECT, &object, NULL, error)) {
2403 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
2407 *icalcomp = icalparser_parse_string (object);
2411 status = E_CALENDAR_STATUS_INVALID_OBJECT;
2413 status = E_CALENDAR_STATUS_OK;
2415 E_CALENDAR_CHECK_STATUS (status, error);
2417 status = E_CALENDAR_STATUS_OTHER_ERROR;
2419 E_CALENDAR_CHECK_STATUS (status, error);
2423 * e_cal_get_attachments_for_comp:
2424 * @ecal: A calendar client.
2425 * @uid: Unique identifier for a calendar component.
2426 * @rid: Recurrence identifier.
2427 * @list: Return the list of attachment uris.
2428 * @error: Placeholder for error information.
2430 * Queries a calendar for a calendar component object based on its unique
2431 * identifier and gets the attachments for the component.
2433 * Returns: TRUE if the call was successful, FALSE otherwise.
2435 * Deprecated: 3.2: Use e_cal_client_get_attachment_uris_sync() instead.
2438 e_cal_get_attachments_for_comp (ECal *ecal,
2445 ECalendarStatus status;
2449 e_return_error_if_fail (uid != NULL, E_CALENDAR_STATUS_INVALID_ARG);
2450 e_return_error_if_fail (list != NULL, E_CALENDAR_STATUS_INVALID_ARG);
2451 e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
2453 e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
2456 if (priv->load_state != E_CAL_LOAD_LOADED) {
2457 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
2460 strv = e_gdbus_cal_encode_get_attachment_uris (uid, rid);
2461 if (!e_gdbus_cal_call_get_attachment_uris_sync (priv->gdbus_cal, (const gchar * const *) strv, &list_array, NULL, error)) {
2464 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
2471 for (string = list_array; *string; string++) {
2472 *list = g_slist_append (*list, g_strdup (*string));
2474 g_strfreev (list_array);
2475 status = E_CALENDAR_STATUS_OK;
2477 status = E_CALENDAR_STATUS_OTHER_ERROR;
2479 E_CALENDAR_CHECK_STATUS (status, error);
2484 * @ecal: A calendar client.
2485 * @uid: Unique identifier for a calendar component.
2486 * @rid: Recurrence identifier.
2487 * @icalcomp: Return value for the calendar component object.
2488 * @error: Placeholder for error information.
2490 * Queries a calendar for a calendar component object based on its unique
2493 * Returns: TRUE if the call was successful, FALSE otherwise.
2495 * Deprecated: 3.2: Use e_cal_client_get_object_sync() instead.
2498 e_cal_get_object (ECal *ecal,
2501 icalcomponent **icalcomp,
2505 ECalendarStatus status;
2506 gchar *object = NULL, **strv;
2507 icalcomponent *tmp_icalcomp;
2508 icalcomponent_kind kind;
2510 e_return_error_if_fail (uid != NULL, E_CALENDAR_STATUS_INVALID_ARG);
2511 e_return_error_if_fail (icalcomp != NULL, E_CALENDAR_STATUS_INVALID_ARG);
2512 e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
2514 e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
2517 if (priv->load_state != E_CAL_LOAD_LOADED) {
2518 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
2521 strv = e_gdbus_cal_encode_get_object (uid, rid);
2522 if (!e_gdbus_cal_call_get_object_sync (priv->gdbus_cal, (const gchar * const *) strv, &object, NULL, error)) {
2525 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
2530 status = E_CALENDAR_STATUS_OK;
2531 tmp_icalcomp = icalparser_parse_string (object);
2532 if (!tmp_icalcomp) {
2533 status = E_CALENDAR_STATUS_INVALID_OBJECT;
2536 kind = icalcomponent_isa (tmp_icalcomp);
2537 if ((kind == ICAL_VEVENT_COMPONENT && priv->type == E_CAL_SOURCE_TYPE_EVENT) ||
2538 (kind == ICAL_VTODO_COMPONENT && priv->type == E_CAL_SOURCE_TYPE_TODO) ||
2539 (kind == ICAL_VJOURNAL_COMPONENT && priv->type == E_CAL_SOURCE_TYPE_JOURNAL)) {
2540 *icalcomp = icalcomponent_new_clone (tmp_icalcomp);
2541 } else if (kind == ICAL_VCALENDAR_COMPONENT) {
2542 icalcomponent *subcomp = NULL;
2544 switch (priv->type) {
2545 case E_CAL_SOURCE_TYPE_EVENT :
2546 subcomp = icalcomponent_get_first_component (tmp_icalcomp, ICAL_VEVENT_COMPONENT);
2548 case E_CAL_SOURCE_TYPE_TODO :
2549 subcomp = icalcomponent_get_first_component (tmp_icalcomp, ICAL_VTODO_COMPONENT);
2551 case E_CAL_SOURCE_TYPE_JOURNAL :
2552 subcomp = icalcomponent_get_first_component (tmp_icalcomp, ICAL_VJOURNAL_COMPONENT);
2555 /* ignore everything else */
2559 /* we are only interested in the first component */
2561 *icalcomp = icalcomponent_new_clone (subcomp);
2564 icalcomponent_free (tmp_icalcomp);
2569 E_CALENDAR_CHECK_STATUS (status, error);
2573 * e_cal_get_objects_for_uid:
2574 * @ecal: A calendar client.
2575 * @uid: Unique identifier for a calendar component.
2576 * @objects: Return value for the list of objects obtained from the backend.
2577 * @error: Placeholder for error information.
2579 * Queries a calendar for all calendar components with the given unique
2580 * ID. This will return any recurring event and all its detached recurrences.
2581 * For non-recurring events, it will just return the object with that ID.
2583 * Returns: TRUE if the call was successful, FALSE otherwise.
2585 * Deprecated: 3.2: Use e_cal_client_get_objects_for_uid_sync() instead.
2588 e_cal_get_objects_for_uid (ECal *ecal,
2594 ECalendarStatus status;
2595 gchar *object = NULL, **strv;
2597 e_return_error_if_fail (uid != NULL, E_CALENDAR_STATUS_INVALID_ARG);
2598 e_return_error_if_fail (objects != NULL, E_CALENDAR_STATUS_INVALID_ARG);
2599 e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
2601 e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
2604 if (priv->load_state != E_CAL_LOAD_LOADED) {
2605 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
2608 strv = e_gdbus_cal_encode_get_object (uid, "");
2609 if (!e_gdbus_cal_call_get_object_sync (priv->gdbus_cal, (const gchar * const *) strv, &object, NULL, error)) {
2612 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
2617 status = E_CALENDAR_STATUS_OK;
2619 icalcomponent *icalcomp;
2620 icalcomponent_kind kind;
2622 icalcomp = icalparser_parse_string (object);
2624 status = E_CALENDAR_STATUS_INVALID_OBJECT;
2627 ECalComponent *comp;
2629 kind = icalcomponent_isa (icalcomp);
2630 if ((kind == ICAL_VEVENT_COMPONENT && priv->type == E_CAL_SOURCE_TYPE_EVENT) ||
2631 (kind == ICAL_VTODO_COMPONENT && priv->type == E_CAL_SOURCE_TYPE_TODO) ||
2632 (kind == ICAL_VJOURNAL_COMPONENT && priv->type == E_CAL_SOURCE_TYPE_JOURNAL)) {
2633 comp = e_cal_component_new ();
2634 e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (icalcomp));
2635 *objects = g_list_append (NULL, comp);
2636 } else if (kind == ICAL_VCALENDAR_COMPONENT) {
2637 icalcomponent *subcomp;
2638 icalcomponent_kind kind_to_find;
2640 switch (priv->type) {
2641 case E_CAL_SOURCE_TYPE_TODO :
2642 kind_to_find = ICAL_VTODO_COMPONENT;
2644 case E_CAL_SOURCE_TYPE_JOURNAL :
2645 kind_to_find = ICAL_VJOURNAL_COMPONENT;
2647 case E_CAL_SOURCE_TYPE_EVENT :
2649 kind_to_find = ICAL_VEVENT_COMPONENT;
2654 subcomp = icalcomponent_get_first_component (icalcomp, kind_to_find);
2656 comp = e_cal_component_new ();
2657 e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (subcomp));
2658 *objects = g_list_append (*objects, comp);
2659 subcomp = icalcomponent_get_next_component (icalcomp, kind_to_find);
2663 icalcomponent_free (icalcomp);
2668 E_CALENDAR_CHECK_STATUS (status, error);
2672 * e_cal_resolve_tzid_cb:
2673 * @tzid: ID of the timezone to resolve.
2674 * @data: Closure data for the callback.
2676 * Resolves TZIDs for the recurrence generator.
2678 * Returns: The timezone identified by the @tzid argument, or %NULL if
2679 * it could not be found.
2681 * Deprecated: 3.2: Use e_cal_client_resolve_tzid_cb() instead.
2684 e_cal_resolve_tzid_cb (const gchar *tzid,
2688 icaltimezone *zone = NULL;
2690 g_return_val_if_fail (data != NULL, NULL);
2691 g_return_val_if_fail (E_IS_CAL (data), NULL);
2693 ecal = E_CAL (data);
2695 /* FIXME: Handle errors. */
2696 e_cal_get_timezone (ecal, tzid, &zone, NULL);
2702 * e_cal_get_changes:
2703 * @ecal: A calendar client.
2704 * @change_id: ID to use for comparing changes.
2705 * @changes: Return value for the list of changes.
2706 * @error: Placeholder for error information.
2708 * Returns a list of changes made to the calendar since a specific time. That time
2709 * is identified by the @change_id argument, which is used by the backend to
2710 * compute the changes done.
2712 * Returns: TRUE if the call was successful, FALSE otherwise.
2714 * Deprecated: 3.2: This function has been dropped completely.
2717 e_cal_get_changes (ECal *ecal,
2718 const gchar *change_id,
2724 e_return_error_if_fail (changes != NULL, E_CALENDAR_STATUS_INVALID_ARG);
2725 e_return_error_if_fail (change_id != NULL, E_CALENDAR_STATUS_INVALID_ARG);
2726 e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
2728 e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
2731 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_NOT_SUPPORTED, error);
2735 * e_cal_free_change_list:
2736 * @list: List of changes to be freed.
2738 * Free a list of changes as returned by #e_cal_get_changes.
2740 * Deprecated: 3.2: Use () instead.
2743 e_cal_free_change_list (GList *list)
2748 for (l = list; l; l = l->next) {
2751 if (c != NULL && c->comp != NULL) {
2752 g_object_unref (G_OBJECT (c->comp));
2755 g_warn_if_reached ();
2762 * e_cal_get_object_list:
2763 * @ecal: A calendar client.
2764 * @query: Query string.
2765 * @objects: (out) (element-type long): Return value for list of objects.
2766 * @error: Placeholder for error information.
2768 * Gets a list of objects from the calendar that match the query specified
2769 * by the @query argument. The objects will be returned in the @objects
2770 * argument, which is a list of #icalcomponent. When done, this list
2771 * should be freed by using the #e_cal_free_object_list function.
2773 * Returns: TRUE if the operation was successful, FALSE otherwise.
2775 * Deprecated: 3.2: Use e_cal_client_get_object_list_sync() instead.
2778 e_cal_get_object_list (ECal *ecal,
2784 gchar **object_array = NULL, *gdbus_query = NULL;
2786 e_return_error_if_fail (objects != NULL, E_CALENDAR_STATUS_INVALID_ARG);
2787 e_return_error_if_fail (query, E_CALENDAR_STATUS_INVALID_ARG);
2788 e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
2790 e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
2793 if (priv->load_state != E_CAL_LOAD_LOADED) {
2794 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
2797 if (!e_gdbus_cal_call_get_object_list_sync (priv->gdbus_cal, e_util_ensure_gdbus_string (query, &gdbus_query), &object_array, NULL, error)) {
2798 g_free (gdbus_query);
2800 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
2803 g_free (gdbus_query);
2806 icalcomponent *comp;
2808 for (object = object_array; *object; object++) {
2809 comp = icalcomponent_new_from_string (*object);
2810 if (!comp) continue;
2811 *objects = g_list_prepend (*objects, comp);
2814 g_strfreev (object_array);
2816 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
2819 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OTHER_ERROR, error);
2823 * e_cal_get_object_list_as_comp:
2824 * @ecal: A calendar client.
2825 * @query: Query string.
2826 * @objects: Return value for list of objects.
2827 * @error: Placeholder for error information.
2829 * Gets a list of objects from the calendar that match the query specified
2830 * by the @query argument. The objects will be returned in the @objects
2831 * argument, which is a list of #ECalComponent.
2833 * Returns: TRUE if the operation was successful, FALSE otherwise.
2835 * Deprecated: 3.2: Use e_cal_client_get_object_list_as_comps_sync() instead.
2838 e_cal_get_object_list_as_comp (ECal *ecal,
2843 GList *ical_objects = NULL;
2846 e_return_error_if_fail (objects != NULL, E_CALENDAR_STATUS_INVALID_ARG);
2849 e_return_error_if_fail (ecal && E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
2850 e_return_error_if_fail (query, E_CALENDAR_STATUS_INVALID_ARG);
2852 if (!e_cal_get_object_list (ecal, query, &ical_objects, error))
2855 for (l = ical_objects; l; l = l->next) {
2856 ECalComponent *comp;
2858 comp = e_cal_component_new ();
2859 e_cal_component_set_icalcomponent (comp, l->data);
2860 *objects = g_list_prepend (*objects, comp);
2863 g_list_free (ical_objects);
2869 * e_cal_free_object_list:
2870 * @objects: List of objects to be freed.
2872 * Frees a list of objects as returned by #e_cal_get_object_list.
2874 * Deprecated: 3.2: Use e_cal_client_free_icalcomp_slist() instead.
2877 e_cal_free_object_list (GList *objects)
2881 for (l = objects; l; l = l->next)
2882 icalcomponent_free (l->data);
2884 g_list_free (objects);
2888 * e_cal_get_free_busy
2889 * @ecal: A calendar client.
2890 * @users: List of users to retrieve free/busy information for.
2891 * @start: Start time for query.
2892 * @end: End time for query.
2893 * @freebusy: Return value for VFREEBUSY objects.
2894 * @error: Placeholder for error information.
2896 * Gets free/busy information from the calendar server.
2898 * Returns: TRUE if the operation was successful, FALSE otherwise.
2900 * Deprecated: 3.2: Use e_cal_client_get_free_busy_sync() instead.
2903 e_cal_get_free_busy (ECal *ecal,
2915 e_return_error_if_fail (users != NULL, E_CALENDAR_STATUS_INVALID_ARG);
2916 e_return_error_if_fail (freebusy != NULL, E_CALENDAR_STATUS_INVALID_ARG);
2917 e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
2919 e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
2922 if (priv->load_state != E_CAL_LOAD_LOADED) {
2923 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
2927 for (l = users; l; l = l->next) {
2928 susers = g_slist_prepend (susers, l->data);
2930 susers = g_slist_reverse (susers);
2931 strv = e_gdbus_cal_encode_get_free_busy (start, end, susers);
2932 g_slist_free (susers);
2934 g_mutex_lock (priv->free_busy_data_lock);
2935 priv->free_busy_data = freebusy;
2936 g_mutex_unlock (priv->free_busy_data_lock);
2938 if (!e_gdbus_cal_call_get_free_busy_sync (priv->gdbus_cal, (const gchar * const *) strv, NULL, error)) {
2940 g_mutex_lock (priv->free_busy_data_lock);
2941 priv->free_busy_data = NULL;
2942 g_mutex_unlock (priv->free_busy_data_lock);
2944 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
2948 g_mutex_lock (priv->free_busy_data_lock);
2949 priv->free_busy_data = NULL;
2950 g_mutex_unlock (priv->free_busy_data_lock);
2952 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
2955 struct comp_instance {
2956 ECalComponent *comp;
2961 struct instances_info {
2963 icaltimezone *start_zone;
2966 /* Called from cal_recur_generate_instances(); adds an instance to the list */
2968 add_instance (ECalComponent *comp,
2974 struct comp_instance *ci;
2975 struct icaltimetype itt;
2976 icalcomponent *icalcomp;
2977 struct instances_info *instances_hold;
2979 instances_hold = data;
2980 list = instances_hold->instances;
2982 ci = g_new (struct comp_instance, 1);
2984 icalcomp = icalcomponent_new_clone (e_cal_component_get_icalcomponent (comp));
2986 /* add the instance to the list */
2987 ci->comp = e_cal_component_new ();
2988 e_cal_component_set_icalcomponent (ci->comp, icalcomp);
2990 /* set the RECUR-ID for the instance */
2991 if (e_cal_util_component_has_recurrences (icalcomp)) {
2992 if (!(icalcomponent_get_first_property (icalcomp, ICAL_RECURRENCEID_PROPERTY))) {
2993 ECalComponentRange *range;
2994 ECalComponentDateTime datetime;
2996 e_cal_component_get_dtstart (comp, &datetime);
2998 if (instances_hold->start_zone)
2999 itt = icaltime_from_timet_with_zone (start, datetime.value->is_date, instances_hold->start_zone);
3001 itt = icaltime_from_timet (start, datetime.value->is_date);
3003 if (datetime.tzid) {
3004 g_free ((gchar *) datetime.tzid);
3005 datetime.tzid = NULL;
3009 g_free (datetime.value);
3010 datetime.value = &itt;
3012 range = g_new0 (ECalComponentRange, 1);
3013 range->type = E_CAL_COMPONENT_RANGE_SINGLE;
3014 range->datetime = datetime;
3016 e_cal_component_set_recurid (ci->comp, range);
3019 g_free ((gchar *) datetime.tzid);
3027 *list = g_list_prepend (*list, ci);
3032 /* Used from g_list_sort(); compares two struct comp_instance structures */
3034 compare_comp_instance (gconstpointer a,
3037 const struct comp_instance *cia, *cib;
3043 diff = cia->start - cib->start;
3044 return (diff < 0) ? -1 : (diff > 0) ? 1 : 0;
3048 process_detached_instances (GList *instances,
3049 GList *detached_instances)
3051 struct comp_instance *ci, *cid;
3052 GList *dl, *unprocessed_instances = NULL;
3054 for (dl = detached_instances; dl != NULL; dl = dl->next) {
3058 ECalComponentRange recur_id, instance_recur_id;
3061 recur_id.type = E_CAL_COMPONENT_RANGE_SINGLE;
3062 instance_recur_id.type = E_CAL_COMPONENT_RANGE_SINGLE;
3065 e_cal_component_get_uid (cid->comp, &uid);
3066 e_cal_component_get_recurid (cid->comp, &recur_id);
3068 /* search for coincident instances already expanded */
3069 for (il = instances; il != NULL; il = il->next) {
3070 const gchar *instance_uid;
3074 e_cal_component_get_uid (ci->comp, &instance_uid);
3075 e_cal_component_get_recurid (ci->comp, &instance_recur_id);
3076 if (strcmp (uid, instance_uid) == 0) {
3077 gchar *i_rid = NULL, *d_rid = NULL;
3079 i_rid = e_cal_component_get_recurid_as_string (ci->comp);
3080 d_rid = e_cal_component_get_recurid_as_string (cid->comp);
3082 if (i_rid && d_rid && strcmp (i_rid, d_rid) == 0) {
3083 g_object_unref (ci->comp);
3084 ci->comp = g_object_ref (cid->comp);
3085 ci->start = cid->start;
3090 if (!instance_recur_id.datetime.value ||
3091 !recur_id.datetime.value) {
3093 * Prevent obvious segfault by ignoring missing
3094 * recurrency ids. Real problem might be elsewhere,
3095 * but anything is better than crashing...
3097 g_log (G_LOG_DOMAIN,
3098 G_LOG_LEVEL_CRITICAL,
3099 "UID %s: instance RECURRENCE-ID %s + detached instance RECURRENCE-ID %s: cannot compare",
3104 e_cal_component_free_datetime (&instance_recur_id.datetime);
3109 cmp = icaltime_compare (*instance_recur_id.datetime.value,
3110 *recur_id.datetime.value);
3111 if ((recur_id.type == E_CAL_COMPONENT_RANGE_THISPRIOR && cmp <= 0) ||
3112 (recur_id.type == E_CAL_COMPONENT_RANGE_THISFUTURE && cmp >= 0)) {
3113 ECalComponent *comp;
3115 comp = e_cal_component_new ();
3116 e_cal_component_set_icalcomponent (
3118 icalcomponent_new_clone (e_cal_component_get_icalcomponent (cid->comp)));
3119 e_cal_component_set_recurid (comp, &instance_recur_id);
3121 /* replace the generated instances */
3122 g_object_unref (ci->comp);
3129 e_cal_component_free_datetime (&instance_recur_id.datetime);
3132 e_cal_component_free_datetime (&recur_id.datetime);
3135 unprocessed_instances = g_list_prepend (unprocessed_instances, cid);
3138 /* add the unprocessed instances (ie, detached instances with no master object */
3139 while (unprocessed_instances != NULL) {
3140 cid = unprocessed_instances->data;
3141 ci = g_new0 (struct comp_instance, 1);
3142 ci->comp = g_object_ref (cid->comp);
3143 ci->start = cid->start;
3145 instances = g_list_append (instances, ci);
3147 unprocessed_instances = g_list_remove (unprocessed_instances, cid);
3154 generate_instances (ECal *ecal,
3158 ECalRecurInstanceFn cb,
3161 GList *objects = NULL;
3162 GList *instances, *detached_instances = NULL;
3165 gchar *iso_start, *iso_end;
3170 /* Generate objects */
3172 GError *error = NULL;
3176 if (!e_cal_get_objects_for_uid (ecal, uid, &objects, &error)) {
3177 if (error->code == E_CALENDAR_STATUS_BUSY && tries >= 10) {
3180 g_clear_error (&error);
3185 unwrap_gerror (&error);
3186 g_message ("Failed to get recurrence objects for uid %s \n", error ? error->message : "Unknown error");
3187 g_clear_error (&error);
3192 iso_start = isodate_from_time_t (start);
3196 iso_end = isodate_from_time_t (end);
3202 query = g_strdup_printf ("(occur-in-time-range? (make-time \"%s\") (make-time \"%s\"))",
3203 iso_start, iso_end);
3206 if (!e_cal_get_object_list_as_comp (ecal, query, &objects, NULL)) {
3215 for (l = objects; l; l = l->next) {
3216 ECalComponent *comp;
3217 icaltimezone *default_zone;
3219 if (priv->default_zone)
3220 default_zone = priv->default_zone;
3222 default_zone = icaltimezone_get_utc_timezone ();
3225 if (e_cal_component_is_instance (comp)) {
3226 struct comp_instance *ci;
3227 ECalComponentDateTime dtstart, dtend;
3228 icaltimezone *start_zone = NULL, *end_zone = NULL;
3230 /* keep the detached instances apart */
3231 ci = g_new0 (struct comp_instance, 1);
3234 e_cal_component_get_dtstart (comp, &dtstart);
3235 e_cal_component_get_dtend (comp, &dtend);
3237 /* For DATE-TIME values with a TZID, we use
3238 * e_cal_resolve_tzid_cb to resolve the TZID.
3239 * For DATE values and DATE-TIME values without a
3240 * TZID (i.e. floating times) we use the default
3242 if (dtstart.tzid && !dtstart.value->is_date) {
3243 start_zone = e_cal_resolve_tzid_cb (dtstart.tzid, ecal);
3245 start_zone = default_zone;
3247 start_zone = default_zone;
3250 if (dtend.tzid && !dtend.value->is_date) {
3251 end_zone = e_cal_resolve_tzid_cb (dtend.tzid, ecal);
3253 end_zone = default_zone;
3255 end_zone = default_zone;
3258 ci->start = icaltime_as_timet_with_zone (*dtstart.value, start_zone);
3261 ci->end = icaltime_as_timet_with_zone (*dtend.value, end_zone);
3262 else if (icaltime_is_date (*dtstart.value))
3263 ci->end = time_day_end (ci->start);
3265 ci->end = ci->start;
3267 e_cal_component_free_datetime (&dtstart);
3268 e_cal_component_free_datetime (&dtend);
3270 if (ci->start <= end && ci->end >= start) {
3271 detached_instances = g_list_prepend (detached_instances, ci);
3273 /* it doesn't fit to our time range, thus skip it */
3274 g_object_unref (G_OBJECT (ci->comp));
3278 ECalComponentDateTime datetime;
3279 icaltimezone *start_zone = NULL;
3280 struct instances_info *instances_hold;
3282 /* Get the start timezone */
3283 e_cal_component_get_dtstart (comp, &datetime);
3285 e_cal_get_timezone (ecal, datetime.tzid, &start_zone, NULL);
3288 e_cal_component_free_datetime (&datetime);
3290 instances_hold = g_new0 (struct instances_info, 1);
3291 instances_hold->instances = &instances;
3292 instances_hold->start_zone = start_zone;
3294 e_cal_recur_generate_instances (comp, start, end, add_instance, instances_hold,
3295 e_cal_resolve_tzid_cb, ecal,
3298 g_free (instances_hold);
3299 g_object_unref (comp);
3303 g_list_free (objects);
3305 /* Generate instances and spew them out */
3307 instances = g_list_sort (instances, compare_comp_instance);
3308 instances = process_detached_instances (instances, detached_instances);
3310 for (l = instances; l; l = l->next) {
3311 struct comp_instance *ci;
3316 result = (* cb) (ci->comp, ci->start, ci->end, cb_data);
3324 for (l = instances; l; l = l->next) {
3325 struct comp_instance *ci;
3328 g_object_unref (G_OBJECT (ci->comp));
3332 g_list_free (instances);
3334 for (l = detached_instances; l; l = l->next) {
3335 struct comp_instance *ci;
3338 g_object_unref (G_OBJECT (ci->comp));
3342 g_list_free (detached_instances);
3347 * e_cal_generate_instances:
3348 * @ecal: A calendar client.
3349 * @start: Start time for query.
3350 * @end: End time for query.
3351 * @cb: Callback for each generated instance.
3352 * @cb_data: Closure data for the callback.
3354 * Does a combination of #e_cal_get_object_list () and
3355 * #e_cal_recur_generate_instances().
3357 * The callback function should do a g_object_ref() of the calendar component
3358 * it gets passed if it intends to keep it around, since it will be unref'ed
3359 * as soon as the callback returns.
3361 * Deprecated: 3.2: Use e_cal_client_generate_instances() instead.
3364 e_cal_generate_instances (ECal *ecal,
3367 ECalRecurInstanceFn cb,
3372 g_return_if_fail (ecal != NULL);
3373 g_return_if_fail (E_IS_CAL (ecal));
3376 g_return_if_fail (priv->load_state == E_CAL_LOAD_LOADED);
3378 g_return_if_fail (start >= 0);
3379 g_return_if_fail (end >= 0);
3380 g_return_if_fail (cb != NULL);
3382 generate_instances (ecal, start, end, NULL, cb, cb_data);
3386 * e_cal_generate_instances_for_object:
3387 * @ecal: A calendar client.
3388 * @icalcomp: Object to generate instances from.
3389 * @start: Start time for query.
3390 * @end: End time for query.
3391 * @cb: Callback for each generated instance.
3392 * @cb_data: Closure data for the callback.
3394 * Does a combination of #e_cal_get_object_list () and
3395 * #e_cal_recur_generate_instances(), like #e_cal_generate_instances(), but
3396 * for a single object.
3398 * The callback function should do a g_object_ref() of the calendar component
3399 * it gets passed if it intends to keep it around, since it will be unref'ed
3400 * as soon as the callback returns.
3402 * Deprecated: 3.2: Use e_cal_client_generate_instances_for_object() instead.
3405 e_cal_generate_instances_for_object (ECal *ecal,
3406 icalcomponent *icalcomp,
3409 ECalRecurInstanceFn cb,
3412 ECalComponent *comp;
3416 GList *instances = NULL;
3417 ECalComponentDateTime datetime;
3418 icaltimezone *start_zone = NULL;
3419 struct instances_info *instances_hold;
3420 gboolean is_single_instance = FALSE;
3422 g_return_if_fail (E_IS_CAL (ecal));
3423 g_return_if_fail (start >= 0);
3424 g_return_if_fail (end >= 0);
3425 g_return_if_fail (cb != NULL);
3427 comp = e_cal_component_new ();
3428 e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (icalcomp));
3430 if (!e_cal_component_has_recurrences (comp))
3431 is_single_instance = TRUE;
3433 /*If the backend stores it as individual instances and does not
3434 * have a master object - do not expand*/
3435 if (is_single_instance || e_cal_get_static_capability (ecal, CAL_STATIC_CAPABILITY_RECURRENCES_NO_MASTER)) {
3437 /*return the same instance */
3438 result = (* cb) (comp, icaltime_as_timet_with_zone (icalcomponent_get_dtstart (icalcomp), ecal->priv->default_zone),
3439 icaltime_as_timet_with_zone (icalcomponent_get_dtend (icalcomp), ecal->priv->default_zone), cb_data);
3440 g_object_unref (comp);
3444 e_cal_component_get_uid (comp, &uid);
3445 rid = e_cal_component_get_recurid_as_string (comp);
3447 /* Get the start timezone */
3448 e_cal_component_get_dtstart (comp, &datetime);
3450 e_cal_get_timezone (ecal, datetime.tzid, &start_zone, NULL);
3453 e_cal_component_free_datetime (&datetime);
3455 instances_hold = g_new0 (struct instances_info, 1);
3456 instances_hold->instances = &instances;
3457 instances_hold->start_zone = start_zone;
3459 /* generate all instances in the given time range */
3460 generate_instances (ecal, start, end, uid, add_instance, instances_hold);
3462 instances = *(instances_hold->instances);
3463 /* now only return back the instances for the given object */
3465 while (instances != NULL) {
3466 struct comp_instance *ci;
3467 gchar *instance_rid = NULL;
3469 ci = instances->data;
3472 instance_rid = e_cal_component_get_recurid_as_string (ci->comp);
3475 if (instance_rid && *instance_rid && strcmp (rid, instance_rid) == 0)
3476 result = (* cb) (ci->comp, ci->start, ci->end, cb_data);
3478 result = (* cb) (ci->comp, ci->start, ci->end, cb_data);
3481 /* remove instance from list */
3482 instances = g_list_remove (instances, ci);
3483 g_object_unref (ci->comp);
3485 g_free (instance_rid);
3489 g_object_unref (comp);
3490 g_free (instances_hold);
3494 /* Builds a list of ECalComponentAlarms structures */
3496 build_component_alarms_list (ECal *ecal,
3501 GSList *comp_alarms;
3506 for (l = object_list; l != NULL; l = l->next) {
3507 ECalComponent *comp;
3508 ECalComponentAlarms *alarms;
3509 ECalComponentAlarmAction omit[] = {-1};
3511 comp = e_cal_component_new ();
3512 if (!e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (l->data))) {
3513 g_object_unref (G_OBJECT (comp));
3517 alarms = e_cal_util_generate_alarms_for_comp (comp, start, end, omit, e_cal_resolve_tzid_cb,
3518 ecal, ecal->priv->default_zone);
3520 comp_alarms = g_slist_prepend (comp_alarms, alarms);
3527 * e_cal_get_alarms_in_range:
3528 * @ecal: A calendar client.
3529 * @start: Start time for query.
3530 * @end: End time for query.
3532 * Queries a calendar for the alarms that trigger in the specified range of
3535 * Returns: A list of #ECalComponentAlarms structures. This should be freed
3536 * using the #e_cal_free_alarms() function, or by freeing each element
3537 * separately with #e_cal_component_alarms_free() and then freeing the list with
3540 * Deprecated: 3.2: This function has been dropped completely.
3543 e_cal_get_alarms_in_range (ECal *ecal,
3549 gchar *sexp, *iso_start, *iso_end;
3550 GList *object_list = NULL;
3552 g_return_val_if_fail (ecal != NULL, NULL);
3553 g_return_val_if_fail (E_IS_CAL (ecal), NULL);
3556 g_return_val_if_fail (priv->load_state == E_CAL_LOAD_LOADED, NULL);
3558 g_return_val_if_fail (start >= 0 && end >= 0, NULL);
3559 g_return_val_if_fail (start <= end, NULL);
3561 iso_start = isodate_from_time_t (start);
3565 iso_end = isodate_from_time_t (end);
3571 /* build the query string */
3572 sexp = g_strdup_printf ("(has-alarms-in-range? (make-time \"%s\") (make-time \"%s\"))",
3573 iso_start, iso_end);
3577 /* execute the query on the server */
3578 if (!e_cal_get_object_list (ecal, sexp, &object_list, NULL)) {
3583 alarms = build_component_alarms_list (ecal, object_list, start, end);
3585 g_list_foreach (object_list, (GFunc) icalcomponent_free, NULL);
3586 g_list_free (object_list);
3593 * e_cal_free_alarms:
3594 * @comp_alarms: A list of #ECalComponentAlarms structures.
3596 * Frees a list of #ECalComponentAlarms structures as returned by
3597 * e_cal_get_alarms_in_range().
3599 * Deprecated: 3.2: This function has been dropped completely.
3602 e_cal_free_alarms (GSList *comp_alarms)
3606 for (l = comp_alarms; l; l = l->next) {
3607 ECalComponentAlarms *alarms;
3611 e_cal_component_alarms_free (alarms);
3613 g_warn_if_reached ();
3616 g_slist_free (comp_alarms);
3620 * e_cal_get_alarms_for_object:
3621 * @ecal: A calendar client.
3622 * @id: Unique identifier for a calendar component.
3623 * @start: Start time for query.
3624 * @end: End time for query.
3625 * @alarms: Return value for the component's alarm instances. Will return NULL
3626 * if no instances occur within the specified time range. This should be freed
3627 * using the e_cal_component_alarms_free() function.
3629 * Queries a calendar for the alarms of a particular object that trigger in the
3630 * specified range of time.
3632 * Returns: TRUE on success, FALSE if the object was not found.
3634 * Deprecated: 3.2: This function has been dropped completely.
3637 e_cal_get_alarms_for_object (ECal *ecal,
3638 const ECalComponentId *id,
3641 ECalComponentAlarms **alarms)
3644 icalcomponent *icalcomp;
3645 ECalComponent *comp;
3646 ECalComponentAlarmAction omit[] = {-1};
3648 g_return_val_if_fail (alarms != NULL, FALSE);
3651 g_return_val_if_fail (ecal != NULL, FALSE);
3652 g_return_val_if_fail (E_IS_CAL (ecal), FALSE);
3655 g_return_val_if_fail (priv->load_state == E_CAL_LOAD_LOADED, FALSE);
3657 g_return_val_if_fail (id != NULL, FALSE);
3658 g_return_val_if_fail (start >= 0 && end >= 0, FALSE);
3659 g_return_val_if_fail (start <= end, FALSE);
3661 if (!e_cal_get_object (ecal, id->uid, id->rid, &icalcomp, NULL))
3666 comp = e_cal_component_new ();
3667 if (!e_cal_component_set_icalcomponent (comp, icalcomp)) {
3668 icalcomponent_free (icalcomp);
3669 g_object_unref (G_OBJECT (comp));
3673 *alarms = e_cal_util_generate_alarms_for_comp (comp, start, end, omit, e_cal_resolve_tzid_cb,
3674 ecal, priv->default_zone);
3680 * e_cal_discard_alarm
3681 * @ecal: A calendar ecal.
3682 * @comp: The component to discard the alarm from.
3683 * @auid: Unique identifier of the alarm to be discarded.
3684 * @error: Placeholder for error information.
3686 * Tells the calendar backend to get rid of the alarm identified by the
3687 * @auid argument in @comp. Some backends might remove the alarm or
3688 * update internal information about the alarm be discarded, or, like
3689 * the file backend does, ignore the operation.
3691 * CALOBJ_MOD_ONLY_THIS is not supported in this call.
3693 * Returns: TRUE if the operation was successful, FALSE otherwise.
3695 * Deprecated: 3.2: Use e_cal_client_discard_alarm_sync() instead.
3698 e_cal_discard_alarm (ECal *ecal,
3699 ECalComponent *comp,
3705 e_return_error_if_fail (ecal != NULL, E_CALENDAR_STATUS_INVALID_ARG);
3706 e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
3707 e_return_error_if_fail (comp != NULL, E_CALENDAR_STATUS_INVALID_ARG);
3708 e_return_error_if_fail (E_IS_CAL_COMPONENT (comp), E_CALENDAR_STATUS_INVALID_ARG);
3709 e_return_error_if_fail (auid != NULL, E_CALENDAR_STATUS_INVALID_ARG);
3711 e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
3713 if (priv->load_state != E_CAL_LOAD_LOADED) {
3714 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
3717 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_NOT_SUPPORTED, error);
3720 typedef struct _ForeachTZIDCallbackData ForeachTZIDCallbackData;
3721 struct _ForeachTZIDCallbackData {
3723 GHashTable *timezone_hash;
3724 gboolean include_all_timezones;
3728 /* This adds the VTIMEZONE given by the TZID parameter to the GHashTable in
3731 foreach_tzid_callback (icalparameter *param,
3734 ForeachTZIDCallbackData *data = cbdata;
3737 icaltimezone *zone = NULL;
3738 icalcomponent *vtimezone_comp;
3739 gchar *vtimezone_as_string;
3741 priv = data->ecal->priv;
3743 /* Get the TZID string from the parameter. */
3744 tzid = icalparameter_get_tzid (param);
3748 /* Check if we've already added it to the GHashTable. */
3749 if (g_hash_table_lookup (data->timezone_hash, tzid))
3752 if (data->include_all_timezones) {
3753 if (!e_cal_get_timezone (data->ecal, tzid, &zone, NULL)) {
3754 data->success = FALSE;
3758 /* Check if it is in our cache. If it is, it must already be
3759 * on the server so return. */
3760 if (g_hash_table_lookup (priv->timezones, tzid))
3763 /* Check if it is a builtin timezone. If it isn't, return. */
3764 zone = icaltimezone_get_builtin_timezone_from_tzid (tzid);
3769 /* Convert it to a string and add it to the hash. */
3770 vtimezone_comp = icaltimezone_get_component (zone);
3771 if (!vtimezone_comp)
3774 vtimezone_as_string = icalcomponent_as_ical_string_r (vtimezone_comp);
3776 g_hash_table_insert (data->timezone_hash, (gchar *) tzid,
3777 vtimezone_as_string);
3780 /* This appends the value string to the GString given in data. */
3782 append_timezone_string (gpointer key,
3786 GString *vcal_string = data;
3788 g_string_append (vcal_string, value);
3792 /* This simply frees the hash values. */
3794 free_timezone_string (gpointer key,
3801 /* This converts the VEVENT/VTODO to a string. If include_all_timezones is
3802 * TRUE, it includes all the VTIMEZONE components needed for the VEVENT/VTODO.
3803 * If not, it only includes builtin timezones that may not be on the server.
3805 * To do that we check every TZID in the component to see if it is a builtin
3806 * timezone. If it is, we see if it it in our cache. If it is in our cache,
3807 * then we know the server already has it and we don't need to send it.
3808 * If it isn't in our cache, then we need to send it to the server.
3809 * If we need to send any timezones to the server, then we have to create a
3810 * complete VCALENDAR object, otherwise we can just send a single VEVENT/VTODO
3813 e_cal_get_component_as_string_internal (ECal *ecal,
3814 icalcomponent *icalcomp,
3815 gboolean include_all_timezones)
3817 GHashTable *timezone_hash;
3818 GString *vcal_string;
3819 gint initial_vcal_string_len;
3820 ForeachTZIDCallbackData cbdata;
3823 timezone_hash = g_hash_table_new (g_str_hash, g_str_equal);
3825 /* Add any timezones needed to the hash. We use a hash since we only
3826 * want to add each timezone once at most. */
3828 cbdata.timezone_hash = timezone_hash;
3829 cbdata.include_all_timezones = include_all_timezones;
3830 cbdata.success = TRUE;
3831 icalcomponent_foreach_tzid (icalcomp, foreach_tzid_callback, &cbdata);
3832 if (!cbdata.success) {
3833 g_hash_table_foreach (timezone_hash, free_timezone_string,
3838 /* Create the start of a VCALENDAR, to add the VTIMEZONES to,
3839 * and remember its length so we know if any VTIMEZONEs get added. */
3840 vcal_string = g_string_new (NULL);
3841 g_string_append (vcal_string,
3843 "PRODID:-//Ximian//NONSGML Evolution Calendar//EN\n"
3845 "METHOD:PUBLISH\n");
3846 initial_vcal_string_len = vcal_string->len;
3848 /* Now concatenate all the timezone strings. This also frees the
3849 * timezone strings as it goes. */
3850 g_hash_table_foreach (timezone_hash, append_timezone_string,
3853 /* Get the string for the VEVENT/VTODO. */
3854 obj_string = icalcomponent_as_ical_string_r (icalcomp);
3856 /* If there were any timezones to send, create a complete VCALENDAR,
3857 * else just send the VEVENT / VTODO string. */
3858 if (!include_all_timezones
3859 && vcal_string->len == initial_vcal_string_len) {
3860 g_string_free (vcal_string, TRUE);
3862 g_string_append (vcal_string, obj_string);
3863 g_string_append (vcal_string, "END:VCALENDAR\n");
3864 g_free (obj_string);
3865 obj_string = vcal_string->str;
3866 g_string_free (vcal_string, FALSE);
3869 g_hash_table_destroy (timezone_hash);
3875 * e_cal_get_component_as_string:
3876 * @ecal: A calendar client.
3877 * @icalcomp: A calendar component object.
3879 * Gets a calendar component as an iCalendar string, with a toplevel
3880 * VCALENDAR component and all VTIMEZONEs needed for the component.
3882 * Returns: the component as a complete iCalendar string, or NULL on
3883 * failure. The string should be freed after use.
3885 * Deprecated: 3.2: Use e_cal_client_get_component_as_string() instead.
3888 e_cal_get_component_as_string (ECal *ecal,
3889 icalcomponent *icalcomp)
3891 return e_cal_get_component_as_string_internal (ecal, icalcomp, TRUE);
3895 * e_cal_create_object:
3896 * @ecal: A calendar client.
3897 * @icalcomp: The component to create.
3898 * @uid: Return value for the UID assigned to the new component by the calendar backend.
3899 * @error: Placeholder for error information.
3901 * Requests the calendar backend to create the object specified by the @icalcomp
3902 * argument. Some backends would assign a specific UID to the newly created object,
3903 * in those cases that UID would be returned in the @uid argument.
3905 * Returns: TRUE if the operation was successful, FALSE otherwise.
3907 * Deprecated: 3.2: Use e_cal_client_create_object_sync() instead.
3910 e_cal_create_object (ECal *ecal,
3911 icalcomponent *icalcomp,
3916 gchar *obj, *gdbus_obj = NULL;
3917 const gchar *strv[2];
3918 gchar **muids = NULL;
3920 e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
3921 e_return_error_if_fail (icalcomp != NULL, E_CALENDAR_STATUS_INVALID_ARG);
3922 e_return_error_if_fail (icalcomponent_is_valid (icalcomp), E_CALENDAR_STATUS_INVALID_ARG);
3924 e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
3926 if (priv->load_state != E_CAL_LOAD_LOADED) {
3927 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
3930 obj = icalcomponent_as_ical_string_r (icalcomp);
3931 strv[0] = e_util_ensure_gdbus_string (obj, &gdbus_obj);
3934 if (!e_gdbus_cal_call_create_objects_sync (priv->gdbus_cal, strv, &muids, NULL, error)) {
3938 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
3945 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OTHER_ERROR, error);
3947 icalcomponent_set_uid (icalcomp, muids[0]);
3950 *uid = g_strdup (muids[0]);
3954 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
3959 * e_cal_modify_object:
3960 * @ecal: A calendar client.
3961 * @icalcomp: Component to modify.
3962 * @mod: Type of modification.
3963 * @error: Placeholder for error information.
3965 * Requests the calendar backend to modify an existing object. If the object
3966 * does not exist on the calendar, an error will be returned.
3968 * For recurrent appointments, the @mod argument specifies what to modify,
3969 * if all instances (CALOBJ_MOD_ALL), a single instance (CALOBJ_MOD_THIS),
3970 * or a specific set of instances (CALOBJ_MOD_THISNADPRIOR and
3971 * CALOBJ_MOD_THISANDFUTURE).
3973 * Returns: TRUE if the operation was successful, FALSE otherwise.
3975 * Deprecated: 3.2: Use e_cal_client_modify_object_sync() instead.
3978 e_cal_modify_object (ECal *ecal,
3979 icalcomponent *icalcomp,
3987 e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
3988 e_return_error_if_fail (icalcomp, E_CALENDAR_STATUS_INVALID_ARG);
3989 e_return_error_if_fail (icalcomponent_is_valid (icalcomp), E_CALENDAR_STATUS_INVALID_ARG);
3991 case CALOBJ_MOD_THIS:
3992 case CALOBJ_MOD_THISANDPRIOR:
3993 case CALOBJ_MOD_THISANDFUTURE:
3994 case CALOBJ_MOD_ALL:
3997 e_return_error_if_fail ("valid CalObjModType" && FALSE, E_CALENDAR_STATUS_INVALID_ARG);
4000 e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
4002 if (priv->load_state != E_CAL_LOAD_LOADED) {
4003 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
4006 obj = icalcomponent_as_ical_string_r (icalcomp);
4008 strv = e_gdbus_cal_encode_modify_objects (&objs, mod);
4009 if (!e_gdbus_cal_call_modify_objects_sync (priv->gdbus_cal, (const gchar * const *) strv, NULL, error)) {
4013 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
4019 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
4023 * e_cal_remove_object_with_mod:
4024 * @ecal: A calendar client.
4025 * @uid: UID of the object to remove.
4026 * @rid: Recurrence ID of the specific recurrence to remove.
4027 * @mod: Type of removal.
4028 * @error: Placeholder for error information.
4030 * This function allows the removal of instances of a recurrent
4031 * appointment. If what you want is to remove all instances, use
4032 * e_cal_remove_object instead.
4034 * By using a combination of the @uid, @rid and @mod arguments, you
4035 * can remove specific instances. @uid is mandatory. Empty or NULL
4036 * @rid selects the parent appointment (the one with the recurrence
4037 * rule). A non-empty @rid selects the recurrence at the time specified
4038 * in @rid, using the same time zone as the parent appointment's start
4041 * The exact semantic then depends on @mod. CALOBJ_MOD_THIS,
4042 * CALOBJ_MOD_THISANDPRIOR, CALOBJ_MOD_THISANDFUTURE and
4043 * CALOBJ_MOD_ALL ensure that the event does not recur at the selected
4044 * instance(s). This is done by removing any detached recurrence
4045 * matching the selection criteria and modifying the parent
4046 * appointment (adding EXDATE, adjusting recurrence rules, etc.). It
4047 * is not an error if @uid+@rid do not match an existing instance.
4049 * If not all instances are removed, the client will get a
4050 * "obj_modified" signal for the parent appointment, while it will get
4051 * an "obj_removed" signal when all instances are removed.
4053 * CALOBJ_MOD_ONLY_THIS changes the semantic of CALOBJ_MOD_THIS: @uid
4054 * and @rid must select an existing instance. That instance is
4055 * removed without modifying the parent appointment. In other words,
4056 * e_cal_remove_object_with_mod(CALOBJ_MOD_ONLY_THIS) is the inverse
4057 * operation for adding a detached recurrence. The client is
4058 * always sent an "obj_removed" signal.
4060 * Note that not all backends support CALOBJ_MOD_ONLY_THIS. Check for
4061 * the CAL_STATIC_CAPABILITY_REMOVE_ONLY_THIS capability before using
4062 * it. Previous releases did not check consistently for unknown
4063 * @mod values, using it with them may have had unexpected results.
4065 * Returns: TRUE if the operation was successful, FALSE otherwise.
4067 * Deprecated: 3.2: Use e_cal_client_remove_object_sync() instead.
4070 e_cal_remove_object_with_mod (ECal *ecal,
4081 e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
4082 e_return_error_if_fail (uid, E_CALENDAR_STATUS_INVALID_ARG);
4084 case CALOBJ_MOD_THIS:
4085 case CALOBJ_MOD_THISANDPRIOR:
4086 case CALOBJ_MOD_THISANDFUTURE:
4087 case CALOBJ_MOD_ONLY_THIS:
4088 case CALOBJ_MOD_ALL:
4091 e_return_error_if_fail ("valid CalObjModType" && FALSE, E_CALENDAR_STATUS_INVALID_ARG);
4094 e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
4096 if (priv->load_state != E_CAL_LOAD_LOADED) {
4097 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
4100 id.uid = (gchar *) uid;
4101 id.rid = (gchar *) rid;
4103 strv = e_gdbus_cal_encode_remove_objects (&ids, mod);
4104 if (!e_gdbus_cal_call_remove_objects_sync (priv->gdbus_cal, (const gchar * const *) strv, NULL, error)) {
4107 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
4112 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
4116 * e_cal_remove_object:
4117 * @ecal: A calendar client.
4118 * @uid: Unique identifier of the calendar component to remove.
4119 * @error: Placeholder for error information.
4121 * Asks a calendar to remove all components with the given UID.
4122 * If more control of the removal is desired, then use e_cal_remove_object_with_mod().
4123 * If the server is able to remove the component(s), all clients will
4124 * be notified and they will emit the "obj_removed" signal.
4126 * Returns: %TRUE if successful, %FALSE otherwise.
4128 * Deprecated: 3.2: Use e_cal_client_remove_object_sync() instead, with rid set to NULL and mod set to CALOBJ_MOD_ALL.
4131 e_cal_remove_object (ECal *ecal,
4135 e_return_error_if_fail (ecal && E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
4136 e_return_error_if_fail (uid, E_CALENDAR_STATUS_INVALID_ARG);
4138 return e_cal_remove_object_with_mod (ecal, uid, NULL, CALOBJ_MOD_ALL, error);
4142 * e_cal_receive_objects:
4143 * @ecal: A calendar client.
4144 * @icalcomp: An icalcomponent.
4145 * @error: Placeholder for error information.
4147 * Makes the backend receive the set of iCalendar objects specified in the
4148 * @icalcomp argument. This is used for iTIP confirmation/cancellation
4149 * messages for scheduled meetings.
4151 * Returns: %TRUE if successful, %FALSE otherwise.
4153 * Deprecated: 3.2: Use e_cal_client_receive_objects_sync() instead.
4156 e_cal_receive_objects (ECal *ecal,
4157 icalcomponent *icalcomp,
4161 gchar *obj, *gdbus_obj = NULL;
4163 e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
4164 e_return_error_if_fail (icalcomp, E_CALENDAR_STATUS_INVALID_ARG);
4165 e_return_error_if_fail (icalcomponent_is_valid (icalcomp), E_CALENDAR_STATUS_INVALID_ARG);
4167 e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
4169 if (priv->load_state != E_CAL_LOAD_LOADED) {
4170 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
4173 obj = icalcomponent_as_ical_string_r (icalcomp);
4174 if (!e_gdbus_cal_call_receive_objects_sync (priv->gdbus_cal, e_util_ensure_gdbus_string (obj, &gdbus_obj), NULL, error)) {
4178 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
4184 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
4188 * e_cal_send_objects:
4189 * @ecal: A calendar client.
4190 * @icalcomp: An icalcomponent.
4191 * @users: List of users to send the objects to.
4192 * @modified_icalcomp: Return value for the icalcomponent after all the operations
4194 * @error: Placeholder for error information.
4196 * Requests a calendar backend to send meeting information to the specified list
4199 * Returns: TRUE if the operation was successful, FALSE otherwise.
4201 * Deprecated: 3.2: Use e_cal_client_send_objects_sync() instead.
4204 e_cal_send_objects (ECal *ecal,
4205 icalcomponent *icalcomp,
4207 icalcomponent **modified_icalcomp,
4211 ECalendarStatus status;
4212 gchar **out_array = NULL;
4213 gchar *obj, *gdbus_obj = NULL;
4215 e_return_error_if_fail (users != NULL, E_CALENDAR_STATUS_INVALID_ARG);
4216 e_return_error_if_fail (modified_icalcomp != NULL, E_CALENDAR_STATUS_INVALID_ARG);
4217 e_return_error_if_fail (icalcomp != NULL, E_CALENDAR_STATUS_INVALID_ARG);
4218 e_return_error_if_fail (icalcomponent_is_valid (icalcomp), E_CALENDAR_STATUS_INVALID_ARG);
4219 e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
4221 e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
4223 *modified_icalcomp = NULL;
4225 if (priv->load_state != E_CAL_LOAD_LOADED) {
4226 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
4229 obj = icalcomponent_as_ical_string_r (icalcomp);
4230 if (!e_gdbus_cal_call_send_objects_sync (priv->gdbus_cal, e_util_ensure_gdbus_string (obj, &gdbus_obj), &out_array, NULL, error)) {
4234 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
4240 status = E_CALENDAR_STATUS_OK;
4242 GSList *susers = NULL, *iter;
4243 gchar *object = NULL;
4245 e_return_error_if_fail (e_gdbus_cal_decode_send_objects ((const gchar * const *) out_array, &object, &susers), E_CALENDAR_STATUS_OTHER_ERROR);
4247 *modified_icalcomp = icalparser_parse_string (object);
4248 if (!(*modified_icalcomp))
4249 status = E_CALENDAR_STATUS_INVALID_OBJECT;
4252 for (iter = susers; iter; iter = iter->next) {
4253 *users = g_list_append (*users, iter->data);
4255 /* do not call g_free() on item's data of susers, it's moved to *users */
4256 g_slist_free (susers);
4257 g_strfreev (out_array);
4260 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OTHER_ERROR, error);
4262 E_CALENDAR_CHECK_STATUS (status, error);
4266 * e_cal_get_timezone:
4267 * @ecal: A calendar client.
4268 * @tzid: ID of the timezone to retrieve.
4269 * @zone: Return value for the timezone.
4270 * @error: Placeholder for error information.
4272 * Retrieves a timezone object from the calendar backend.
4274 * Returns: TRUE if the operation was successful, FALSE otherwise.
4276 * Deprecated: 3.2: Use e_cal_client_get_timezone_sync() instead.
4279 e_cal_get_timezone (ECal *ecal,
4281 icaltimezone **zone,
4285 ECalendarStatus status = E_CALENDAR_STATUS_OK;
4286 icalcomponent *icalcomp = NULL;
4287 gchar *object = NULL, *gdbus_tzid = NULL;
4288 const gchar *systzid = NULL;
4290 e_return_error_if_fail (zone, E_CALENDAR_STATUS_INVALID_ARG);
4291 e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
4293 e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
4296 if (priv->load_state != E_CAL_LOAD_LOADED) {
4297 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
4300 /* Check for well known zones and in the cache */
4301 /* If tzid is NULL or "" we return NULL, since it is a 'local time'. */
4302 if (!tzid || !tzid[0]) {
4303 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
4307 /* If it is UTC, we return the special UTC timezone. */
4308 if (!strcmp (tzid, "UTC")) {
4309 *zone = icaltimezone_get_utc_timezone ();
4311 /* See if we already have it in the cache. */
4312 *zone = g_hash_table_lookup (priv->timezones, tzid);
4317 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
4321 * Try to replace the original time zone with a more complete
4322 * and/or potentially updated system time zone. Note that this
4323 * also applies to TZIDs which match system time zones exactly:
4324 * they are extracted via icaltimezone_get_builtin_timezone_from_tzid()
4325 * below without a roundtrip to the backend.
4327 systzid = e_cal_match_tzid (tzid);
4329 /* call the backend */
4330 if (!e_gdbus_cal_call_get_timezone_sync (priv->gdbus_cal, e_util_ensure_gdbus_string (tzid, &gdbus_tzid), &object, NULL, error)) {
4331 g_free (gdbus_tzid);
4334 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
4337 g_free (gdbus_tzid);
4339 icalcomp = icalparser_parse_string (object);
4341 status = E_CALENDAR_STATUS_INVALID_OBJECT;
4345 * Use built-in time zone *and* rename it:
4346 * if the caller is asking for a TZID=FOO,
4347 * then likely because it has an event with
4348 * such a TZID. Returning a different TZID
4349 * would lead to broken VCALENDARs in the
4352 icaltimezone *syszone = icaltimezone_get_builtin_timezone_from_tzid (systzid);
4354 gboolean found = FALSE;
4357 icalcomp = icalcomponent_new_clone (icaltimezone_get_component (syszone));
4358 prop = icalcomponent_get_first_property (icalcomp,
4360 while (!found && prop) {
4361 if (icalproperty_isa (prop) == ICAL_TZID_PROPERTY) {
4362 icalproperty_set_value_from_string(prop, tzid, "NO");
4365 prop = icalcomponent_get_next_property (icalcomp,
4369 status = E_CALENDAR_STATUS_INVALID_OBJECT;
4375 E_CALENDAR_CHECK_STATUS (status, error);
4378 *zone = icaltimezone_new ();
4379 if (!icaltimezone_set_component (*zone, icalcomp)) {
4380 icaltimezone_free (*zone, 1);
4382 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OBJECT_NOT_FOUND, error);
4385 /* Now add it to the cache, to avoid the server call in future. */
4386 g_hash_table_insert (priv->timezones, (gpointer) icaltimezone_get_tzid (*zone), *zone);
4393 * e_cal_add_timezone
4394 * @ecal: A calendar client.
4395 * @izone: The timezone to add.
4396 * @error: Placeholder for error information.
4398 * Add a VTIMEZONE object to the given calendar.
4400 * Returns: TRUE if successful, FALSE otherwise.
4402 * Deprecated: 3.2: Use e_cal_client_add_timezone_sync() instead.
4405 e_cal_add_timezone (ECal *ecal,
4406 icaltimezone *izone,
4410 gchar *tzobj, *gdbus_tzobj = NULL;
4411 icalcomponent *icalcomp;
4413 e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
4414 e_return_error_if_fail (izone, E_CALENDAR_STATUS_INVALID_ARG);
4416 e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
4418 if (priv->load_state != E_CAL_LOAD_LOADED) {
4419 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
4422 /* Make sure we have a valid component - UTC doesn't, nor do
4423 * we really have to add it */
4424 if (izone == icaltimezone_get_utc_timezone ()) {
4425 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
4428 icalcomp = icaltimezone_get_component (izone);
4430 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_INVALID_ARG, error);
4433 /* convert icaltimezone into a string */
4434 tzobj = icalcomponent_as_ical_string_r (icalcomp);
4436 /* call the backend */
4437 if (!e_gdbus_cal_call_add_timezone_sync (priv->gdbus_cal, e_util_ensure_gdbus_string (tzobj, &gdbus_tzobj), NULL, error)) {
4439 g_free (gdbus_tzobj);
4441 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
4445 g_free (gdbus_tzobj);
4447 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
4452 * @ecal: A calendar client.
4453 * @sexp: S-expression representing the query.
4454 * @query: (out): Return value for the new query.
4455 * @error: Placeholder for error information.
4457 * Creates a live query object from a loaded calendar.
4459 * Returns: A query object that will emit notification signals as calendar
4460 * components are added and removed from the query in the server.
4462 * Deprecated: 3.2: Use e_cal_client_get_view_sync() instead.
4465 e_cal_get_query (ECal *ecal,
4471 ECalendarStatus status;
4472 gchar *query_path = NULL, *gdbus_sexp = NULL;
4473 EGdbusCalView *gdbus_calview;
4475 e_return_error_if_fail (sexp, E_CALENDAR_STATUS_INVALID_ARG);
4476 e_return_error_if_fail (query, E_CALENDAR_STATUS_INVALID_ARG);
4477 e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
4479 e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
4482 if (priv->load_state != E_CAL_LOAD_LOADED) {
4483 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
4486 if (!e_gdbus_cal_call_get_view_sync (priv->gdbus_cal, e_util_ensure_gdbus_string (sexp, &gdbus_sexp), &query_path, NULL, error)) {
4487 g_free (gdbus_sexp);
4489 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
4492 g_free (gdbus_sexp);
4494 status = E_CALENDAR_STATUS_OK;
4496 gdbus_calview = e_gdbus_cal_view_proxy_new_sync (g_dbus_proxy_get_connection (G_DBUS_PROXY (cal_factory_proxy)),
4497 G_DBUS_PROXY_FLAGS_NONE,
4498 CALENDAR_DBUS_SERVICE_NAME,
4503 g_free (query_path);
4505 if (!gdbus_calview) {
4507 status = E_CALENDAR_STATUS_OTHER_ERROR;
4509 *query = _e_cal_view_new (ecal, gdbus_calview);
4510 g_object_unref (gdbus_calview);
4513 E_CALENDAR_CHECK_STATUS (status, error);
4517 * e_cal_set_default_timezone:
4518 * @ecal: A calendar client.
4519 * @zone: A timezone object.
4520 * @error: Placeholder for error information.
4522 * Sets the default timezone on the calendar. This should be called before opening
4525 * Returns: TRUE if the operation was successful, FALSE otherwise.
4527 * Deprecated: 3.2: Use e_cal_client_set_default_timezone() instead.
4530 e_cal_set_default_timezone (ECal *ecal,
4536 e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
4537 e_return_error_if_fail (zone, E_CALENDAR_STATUS_INVALID_ARG);
4539 e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
4541 /* If the same timezone is already set, we don't have to do anything. */
4542 if (priv->default_zone == zone)
4545 /* FIXME Adding it to the server to change the tzid */
4546 if (!icaltimezone_get_component (zone)) {
4547 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_INVALID_ARG, error);
4550 priv->default_zone = zone;
4552 E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
4556 * e_cal_get_error_message
4557 * @status: A status code.
4559 * Gets an error message for the given status code.
4561 * Returns: the error message.
4563 * Deprecated: 3.2: Use e_cal_client_error_to_string() instead.
4566 e_cal_get_error_message (ECalendarStatus status)
4569 case E_CALENDAR_STATUS_INVALID_ARG :
4570 return _("Invalid argument");
4571 case E_CALENDAR_STATUS_BUSY :
4572 return _("Backend is busy");
4573 case E_CALENDAR_STATUS_REPOSITORY_OFFLINE :
4574 return _("Repository is offline");
4575 case E_CALENDAR_STATUS_NO_SUCH_CALENDAR :
4576 return _("No such calendar");
4577 case E_CALENDAR_STATUS_OBJECT_NOT_FOUND :
4578 return _("Object not found");
4579 case E_CALENDAR_STATUS_INVALID_OBJECT :
4580 return _("Invalid object");
4581 case E_CALENDAR_STATUS_URI_NOT_LOADED :
4582 return _("URI not loaded");
4583 case E_CALENDAR_STATUS_URI_ALREADY_LOADED :
4584 return _("URI already loaded");
4585 case E_CALENDAR_STATUS_PERMISSION_DENIED :
4586 return _("Permission denied");
4587 case E_CALENDAR_STATUS_UNKNOWN_USER :
4588 return _("Unknown User");
4589 case E_CALENDAR_STATUS_OBJECT_ID_ALREADY_EXISTS :
4590 return _("Object ID already exists");
4591 case E_CALENDAR_STATUS_PROTOCOL_NOT_SUPPORTED :
4592 return _("Protocol not supported");
4593 case E_CALENDAR_STATUS_CANCELLED :
4594 return _("Operation has been canceled");
4595 case E_CALENDAR_STATUS_COULD_NOT_CANCEL :
4596 return _("Could not cancel operation");
4597 case E_CALENDAR_STATUS_AUTHENTICATION_FAILED :
4598 return _("Authentication failed");
4599 case E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED :
4600 return _("Authentication required");
4601 case E_CALENDAR_STATUS_DBUS_EXCEPTION :
4602 return _("A D-Bus exception has occurred");
4603 case E_CALENDAR_STATUS_OTHER_ERROR :
4604 return _("Unknown error");
4605 case E_CALENDAR_STATUS_OK :
4606 return _("No error");
4607 case E_CALENDAR_STATUS_NOT_SUPPORTED :
4608 /* Translators: The string for NOT_SUPPORTED error */
4609 return _("Not supported");
4611 /* ignore everything else */
4619 * e_cal_open_default:
4620 * @ecal: A calendar client.
4621 * @type: Type of the calendar.
4622 * @func: Authentication function.
4623 * @data: Closure data for the authentication function.
4624 * @error: Placeholder for error information.
4626 * Opens the default calendar.
4628 * Returns: TRUE if it opened correctly, FALSE otherwise.
4630 * Deprecated: 3.2: Use e_cal_client_new_default_calendar() instead
4631 * and open it on your own.
4634 e_cal_open_default (ECal **ecal,
4635 ECalSourceType type,
4640 ESourceList *source_list;
4644 g_return_val_if_fail (ecal != NULL, FALSE);
4646 /* In case something goes wrong... */
4649 if (!e_cal_get_sources (&source_list, type, error))
4652 source = e_source_list_peek_default_source (source_list);
4654 g_set_error_literal (error, E_CALENDAR_ERROR,
4655 E_CALENDAR_STATUS_NO_SUCH_CALENDAR,
4656 e_cal_get_error_message (E_CALENDAR_STATUS_NO_SUCH_CALENDAR));
4657 g_object_unref (source_list);
4661 /* XXX So this can fail, but doesn't take a GError!? */
4662 client = e_cal_new (source, type);
4664 if (client == NULL) {
4665 g_set_error_literal (
4666 error, E_CALENDAR_ERROR,
4667 E_CALENDAR_STATUS_OTHER_ERROR,
4668 e_cal_get_error_message (E_CALENDAR_STATUS_OTHER_ERROR));
4669 g_object_unref (source_list);
4673 e_cal_set_auth_func (client, func, data);
4674 if (!e_cal_open (client, TRUE, error)) {
4675 g_object_unref (client);
4676 g_object_unref (source_list);
4682 g_object_unref (source_list);
4688 * e_cal_set_default:
4690 * @error: return location for a #GError, or %NULL
4692 * Sets the #ESource in @ecal as default.
4694 * Returns: TRUE if the operation was successful, FALSE otherwise.
4696 * Deprecated: 3.2: Use e_cal_client_set_default() instead.
4699 e_cal_set_default (ECal *ecal,
4703 ECalSourceType source_type;
4705 g_return_val_if_fail (E_IS_CAL (ecal), FALSE);
4707 source = e_cal_get_source (ecal);
4708 source_type = e_cal_get_source_type (ecal);
4710 return e_cal_set_default_source (source, source_type, error);
4714 set_default_source (ESourceList *sources,
4722 uid = e_source_get_uid (source);
4724 /* make sure the source is actually in the ESourceList. if
4725 * it's not we don't bother adding it, just return an error */
4726 source = e_source_list_peek_source_by_uid (sources, uid);
4728 g_set_error_literal (error, E_CALENDAR_ERROR,
4729 E_CALENDAR_STATUS_NO_SUCH_CALENDAR,
4730 e_cal_get_error_message (E_CALENDAR_STATUS_NO_SUCH_CALENDAR));
4731 g_object_unref (sources);
4735 /* loop over all the sources clearing out any "default"
4736 * properties we find */
4737 for (g = e_source_list_peek_groups (sources); g; g = g->next) {
4739 for (s = e_source_group_peek_sources (E_SOURCE_GROUP (g->data));
4741 e_source_set_property (E_SOURCE (s->data), "default", NULL);
4745 /* set the "default" property on the source */
4746 e_source_set_property (source, "default", "true");
4748 if (!e_source_list_sync (sources, &err)) {
4749 g_propagate_error (error, err);
4757 * e_cal_set_default_source:
4758 * @source: an #ESource
4759 * @type: type of the source
4760 * @error: return location for a #GError, or %NULL
4762 * Sets @source as the default source for the specified @type.
4764 * Returns: TRUE if the operation was successful, FALSE otherwise.
4766 * Deprecated: 3.2: Use e_cal_client_set_default_source() instead.
4769 e_cal_set_default_source (ESource *source,
4770 ECalSourceType type,
4773 ESourceList *sources;
4776 if (!e_cal_get_sources (&sources, type, &err)) {
4777 g_propagate_error (error, err);
4781 return set_default_source (sources, source, error);
4785 get_sources (ESourceList **sources,
4789 GConfClient *gconf = gconf_client_get_default ();
4791 *sources = e_source_list_new_for_gconf (gconf, key);
4792 g_object_unref (gconf);
4798 * e_cal_get_sources:
4799 * @sources: Return value for list of sources.
4800 * @type: Type of the sources to get.
4801 * @error: Placeholder for error information.
4803 * Gets the list of sources defined in the configuration for the given @type.
4805 * Returns: TRUE if the operation was successful, FALSE otherwise.
4807 * Deprecated: 3.2: Use e_cal_client_get_sources() instead.
4810 e_cal_get_sources (ESourceList **sources,
4811 ECalSourceType type,
4814 e_return_error_if_fail (sources != NULL, E_CALENDAR_STATUS_INVALID_ARG);
4818 case E_CAL_SOURCE_TYPE_EVENT:
4819 return get_sources (sources, "/apps/evolution/calendar/sources", error);
4821 case E_CAL_SOURCE_TYPE_TODO:
4822 return get_sources (sources, "/apps/evolution/tasks/sources", error);
4824 case E_CAL_SOURCE_TYPE_JOURNAL:
4825 return get_sources (sources, "/apps/evolution/memos/sources", error);
4828 g_set_error_literal (error, E_CALENDAR_ERROR,
4829 E_CALENDAR_STATUS_NO_SUCH_CALENDAR,
4830 e_cal_get_error_message (E_CALENDAR_STATUS_NO_SUCH_CALENDAR));
4834 g_set_error_literal (error, E_CALENDAR_ERROR,
4835 E_CALENDAR_STATUS_NO_SUCH_CALENDAR,
4836 e_cal_get_error_message (E_CALENDAR_STATUS_NO_SUCH_CALENDAR));