4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) version 3.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with the program; if not, see <http://www.gnu.org/licenses/>
18 * Copyright (C) 2011 Red Hat, Inc. (www.redhat.com)
26 #include <glib/gi18n-lib.h>
29 #include <libedataserver/e-client-private.h>
31 #include "e-cal-client.h"
32 #include "e-cal-component.h"
33 #include "e-cal-check-timezones.h"
34 #include "e-cal-time-util.h"
35 #include "e-cal-types.h"
36 #include "e-timezone-cache.h"
38 #include "e-gdbus-cal.h"
39 #include "e-gdbus-cal-factory.h"
41 #define E_CAL_CLIENT_GET_PRIVATE(obj) \
42 (G_TYPE_INSTANCE_GET_PRIVATE \
43 ((obj), E_TYPE_CAL_CLIENT, ECalClientPrivate))
45 struct _ECalClientPrivate {
46 GDBusProxy *dbus_proxy;
49 ECalClientSourceType source_type;
50 icaltimezone *default_zone;
53 GMutex zone_cache_lock;
54 GHashTable *zone_cache;
62 /* Forward Declarations */
63 static void e_cal_client_timezone_cache_init
64 (ETimezoneCacheInterface *interface);
66 static guint signals[LAST_SIGNAL];
68 G_DEFINE_TYPE_WITH_CODE (
72 G_IMPLEMENT_INTERFACE (
73 E_TYPE_TIMEZONE_CACHE,
74 e_cal_client_timezone_cache_init))
77 free_zone_cb (gpointer zone)
79 icaltimezone_free (zone, 1);
83 * Well-known calendar backend properties:
84 * @CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS: Contains default calendar's email
85 * address suggested by the backend.
86 * @CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS: Contains default alarm email
87 * address suggested by the backend.
88 * @CAL_BACKEND_PROPERTY_DEFAULT_OBJECT: Contains iCal component string
89 * of an #icalcomponent with the default values for properties needed.
90 * Preferred way of retrieving this property is by
91 * calling e_cal_client_get_default_object().
93 * See also: @CLIENT_BACKEND_PROPERTY_OPENED, @CLIENT_BACKEND_PROPERTY_OPENING,
94 * @CLIENT_BACKEND_PROPERTY_ONLINE, @CLIENT_BACKEND_PROPERTY_READONLY
95 * @CLIENT_BACKEND_PROPERTY_CACHE_DIR, @CLIENT_BACKEND_PROPERTY_CAPABILITIES
98 G_DEFINE_QUARK (e-cal-client-error-quark, e_cal_client_error)
101 * e_cal_client_error_to_string:
103 * FIXME: Document me.
108 e_cal_client_error_to_string (ECalClientError code)
111 case E_CAL_CLIENT_ERROR_NO_SUCH_CALENDAR:
112 return _("No such calendar");
113 case E_CAL_CLIENT_ERROR_OBJECT_NOT_FOUND:
114 return _("Object not found");
115 case E_CAL_CLIENT_ERROR_INVALID_OBJECT:
116 return _("Invalid object");
117 case E_CAL_CLIENT_ERROR_UNKNOWN_USER:
118 return _("Unknown user");
119 case E_CAL_CLIENT_ERROR_OBJECT_ID_ALREADY_EXISTS:
120 return _("Object ID already exists");
121 case E_CAL_CLIENT_ERROR_INVALID_RANGE:
122 return _("Invalid range");
125 return _("Unknown error");
129 * e_cal_client_error_create:
130 * @code: an #ECalClientError code to create
131 * @custom_msg: custom message to use for the error; can be %NULL
133 * Returns: a new #GError containing an E_CAL_CLIENT_ERROR of the given
134 * @code. If the @custom_msg is NULL, then the error message is
135 * the one returned from e_cal_client_error_to_string() for the @code,
136 * otherwise the given message is used.
138 * Returned pointer should be freed with g_error_free().
143 e_cal_client_error_create (ECalClientError code,
144 const gchar *custom_msg)
146 return g_error_new_literal (E_CAL_CLIENT_ERROR, code, custom_msg ? custom_msg : e_cal_client_error_to_string (code));
150 * If the specified GError is a remote error, then create a new error
151 * representing the remote error. If the error is anything else, then
155 unwrap_dbus_error (GError *error,
156 GError **client_error)
158 #define err(a,b) "org.gnome.evolution.dataserver.Calendar." a, b
159 static EClientErrorsList cal_errors[] = {
160 { err ("Success", -1) },
161 { err ("ObjectNotFound", E_CAL_CLIENT_ERROR_OBJECT_NOT_FOUND) },
162 { err ("InvalidObject", E_CAL_CLIENT_ERROR_INVALID_OBJECT) },
163 { err ("ObjectIdAlreadyExists", E_CAL_CLIENT_ERROR_OBJECT_ID_ALREADY_EXISTS) },
164 { err ("NoSuchCal", E_CAL_CLIENT_ERROR_NO_SUCH_CALENDAR) },
165 { err ("UnknownUser", E_CAL_CLIENT_ERROR_UNKNOWN_USER) },
166 { err ("InvalidRange", E_CAL_CLIENT_ERROR_INVALID_RANGE) },
168 { err ("Busy", E_CLIENT_ERROR_BUSY) },
169 { err ("InvalidArg", E_CLIENT_ERROR_INVALID_ARG) },
170 { err ("RepositoryOffline", E_CLIENT_ERROR_REPOSITORY_OFFLINE) },
171 { err ("OfflineUnavailable", E_CLIENT_ERROR_OFFLINE_UNAVAILABLE) },
172 { err ("PermissionDenied", E_CLIENT_ERROR_PERMISSION_DENIED) },
173 { err ("AuthenticationFailed", E_CLIENT_ERROR_AUTHENTICATION_FAILED) },
174 { err ("AuthenticationRequired", E_CLIENT_ERROR_AUTHENTICATION_REQUIRED) },
175 { err ("CouldNotCancel", E_CLIENT_ERROR_COULD_NOT_CANCEL) },
176 { err ("NotSupported", E_CLIENT_ERROR_NOT_SUPPORTED) },
177 { err ("UnsupportedAuthenticationMethod", E_CLIENT_ERROR_UNSUPPORTED_AUTHENTICATION_METHOD) },
178 { err ("TLSNotAvailable", E_CLIENT_ERROR_TLS_NOT_AVAILABLE) },
179 { err ("SearchSizeLimitExceeded", E_CLIENT_ERROR_SEARCH_SIZE_LIMIT_EXCEEDED) },
180 { err ("SearchTimeLimitExceeded", E_CLIENT_ERROR_SEARCH_TIME_LIMIT_EXCEEDED) },
181 { err ("InvalidQuery", E_CLIENT_ERROR_INVALID_QUERY) },
182 { err ("QueryRefused", E_CLIENT_ERROR_QUERY_REFUSED) },
183 { err ("NotOpened", E_CLIENT_ERROR_NOT_OPENED) },
184 { err ("UnsupportedField", E_CLIENT_ERROR_OTHER_ERROR) },
185 { err ("UnsupportedMethod", E_CLIENT_ERROR_OTHER_ERROR) },
186 { err ("InvalidServerVersion", E_CLIENT_ERROR_OTHER_ERROR) },
187 { err ("OtherError", E_CLIENT_ERROR_OTHER_ERROR) }
194 if (!e_client_util_unwrap_dbus_error (error, client_error, cal_errors, G_N_ELEMENTS (cal_errors), E_CAL_CLIENT_ERROR, TRUE))
195 e_client_util_unwrap_dbus_error (error, client_error, cl_errors, G_N_ELEMENTS (cl_errors), E_CLIENT_ERROR, FALSE);
201 set_proxy_gone_error (GError **error)
203 /* do not translate this string, it should ideally never happen */
204 g_set_error_literal (error, E_CLIENT_ERROR, E_CLIENT_ERROR_DBUS_ERROR, "D-Bus calendar proxy gone");
207 static guint active_cal_clients = 0, cal_connection_closed_id = 0;
208 static EGdbusCalFactory *cal_factory = NULL;
209 static GRecMutex cal_factory_lock;
210 #define LOCK_FACTORY() g_rec_mutex_lock (&cal_factory_lock)
211 #define UNLOCK_FACTORY() g_rec_mutex_unlock (&cal_factory_lock)
213 static void gdbus_cal_factory_closed_cb (GDBusConnection *connection, gboolean remote_peer_vanished, GError *error, gpointer user_data);
216 gdbus_cal_factory_disconnect (GDBusConnection *connection)
220 if (!connection && cal_factory)
221 connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (cal_factory));
223 if (connection && cal_connection_closed_id) {
224 g_dbus_connection_signal_unsubscribe (connection, cal_connection_closed_id);
225 g_signal_handlers_disconnect_by_func (connection, gdbus_cal_factory_closed_cb, NULL);
228 if (cal_factory != NULL)
229 g_object_unref (cal_factory);
231 cal_connection_closed_id = 0;
238 gdbus_cal_factory_closed_cb (GDBusConnection *connection,
239 gboolean remote_peer_vanished,
247 gdbus_cal_factory_disconnect (connection);
250 unwrap_dbus_error (g_error_copy (error), &err);
253 g_debug ("GDBus connection is closed%s: %s", remote_peer_vanished ? ", remote peer vanished" : "", err->message);
255 } else if (active_cal_clients) {
256 g_debug ("GDBus connection is closed%s", remote_peer_vanished ? ", remote peer vanished" : "");
263 gdbus_cal_factory_connection_gone_cb (GDBusConnection *connection,
264 const gchar *sender_name,
265 const gchar *object_path,
266 const gchar *interface_name,
267 const gchar *signal_name,
268 GVariant *parameters,
271 /* signal subscription takes care of correct parameters,
272 * thus just do what is to be done here */
273 gdbus_cal_factory_closed_cb (connection, TRUE, NULL, user_data);
277 gdbus_cal_factory_activate (GCancellable *cancellable,
280 GDBusConnection *connection;
284 if (G_LIKELY (cal_factory != NULL)) {
289 cal_factory = e_gdbus_cal_factory_proxy_new_for_bus_sync (
291 G_DBUS_PROXY_FLAGS_NONE,
292 CALENDAR_DBUS_SERVICE_NAME,
293 "/org/gnome/evolution/dataserver/CalendarFactory",
296 if (cal_factory == NULL) {
301 connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (cal_factory));
302 cal_connection_closed_id = g_dbus_connection_signal_subscribe (
305 "org.freedesktop.DBus", /* interface */
306 "NameOwnerChanged", /* member */
307 "/org/freedesktop/DBus", /* object_path */
308 "org.gnome.evolution.dataserver.Calendar", /* arg0 */
309 G_DBUS_SIGNAL_FLAGS_NONE,
310 gdbus_cal_factory_connection_gone_cb, NULL, NULL);
313 connection, "closed",
314 G_CALLBACK (gdbus_cal_factory_closed_cb), NULL);
321 static void gdbus_cal_client_disconnect (ECalClient *client);
324 * Called when the calendar server dies.
327 gdbus_cal_client_closed_cb (GDBusConnection *connection,
328 gboolean remote_peer_vanished,
334 g_assert (E_IS_CAL_CLIENT (client));
337 unwrap_dbus_error (g_error_copy (error), &err);
340 g_debug (G_STRLOC ": ECalClient GDBus connection is closed%s: %s", remote_peer_vanished ? ", remote peer vanished" : "", err->message);
343 g_debug (G_STRLOC ": ECalClient GDBus connection is closed%s", remote_peer_vanished ? ", remote peer vanished" : "");
346 gdbus_cal_client_disconnect (client);
348 e_client_emit_backend_died (E_CLIENT (client));
352 gdbus_cal_client_connection_gone_cb (GDBusConnection *connection,
353 const gchar *sender_name,
354 const gchar *object_path,
355 const gchar *interface_name,
356 const gchar *signal_name,
357 GVariant *parameters,
360 /* signal subscription takes care of correct parameters,
361 * thus just do what is to be done here */
362 gdbus_cal_client_closed_cb (connection, TRUE, NULL, user_data);
366 gdbus_cal_client_disconnect (ECalClient *client)
368 g_return_if_fail (E_IS_CAL_CLIENT (client));
370 /* Ensure that everything relevant is NULL */
373 if (client->priv->dbus_proxy != NULL) {
374 GDBusConnection *connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (client->priv->dbus_proxy));
376 g_signal_handlers_disconnect_by_func (connection, gdbus_cal_client_closed_cb, client);
377 g_dbus_connection_signal_unsubscribe (connection, client->priv->gone_signal_id);
378 client->priv->gone_signal_id = 0;
380 e_gdbus_cal_call_close_sync (client->priv->dbus_proxy, NULL, NULL);
381 g_object_unref (client->priv->dbus_proxy);
382 client->priv->dbus_proxy = NULL;
389 backend_error_cb (EGdbusCal *object,
390 const gchar *message,
393 g_return_if_fail (E_IS_CAL_CLIENT (client));
394 g_return_if_fail (message != NULL);
396 e_client_emit_backend_error (E_CLIENT (client), message);
400 readonly_cb (EGdbusCal *object,
404 g_return_if_fail (E_IS_CAL_CLIENT (client));
406 e_client_set_readonly (E_CLIENT (client), readonly);
410 online_cb (EGdbusCal *object,
414 g_return_if_fail (E_IS_CAL_CLIENT (client));
416 e_client_set_online (E_CLIENT (client), is_online);
420 opened_cb (EGdbusCal *object,
421 const gchar * const *error_strv,
424 GError *error = NULL;
426 g_return_if_fail (E_IS_CAL_CLIENT (client));
427 g_return_if_fail (error_strv != NULL);
428 g_return_if_fail (e_gdbus_templates_decode_error (error_strv, &error));
430 e_client_emit_opened (E_CLIENT (client), error);
433 g_error_free (error);
437 free_busy_data_cb (EGdbusCal *object,
438 const gchar * const *free_busy_strv,
441 GSList *ecalcomps = NULL;
444 g_return_if_fail (E_IS_CAL_CLIENT (client));
445 g_return_if_fail (free_busy_strv != NULL);
447 for (ii = 0; free_busy_strv[ii]; ii++) {
449 icalcomponent *icalcomp;
450 icalcomponent_kind kind;
452 icalcomp = icalcomponent_new_from_string (free_busy_strv[ii]);
456 kind = icalcomponent_isa (icalcomp);
457 if (kind == ICAL_VFREEBUSY_COMPONENT) {
458 comp = e_cal_component_new ();
459 if (!e_cal_component_set_icalcomponent (comp, icalcomp)) {
460 icalcomponent_free (icalcomp);
461 g_object_unref (G_OBJECT (comp));
465 ecalcomps = g_slist_prepend (ecalcomps, comp);
467 icalcomponent_free (icalcomp);
471 ecalcomps = g_slist_reverse (ecalcomps);
473 g_signal_emit (client, signals[FREE_BUSY_DATA], 0, ecalcomps);
475 e_client_util_free_object_slist (ecalcomps);
479 backend_property_changed_cb (EGdbusCal *object,
480 const gchar * const *name_value_strv,
483 gchar *prop_name = NULL, *prop_value = NULL;
485 g_return_if_fail (E_IS_CAL_CLIENT (client));
486 g_return_if_fail (name_value_strv != NULL);
487 g_return_if_fail (e_gdbus_templates_decode_two_strings (name_value_strv, &prop_name, &prop_value));
488 g_return_if_fail (prop_name != NULL);
489 g_return_if_fail (*prop_name);
490 g_return_if_fail (prop_value != NULL);
492 e_client_emit_backend_property_changed (E_CLIENT (client), prop_name, prop_value);
498 static EDataCalObjType
499 convert_type (ECalClientSourceType type)
502 case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
504 case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
506 case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
516 * Converts a GSList of icalcomponents into a NULL-terminated array of
517 * valid UTF-8 strings, suitable for sending over DBus.
520 icalcomponent_slist_to_utf8_icomp_array (GSList *icalcomponents)
526 array = g_new0 (gchar *, g_slist_length (icalcomponents) + 1);
527 for (l = icalcomponents; l != NULL; l = l->next) {
528 gchar *comp_str = icalcomponent_as_ical_string_r ((icalcomponent *) l->data);
529 array[i++] = e_util_utf8_make_valid (comp_str);
537 * Converts a GSList of icalcomponents into a GSList of strings.
540 icalcomponent_slist_to_string_slist (GSList *icalcomponents)
542 GSList *strings = NULL;
545 for (l = icalcomponents; l != NULL; l = l->next) {
546 strings = g_slist_prepend (strings, icalcomponent_as_ical_string_r ((icalcomponent *) l->data));
549 return g_slist_reverse (strings);
553 cal_client_get_backend_property_from_cache_finish (EClient *client,
554 GAsyncResult *result,
558 GSimpleAsyncResult *simple;
559 GError *local_error = NULL;
561 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
562 g_return_val_if_fail (result != NULL, FALSE);
563 g_return_val_if_fail (prop_value != NULL, FALSE);
564 g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (client), cal_client_get_backend_property_from_cache_finish), FALSE);
566 simple = G_SIMPLE_ASYNC_RESULT (result);
568 if (g_simple_async_result_propagate_error (simple, &local_error)) {
569 e_client_unwrap_dbus_error (client, local_error, error);
573 *prop_value = g_strdup (g_simple_async_result_get_op_res_gpointer (simple));
575 return *prop_value != NULL;
579 cal_client_dispose (GObject *object)
583 client = E_CLIENT (object);
585 e_client_cancel_all (client);
587 gdbus_cal_client_disconnect (E_CAL_CLIENT (client));
589 /* Chain up to parent's dispose() method. */
590 G_OBJECT_CLASS (e_cal_client_parent_class)->dispose (object);
594 cal_client_finalize (GObject *object)
597 ECalClientPrivate *priv;
599 client = E_CAL_CLIENT (object);
603 g_free (priv->cache_dir);
604 priv->cache_dir = NULL;
606 if (priv->default_zone && priv->default_zone != icaltimezone_get_utc_timezone ())
607 icaltimezone_free (priv->default_zone, 1);
608 priv->default_zone = NULL;
610 g_mutex_lock (&priv->zone_cache_lock);
611 g_hash_table_destroy (priv->zone_cache);
612 priv->zone_cache = NULL;
613 g_mutex_unlock (&priv->zone_cache_lock);
614 g_mutex_clear (&priv->zone_cache_lock);
616 /* Chain up to parent's finalize() method. */
617 G_OBJECT_CLASS (e_cal_client_parent_class)->finalize (object);
620 active_cal_clients--;
621 if (!active_cal_clients)
622 gdbus_cal_factory_disconnect (NULL);
627 cal_client_get_dbus_proxy (EClient *client)
629 ECalClientPrivate *priv;
631 priv = E_CAL_CLIENT_GET_PRIVATE (client);
633 return priv->dbus_proxy;
637 cal_client_unwrap_dbus_error (EClient *client,
641 unwrap_dbus_error (dbus_error, out_error);
645 cal_client_retrieve_capabilities (EClient *client,
646 GCancellable *cancellable,
647 GAsyncReadyCallback callback,
650 g_return_if_fail (E_IS_CAL_CLIENT (client));
652 e_client_get_backend_property (client, CLIENT_BACKEND_PROPERTY_CAPABILITIES, cancellable, callback, user_data);
656 cal_client_retrieve_capabilities_finish (EClient *client,
657 GAsyncResult *result,
658 gchar **capabilities,
661 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
663 return e_client_get_backend_property_finish (client, result, capabilities, error);
667 cal_client_retrieve_capabilities_sync (EClient *client,
668 gchar **capabilities,
669 GCancellable *cancellable,
672 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
674 return e_client_get_backend_property_sync (client, CLIENT_BACKEND_PROPERTY_CAPABILITIES, capabilities, cancellable, error);
678 cal_client_get_backend_property (EClient *client,
679 const gchar *prop_name,
680 GCancellable *cancellable,
681 GAsyncReadyCallback callback,
686 prop_value = e_client_get_backend_property_from_cache (client, prop_name);
688 e_client_finish_async_without_dbus (client, cancellable, callback, user_data, cal_client_get_backend_property_from_cache_finish, prop_value, g_free);
690 e_client_proxy_call_string_with_res_op_data (
691 client, prop_name, cancellable, callback, user_data, cal_client_get_backend_property, prop_name,
692 e_gdbus_cal_call_get_backend_property,
693 NULL, NULL, e_gdbus_cal_call_get_backend_property_finish, NULL, NULL);
698 cal_client_get_backend_property_finish (EClient *client,
699 GAsyncResult *result,
706 g_return_val_if_fail (prop_value != NULL, FALSE);
708 if (g_simple_async_result_get_source_tag (G_SIMPLE_ASYNC_RESULT (result)) == cal_client_get_backend_property_from_cache_finish) {
709 res = cal_client_get_backend_property_from_cache_finish (client, result, &str, error);
711 res = e_client_proxy_call_finish_string (client, result, &str, error, cal_client_get_backend_property);
713 const gchar *prop_name = g_object_get_data (G_OBJECT (result), "res-op-data");
715 if (prop_name && *prop_name)
716 e_client_update_backend_property_cache (client, prop_name, str);
726 cal_client_get_backend_property_sync (EClient *client,
727 const gchar *prop_name,
729 GCancellable *cancellable,
732 ECalClient *cal_client;
736 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
738 cal_client = E_CAL_CLIENT (client);
740 if (cal_client->priv->dbus_proxy == NULL) {
741 set_proxy_gone_error (error);
745 prop_val = e_client_get_backend_property_from_cache (client, prop_name);
747 g_return_val_if_fail (prop_value != NULL, FALSE);
749 *prop_value = prop_val;
754 res = e_client_proxy_call_sync_string__string (client, prop_name, prop_value, cancellable, error, e_gdbus_cal_call_get_backend_property_sync);
756 if (res && prop_value)
757 e_client_update_backend_property_cache (client, prop_name, *prop_value);
763 cal_client_set_backend_property (EClient *client,
764 const gchar *prop_name,
765 const gchar *prop_value,
766 GCancellable *cancellable,
767 GAsyncReadyCallback callback,
770 gchar **prop_name_value;
772 prop_name_value = e_gdbus_cal_encode_set_backend_property (prop_name, prop_value);
774 e_client_proxy_call_strv (
775 client, (const gchar * const *) prop_name_value, cancellable, callback, user_data, cal_client_set_backend_property,
776 e_gdbus_cal_call_set_backend_property,
777 e_gdbus_cal_call_set_backend_property_finish, NULL, NULL, NULL, NULL);
779 g_strfreev (prop_name_value);
783 cal_client_set_backend_property_finish (EClient *client,
784 GAsyncResult *result,
787 return e_client_proxy_call_finish_void (client, result, error, cal_client_set_backend_property);
791 cal_client_set_backend_property_sync (EClient *client,
792 const gchar *prop_name,
793 const gchar *prop_value,
794 GCancellable *cancellable,
797 ECalClient *cal_client;
799 gchar **prop_name_value;
801 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
803 cal_client = E_CAL_CLIENT (client);
805 if (cal_client->priv->dbus_proxy == NULL) {
806 set_proxy_gone_error (error);
810 prop_name_value = e_gdbus_cal_encode_set_backend_property (prop_name, prop_value);
811 res = e_client_proxy_call_sync_strv__void (client, (const gchar * const *) prop_name_value, cancellable, error, e_gdbus_cal_call_set_backend_property_sync);
812 g_strfreev (prop_name_value);
818 cal_client_open (EClient *client,
819 gboolean only_if_exists,
820 GCancellable *cancellable,
821 GAsyncReadyCallback callback,
824 e_client_proxy_call_boolean (
825 client, only_if_exists, cancellable, callback, user_data, cal_client_open,
826 e_gdbus_cal_call_open,
827 e_gdbus_cal_call_open_finish, NULL, NULL, NULL, NULL);
831 cal_client_open_finish (EClient *client,
832 GAsyncResult *result,
835 return e_client_proxy_call_finish_void (client, result, error, cal_client_open);
839 cal_client_open_sync (EClient *client,
840 gboolean only_if_exists,
841 GCancellable *cancellable,
844 ECalClient *cal_client;
846 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
848 cal_client = E_CAL_CLIENT (client);
850 if (cal_client->priv->dbus_proxy == NULL) {
851 set_proxy_gone_error (error);
855 return e_client_proxy_call_sync_boolean__void (client, only_if_exists, cancellable, error, e_gdbus_cal_call_open_sync);
859 cal_client_refresh (EClient *client,
860 GCancellable *cancellable,
861 GAsyncReadyCallback callback,
864 e_client_proxy_call_void (
865 client, cancellable, callback, user_data, cal_client_refresh,
866 e_gdbus_cal_call_refresh,
867 e_gdbus_cal_call_refresh_finish, NULL, NULL, NULL, NULL);
871 cal_client_refresh_finish (EClient *client,
872 GAsyncResult *result,
875 return e_client_proxy_call_finish_void (client, result, error, cal_client_refresh);
879 cal_client_refresh_sync (EClient *client,
880 GCancellable *cancellable,
883 ECalClient *cal_client;
885 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
887 cal_client = E_CAL_CLIENT (client);
889 if (cal_client->priv->dbus_proxy == NULL) {
890 set_proxy_gone_error (error);
894 return e_client_proxy_call_sync_void__void (client, cancellable, error, e_gdbus_cal_call_refresh_sync);
898 cal_client_add_cached_timezone (ETimezoneCache *cache,
901 ECalClientPrivate *priv;
903 gboolean timezone_added = FALSE;
905 priv = E_CAL_CLIENT_GET_PRIVATE (cache);
907 g_mutex_lock (&priv->zone_cache_lock);
909 tzid = icaltimezone_get_tzid (zone);
911 /* Avoid replacing an existing cache entry. We don't want to
912 * invalidate any icaltimezone pointers that may have already
913 * been returned through e_timezone_cache_get_timezone(). */
914 if (!g_hash_table_contains (priv->zone_cache, tzid)) {
915 icalcomponent *icalcomp;
916 icaltimezone *cached_zone;
918 cached_zone = icaltimezone_new ();
919 icalcomp = icaltimezone_get_component (zone);
920 icalcomp = icalcomponent_new_clone (icalcomp);
921 icaltimezone_set_component (cached_zone, icalcomp);
923 g_hash_table_insert (
925 g_strdup (tzid), cached_zone);
927 timezone_added = TRUE;
930 g_mutex_unlock (&priv->zone_cache_lock);
932 /* FIXME Should emit this from an idle GSource on
933 * a stored GMainContext, but we don't have
934 * a stored GMainContext. Check back after
935 * the D-Bus API rewrite. */
937 g_signal_emit_by_name (cache, "timezone-added", zone);
940 static icaltimezone *
941 cal_client_get_cached_timezone (ETimezoneCache *cache,
944 ECalClientPrivate *priv;
945 icaltimezone *zone = NULL;
946 icaltimezone *builtin_zone = NULL;
947 icalcomponent *icalcomp;
949 const gchar *builtin_tzid;
951 priv = E_CAL_CLIENT_GET_PRIVATE (cache);
953 if (g_str_equal (tzid, "UTC"))
954 return icaltimezone_get_utc_timezone ();
956 g_mutex_lock (&priv->zone_cache_lock);
958 /* See if we already have it in the cache. */
959 zone = g_hash_table_lookup (priv->zone_cache, tzid);
964 /* Try to replace the original time zone with a more complete
965 * and/or potentially updated built-in time zone. Note this also
966 * applies to TZIDs which match built-in time zones exactly: they
967 * are extracted via icaltimezone_get_builtin_timezone_from_tzid()
968 * below without a roundtrip to the backend. */
970 builtin_tzid = e_cal_match_tzid (tzid);
972 if (builtin_tzid != NULL)
973 builtin_zone = icaltimezone_get_builtin_timezone_from_tzid (
976 if (builtin_zone == NULL)
979 /* Use the built-in time zone *and* rename it. Likely the caller
980 * is asking for a specific TZID because it has an event with such
981 * a TZID. Returning an icaltimezone with a different TZID would
982 * lead to broken VCALENDARs in the caller. */
984 icalcomp = icaltimezone_get_component (builtin_zone);
985 icalcomp = icalcomponent_new_clone (icalcomp);
987 prop = icalcomponent_get_first_property (
988 icalcomp, ICAL_ANY_PROPERTY);
990 while (prop != NULL) {
991 if (icalproperty_isa (prop) == ICAL_TZID_PROPERTY) {
992 icalproperty_set_value_from_string (prop, tzid, "NO");
996 prop = icalcomponent_get_next_property (
997 icalcomp, ICAL_ANY_PROPERTY);
1000 if (icalcomp != NULL) {
1001 zone = icaltimezone_new ();
1002 if (icaltimezone_set_component (zone, icalcomp)) {
1003 tzid = icaltimezone_get_tzid (zone);
1004 g_hash_table_insert (
1006 g_strdup (tzid), zone);
1008 icalcomponent_free (icalcomp);
1009 icaltimezone_free (zone, 1);
1015 g_mutex_unlock (&priv->zone_cache_lock);
1021 cal_client_list_cached_timezones (ETimezoneCache *cache)
1023 ECalClientPrivate *priv;
1026 priv = E_CAL_CLIENT_GET_PRIVATE (cache);
1028 g_mutex_lock (&priv->zone_cache_lock);
1030 list = g_hash_table_get_values (priv->zone_cache);
1032 g_mutex_unlock (&priv->zone_cache_lock);
1038 e_cal_client_class_init (ECalClientClass *class)
1040 GObjectClass *object_class;
1041 EClientClass *client_class;
1043 g_type_class_add_private (class, sizeof (ECalClientPrivate));
1045 object_class = G_OBJECT_CLASS (class);
1046 object_class->dispose = cal_client_dispose;
1047 object_class->finalize = cal_client_finalize;
1049 client_class = E_CLIENT_CLASS (class);
1050 client_class->get_dbus_proxy = cal_client_get_dbus_proxy;
1051 client_class->unwrap_dbus_error = cal_client_unwrap_dbus_error;
1052 client_class->retrieve_capabilities = cal_client_retrieve_capabilities;
1053 client_class->retrieve_capabilities_finish = cal_client_retrieve_capabilities_finish;
1054 client_class->retrieve_capabilities_sync = cal_client_retrieve_capabilities_sync;
1055 client_class->get_backend_property = cal_client_get_backend_property;
1056 client_class->get_backend_property_finish = cal_client_get_backend_property_finish;
1057 client_class->get_backend_property_sync = cal_client_get_backend_property_sync;
1058 client_class->set_backend_property = cal_client_set_backend_property;
1059 client_class->set_backend_property_finish = cal_client_set_backend_property_finish;
1060 client_class->set_backend_property_sync = cal_client_set_backend_property_sync;
1061 client_class->open = cal_client_open;
1062 client_class->open_finish = cal_client_open_finish;
1063 client_class->open_sync = cal_client_open_sync;
1064 client_class->refresh = cal_client_refresh;
1065 client_class->refresh_finish = cal_client_refresh_finish;
1066 client_class->refresh_sync = cal_client_refresh_sync;
1068 signals[FREE_BUSY_DATA] = g_signal_new (
1070 G_OBJECT_CLASS_TYPE (class),
1072 G_STRUCT_OFFSET (ECalClientClass, free_busy_data),
1074 g_cclosure_marshal_VOID__POINTER,
1080 e_cal_client_timezone_cache_init (ETimezoneCacheInterface *interface)
1082 interface->add_timezone = cal_client_add_cached_timezone;
1083 interface->get_timezone = cal_client_get_cached_timezone;
1084 interface->list_timezones = cal_client_list_cached_timezones;
1088 e_cal_client_init (ECalClient *client)
1090 GHashTable *zone_cache;
1092 zone_cache = g_hash_table_new_full (
1093 (GHashFunc) g_str_hash,
1094 (GEqualFunc) g_str_equal,
1095 (GDestroyNotify) g_free,
1096 (GDestroyNotify) free_zone_cb);
1099 active_cal_clients++;
1102 client->priv = E_CAL_CLIENT_GET_PRIVATE (client);
1103 client->priv->source_type = E_CAL_CLIENT_SOURCE_TYPE_LAST;
1104 client->priv->default_zone = icaltimezone_get_utc_timezone ();
1105 g_mutex_init (&client->priv->zone_cache_lock);
1106 client->priv->zone_cache = zone_cache;
1111 * @source: An #ESource pointer
1112 * @source_type: source type of the calendar
1113 * @error: A #GError pointer
1115 * Creates a new #ECalClient corresponding to the given source. There are
1116 * only two operations that are valid on this calendar at this point:
1117 * e_client_open(), and e_client_remove().
1119 * Returns: a new but unopened #ECalClient.
1124 e_cal_client_new (ESource *source,
1125 ECalClientSourceType source_type,
1130 GDBusConnection *connection;
1133 gchar *object_path = NULL;
1135 g_return_val_if_fail (E_IS_SOURCE (source), NULL);
1136 g_return_val_if_fail (
1137 source_type == E_CAL_CLIENT_SOURCE_TYPE_EVENTS ||
1138 source_type == E_CAL_CLIENT_SOURCE_TYPE_TASKS ||
1139 source_type == E_CAL_CLIENT_SOURCE_TYPE_MEMOS, NULL);
1142 /* XXX Oops, e_cal_client_new() forgot to take a GCancellable. */
1143 if (!gdbus_cal_factory_activate (NULL, &err)) {
1146 unwrap_dbus_error (err, &err);
1147 g_warning ("%s: Failed to run calendar factory: %s", G_STRFUNC, err->message);
1148 g_propagate_error (error, err);
1150 g_warning ("%s: Failed to run calendar factory: Unknown error", G_STRFUNC);
1151 g_set_error_literal (error, E_CLIENT_ERROR, E_CLIENT_ERROR_DBUS_ERROR, _("Failed to run calendar factory"));
1157 uid = e_source_get_uid (source);
1158 strv = e_gdbus_cal_factory_encode_get_cal (uid, convert_type (source_type));
1160 g_set_error_literal (error, E_CLIENT_ERROR, E_CLIENT_ERROR_OTHER_ERROR, _("Other error"));
1164 client = g_object_new (E_TYPE_CAL_CLIENT, "source", source, NULL);
1165 client->priv->source_type = source_type;
1169 e_gdbus_cal_factory_call_get_cal_sync (
1170 G_DBUS_PROXY (cal_factory),
1171 (const gchar * const *) strv,
1172 &object_path, NULL, &err);
1177 g_return_val_if_fail (
1178 ((object_path != NULL) && (err == NULL)) ||
1179 ((object_path == NULL) && (err != NULL)), NULL);
1182 unwrap_dbus_error (err, &err);
1183 g_propagate_error (error, err);
1184 g_object_unref (client);
1188 connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (cal_factory));
1190 client->priv->dbus_proxy = G_DBUS_PROXY (e_gdbus_cal_proxy_new_sync (
1192 G_DBUS_PROXY_FLAGS_NONE,
1193 CALENDAR_DBUS_SERVICE_NAME,
1197 g_free (object_path);
1200 g_return_val_if_fail (
1201 ((object_path != NULL) && (err == NULL)) ||
1202 ((object_path == NULL) && (err != NULL)), NULL);
1205 unwrap_dbus_error (err, &err);
1206 g_propagate_error (error, err);
1207 g_object_unref (client);
1211 client->priv->gone_signal_id = g_dbus_connection_signal_subscribe (
1213 "org.freedesktop.DBus", /* sender */
1214 "org.freedesktop.DBus", /* interface */
1215 "NameOwnerChanged", /* member */
1216 "/org/freedesktop/DBus", /* object_path */
1217 "org.gnome.evolution.dataserver.Calendar", /* arg0 */
1218 G_DBUS_SIGNAL_FLAGS_NONE,
1219 gdbus_cal_client_connection_gone_cb, client, NULL);
1222 connection, "closed",
1223 G_CALLBACK (gdbus_cal_client_closed_cb), client);
1226 client->priv->dbus_proxy, "backend_error",
1227 G_CALLBACK (backend_error_cb), client);
1230 client->priv->dbus_proxy, "readonly",
1231 G_CALLBACK (readonly_cb), client);
1234 client->priv->dbus_proxy, "online",
1235 G_CALLBACK (online_cb), client);
1238 client->priv->dbus_proxy, "opened",
1239 G_CALLBACK (opened_cb), client);
1242 client->priv->dbus_proxy, "free-busy-data",
1243 G_CALLBACK (free_busy_data_cb), client);
1246 client->priv->dbus_proxy, "backend-property-changed",
1247 G_CALLBACK (backend_property_changed_cb), client);
1253 * e_cal_client_get_source_type:
1254 * @client: A calendar client.
1256 * Gets the source type of the calendar client.
1258 * Returns: an #ECalClientSourceType value corresponding
1259 * to the source type of the calendar client.
1263 ECalClientSourceType
1264 e_cal_client_get_source_type (ECalClient *client)
1266 g_return_val_if_fail (E_IS_CAL_CLIENT (client), E_CAL_CLIENT_SOURCE_TYPE_LAST);
1268 return client->priv->source_type;
1272 * e_cal_client_get_local_attachment_store:
1273 * @client: A calendar client.
1275 * Queries the URL where the calendar attachments are
1276 * serialized in the local filesystem. This enable clients
1277 * to operate with the reference to attachments rather than the data itself
1278 * unless it specifically uses the attachments for open/sending
1281 * Returns: The URL where the attachments are serialized in the
1287 e_cal_client_get_local_attachment_store (ECalClient *client)
1289 gchar *cache_dir = NULL;
1290 GError *error = NULL;
1292 g_return_val_if_fail (E_IS_CAL_CLIENT (client), NULL);
1294 if (client->priv->cache_dir || !client->priv->dbus_proxy)
1295 return client->priv->cache_dir;
1297 cache_dir = e_client_get_backend_property_from_cache (E_CLIENT (client), CLIENT_BACKEND_PROPERTY_CACHE_DIR);
1299 e_gdbus_cal_call_get_backend_property_sync (client->priv->dbus_proxy, CLIENT_BACKEND_PROPERTY_CACHE_DIR, &cache_dir, NULL, &error);
1301 if (error == NULL) {
1302 client->priv->cache_dir = cache_dir;
1304 unwrap_dbus_error (error, &error);
1305 g_warning ("%s", error->message);
1306 g_error_free (error);
1309 return client->priv->cache_dir;
1312 /* icaltimezone_copy does a shallow copy while icaltimezone_free tries to free the entire
1313 * the contents inside the structure with libical 0.43. Use this, till eds allows older libical.
1315 static icaltimezone *
1316 copy_timezone (icaltimezone *ozone)
1318 icaltimezone *zone = NULL;
1321 tzid = icaltimezone_get_tzid (ozone);
1323 if (g_strcmp0 (tzid, "UTC") != 0) {
1324 icalcomponent *comp;
1326 comp = icaltimezone_get_component (ozone);
1328 zone = icaltimezone_new ();
1329 icaltimezone_set_component (zone, icalcomponent_new_clone (comp));
1334 zone = icaltimezone_get_utc_timezone ();
1340 * e_cal_client_set_default_timezone:
1341 * @client: A calendar client.
1342 * @zone: A timezone object.
1344 * Sets the default timezone to use to resolve DATE and floating DATE-TIME
1345 * values. This will typically be from the user's timezone setting. Call this
1346 * before using any other object fetching functions.
1351 e_cal_client_set_default_timezone (ECalClient *client, /* const */ icaltimezone *zone)
1353 g_return_if_fail (E_IS_CAL_CLIENT (client));
1354 g_return_if_fail (zone != NULL);
1356 if (client->priv->default_zone != icaltimezone_get_utc_timezone ())
1357 icaltimezone_free (client->priv->default_zone, 1);
1359 if (zone == icaltimezone_get_utc_timezone ())
1360 client->priv->default_zone = zone;
1362 client->priv->default_zone = copy_timezone (zone);
1366 * e_cal_client_get_default_timezone:
1367 * @client: A calendar client.
1369 * Returns: Default timezone previously set with e_cal_client_set_default_timezone().
1370 * Returned pointer is owned by the @client and should not be freed.
1374 /* const */ icaltimezone *
1375 e_cal_client_get_default_timezone (ECalClient *client)
1377 g_return_val_if_fail (E_IS_CAL_CLIENT (client), NULL);
1379 return client->priv->default_zone;
1383 * e_cal_client_check_one_alarm_only:
1384 * @client: A calendar client.
1386 * Checks if a calendar supports only one alarm per component.
1388 * Returns: TRUE if the calendar allows only one alarm, FALSE otherwise.
1393 e_cal_client_check_one_alarm_only (ECalClient *client)
1395 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
1397 return e_client_check_capability (E_CLIENT (client), CAL_STATIC_CAPABILITY_ONE_ALARM_ONLY);
1401 * e_cal_client_check_save_schedules:
1402 * @client: A calendar client.
1404 * Checks whether the calendar saves schedules.
1406 * Returns: TRUE if it saves schedules, FALSE otherwise.
1411 e_cal_client_check_save_schedules (ECalClient *client)
1413 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
1415 return e_client_check_capability (E_CLIENT (client), CAL_STATIC_CAPABILITY_SAVE_SCHEDULES);
1419 * e_cal_client_check_organizer_must_attend:
1420 * @client: A calendar client.
1422 * Checks if a calendar forces organizers of meetings to be also attendees.
1424 * Returns: TRUE if the calendar forces organizers to attend meetings,
1430 e_cal_client_check_organizer_must_attend (ECalClient *client)
1432 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
1434 return e_client_check_capability (E_CLIENT (client), CAL_STATIC_CAPABILITY_ORGANIZER_MUST_ATTEND);
1438 * e_cal_client_check_organizer_must_accept:
1439 * @client: A calendar client.
1441 * Checks whether a calendar requires organizer to accept their attendance to
1444 * Returns: TRUE if the calendar requires organizers to accept, FALSE
1450 e_cal_client_check_organizer_must_accept (ECalClient *client)
1452 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
1454 return e_client_check_capability (E_CLIENT (client), CAL_STATIC_CAPABILITY_ORGANIZER_MUST_ACCEPT);
1458 * e_cal_client_check_recurrences_no_master:
1459 * @client: A calendar client.
1461 * Checks if the calendar has a master object for recurrences.
1463 * Returns: TRUE if the calendar has a master object for recurrences,
1469 e_cal_client_check_recurrences_no_master (ECalClient *client)
1471 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
1473 return e_client_check_capability (E_CLIENT (client), CAL_STATIC_CAPABILITY_RECURRENCES_NO_MASTER);
1477 * e_cal_client_free_icalcomp_slist:
1478 * @icalcomps: (element-type icalcomponent): list of icalcomponent objects
1480 * Frees each element of the @icalcomps list and the list itself.
1481 * Each element is an object of type #icalcomponent.
1486 e_cal_client_free_icalcomp_slist (GSList *icalcomps)
1488 g_slist_foreach (icalcomps, (GFunc) icalcomponent_free, NULL);
1489 g_slist_free (icalcomps);
1493 * e_cal_client_free_ecalcomp_slist:
1494 * @ecalcomps: (element-type ECalComponent): list of #ECalComponent objects
1496 * Frees each element of the @ecalcomps list and the list itself.
1497 * Each element is an object of type #ECalComponent.
1502 e_cal_client_free_ecalcomp_slist (GSList *ecalcomps)
1504 g_slist_foreach (ecalcomps, (GFunc) g_object_unref, NULL);
1505 g_slist_free (ecalcomps);
1509 * e_cal_client_resolve_tzid_cb:
1510 * @tzid: ID of the timezone to resolve.
1511 * @data: Closure data for the callback, in this case #ECalClient.
1513 * Resolves TZIDs for the recurrence generator.
1515 * Returns: The timezone identified by the @tzid argument, or %NULL if
1516 * it could not be found.
1521 e_cal_client_resolve_tzid_cb (const gchar *tzid,
1524 ECalClient *client = data;
1525 icaltimezone *zone = NULL;
1526 GError *error = NULL;
1528 g_return_val_if_fail (E_IS_CAL_CLIENT (client), NULL);
1530 e_cal_client_get_timezone_sync (client, tzid, &zone, NULL, &error);
1533 g_debug ("%s: Failed to find '%s' timezone: %s", G_STRFUNC, tzid, error->message);
1534 g_error_free (error);
1540 struct comp_instance {
1541 ECalComponent *comp;
1546 struct instances_info {
1548 icaltimezone *start_zone;
1549 icaltimezone *end_zone;
1552 /* Called from cal_recur_generate_instances(); adds an instance to the list */
1554 add_instance (ECalComponent *comp,
1560 struct comp_instance *ci;
1561 icalcomponent *icalcomp;
1562 struct instances_info *instances_hold;
1564 instances_hold = data;
1565 list = instances_hold->instances;
1567 ci = g_new (struct comp_instance, 1);
1569 icalcomp = icalcomponent_new_clone (e_cal_component_get_icalcomponent (comp));
1571 /* add the instance to the list */
1572 ci->comp = e_cal_component_new ();
1573 e_cal_component_set_icalcomponent (ci->comp, icalcomp);
1575 /* make sure we return an instance */
1576 if (e_cal_util_component_has_recurrences (icalcomp) &&
1577 !(icalcomponent_get_first_property (icalcomp, ICAL_RECURRENCEID_PROPERTY))) {
1578 ECalComponentRange *range;
1579 struct icaltimetype itt;
1580 ECalComponentDateTime dtstart, dtend;
1582 /* update DTSTART */
1583 dtstart.value = NULL;
1584 dtstart.tzid = NULL;
1586 e_cal_component_get_dtstart (comp, &dtstart);
1588 if (instances_hold->start_zone) {
1589 itt = icaltime_from_timet_with_zone (start, dtstart.value && dtstart.value->is_date, instances_hold->start_zone);
1590 g_free ((gchar *) dtstart.tzid);
1591 dtstart.tzid = g_strdup (icaltimezone_get_tzid (instances_hold->start_zone));
1593 itt = icaltime_from_timet (start, dtstart.value && dtstart.value->is_date);
1595 g_free ((gchar *) dtstart.tzid);
1596 dtstart.tzid = NULL;
1600 g_free (dtstart.value);
1601 dtstart.value = &itt;
1602 e_cal_component_set_dtstart (ci->comp, &dtstart);
1604 /* set the RECUR-ID for the instance */
1605 range = g_new0 (ECalComponentRange, 1);
1606 range->type = E_CAL_COMPONENT_RANGE_SINGLE;
1607 range->datetime = dtstart;
1609 e_cal_component_set_recurid (ci->comp, range);
1612 g_free ((gchar *) dtstart.tzid);
1618 e_cal_component_get_dtend (comp, &dtend);
1620 if (instances_hold->end_zone) {
1621 itt = icaltime_from_timet_with_zone (end, dtend.value && dtend.value->is_date, instances_hold->end_zone);
1622 g_free ((gchar *) dtend.tzid);
1623 dtend.tzid = g_strdup (icaltimezone_get_tzid (instances_hold->end_zone));
1625 itt = icaltime_from_timet (end, dtend.value && dtend.value->is_date);
1627 g_free ((gchar *) dtend.tzid);
1632 g_free (dtend.value);
1634 e_cal_component_set_dtend (ci->comp, &dtend);
1636 g_free ((gchar *) dtend.tzid);
1642 *list = g_slist_prepend (*list, ci);
1647 /* Used from g_slist_sort(); compares two struct comp_instance structures */
1649 compare_comp_instance (gconstpointer a,
1652 const struct comp_instance *cia, *cib;
1658 diff = cia->start - cib->start;
1659 return (diff < 0) ? -1 : (diff > 0) ? 1 : 0;
1663 process_detached_instances (GSList *instances,
1664 GSList *detached_instances)
1666 struct comp_instance *ci, *cid;
1667 GSList *dl, *unprocessed_instances = NULL;
1669 for (dl = detached_instances; dl != NULL; dl = dl->next) {
1673 ECalComponentRange recur_id, instance_recur_id;
1676 recur_id.type = E_CAL_COMPONENT_RANGE_SINGLE;
1677 instance_recur_id.type = E_CAL_COMPONENT_RANGE_SINGLE;
1680 e_cal_component_get_uid (cid->comp, &uid);
1681 e_cal_component_get_recurid (cid->comp, &recur_id);
1683 /* search for coincident instances already expanded */
1684 for (il = instances; il != NULL; il = il->next) {
1685 const gchar *instance_uid;
1689 e_cal_component_get_uid (ci->comp, &instance_uid);
1690 e_cal_component_get_recurid (ci->comp, &instance_recur_id);
1691 if (strcmp (uid, instance_uid) == 0) {
1692 gchar *i_rid = NULL, *d_rid = NULL;
1694 i_rid = e_cal_component_get_recurid_as_string (ci->comp);
1695 d_rid = e_cal_component_get_recurid_as_string (cid->comp);
1697 if (i_rid && d_rid && strcmp (i_rid, d_rid) == 0) {
1698 g_object_unref (ci->comp);
1699 ci->comp = g_object_ref (cid->comp);
1700 ci->start = cid->start;
1705 if (!instance_recur_id.datetime.value ||
1706 !recur_id.datetime.value) {
1708 * Prevent obvious segfault by ignoring missing
1709 * recurrency ids. Real problem might be elsewhere,
1710 * but anything is better than crashing...
1714 G_LOG_LEVEL_CRITICAL,
1715 "UID %s: instance RECURRENCE-ID %s + detached instance RECURRENCE-ID %s: cannot compare",
1720 e_cal_component_free_datetime (&instance_recur_id.datetime);
1725 cmp = icaltime_compare (
1726 *instance_recur_id.datetime.value,
1727 *recur_id.datetime.value);
1728 if ((recur_id.type == E_CAL_COMPONENT_RANGE_THISPRIOR && cmp <= 0) ||
1729 (recur_id.type == E_CAL_COMPONENT_RANGE_THISFUTURE && cmp >= 0)) {
1730 ECalComponent *comp;
1732 comp = e_cal_component_new ();
1733 e_cal_component_set_icalcomponent (
1735 icalcomponent_new_clone (e_cal_component_get_icalcomponent (cid->comp)));
1736 e_cal_component_set_recurid (comp, &instance_recur_id);
1738 /* replace the generated instances */
1739 g_object_unref (ci->comp);
1746 e_cal_component_free_datetime (&instance_recur_id.datetime);
1749 e_cal_component_free_datetime (&recur_id.datetime);
1752 unprocessed_instances = g_slist_prepend (unprocessed_instances, cid);
1755 /* add the unprocessed instances (ie, detached instances with no master object */
1756 while (unprocessed_instances != NULL) {
1757 cid = unprocessed_instances->data;
1758 ci = g_new0 (struct comp_instance, 1);
1759 ci->comp = g_object_ref (cid->comp);
1760 ci->start = cid->start;
1762 instances = g_slist_append (instances, ci);
1764 unprocessed_instances = g_slist_remove (unprocessed_instances, cid);
1771 generate_instances (ECalClient *client,
1775 GCancellable *cancellable,
1776 ECalRecurInstanceFn cb,
1779 GSList *instances, *detached_instances = NULL;
1781 ECalClientPrivate *priv;
1783 priv = client->priv;
1787 for (l = objects; l && !g_cancellable_is_cancelled (cancellable); l = l->next) {
1788 ECalComponent *comp;
1789 icaltimezone *default_zone;
1791 if (priv->default_zone)
1792 default_zone = priv->default_zone;
1794 default_zone = icaltimezone_get_utc_timezone ();
1797 if (e_cal_component_is_instance (comp)) {
1798 struct comp_instance *ci;
1799 ECalComponentDateTime dtstart, dtend;
1800 icaltimezone *start_zone = NULL, *end_zone = NULL;
1802 /* keep the detached instances apart */
1803 ci = g_new0 (struct comp_instance, 1);
1804 ci->comp = g_object_ref (comp);
1806 e_cal_component_get_dtstart (comp, &dtstart);
1807 e_cal_component_get_dtend (comp, &dtend);
1809 /* For DATE-TIME values with a TZID, we use
1810 * e_cal_resolve_tzid_cb to resolve the TZID.
1811 * For DATE values and DATE-TIME values without a
1812 * TZID (i.e. floating times) we use the default
1814 if (dtstart.tzid && dtstart.value && !dtstart.value->is_date) {
1815 start_zone = e_cal_client_resolve_tzid_cb (dtstart.tzid, client);
1817 start_zone = default_zone;
1819 start_zone = default_zone;
1822 if (dtend.tzid && dtend.value && !dtend.value->is_date) {
1823 end_zone = e_cal_client_resolve_tzid_cb (dtend.tzid, client);
1825 end_zone = default_zone;
1827 end_zone = default_zone;
1830 ci->start = icaltime_as_timet_with_zone (*dtstart.value, start_zone);
1833 ci->end = icaltime_as_timet_with_zone (*dtend.value, end_zone);
1834 else if (icaltime_is_date (*dtstart.value))
1835 ci->end = time_day_end (ci->start);
1837 ci->end = ci->start;
1839 e_cal_component_free_datetime (&dtstart);
1840 e_cal_component_free_datetime (&dtend);
1842 if (ci->start <= end && ci->end >= start) {
1843 detached_instances = g_slist_prepend (detached_instances, ci);
1845 /* it doesn't fit to our time range, thus skip it */
1846 g_object_unref (G_OBJECT (ci->comp));
1850 ECalComponentDateTime datetime;
1851 icaltimezone *start_zone = NULL, *end_zone = NULL;
1852 struct instances_info *instances_hold;
1854 /* Get the start timezone */
1855 e_cal_component_get_dtstart (comp, &datetime);
1857 e_cal_client_get_timezone_sync (client, datetime.tzid, &start_zone, cancellable, NULL);
1860 e_cal_component_free_datetime (&datetime);
1862 /* Get the end timezone */
1863 e_cal_component_get_dtend (comp, &datetime);
1865 e_cal_client_get_timezone_sync (client, datetime.tzid, &end_zone, cancellable, NULL);
1868 e_cal_component_free_datetime (&datetime);
1870 instances_hold = g_new0 (struct instances_info, 1);
1871 instances_hold->instances = &instances;
1872 instances_hold->start_zone = start_zone;
1873 instances_hold->end_zone = end_zone;
1875 e_cal_recur_generate_instances (
1876 comp, start, end, add_instance, instances_hold,
1877 e_cal_client_resolve_tzid_cb, client,
1880 g_free (instances_hold);
1884 g_slist_foreach (objects, (GFunc) g_object_unref, NULL);
1885 g_slist_free (objects);
1887 /* Generate instances and spew them out */
1889 if (!g_cancellable_is_cancelled (cancellable)) {
1890 instances = g_slist_sort (instances, compare_comp_instance);
1891 instances = process_detached_instances (instances, detached_instances);
1894 for (l = instances; l && !g_cancellable_is_cancelled (cancellable); l = l->next) {
1895 struct comp_instance *ci;
1900 result = (* cb) (ci->comp, ci->start, ci->end, cb_data);
1908 for (l = instances; l; l = l->next) {
1909 struct comp_instance *ci;
1912 g_object_unref (G_OBJECT (ci->comp));
1916 g_slist_free (instances);
1918 for (l = detached_instances; l; l = l->next) {
1919 struct comp_instance *ci;
1922 g_object_unref (G_OBJECT (ci->comp));
1926 g_slist_free (detached_instances);
1930 get_objects_sync (ECalClient *client,
1935 GSList *objects = NULL;
1937 /* Generate objects */
1939 GError *error = NULL;
1943 if (!e_cal_client_get_objects_for_uid_sync (client, uid, &objects, NULL, &error)) {
1944 if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_BUSY) && tries <= 10) {
1947 g_clear_error (&error);
1952 unwrap_dbus_error (error, &error);
1953 g_message ("Failed to get recurrence objects for uid %s \n", error ? error->message : "Unknown error");
1954 g_clear_error (&error);
1958 gchar *iso_start, *iso_end;
1961 iso_start = isodate_from_time_t (start);
1965 iso_end = isodate_from_time_t (end);
1971 query = g_strdup_printf (
1972 "(occur-in-time-range? (make-time \"%s\") (make-time \"%s\"))",
1973 iso_start, iso_end);
1976 if (!e_cal_client_get_object_list_as_comps_sync (client, query, &objects, NULL, NULL)) {
1986 struct get_objects_async_data
1988 GCancellable *cancellable;
1992 ECalRecurInstanceFn cb;
1994 GDestroyNotify destroy_cb_data;
1998 void (* ready_cb) (struct get_objects_async_data *goad, GSList *objects);
1999 icaltimezone *start_zone;
2000 icaltimezone *end_zone;
2001 ECalComponent *comp;
2005 free_get_objects_async_data (struct get_objects_async_data *goad)
2010 if (goad->cancellable)
2011 g_object_unref (goad->cancellable);
2012 if (goad->destroy_cb_data)
2013 goad->destroy_cb_data (goad->cb_data);
2015 g_object_unref (goad->client);
2017 g_object_unref (goad->comp);
2018 g_free (goad->query);
2023 static gboolean repeat_get_objects_for_uid_timeout_cb (gpointer user_data);
2026 got_objects_for_uid_cb (GObject *source_object,
2027 GAsyncResult *result,
2030 struct get_objects_async_data *goad = user_data;
2031 GSList *objects = NULL;
2032 GError *error = NULL;
2034 g_return_if_fail (source_object != NULL);
2035 g_return_if_fail (result != NULL);
2036 g_return_if_fail (goad != NULL);
2037 g_return_if_fail (goad->client == E_CAL_CLIENT (source_object));
2039 if (!e_cal_client_get_objects_for_uid_finish (goad->client, result, &objects, &error)) {
2040 if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED) ||
2041 g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
2042 free_get_objects_async_data (goad);
2043 g_clear_error (&error);
2047 if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_BUSY) && goad->tries < 10) {
2049 g_timeout_add (250, repeat_get_objects_for_uid_timeout_cb, goad);
2050 g_clear_error (&error);
2054 g_clear_error (&error);
2058 g_return_if_fail (goad->ready_cb != NULL);
2060 /* takes care of the objects and goad */
2061 goad->ready_cb (goad, objects);
2065 repeat_get_objects_for_uid_timeout_cb (gpointer user_data)
2067 struct get_objects_async_data *goad = user_data;
2069 g_return_val_if_fail (goad != NULL, FALSE);
2071 e_cal_client_get_objects_for_uid (goad->client, goad->uid, goad->cancellable, got_objects_for_uid_cb, goad);
2076 static gboolean repeat_get_object_list_as_comps_timeout_cb (gpointer user_data);
2079 got_object_list_as_comps_cb (GObject *source_object,
2080 GAsyncResult *result,
2083 struct get_objects_async_data *goad = user_data;
2084 GSList *objects = NULL;
2085 GError *error = NULL;
2087 g_return_if_fail (source_object != NULL);
2088 g_return_if_fail (result != NULL);
2089 g_return_if_fail (goad != NULL);
2090 g_return_if_fail (goad->client == E_CAL_CLIENT (source_object));
2092 if (!e_cal_client_get_object_list_as_comps_finish (goad->client, result, &objects, &error)) {
2093 if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED) ||
2094 g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
2095 free_get_objects_async_data (goad);
2096 g_clear_error (&error);
2100 if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_BUSY) && goad->tries < 10) {
2102 g_timeout_add (250, repeat_get_object_list_as_comps_timeout_cb, goad);
2103 g_clear_error (&error);
2107 g_clear_error (&error);
2111 g_return_if_fail (goad->ready_cb != NULL);
2113 /* takes care of the objects and goad */
2114 goad->ready_cb (goad, objects);
2118 repeat_get_object_list_as_comps_timeout_cb (gpointer user_data)
2120 struct get_objects_async_data *goad = user_data;
2122 g_return_val_if_fail (goad != NULL, FALSE);
2124 e_cal_client_get_object_list_as_comps (goad->client, goad->query, goad->cancellable, got_object_list_as_comps_cb, goad);
2129 /* ready_cb may take care of both arguments, goad and objects; objects can be also NULL */
2131 get_objects_async (void (*ready_cb) (struct get_objects_async_data *goad,
2133 struct get_objects_async_data *goad)
2135 g_return_if_fail (ready_cb != NULL);
2136 g_return_if_fail (goad != NULL);
2138 goad->ready_cb = ready_cb;
2140 if (goad->uid && *goad->uid) {
2141 e_cal_client_get_objects_for_uid (goad->client, goad->uid, goad->cancellable, got_objects_for_uid_cb, goad);
2143 gchar *iso_start, *iso_end;
2145 iso_start = isodate_from_time_t (goad->start);
2147 free_get_objects_async_data (goad);
2151 iso_end = isodate_from_time_t (goad->end);
2154 free_get_objects_async_data (goad);
2158 goad->query = g_strdup_printf ("(occur-in-time-range? (make-time \"%s\") (make-time \"%s\"))", iso_start, iso_end);
2163 e_cal_client_get_object_list_as_comps (goad->client, goad->query, goad->cancellable, got_object_list_as_comps_cb, goad);
2168 generate_instances_got_objects_cb (struct get_objects_async_data *goad,
2171 g_return_if_fail (goad != NULL);
2173 /* generate_instaces () frees 'objects' slist */
2175 generate_instances (goad->client, goad->start, goad->end, objects, goad->cancellable, goad->cb, goad->cb_data);
2177 free_get_objects_async_data (goad);
2181 * e_cal_client_generate_instances:
2182 * @client: A calendar client.
2183 * @start: Start time for query.
2184 * @end: End time for query.
2185 * @cancellable: a #GCancellable; can be %NULL
2186 * @cb: Callback for each generated instance.
2187 * @cb_data: Closure data for the callback.
2188 * @destroy_cb_data: Function to call when the processing is done, to free @cb_data; can be %NULL.
2190 * Does a combination of e_cal_client_get_object_list() and
2191 * e_cal_client_recur_generate_instances(). Unlike e_cal_client_generate_instances_sync(),
2192 * this returns immediately and the @cb callback is called asynchronously.
2194 * The callback function should do a g_object_ref() of the calendar component
2195 * it gets passed if it intends to keep it around, since it will be unref'ed
2196 * as soon as the callback returns.
2201 e_cal_client_generate_instances (ECalClient *client,
2204 GCancellable *cancellable,
2205 ECalRecurInstanceFn cb,
2207 GDestroyNotify destroy_cb_data)
2209 struct get_objects_async_data *goad;
2210 GCancellable *use_cancellable;
2212 g_return_if_fail (E_IS_CAL_CLIENT (client));
2213 g_return_if_fail (e_client_is_opened (E_CLIENT (client)));
2215 g_return_if_fail (start >= 0);
2216 g_return_if_fail (end >= 0);
2217 g_return_if_fail (cb != NULL);
2219 use_cancellable = cancellable;
2220 if (!use_cancellable)
2221 use_cancellable = g_cancellable_new ();
2223 goad = g_new0 (struct get_objects_async_data, 1);
2224 goad->cancellable = g_object_ref (use_cancellable);
2225 goad->client = g_object_ref (client);
2226 goad->start = start;
2229 goad->cb_data = cb_data;
2230 goad->destroy_cb_data = destroy_cb_data;
2232 get_objects_async (generate_instances_got_objects_cb, goad);
2234 if (use_cancellable != cancellable)
2235 g_object_unref (use_cancellable);
2239 * e_cal_client_generate_instances_sync:
2240 * @client: A calendar client
2241 * @start: Start time for query
2242 * @end: End time for query
2243 * @cb: (closure cb_data) (scope call): Callback for each generated instance
2244 * @cb_data: (closure): Closure data for the callback
2246 * Does a combination of e_cal_client_get_object_list() and
2247 * e_cal_client_recur_generate_instances().
2249 * The callback function should do a g_object_ref() of the calendar component
2250 * it gets passed if it intends to keep it around, since it will be unreffed
2251 * as soon as the callback returns.
2256 e_cal_client_generate_instances_sync (ECalClient *client,
2259 ECalRecurInstanceFn cb,
2262 GSList *objects = NULL;
2264 g_return_if_fail (E_IS_CAL_CLIENT (client));
2265 g_return_if_fail (e_client_is_opened (E_CLIENT (client)));
2267 g_return_if_fail (start >= 0);
2268 g_return_if_fail (end >= 0);
2269 g_return_if_fail (cb != NULL);
2271 objects = get_objects_sync (client, start, end, NULL);
2275 /* generate_instaces frees 'objects' slist */
2276 generate_instances (client, start, end, objects, NULL, cb, cb_data);
2279 /* also frees 'instances' GSList */
2281 process_instances (ECalComponent *comp,
2283 ECalRecurInstanceFn cb,
2289 g_return_if_fail (comp != NULL);
2290 g_return_if_fail (cb != NULL);
2292 rid = e_cal_component_get_recurid_as_string (comp);
2294 /* Reverse the instances list because the add_instance() function is prepending */
2295 instances = g_slist_reverse (instances);
2297 /* now only return back the instances for the given object */
2299 while (instances != NULL) {
2300 struct comp_instance *ci;
2301 gchar *instance_rid = NULL;
2303 ci = instances->data;
2306 instance_rid = e_cal_component_get_recurid_as_string (ci->comp);
2309 if (instance_rid && *instance_rid && strcmp (rid, instance_rid) == 0)
2310 result = (* cb) (ci->comp, ci->start, ci->end, cb_data);
2312 result = (* cb) (ci->comp, ci->start, ci->end, cb_data);
2315 /* remove instance from list */
2316 instances = g_slist_remove (instances, ci);
2317 g_object_unref (ci->comp);
2319 g_free (instance_rid);
2327 generate_instances_for_object_got_objects_cb (struct get_objects_async_data *goad,
2330 struct instances_info *instances_hold;
2331 GSList *instances = NULL;
2333 g_return_if_fail (goad != NULL);
2335 instances_hold = g_new0 (struct instances_info, 1);
2336 instances_hold->instances = &instances;
2337 instances_hold->start_zone = goad->start_zone;
2338 instances_hold->end_zone = goad->end_zone;
2340 /* generate all instances in the given time range */
2341 generate_instances (goad->client, goad->start, goad->end, objects, goad->cancellable, add_instance, instances_hold);
2343 /* it also frees 'instances' GSList */
2344 process_instances (goad->comp, *(instances_hold->instances), goad->cb, goad->cb_data);
2347 free_get_objects_async_data (goad);
2348 g_free (instances_hold);
2352 * e_cal_client_generate_instances_for_object:
2353 * @client: A calendar client.
2354 * @icalcomp: Object to generate instances from.
2355 * @start: Start time for query.
2356 * @end: End time for query.
2357 * @cancellable: a #GCancellable; can be %NULL
2358 * @cb: Callback for each generated instance.
2359 * @cb_data: Closure data for the callback.
2360 * @destroy_cb_data: Function to call when the processing is done, to free @cb_data; can be %NULL.
2362 * Does a combination of e_cal_client_get_object_list() and
2363 * e_cal_client_recur_generate_instances(), like e_cal_client_generate_instances(), but
2364 * for a single object. Unlike e_cal_client_generate_instances_for_object_sync(),
2365 * this returns immediately and the @cb callback is called asynchronously.
2367 * The callback function should do a g_object_ref() of the calendar component
2368 * it gets passed if it intends to keep it around, since it will be unref'ed
2369 * as soon as the callback returns.
2374 e_cal_client_generate_instances_for_object (ECalClient *client,
2375 icalcomponent *icalcomp,
2378 GCancellable *cancellable,
2379 ECalRecurInstanceFn cb,
2381 GDestroyNotify destroy_cb_data)
2383 ECalComponent *comp;
2385 ECalComponentDateTime datetime;
2386 icaltimezone *start_zone = NULL, *end_zone = NULL;
2387 gboolean is_single_instance = FALSE;
2388 struct get_objects_async_data *goad;
2389 GCancellable *use_cancellable;
2391 g_return_if_fail (E_IS_CAL_CLIENT (client));
2392 g_return_if_fail (e_client_is_opened (E_CLIENT (client)));
2394 g_return_if_fail (start >= 0);
2395 g_return_if_fail (end >= 0);
2396 g_return_if_fail (cb != NULL);
2398 comp = e_cal_component_new ();
2399 e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (icalcomp));
2401 if (!e_cal_component_has_recurrences (comp))
2402 is_single_instance = TRUE;
2404 /* If the backend stores it as individual instances and does not
2405 * have a master object - do not expand */
2406 if (is_single_instance || e_client_check_capability (E_CLIENT (client), CAL_STATIC_CAPABILITY_RECURRENCES_NO_MASTER)) {
2407 /* return the same instance */
2408 (* cb) (comp, icaltime_as_timet_with_zone (icalcomponent_get_dtstart (icalcomp), client->priv->default_zone),
2409 icaltime_as_timet_with_zone (icalcomponent_get_dtend (icalcomp), client->priv->default_zone), cb_data);
2410 g_object_unref (comp);
2412 if (destroy_cb_data)
2413 destroy_cb_data (cb_data);
2417 e_cal_component_get_uid (comp, &uid);
2419 /* Get the start timezone */
2420 e_cal_component_get_dtstart (comp, &datetime);
2422 e_cal_client_get_timezone_sync (client, datetime.tzid, &start_zone, NULL, NULL);
2425 e_cal_component_free_datetime (&datetime);
2427 /* Get the end timezone */
2428 e_cal_component_get_dtend (comp, &datetime);
2430 e_cal_client_get_timezone_sync (client, datetime.tzid, &end_zone, NULL, NULL);
2433 e_cal_component_free_datetime (&datetime);
2435 use_cancellable = cancellable;
2436 if (!use_cancellable)
2437 use_cancellable = g_cancellable_new ();
2439 goad = g_new0 (struct get_objects_async_data, 1);
2440 goad->cancellable = g_object_ref (use_cancellable);
2441 goad->client = g_object_ref (client);
2442 goad->start = start;
2445 goad->cb_data = cb_data;
2446 goad->destroy_cb_data = destroy_cb_data;
2447 goad->start_zone = start_zone;
2448 goad->end_zone = end_zone;
2450 goad->uid = g_strdup (uid);
2452 get_objects_async (generate_instances_for_object_got_objects_cb, goad);
2454 if (use_cancellable != cancellable)
2455 g_object_unref (use_cancellable);
2459 * e_cal_client_generate_instances_for_object_sync:
2460 * @client: A calendar client
2461 * @icalcomp: Object to generate instances from
2462 * @start: Start time for query
2463 * @end: End time for query
2464 * @cb: (closure cb_data) (scope call): Callback for each generated instance
2465 * @cb_data: (closure): Closure data for the callback
2467 * Does a combination of e_cal_client_get_object_list() and
2468 * e_cal_client_recur_generate_instances(), like e_cal_client_generate_instances_sync(), but
2469 * for a single object.
2471 * The callback function should do a g_object_ref() of the calendar component
2472 * it gets passed if it intends to keep it around, since it will be unref'ed
2473 * as soon as the callback returns.
2478 e_cal_client_generate_instances_for_object_sync (ECalClient *client,
2479 icalcomponent *icalcomp,
2482 ECalRecurInstanceFn cb,
2485 ECalComponent *comp;
2487 GSList *instances = NULL;
2488 ECalComponentDateTime datetime;
2489 icaltimezone *start_zone = NULL, *end_zone = NULL;
2490 struct instances_info *instances_hold;
2491 gboolean is_single_instance = FALSE;
2493 g_return_if_fail (E_IS_CAL_CLIENT (client));
2494 g_return_if_fail (e_client_is_opened (E_CLIENT (client)));
2496 g_return_if_fail (start >= 0);
2497 g_return_if_fail (end >= 0);
2498 g_return_if_fail (cb != NULL);
2500 comp = e_cal_component_new ();
2501 e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (icalcomp));
2503 if (!e_cal_component_has_recurrences (comp))
2504 is_single_instance = TRUE;
2506 /* If the backend stores it as individual instances and does not
2507 * have a master object - do not expand */
2508 if (is_single_instance || e_client_check_capability (E_CLIENT (client), CAL_STATIC_CAPABILITY_RECURRENCES_NO_MASTER)) {
2509 /* return the same instance */
2510 (* cb) (comp, icaltime_as_timet_with_zone (icalcomponent_get_dtstart (icalcomp), client->priv->default_zone),
2511 icaltime_as_timet_with_zone (icalcomponent_get_dtend (icalcomp), client->priv->default_zone), cb_data);
2512 g_object_unref (comp);
2516 e_cal_component_get_uid (comp, &uid);
2518 /* Get the start timezone */
2519 e_cal_component_get_dtstart (comp, &datetime);
2521 e_cal_client_get_timezone_sync (client, datetime.tzid, &start_zone, NULL, NULL);
2524 e_cal_component_free_datetime (&datetime);
2526 /* Get the end timezone */
2527 e_cal_component_get_dtend (comp, &datetime);
2529 e_cal_client_get_timezone_sync (client, datetime.tzid, &end_zone, NULL, NULL);
2532 e_cal_component_free_datetime (&datetime);
2534 instances_hold = g_new0 (struct instances_info, 1);
2535 instances_hold->instances = &instances;
2536 instances_hold->start_zone = start_zone;
2537 instances_hold->end_zone = end_zone;
2539 /* generate all instances in the given time range */
2540 generate_instances (client, start, end, get_objects_sync (client, start, end, uid), NULL, add_instance, instances_hold);
2542 /* it also frees 'instances' GSList */
2543 process_instances (comp, *(instances_hold->instances), cb, cb_data);
2546 g_object_unref (comp);
2547 g_free (instances_hold);
2550 typedef struct _ForeachTZIDCallbackData ForeachTZIDCallbackData;
2551 struct _ForeachTZIDCallbackData {
2553 GHashTable *timezone_hash;
2557 /* This adds the VTIMEZONE given by the TZID parameter to the GHashTable in
2560 foreach_tzid_callback (icalparameter *param,
2563 ForeachTZIDCallbackData *data = cbdata;
2565 icaltimezone *zone = NULL;
2566 icalcomponent *vtimezone_comp;
2567 gchar *vtimezone_as_string;
2569 /* Get the TZID string from the parameter. */
2570 tzid = icalparameter_get_tzid (param);
2574 /* Check if we've already added it to the GHashTable. */
2575 if (g_hash_table_lookup (data->timezone_hash, tzid))
2578 if (!e_cal_client_get_timezone_sync (data->client, tzid, &zone, NULL, NULL) || !zone) {
2579 data->success = FALSE;
2583 /* Convert it to a string and add it to the hash. */
2584 vtimezone_comp = icaltimezone_get_component (zone);
2585 if (!vtimezone_comp)
2588 vtimezone_as_string = icalcomponent_as_ical_string_r (vtimezone_comp);
2590 g_hash_table_insert (data->timezone_hash, (gchar *) tzid, vtimezone_as_string);
2593 /* This appends the value string to the GString given in data. */
2595 append_timezone_string (gpointer key,
2599 GString *vcal_string = data;
2601 g_string_append (vcal_string, value);
2605 /* This simply frees the hash values. */
2607 free_timezone_string (gpointer key,
2615 * e_cal_client_get_component_as_string:
2616 * @client: A calendar client.
2617 * @icalcomp: A calendar component object.
2619 * Gets a calendar component as an iCalendar string, with a toplevel
2620 * VCALENDAR component and all VTIMEZONEs needed for the component.
2622 * Returns: the component as a complete iCalendar string, or NULL on
2623 * failure. The string should be freed with g_free().
2628 e_cal_client_get_component_as_string (ECalClient *client,
2629 icalcomponent *icalcomp)
2631 GHashTable *timezone_hash;
2632 GString *vcal_string;
2633 ForeachTZIDCallbackData cbdata;
2636 g_return_val_if_fail (E_IS_CAL_CLIENT (client), NULL);
2637 g_return_val_if_fail (icalcomp != NULL, NULL);
2639 timezone_hash = g_hash_table_new (g_str_hash, g_str_equal);
2641 /* Add any timezones needed to the hash. We use a hash since we only
2642 * want to add each timezone once at most. */
2643 cbdata.client = client;
2644 cbdata.timezone_hash = timezone_hash;
2645 cbdata.success = TRUE;
2646 icalcomponent_foreach_tzid (icalcomp, foreach_tzid_callback, &cbdata);
2647 if (!cbdata.success) {
2648 g_hash_table_foreach (timezone_hash, free_timezone_string, NULL);
2652 /* Create the start of a VCALENDAR, to add the VTIMEZONES to,
2653 * and remember its length so we know if any VTIMEZONEs get added. */
2654 vcal_string = g_string_new (NULL);
2658 "PRODID:-//Ximian//NONSGML Evolution Calendar//EN\n"
2660 "METHOD:PUBLISH\n");
2662 /* Now concatenate all the timezone strings. This also frees the
2663 * timezone strings as it goes. */
2664 g_hash_table_foreach (timezone_hash, append_timezone_string, vcal_string);
2666 /* Get the string for the VEVENT/VTODO. */
2667 obj_string = icalcomponent_as_ical_string_r (icalcomp);
2669 /* If there were any timezones to send, create a complete VCALENDAR,
2670 * else just send the VEVENT/VTODO string. */
2671 g_string_append (vcal_string, obj_string);
2672 g_string_append (vcal_string, "END:VCALENDAR\n");
2673 g_free (obj_string);
2675 obj_string = g_string_free (vcal_string, FALSE);
2677 g_hash_table_destroy (timezone_hash);
2683 complete_string_exchange (gboolean res,
2688 g_return_val_if_fail (result != NULL, FALSE);
2690 if (res && out_string) {
2692 *result = out_string;
2694 /* empty string is returned as NULL */
2696 g_free (out_string);
2700 g_free (out_string);
2703 if (error && !*error)
2704 g_propagate_error (error, e_client_error_create (E_CLIENT_ERROR_INVALID_ARG, NULL));
2711 complete_strv_exchange (gboolean res,
2712 gchar **out_strings,
2716 g_return_val_if_fail (result != NULL, FALSE);
2718 if (res && out_strings) {
2719 *result = e_client_util_strv_to_slist ((const gchar * const*) out_strings);
2724 if (error && !*error)
2725 g_propagate_error (error, e_client_error_create (E_CLIENT_ERROR_INVALID_ARG, NULL));
2728 g_strfreev (out_strings);
2734 cal_client_get_default_object_from_cache_finish (EClient *client,
2735 GAsyncResult *result,
2739 GSimpleAsyncResult *simple;
2740 GError *local_error = NULL;
2742 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
2743 g_return_val_if_fail (result != NULL, FALSE);
2744 g_return_val_if_fail (prop_value != NULL, FALSE);
2745 g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (client), cal_client_get_default_object_from_cache_finish), FALSE);
2747 simple = G_SIMPLE_ASYNC_RESULT (result);
2749 if (g_simple_async_result_propagate_error (simple, &local_error)) {
2750 e_client_unwrap_dbus_error (client, local_error, error);
2754 *prop_value = g_strdup (g_simple_async_result_get_op_res_gpointer (simple));
2756 return *prop_value != NULL;
2760 * e_cal_client_get_default_object:
2761 * @client: an #ECalClient
2762 * @cancellable: a #GCancellable; can be %NULL
2763 * @callback: callback to call when a result is ready
2764 * @user_data: user data for the @callback
2766 * Retrives an #icalcomponent from the backend that contains the default
2767 * values for properties needed. The call is finished
2768 * by e_cal_client_get_default_object_finish() from the @callback.
2773 e_cal_client_get_default_object (ECalClient *client,
2774 GCancellable *cancellable,
2775 GAsyncReadyCallback callback,
2779 EClient *base_client = E_CLIENT (client);
2781 prop_value = e_client_get_backend_property_from_cache (base_client, CAL_BACKEND_PROPERTY_DEFAULT_OBJECT);
2783 e_client_finish_async_without_dbus (base_client, cancellable, callback, user_data, cal_client_get_default_object_from_cache_finish, prop_value, g_free);
2785 e_client_proxy_call_string (
2786 base_client, CAL_BACKEND_PROPERTY_DEFAULT_OBJECT, cancellable, callback, user_data, e_cal_client_get_default_object,
2787 e_gdbus_cal_call_get_backend_property,
2788 NULL, NULL, e_gdbus_cal_call_get_backend_property_finish, NULL, NULL);
2793 complete_get_object (gboolean res,
2795 icalcomponent **icalcomp,
2796 gboolean ensure_unique_uid,
2799 g_return_val_if_fail (icalcomp != NULL, FALSE);
2801 if (res && out_string) {
2802 *icalcomp = icalparser_parse_string (out_string);
2804 g_propagate_error (error, e_cal_client_error_create (E_CAL_CLIENT_ERROR_INVALID_OBJECT, NULL));
2806 } else if (ensure_unique_uid && icalcomponent_get_uid (*icalcomp)) {
2807 /* make sure the UID is always unique */
2808 gchar *new_uid = e_cal_component_gen_uid ();
2810 icalcomponent_set_uid (*icalcomp, new_uid);
2818 g_free (out_string);
2824 * e_cal_client_get_default_object_finish:
2825 * @client: an #ECalClient
2826 * @result: a #GAsyncResult
2827 * @icalcomp: (out): Return value for the default calendar object.
2828 * @error: (out): a #GError to set an error, if any
2830 * Finishes previous call of e_cal_client_get_default_object() and
2831 * sets @icalcomp to an #icalcomponent from the backend that contains
2832 * the default values for properties needed. This @icalcomp should be
2833 * freed with icalcomponent_free().
2835 * Returns: %TRUE if successful, %FALSE otherwise.
2840 e_cal_client_get_default_object_finish (ECalClient *client,
2841 GAsyncResult *result,
2842 icalcomponent **icalcomp,
2846 gchar *out_string = NULL;
2848 g_return_val_if_fail (icalcomp != NULL, FALSE);
2850 if (g_simple_async_result_get_source_tag (G_SIMPLE_ASYNC_RESULT (result)) == cal_client_get_default_object_from_cache_finish) {
2851 res = cal_client_get_default_object_from_cache_finish (E_CLIENT (client), result, &out_string, error);
2853 res = e_client_proxy_call_finish_string (E_CLIENT (client), result, &out_string, error, e_cal_client_get_default_object);
2856 return complete_get_object (res, out_string, icalcomp, TRUE, error);
2860 * e_cal_client_get_default_object_sync:
2861 * @client: an #ECalClient
2862 * @icalcomp: (out): Return value for the default calendar object.
2863 * @cancellable: a #GCancellable; can be %NULL
2864 * @error: (out): a #GError to set an error, if any
2866 * Retrives an #icalcomponent from the backend that contains the default
2867 * values for properties needed. This @icalcomp should be freed with
2868 * icalcomponent_free().
2870 * Returns: %TRUE if successful, %FALSE otherwise.
2875 e_cal_client_get_default_object_sync (ECalClient *client,
2876 icalcomponent **icalcomp,
2877 GCancellable *cancellable,
2881 gchar *out_string = NULL;
2883 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
2884 g_return_val_if_fail (icalcomp != NULL, FALSE);
2886 if (client->priv->dbus_proxy == NULL) {
2887 set_proxy_gone_error (error);
2891 out_string = e_client_get_backend_property_from_cache (E_CLIENT (client), CAL_BACKEND_PROPERTY_DEFAULT_OBJECT);
2895 res = e_client_proxy_call_sync_string__string (E_CLIENT (client), CAL_BACKEND_PROPERTY_DEFAULT_OBJECT, &out_string, cancellable, error, e_gdbus_cal_call_get_backend_property_sync);
2897 return complete_get_object (res, out_string, icalcomp, TRUE, error);
2901 complete_get_object_master (ECalClientSourceType source_type,
2904 icalcomponent **icalcomp,
2907 g_return_val_if_fail (icalcomp != NULL, FALSE);
2909 if (res && out_string) {
2910 icalcomponent *tmp_comp = icalparser_parse_string (out_string);
2913 g_propagate_error (error, e_cal_client_error_create (E_CAL_CLIENT_ERROR_INVALID_OBJECT, NULL));
2916 icalcomponent_kind kind;
2917 icalcomponent *master_comp = NULL;
2919 switch (source_type) {
2920 case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
2921 kind = ICAL_VEVENT_COMPONENT;
2923 case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
2924 kind = ICAL_VTODO_COMPONENT;
2926 case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
2927 kind = ICAL_VJOURNAL_COMPONENT;
2930 icalcomponent_free (tmp_comp);
2934 g_warn_if_reached ();
2937 if (res && icalcomponent_isa (tmp_comp) == kind) {
2938 *icalcomp = tmp_comp;
2940 } else if (res && icalcomponent_isa (tmp_comp) == ICAL_VCALENDAR_COMPONENT) {
2941 for (master_comp = icalcomponent_get_first_component (tmp_comp, kind);
2943 master_comp = icalcomponent_get_next_component (tmp_comp, kind)) {
2944 if (!icalcomponent_get_uid (master_comp))
2947 if (icaltime_is_null_time (icalcomponent_get_recurrenceid (master_comp)) ||
2948 !icaltime_is_valid_time (icalcomponent_get_recurrenceid (master_comp)))
2953 master_comp = icalcomponent_get_first_component (tmp_comp, kind);
2955 *icalcomp = master_comp ? icalcomponent_new_clone (master_comp) : NULL;
2959 icalcomponent_free (tmp_comp);
2966 g_free (out_string);
2968 return res && *icalcomp;
2972 * e_cal_client_get_object:
2973 * @client: an #ECalClient
2974 * @uid: Unique identifier for a calendar component.
2975 * @rid: Recurrence identifier.
2976 * @cancellable: a #GCancellable; can be %NULL
2977 * @callback: callback to call when a result is ready
2978 * @user_data: user data for the @callback
2980 * Queries a calendar for a calendar component object based on its unique
2981 * identifier. The call is finished by e_cal_client_get_object_finish()
2982 * from the @callback.
2984 * Use e_cal_client_get_objects_for_uid() to get list of all
2985 * objects for the given uid, which includes master object and
2986 * all detached instances.
2991 e_cal_client_get_object (ECalClient *client,
2994 GCancellable *cancellable,
2995 GAsyncReadyCallback callback,
3000 g_return_if_fail (uid != NULL);
3002 strv = e_gdbus_cal_encode_get_object (uid, rid);
3004 e_client_proxy_call_strv (
3005 E_CLIENT (client), (const gchar * const *) strv, cancellable, callback, user_data, e_cal_client_get_object,
3006 e_gdbus_cal_call_get_object,
3007 NULL, NULL, e_gdbus_cal_call_get_object_finish, NULL, NULL);
3013 * e_cal_client_get_object_finish:
3014 * @client: an #ECalClient
3015 * @result: a #GAsyncResult
3016 * @icalcomp: (out): Return value for the calendar component object.
3017 * @error: (out): a #GError to set an error, if any
3019 * Finishes previous call of e_cal_client_get_object() and
3020 * sets @icalcomp to queried component. This function always returns
3021 * master object for a case of @rid being NULL or an empty string.
3022 * This component should be freed with icalcomponent_free().
3024 * Use e_cal_client_get_objects_for_uid() to get list of all
3025 * objects for the given uid, which includes master object and
3026 * all detached instances.
3028 * Returns: %TRUE if successful, %FALSE otherwise.
3033 e_cal_client_get_object_finish (ECalClient *client,
3034 GAsyncResult *result,
3035 icalcomponent **icalcomp,
3039 gchar *out_string = NULL;
3041 g_return_val_if_fail (icalcomp != NULL, FALSE);
3043 res = e_client_proxy_call_finish_string (E_CLIENT (client), result, &out_string, error, e_cal_client_get_object);
3045 return complete_get_object_master (e_cal_client_get_source_type (client), res, out_string, icalcomp, error);
3049 * e_cal_client_get_object_sync:
3050 * @client: an #ECalClient
3051 * @uid: Unique identifier for a calendar component.
3052 * @rid: Recurrence identifier.
3053 * @icalcomp: (out): Return value for the calendar component object.
3054 * @cancellable: a #GCancellable; can be %NULL
3055 * @error: (out): a #GError to set an error, if any
3057 * Queries a calendar for a calendar component object based
3058 * on its unique identifier. This function always returns
3059 * master object for a case of @rid being NULL or an empty string.
3060 * This component should be freed with icalcomponent_free().
3062 * Use e_cal_client_get_objects_for_uid_sync() to get list of all
3063 * objects for the given uid, which includes master object and
3064 * all detached instances.
3066 * Returns: %TRUE if successful, %FALSE otherwise.
3071 e_cal_client_get_object_sync (ECalClient *client,
3074 icalcomponent **icalcomp,
3075 GCancellable *cancellable,
3079 gchar *out_string = NULL, **strv;
3081 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
3082 g_return_val_if_fail (uid != NULL, FALSE);
3083 g_return_val_if_fail (icalcomp != NULL, FALSE);
3085 if (client->priv->dbus_proxy == NULL) {
3086 set_proxy_gone_error (error);
3090 strv = e_gdbus_cal_encode_get_object (uid, rid);
3091 res = e_client_proxy_call_sync_strv__string (E_CLIENT (client), (const gchar * const *) strv, &out_string, cancellable, error, e_gdbus_cal_call_get_object_sync);
3094 return complete_get_object_master (e_cal_client_get_source_type (client), res, out_string, icalcomp, error);
3098 * e_cal_client_get_objects_for_uid:
3099 * @client: an #ECalClient
3100 * @uid: Unique identifier for a calendar component
3101 * @cancellable: a #GCancellable; can be %NULL
3102 * @callback: callback to call when a result is ready
3103 * @user_data: user data for the @callback
3105 * Queries a calendar for all calendar components with the given unique
3106 * ID. This will return any recurring event and all its detached recurrences.
3107 * For non-recurring events, it will just return the object with that ID.
3108 * The call is finished by e_cal_client_get_objects_for_uid_finish() from
3114 e_cal_client_get_objects_for_uid (ECalClient *client,
3116 GCancellable *cancellable,
3117 GAsyncReadyCallback callback,
3122 g_return_if_fail (uid != NULL);
3124 strv = e_gdbus_cal_encode_get_object (uid, "");
3126 e_client_proxy_call_strv (
3127 E_CLIENT (client), (const gchar * const *) strv, cancellable, callback, user_data, e_cal_client_get_objects_for_uid,
3128 e_gdbus_cal_call_get_object,
3129 NULL, NULL, e_gdbus_cal_call_get_object_finish, NULL, NULL);
3135 complete_get_objects_for_uid (ECalClientSourceType source_type,
3141 icalcomponent *icalcomp = NULL;
3142 icalcomponent_kind kind;
3143 ECalComponent *comp;
3145 res = complete_get_object (res, out_string, &icalcomp, FALSE, error);
3146 if (!res || !icalcomp)
3149 kind = icalcomponent_isa (icalcomp);
3150 if ((kind == ICAL_VEVENT_COMPONENT && source_type == E_CAL_CLIENT_SOURCE_TYPE_EVENTS) ||
3151 (kind == ICAL_VTODO_COMPONENT && source_type == E_CAL_CLIENT_SOURCE_TYPE_TASKS) ||
3152 (kind == ICAL_VJOURNAL_COMPONENT && source_type == E_CAL_CLIENT_SOURCE_TYPE_MEMOS)) {
3153 comp = e_cal_component_new ();
3154 e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (icalcomp));
3155 *ecalcomps = g_slist_append (NULL, comp);
3156 } else if (kind == ICAL_VCALENDAR_COMPONENT) {
3157 icalcomponent *subcomp;
3158 icalcomponent_kind kind_to_find;
3160 switch (source_type) {
3161 case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
3162 kind_to_find = ICAL_VTODO_COMPONENT;
3164 case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
3165 kind_to_find = ICAL_VJOURNAL_COMPONENT;
3167 case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
3169 kind_to_find = ICAL_VEVENT_COMPONENT;
3174 subcomp = icalcomponent_get_first_component (icalcomp, kind_to_find);
3176 comp = e_cal_component_new ();
3177 e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (subcomp));
3178 *ecalcomps = g_slist_prepend (*ecalcomps, comp);
3179 subcomp = icalcomponent_get_next_component (icalcomp, kind_to_find);
3182 *ecalcomps = g_slist_reverse (*ecalcomps);
3185 icalcomponent_free (icalcomp);
3191 * e_cal_client_get_objects_for_uid_finish:
3192 * @client: an #ECalClient
3193 * @result: a #GAsyncResult
3194 * @ecalcomps: (out) (transfer full) (element-type ECalComponent): Return value
3195 * for the list of objects obtained from the backend
3196 * @error: (out): a #GError to set an error, if any
3198 * Finishes previous call of e_cal_client_get_objects_for_uid() and
3199 * sets @ecalcomps to a list of #ECalComponent<!-- -->s corresponding to
3200 * found components for a given uid of the same type as this client.
3201 * This list should be freed with e_cal_client_free_ecalcomp_slist().
3203 * Returns: %TRUE if successful, %FALSE otherwise.
3208 e_cal_client_get_objects_for_uid_finish (ECalClient *client,
3209 GAsyncResult *result,
3214 gchar *out_string = NULL;
3216 g_return_val_if_fail (ecalcomps != NULL, FALSE);
3218 res = e_client_proxy_call_finish_string (E_CLIENT (client), result, &out_string, error, e_cal_client_get_objects_for_uid);
3220 return complete_get_objects_for_uid (e_cal_client_get_source_type (client), res, out_string, ecalcomps, error);
3224 * e_cal_client_get_objects_for_uid_sync:
3225 * @client: an #ECalClient
3226 * @uid: Unique identifier for a calendar component
3227 * @ecalcomps: (out) (transfer full) (element-type ECalComponent): Return value
3228 * for the list of objects obtained from the backend
3229 * @cancellable: (allow-none): a #GCancellable; can be %NULL
3230 * @error: (out): a #GError to set an error, if any
3232 * Queries a calendar for all calendar components with the given unique
3233 * ID. This will return any recurring event and all its detached recurrences.
3234 * For non-recurring events, it will just return the object with that ID.
3235 * This list should be freed with e_cal_client_free_ecalcomp_slist().
3237 * Returns: %TRUE if successful, %FALSE otherwise.
3242 e_cal_client_get_objects_for_uid_sync (ECalClient *client,
3245 GCancellable *cancellable,
3249 gchar *out_string = NULL, **strv = NULL;
3251 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
3252 g_return_val_if_fail (uid != NULL, FALSE);
3253 g_return_val_if_fail (ecalcomps != NULL, FALSE);
3255 if (client->priv->dbus_proxy == NULL) {
3256 set_proxy_gone_error (error);
3260 strv = e_gdbus_cal_encode_get_object (uid, "");
3261 res = e_client_proxy_call_sync_strv__string (E_CLIENT (client), (const gchar * const *) strv, &out_string, cancellable, error, e_gdbus_cal_call_get_object_sync);
3264 return complete_get_objects_for_uid (e_cal_client_get_source_type (client), res, out_string, ecalcomps, error);
3268 * e_cal_client_get_object_list:
3269 * @client: an #ECalClient
3270 * @sexp: an S-expression representing the query
3271 * @cancellable: a #GCancellable; can be %NULL
3272 * @callback: callback to call when a result is ready
3273 * @user_data: user data for the @callback
3275 * Gets a list of objects from the calendar that match the query specified
3276 * by the @sexp argument, returning matching objects as a list of #icalcomponent-s.
3277 * The call is finished by e_cal_client_get_object_list_finish() from
3283 e_cal_client_get_object_list (ECalClient *client,
3285 GCancellable *cancellable,
3286 GAsyncReadyCallback callback,
3289 gchar *gdbus_sexp = NULL;
3291 g_return_if_fail (sexp != NULL);
3293 e_client_proxy_call_string (
3294 E_CLIENT (client), e_util_ensure_gdbus_string (sexp, &gdbus_sexp), cancellable, callback, user_data, e_cal_client_get_object_list,
3295 e_gdbus_cal_call_get_object_list,
3296 NULL, NULL, NULL, e_gdbus_cal_call_get_object_list_finish, NULL);
3298 g_free (gdbus_sexp);
3302 complete_get_object_list (gboolean res,
3307 g_return_val_if_fail (icalcomps != NULL, FALSE);
3311 if (res && out_strv) {
3313 icalcomponent *icalcomp;
3315 for (ii = 0; out_strv[ii]; ii++) {
3316 icalcomp = icalcomponent_new_from_string (out_strv[ii]);
3321 *icalcomps = g_slist_prepend (*icalcomps, icalcomp);
3324 *icalcomps = g_slist_reverse (*icalcomps);
3329 g_strfreev (out_strv);
3335 * e_cal_client_get_object_list_finish:
3336 * @client: an #ECalClient
3337 * @result: a #GAsyncResult
3338 * @icalcomps: (out) (element-type icalcomponent): list of matching
3339 * #icalcomponent<!-- -->s
3340 * @error: (out): a #GError to set an error, if any
3342 * Finishes previous call of e_cal_client_get_object_list() and
3343 * sets @icalcomps to a matching list of #icalcomponent-s.
3344 * This list should be freed with e_cal_client_free_icalcomp_slist().
3346 * Returns: %TRUE if successful, %FALSE otherwise.
3351 e_cal_client_get_object_list_finish (ECalClient *client,
3352 GAsyncResult *result,
3357 gchar **out_strv = NULL;
3359 g_return_val_if_fail (icalcomps != NULL, FALSE);
3361 res = e_client_proxy_call_finish_strv (E_CLIENT (client), result, &out_strv, error, e_cal_client_get_object_list);
3363 return complete_get_object_list (res, out_strv, icalcomps, error);
3367 * e_cal_client_get_object_list_sync:
3368 * @client: an #ECalClient
3369 * @sexp: an S-expression representing the query
3370 * @icalcomps: (out) (element-type icalcomponent): list of matching
3371 * #icalcomponent<!-- -->s
3372 * @cancellable: (allow-none): a #GCancellable; can be %NULL
3373 * @error: (out): a #GError to set an error, if any
3375 * Gets a list of objects from the calendar that match the query specified
3376 * by the @sexp argument. The objects will be returned in the @icalcomps
3377 * argument, which is a list of #icalcomponent.
3378 * This list should be freed with e_cal_client_free_icalcomp_slist().
3380 * Returns: %TRUE if successful, %FALSE otherwise.
3385 e_cal_client_get_object_list_sync (ECalClient *client,
3388 GCancellable *cancellable,
3392 gchar **out_strv = NULL, *gdbus_sexp = NULL;
3394 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
3395 g_return_val_if_fail (sexp != NULL, FALSE);
3396 g_return_val_if_fail (icalcomps != NULL, FALSE);
3398 if (client->priv->dbus_proxy == NULL) {
3399 set_proxy_gone_error (error);
3403 res = e_client_proxy_call_sync_string__strv (E_CLIENT (client), e_util_ensure_gdbus_string (sexp, &gdbus_sexp), &out_strv, cancellable, error, e_gdbus_cal_call_get_object_list_sync);
3404 g_free (gdbus_sexp);
3406 return complete_get_object_list (res, out_strv, icalcomps, error);
3410 * e_cal_client_get_object_list_as_comps:
3411 * @client: an #ECalClient
3412 * @sexp: an S-expression representing the query
3413 * @cancellable: a #GCancellable; can be %NULL
3414 * @callback: callback to call when a result is ready
3415 * @user_data: user data for the @callback
3417 * Gets a list of objects from the calendar that match the query specified
3418 * by the @sexp argument, returning matching objects as a list of #ECalComponent-s.
3419 * The call is finished by e_cal_client_get_object_list_as_comps_finish() from
3425 e_cal_client_get_object_list_as_comps (ECalClient *client,
3427 GCancellable *cancellable,
3428 GAsyncReadyCallback callback,
3431 gchar *gdbus_sexp = NULL;
3433 g_return_if_fail (sexp != NULL);
3435 e_client_proxy_call_string (
3436 E_CLIENT (client), e_util_ensure_gdbus_string (sexp, &gdbus_sexp), cancellable, callback, user_data, e_cal_client_get_object_list_as_comps,
3437 e_gdbus_cal_call_get_object_list,
3438 NULL, NULL, NULL, e_gdbus_cal_call_get_object_list_finish, NULL);
3440 g_free (gdbus_sexp);
3444 complete_get_object_list_as_comps (gboolean res,
3449 GSList *icalcomps = NULL;
3451 g_return_val_if_fail (ecalcomps != NULL, FALSE);
3455 res = complete_get_object_list (res, out_strv, &icalcomps, error);
3460 for (iter = icalcomps; iter; iter = iter->next) {
3461 ECalComponent *comp;
3463 comp = e_cal_component_new ();
3464 /* takes ownership of the icalcomp, thus free only the list at the end */
3465 if (e_cal_component_set_icalcomponent (comp, iter->data))
3466 *ecalcomps = g_slist_prepend (*ecalcomps, comp);
3468 icalcomponent_free (iter->data);
3471 g_slist_free (icalcomps);
3473 *ecalcomps = g_slist_reverse (*ecalcomps);
3475 e_cal_client_free_icalcomp_slist (icalcomps);
3482 * e_cal_client_get_object_list_as_comps_finish:
3483 * @client: an #ECalClient
3484 * @result: a #GAsyncResult
3485 * @ecalcomps: (out) (element-type ECalComponent): list of matching
3486 * #ECalComponent<!-- -->s
3487 * @error: (out): a #GError to set an error, if any
3489 * Finishes previous call of e_cal_client_get_object_list_as_comps() and
3490 * sets @ecalcomps to a matching list of #ECalComponent-s.
3491 * This list should be freed with e_cal_client_free_ecalcomp_slist().
3493 * Returns: %TRUE if successful, %FALSE otherwise.
3498 e_cal_client_get_object_list_as_comps_finish (ECalClient *client,
3499 GAsyncResult *result,
3504 gchar **out_strv = NULL;
3506 g_return_val_if_fail (ecalcomps != NULL, FALSE);
3508 res = e_client_proxy_call_finish_strv (E_CLIENT (client), result, &out_strv, error, e_cal_client_get_object_list_as_comps);
3510 return complete_get_object_list_as_comps (res, out_strv, ecalcomps, error);
3514 * e_cal_client_get_object_list_as_comps_sync:
3515 * @client: an #ECalClient
3516 * @sexp: an S-expression representing the query
3517 * @ecalcomps: (out) (element-type ECalComponent): list of matching
3518 * #ECalComponent<!-- -->s
3519 * @cancellable: (allow-none): a #GCancellable; can be %NULL
3520 * @error: (out): a #GError to set an error, if any
3522 * Gets a list of objects from the calendar that match the query specified
3523 * by the @sexp argument. The objects will be returned in the @ecalcomps
3524 * argument, which is a list of #ECalComponent.
3525 * This list should be freed with e_cal_client_free_ecalcomp_slist().
3527 * Returns: %TRUE if successful, %FALSE otherwise.
3532 e_cal_client_get_object_list_as_comps_sync (ECalClient *client,
3535 GCancellable *cancellable,
3539 gchar **out_strv = NULL, *gdbus_sexp = NULL;
3541 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
3542 g_return_val_if_fail (sexp != NULL, FALSE);
3543 g_return_val_if_fail (ecalcomps != NULL, FALSE);
3545 if (client->priv->dbus_proxy == NULL) {
3546 set_proxy_gone_error (error);
3550 res = e_client_proxy_call_sync_string__strv (E_CLIENT (client), e_util_ensure_gdbus_string (sexp, &gdbus_sexp), &out_strv, cancellable, error, e_gdbus_cal_call_get_object_list_sync);
3551 g_free (gdbus_sexp);
3553 return complete_get_object_list_as_comps (res, out_strv, ecalcomps, error);
3557 * e_cal_client_get_free_busy:
3558 * @client: an #ECalClient
3559 * @start: Start time for query
3560 * @end: End time for query
3561 * @users: (element-type utf8): List of users to retrieve free/busy information for
3562 * @cancellable: (allow-none): a #GCancellable; can be %NULL
3563 * @callback: callback to call when a result is ready
3564 * @user_data: user data for the @callback
3566 * Begins retrieval of free/busy information from the calendar server
3567 * as a list of #ECalComponent-s. Connect to "free-busy-data" signal
3568 * to receive chunks of free/busy components.
3569 * The call is finished by e_cal_client_get_free_busy_finish() from
3575 e_cal_client_get_free_busy (ECalClient *client,
3578 const GSList *users,
3579 GCancellable *cancellable,
3580 GAsyncReadyCallback callback,
3585 g_return_if_fail (start > 0);
3586 g_return_if_fail (end > 0);
3588 strv = e_gdbus_cal_encode_get_free_busy (start, end, users);
3590 e_client_proxy_call_strv (
3591 E_CLIENT (client), (const gchar * const *) strv, cancellable, callback, user_data, e_cal_client_get_free_busy,
3592 e_gdbus_cal_call_get_free_busy,
3593 e_gdbus_cal_call_get_free_busy_finish, NULL, NULL, NULL, NULL);
3599 * e_cal_client_get_free_busy_finish:
3600 * @client: an #ECalClient
3601 * @result: a #GAsyncResult
3602 * @error: (out): a #GError to set an error, if any
3604 * Finishes previous call of e_cal_client_get_free_busy().
3605 * All VFREEBUSY #ECalComponent-s were received by "free-busy-data" signal.
3607 * Returns: %TRUE if successful, %FALSE otherwise.
3612 e_cal_client_get_free_busy_finish (ECalClient *client,
3613 GAsyncResult *result,
3616 return e_client_proxy_call_finish_void (E_CLIENT (client), result, error, e_cal_client_get_free_busy);
3620 * e_cal_client_get_free_busy_sync:
3621 * @client: an #ECalClient
3622 * @start: Start time for query
3623 * @end: End time for query
3624 * @users: (element-type utf8): List of users to retrieve free/busy information for
3625 * @cancellable: (allow-none): a #GCancellable; can be %NULL
3626 * @error: (out): a #GError to set an error, if any
3628 * Gets free/busy information from the calendar server.
3629 * All VFREEBUSY #ECalComponent-s were received by "free-busy-data" signal.
3631 * Returns: %TRUE if successful, %FALSE otherwise.
3636 e_cal_client_get_free_busy_sync (ECalClient *client,
3639 const GSList *users,
3640 GCancellable *cancellable,
3646 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
3648 if (client->priv->dbus_proxy == NULL) {
3649 set_proxy_gone_error (error);
3653 strv = e_gdbus_cal_encode_get_free_busy (start, end, users);
3654 res = e_client_proxy_call_sync_strv__void (E_CLIENT (client), (const gchar * const *) strv, cancellable, error, e_gdbus_cal_call_get_free_busy_sync);
3661 * e_cal_client_create_object:
3662 * @client: an #ECalClient
3663 * @icalcomp: The component to create
3664 * @cancellable: a #GCancellable; can be %NULL
3665 * @callback: callback to call when a result is ready
3666 * @user_data: user data for the @callback
3668 * Requests the calendar backend to create the object specified by the @icalcomp
3669 * argument. Some backends would assign a specific UID to the newly created object,
3670 * but this function does not modify the original @icalcomp if its UID changes.
3671 * The call is finished by e_cal_client_create_object_finish() from
3677 e_cal_client_create_object (ECalClient *client,
3678 /* const */ icalcomponent *icalcomp,
3679 GCancellable *cancellable,
3680 GAsyncReadyCallback callback,
3683 gchar *comp_str, *gdbus_comp = NULL;
3684 const gchar *strv[2];
3686 g_return_if_fail (icalcomp != NULL);
3688 comp_str = icalcomponent_as_ical_string_r (icalcomp);
3689 strv[0] = e_util_ensure_gdbus_string (comp_str, &gdbus_comp);
3692 g_return_if_fail (strv[0] != NULL);
3694 e_client_proxy_call_strv (
3695 E_CLIENT (client), strv, cancellable, callback, user_data, e_cal_client_create_object,
3696 e_gdbus_cal_call_create_objects,
3697 NULL, NULL, NULL, e_gdbus_cal_call_create_objects_finish, NULL);
3700 g_free (gdbus_comp);
3704 * e_cal_client_create_object_finish:
3705 * @client: an #ECalClient
3706 * @result: a #GAsyncResult
3707 * @uid: (out): Return value for the UID assigned to the new component by the calendar backend
3708 * @error: (out): a #GError to set an error, if any
3710 * Finishes previous call of e_cal_client_create_object() and
3711 * sets @uid to newly assigned UID for the created object.
3712 * This @uid should be freed with g_free().
3714 * Returns: %TRUE if successful, %FALSE otherwise.
3719 e_cal_client_create_object_finish (ECalClient *client,
3720 GAsyncResult *result,
3725 gchar **out_strings = NULL;
3726 gchar *out_string = NULL;
3728 g_return_val_if_fail (uid != NULL, FALSE);
3730 res = e_client_proxy_call_finish_strv (E_CLIENT (client), result, &out_strings, error, e_cal_client_create_object);
3732 if (res && out_strings) {
3733 out_string = g_strdup (out_strings[0]);
3734 g_strfreev (out_strings);
3737 return complete_string_exchange (res, out_string, uid, error);
3741 * e_cal_client_create_object_sync:
3742 * @client: an #ECalClient
3743 * @icalcomp: The component to create
3744 * @uid: (out): Return value for the UID assigned to the new component by the calendar backend
3745 * @cancellable: a #GCancellable; can be %NULL
3746 * @error: (out): a #GError to set an error, if any
3748 * Requests the calendar backend to create the object specified by the @icalcomp
3749 * argument. Some backends would assign a specific UID to the newly created object,
3750 * in those cases that UID would be returned in the @uid argument. This function
3751 * does not modify the original @icalcomp if its UID changes.
3752 * Returned @uid should be freed with g_free().
3754 * Returns: %TRUE if successful, %FALSE otherwise.
3759 e_cal_client_create_object_sync (ECalClient *client,
3760 /* const */ icalcomponent *icalcomp,
3762 GCancellable *cancellable,
3766 gchar *comp_str, *gdbus_comp = NULL;
3767 const gchar *strv[2];
3768 gchar **out_strings = NULL;
3769 gchar *out_string = NULL;
3771 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
3772 g_return_val_if_fail (icalcomp != NULL, FALSE);
3773 g_return_val_if_fail (uid != NULL, FALSE);
3775 if (client->priv->dbus_proxy == NULL) {
3776 set_proxy_gone_error (error);
3780 comp_str = icalcomponent_as_ical_string_r (icalcomp);
3781 strv[0] = e_util_ensure_gdbus_string (comp_str, &gdbus_comp);
3784 g_return_val_if_fail (strv[0] != NULL, FALSE);
3786 res = e_client_proxy_call_sync_strv__strv (E_CLIENT (client), strv, &out_strings, cancellable, error, e_gdbus_cal_call_create_objects_sync);
3789 g_free (gdbus_comp);
3791 if (res && out_strings) {
3792 out_string = g_strdup (out_strings[0]);
3793 g_strfreev (out_strings);
3796 return complete_string_exchange (res, out_string, uid, error);
3800 * e_cal_client_create_objects:
3801 * @client: an #ECalClient
3802 * @icalcomps: (element-type icalcomponent): The components to create
3803 * @cancellable: (allow-none): a #GCancellable; can be %NULL
3804 * @callback: callback to call when a result is ready
3805 * @user_data: user data for the @callback
3807 * Requests the calendar backend to create the objects specified by the @icalcomps
3808 * argument. Some backends would assign a specific UID to the newly created object,
3809 * but this function does not modify the original @icalcomps if their UID changes.
3810 * The call is finished by e_cal_client_create_objects_finish() from
3816 e_cal_client_create_objects (ECalClient *client,
3818 GCancellable *cancellable,
3819 GAsyncReadyCallback callback,
3824 g_return_if_fail (E_IS_CAL_CLIENT (client));
3825 g_return_if_fail (icalcomps != NULL);
3827 array = icalcomponent_slist_to_utf8_icomp_array (icalcomps);
3829 e_client_proxy_call_strv (
3830 E_CLIENT (client), (const gchar * const *) array, cancellable, callback, user_data, e_cal_client_create_objects,
3831 e_gdbus_cal_call_create_objects,
3832 NULL, NULL, NULL, e_gdbus_cal_call_create_objects_finish, NULL);
3838 * e_cal_client_create_objects_finish:
3839 * @client: an #ECalClient
3840 * @result: a #GAsyncResult
3841 * @uids: (out) (element-type utf8): Return value for the UIDs assigned to the
3842 * new components by the calendar backend
3843 * @error: (out): a #GError to set an error, if any
3845 * Finishes previous call of e_cal_client_create_objects() and
3846 * sets @uids to newly assigned UIDs for the created objects.
3847 * This @uids should be freed with e_client_util_free_string_slist().
3849 * Returns: %TRUE if successful, %FALSE otherwise.
3854 e_cal_client_create_objects_finish (ECalClient *client,
3855 GAsyncResult *result,
3860 gchar **out_strings = NULL;
3862 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
3863 g_return_val_if_fail (uids != NULL, FALSE);
3865 res = e_client_proxy_call_finish_strv (E_CLIENT (client), result, &out_strings, error, e_cal_client_create_objects);
3867 return complete_strv_exchange (res, out_strings, uids, error);
3871 * e_cal_client_create_objects_sync:
3872 * @client: an #ECalClient
3873 * @icalcomps: (element-type icalcomponent): The components to create
3874 * @uids: (out) (element-type utf8): Return value for the UIDs assigned to the
3875 * new components by the calendar backend
3876 * @cancellable: (allow-none): a #GCancellable; can be %NULL
3877 * @error: (out): a #GError to set an error, if any
3879 * Requests the calendar backend to create the objects specified by the @icalcomps
3880 * argument. Some backends would assign a specific UID to the newly created objects,
3881 * in those cases these UIDs would be returned in the @uids argument. This function
3882 * does not modify the original @icalcomps if their UID changes.
3883 * Returned @uid should be freed with e_client_util_free_string_slist().
3885 * Returns: %TRUE if successful, %FALSE otherwise.
3890 e_cal_client_create_objects_sync (ECalClient *client,
3893 GCancellable *cancellable,
3897 gchar **array, **out_strings = NULL;
3899 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
3900 g_return_val_if_fail (icalcomps != NULL, FALSE);
3901 g_return_val_if_fail (uids != NULL, FALSE);
3903 if (client->priv->dbus_proxy == NULL) {
3904 set_proxy_gone_error (error);
3908 array = icalcomponent_slist_to_utf8_icomp_array (icalcomps);
3910 res = e_client_proxy_call_sync_strv__strv (E_CLIENT (client), (const gchar * const *) array, &out_strings, cancellable, error, e_gdbus_cal_call_create_objects_sync);
3912 return complete_strv_exchange (res, out_strings, uids, error);
3916 * e_cal_client_modify_object:
3917 * @client: an #ECalClient
3918 * @icalcomp: Component to modify
3919 * @mod: Type of modification
3920 * @cancellable: a #GCancellable; can be %NULL
3921 * @callback: callback to call when a result is ready
3922 * @user_data: user data for the @callback
3924 * Requests the calendar backend to modify an existing object. If the object
3925 * does not exist on the calendar, an error will be returned.
3927 * For recurrent appointments, the @mod argument specifies what to modify,
3928 * if all instances (CALOBJ_MOD_ALL), a single instance (CALOBJ_MOD_THIS),
3929 * or a specific set of instances (CALOBJ_MOD_THISNADPRIOR and
3930 * CALOBJ_MOD_THISANDFUTURE).
3932 * The call is finished by e_cal_client_modify_object_finish() from
3938 e_cal_client_modify_object (ECalClient *client,
3939 /* const */ icalcomponent *icalcomp,
3941 GCancellable *cancellable,
3942 GAsyncReadyCallback callback,
3945 gchar *comp_str, **strv;
3946 GSList comp_strings = {0,};
3948 g_return_if_fail (icalcomp != NULL);
3950 comp_str = icalcomponent_as_ical_string_r (icalcomp);
3951 comp_strings.data = comp_str;
3952 strv = e_gdbus_cal_encode_modify_objects (&comp_strings, mod);
3954 e_client_proxy_call_strv (
3955 E_CLIENT (client), (const gchar * const *) strv, cancellable, callback, user_data, e_cal_client_modify_object,
3956 e_gdbus_cal_call_modify_objects,
3957 e_gdbus_cal_call_modify_objects_finish, NULL, NULL, NULL, NULL);
3964 * e_cal_client_modify_object_finish:
3965 * @client: an #ECalClient
3966 * @result: a #GAsyncResult
3967 * @error: (out): a #GError to set an error, if any
3969 * Finishes previous call of e_cal_client_modify_object().
3971 * Returns: %TRUE if successful, %FALSE otherwise.
3976 e_cal_client_modify_object_finish (ECalClient *client,
3977 GAsyncResult *result,
3980 return e_client_proxy_call_finish_void (E_CLIENT (client), result, error, e_cal_client_modify_object);
3984 * e_cal_client_modify_object_sync:
3985 * @client: an #ECalClient
3986 * @icalcomp: Component to modify
3987 * @mod: Type of modification
3988 * @cancellable: a #GCancellable; can be %NULL
3989 * @error: (out): a #GError to set an error, if any
3991 * Requests the calendar backend to modify an existing object. If the object
3992 * does not exist on the calendar, an error will be returned.
3994 * For recurrent appointments, the @mod argument specifies what to modify,
3995 * if all instances (CALOBJ_MOD_ALL), a single instance (CALOBJ_MOD_THIS),
3996 * or a specific set of instances (CALOBJ_MOD_THISNADPRIOR and
3997 * CALOBJ_MOD_THISANDFUTURE).
3999 * Returns: %TRUE if successful, %FALSE otherwise.
4004 e_cal_client_modify_object_sync (ECalClient *client,
4005 /* const */ icalcomponent *icalcomp,
4007 GCancellable *cancellable,
4011 gchar *comp_str, **strv;
4012 GSList comp_strings = {0,};
4014 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
4015 g_return_val_if_fail (icalcomp != NULL, FALSE);
4017 if (client->priv->dbus_proxy == NULL) {
4018 set_proxy_gone_error (error);
4022 comp_str = icalcomponent_as_ical_string_r (icalcomp);
4023 comp_strings.data = comp_str;
4024 strv = e_gdbus_cal_encode_modify_objects (&comp_strings, mod);
4026 res = e_client_proxy_call_sync_strv__void (E_CLIENT (client), (const gchar * const *) strv, cancellable, error, e_gdbus_cal_call_modify_objects_sync);
4035 * e_cal_client_modify_objects:
4036 * @client: an #ECalClient
4037 * @comps: (element-type icalcomponent): Components to modify
4038 * @mod: Type of modification
4039 * @cancellable: (allow-none): a #GCancellable; can be %NULL
4040 * @callback: callback to call when a result is ready
4041 * @user_data: user data for the @callback
4043 * Requests the calendar backend to modify existing objects. If an object
4044 * does not exist on the calendar, an error will be returned.
4046 * For recurrent appointments, the @mod argument specifies what to modify,
4047 * if all instances (CALOBJ_MOD_ALL), a single instance (CALOBJ_MOD_THIS),
4048 * or a specific set of instances (CALOBJ_MOD_THISNADPRIOR and
4049 * CALOBJ_MOD_THISANDFUTURE).
4051 * The call is finished by e_cal_client_modify_objects_finish() from
4057 e_cal_client_modify_objects (ECalClient *client,
4058 /* const */ GSList *comps,
4060 GCancellable *cancellable,
4061 GAsyncReadyCallback callback,
4064 GSList *comp_strings;
4067 g_return_if_fail (E_IS_CAL_CLIENT (client));
4068 g_return_if_fail (comps != NULL);
4070 comp_strings = icalcomponent_slist_to_string_slist (comps);
4071 strv = e_gdbus_cal_encode_modify_objects (comp_strings, mod);
4073 e_client_proxy_call_strv (
4074 E_CLIENT (client), (const gchar * const *) strv, cancellable, callback, user_data, e_cal_client_modify_objects,
4075 e_gdbus_cal_call_modify_objects,
4076 e_gdbus_cal_call_modify_objects_finish, NULL, NULL, NULL, NULL);
4079 e_client_util_free_string_slist (comp_strings);
4083 * e_cal_client_modify_objects_finish:
4084 * @client: an #ECalClient
4085 * @result: a #GAsyncResult
4086 * @error: (out): a #GError to set an error, if any
4088 * Finishes previous call of e_cal_client_modify_objects().
4090 * Returns: %TRUE if successful, %FALSE otherwise.
4095 e_cal_client_modify_objects_finish (ECalClient *client,
4096 GAsyncResult *result,
4099 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
4101 return e_client_proxy_call_finish_void (E_CLIENT (client), result, error, e_cal_client_modify_objects);
4105 * e_cal_client_modify_objects_sync:
4106 * @client: an #ECalClient
4107 * @comps: (element-type icalcomponent): Components to modify
4108 * @mod: Type of modification
4109 * @cancellable: (allow-none): a #GCancellable; can be %NULL
4110 * @error: (out): a #GError to set an error, if any
4112 * Requests the calendar backend to modify existing objects. If an object
4113 * does not exist on the calendar, an error will be returned.
4115 * For recurrent appointments, the @mod argument specifies what to modify,
4116 * if all instances (CALOBJ_MOD_ALL), a single instance (CALOBJ_MOD_THIS),
4117 * or a specific set of instances (CALOBJ_MOD_THISNADPRIOR and
4118 * CALOBJ_MOD_THISANDFUTURE).
4120 * Returns: %TRUE if successful, %FALSE otherwise.
4125 e_cal_client_modify_objects_sync (ECalClient *client,
4126 /* const */ GSList *comps,
4128 GCancellable *cancellable,
4133 GSList *comp_strings;
4135 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
4136 g_return_val_if_fail (comps != NULL, FALSE);
4138 if (client->priv->dbus_proxy == NULL) {
4139 set_proxy_gone_error (error);
4143 comp_strings = icalcomponent_slist_to_string_slist (comps);
4144 strv = e_gdbus_cal_encode_modify_objects (comp_strings, mod);
4146 res = e_client_proxy_call_sync_strv__void (E_CLIENT (client), (const gchar * const *) strv, cancellable, error, e_gdbus_cal_call_modify_objects_sync);
4149 e_client_util_free_string_slist (comp_strings);
4155 * e_cal_client_remove_object:
4156 * @client: an #ECalClient
4157 * @uid: UID of the object to remove
4158 * @rid: Recurrence ID of the specific recurrence to remove
4159 * @mod: Type of the removal
4160 * @cancellable: a #GCancellable; can be %NULL
4161 * @callback: callback to call when a result is ready
4162 * @user_data: user data for the @callback
4164 * This function allows the removal of instances of a recurrent
4165 * appointment. By using a combination of the @uid, @rid and @mod
4166 * arguments, you can remove specific instances. If what you want
4167 * is to remove all instances, use #NULL @rid and CALOBJ_MOD_ALL
4170 * The call is finished by e_cal_client_remove_object_finish() from
4176 e_cal_client_remove_object (ECalClient *client,
4180 GCancellable *cancellable,
4181 GAsyncReadyCallback callback,
4188 g_return_if_fail (uid != NULL);
4190 id.uid = (gchar *) uid;
4191 id.rid = (gchar *) rid;
4193 strv = e_gdbus_cal_encode_remove_objects (&ids, mod);
4195 e_client_proxy_call_strv (
4196 E_CLIENT (client), (const gchar * const *) strv, cancellable, callback, user_data, e_cal_client_remove_object,
4197 e_gdbus_cal_call_remove_objects,
4198 e_gdbus_cal_call_remove_objects_finish, NULL, NULL, NULL, NULL);
4204 * e_cal_client_remove_object_finish:
4205 * @client: an #ECalClient
4206 * @result: a #GAsyncResult
4207 * @error: (out): a #GError to set an error, if any
4209 * Finishes previous call of e_cal_client_remove_object().
4211 * Returns: %TRUE if successful, %FALSE otherwise.
4216 e_cal_client_remove_object_finish (ECalClient *client,
4217 GAsyncResult *result,
4220 return e_client_proxy_call_finish_void (E_CLIENT (client), result, error, e_cal_client_remove_object);
4224 * e_cal_client_remove_object_sync:
4225 * @client: an #ECalClient
4226 * @uid: UID of the object to remove
4227 * @rid: Recurrence ID of the specific recurrence to remove
4228 * @mod: Type of the removal
4229 * @cancellable: a #GCancellable; can be %NULL
4230 * @error: (out): a #GError to set an error, if any
4232 * This function allows the removal of instances of a recurrent
4233 * appointment. By using a combination of the @uid, @rid and @mod
4234 * arguments, you can remove specific instances. If what you want
4235 * is to remove all instances, use #NULL @rid and CALOBJ_MODE_THIS
4238 * Returns: %TRUE if successful, %FALSE otherwise.
4243 e_cal_client_remove_object_sync (ECalClient *client,
4247 GCancellable *cancellable,
4255 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
4256 g_return_val_if_fail (uid != NULL, FALSE);
4258 if (client->priv->dbus_proxy == NULL) {
4259 set_proxy_gone_error (error);
4263 id.uid = (gchar *) uid;
4264 id.rid = (gchar *) rid;
4266 strv = e_gdbus_cal_encode_remove_objects (&ids, mod);
4268 res = e_client_proxy_call_sync_strv__void (E_CLIENT (client), (const gchar * const *) strv, cancellable, error, e_gdbus_cal_call_remove_objects_sync);
4276 * e_cal_client_remove_objects:
4277 * @client: an #ECalClient
4278 * @ids: (element-type ECalComponentId): A list of #ECalComponentId objects
4279 * identifying the objects to remove
4280 * @mod: Type of the removal
4281 * @cancellable: a #GCancellable; can be %NULL
4282 * @callback: callback to call when a result is ready
4283 * @user_data: user data for the @callback
4285 * This function allows the removal of instances of recurrent
4286 * appointments. #ECalComponentId objects can identify specific instances (if rid is not NULL).
4287 * If what you want is to remove all instances, use a #NULL rid in the #ECalComponentId and CALOBJ_MOD_ALL
4290 * The call is finished by e_cal_client_remove_objects_finish() from
4296 e_cal_client_remove_objects (ECalClient *client,
4299 GCancellable *cancellable,
4300 GAsyncReadyCallback callback,
4305 g_return_if_fail (ids != NULL);
4307 strv = e_gdbus_cal_encode_remove_objects (ids, mod);
4309 e_client_proxy_call_strv (
4310 E_CLIENT (client), (const gchar * const *) strv, cancellable, callback, user_data, e_cal_client_remove_objects,
4311 e_gdbus_cal_call_remove_objects,
4312 e_gdbus_cal_call_remove_objects_finish, NULL, NULL, NULL, NULL);
4318 * e_cal_client_remove_objects_finish:
4319 * @client: an #ECalClient
4320 * @result: a #GAsyncResult
4321 * @error: (out): a #GError to set an error, if any
4323 * Finishes previous call of e_cal_client_remove_objects().
4325 * Returns: %TRUE if successful, %FALSE otherwise.
4330 e_cal_client_remove_objects_finish (ECalClient *client,
4331 GAsyncResult *result,
4334 return e_client_proxy_call_finish_void (E_CLIENT (client), result, error, e_cal_client_remove_objects);
4338 * e_cal_client_remove_objects_sync:
4339 * @client: an #ECalClient
4340 * @ids: (element-type ECalComponentId): A list of #ECalComponentId objects
4341 * identifying the objects to remove
4342 * @mod: Type of the removal
4343 * @cancellable: (allow-none): a #GCancellable; can be %NULL
4344 * @error: (out): a #GError to set an error, if any
4346 * This function allows the removal of instances of recurrent
4347 * appointments. #ECalComponentId objects can identify specific instances (if rid is not NULL).
4348 * If what you want is to remove all instances, use a #NULL rid in the #ECalComponentId and CALOBJ_MOD_ALL
4351 * Returns: %TRUE if successful, %FALSE otherwise.
4356 e_cal_client_remove_objects_sync (ECalClient *client,
4359 GCancellable *cancellable,
4365 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
4366 g_return_val_if_fail (ids != NULL, FALSE);
4368 if (client->priv->dbus_proxy == NULL) {
4369 set_proxy_gone_error (error);
4373 strv = e_gdbus_cal_encode_remove_objects (ids, mod);
4375 res = e_client_proxy_call_sync_strv__void (E_CLIENT (client), (const gchar * const *) strv, cancellable, error, e_gdbus_cal_call_remove_objects_sync);
4383 * e_cal_client_receive_objects:
4384 * @client: an #ECalClient
4385 * @icalcomp: An #icalcomponent
4386 * @cancellable: a #GCancellable; can be %NULL
4387 * @callback: callback to call when a result is ready
4388 * @user_data: user data for the @callback
4390 * Makes the backend receive the set of iCalendar objects specified in the
4391 * @icalcomp argument. This is used for iTIP confirmation/cancellation
4392 * messages for scheduled meetings.
4394 * The call is finished by e_cal_client_receive_objects_finish() from
4400 e_cal_client_receive_objects (ECalClient *client,
4401 /* const */ icalcomponent *icalcomp,
4402 GCancellable *cancellable,
4403 GAsyncReadyCallback callback,
4406 gchar *comp_str, *gdbus_comp = NULL;
4408 g_return_if_fail (icalcomp != NULL);
4410 comp_str = icalcomponent_as_ical_string_r (icalcomp);
4412 e_client_proxy_call_string (
4413 E_CLIENT (client), e_util_ensure_gdbus_string (comp_str, &gdbus_comp), cancellable, callback, user_data, e_cal_client_receive_objects,
4414 e_gdbus_cal_call_receive_objects,
4415 e_gdbus_cal_call_receive_objects_finish, NULL, NULL, NULL, NULL);
4418 g_free (gdbus_comp);
4422 * e_cal_client_receive_objects_finish:
4423 * @client: an #ECalClient
4424 * @result: a #GAsyncResult
4425 * @error: (out): a #GError to set an error, if any
4427 * Finishes previous call of e_cal_client_receive_objects().
4429 * Returns: %TRUE if successful, %FALSE otherwise.
4434 e_cal_client_receive_objects_finish (ECalClient *client,
4435 GAsyncResult *result,
4438 return e_client_proxy_call_finish_void (E_CLIENT (client), result, error, e_cal_client_receive_objects);
4442 * e_cal_client_receive_objects_sync:
4443 * @client: an #ECalClient
4444 * @icalcomp: An #icalcomponent
4445 * @cancellable: a #GCancellable; can be %NULL
4446 * @error: (out): a #GError to set an error, if any
4448 * Makes the backend receive the set of iCalendar objects specified in the
4449 * @icalcomp argument. This is used for iTIP confirmation/cancellation
4450 * messages for scheduled meetings.
4452 * Returns: %TRUE if successful, %FALSE otherwise.
4457 e_cal_client_receive_objects_sync (ECalClient *client,
4458 /* const */ icalcomponent *icalcomp,
4459 GCancellable *cancellable,
4463 gchar *comp_str, *gdbus_comp = NULL;
4465 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
4467 if (client->priv->dbus_proxy == NULL) {
4468 set_proxy_gone_error (error);
4472 comp_str = icalcomponent_as_ical_string_r (icalcomp);
4474 res = e_client_proxy_call_sync_string__void (E_CLIENT (client), e_util_ensure_gdbus_string (comp_str, &gdbus_comp), cancellable, error, e_gdbus_cal_call_receive_objects_sync);
4477 g_free (gdbus_comp);
4483 * e_cal_client_send_objects:
4484 * @client: an #ECalClient
4485 * @icalcomp: An icalcomponent to be sent
4486 * @cancellable: a #GCancellable; can be %NULL
4487 * @callback: callback to call when a result is ready
4488 * @user_data: user data for the @callback
4490 * Requests a calendar backend to send meeting information stored in @icalcomp.
4491 * The backend can modify this component and request a send to particular users.
4492 * The call is finished by e_cal_client_send_objects_finish() from
4498 e_cal_client_send_objects (ECalClient *client,
4499 /* const */ icalcomponent *icalcomp,
4500 GCancellable *cancellable,
4501 GAsyncReadyCallback callback,
4504 gchar *comp_str, *gdbus_comp = NULL;
4506 g_return_if_fail (icalcomp != NULL);
4508 comp_str = icalcomponent_as_ical_string_r (icalcomp);
4510 e_client_proxy_call_string (
4511 E_CLIENT (client), e_util_ensure_gdbus_string (comp_str, &gdbus_comp), cancellable, callback, user_data, e_cal_client_send_objects,
4512 e_gdbus_cal_call_send_objects,
4513 NULL, NULL, NULL, e_gdbus_cal_call_send_objects_finish, NULL);
4516 g_free (gdbus_comp);
4520 complete_send_objects (gboolean res,
4523 icalcomponent **modified_icalcomp,
4526 g_return_val_if_fail (users != NULL, FALSE);
4527 g_return_val_if_fail (modified_icalcomp != NULL, FALSE);
4530 *modified_icalcomp = NULL;
4532 if (res && out_strv) {
4533 gchar *calobj = NULL;
4535 if (e_gdbus_cal_decode_send_objects ((const gchar * const *) out_strv, &calobj, users)) {
4536 *modified_icalcomp = icalparser_parse_string (calobj);
4537 if (!*modified_icalcomp) {
4538 g_propagate_error (error, e_cal_client_error_create (E_CAL_CLIENT_ERROR_INVALID_OBJECT, NULL));
4539 e_client_util_free_string_slist (*users);
4544 g_propagate_error (error, e_client_error_create (E_CLIENT_ERROR_INVALID_ARG, NULL));
4545 e_client_util_free_string_slist (*users);
4555 g_strfreev (out_strv);
4561 * e_cal_client_send_objects_finish:
4562 * @client: an #ECalClient
4563 * @result: a #GAsyncResult
4564 * @users: (out) (element-type utf8): List of users to send
4565 * the @modified_icalcomp to
4566 * @modified_icalcomp: (out): Return value for the icalcomponent to be sent
4567 * @error: (out): a #GError to set an error, if any
4569 * Finishes previous call of e_cal_client_send_objects() and
4570 * populates @users with a list of users to send @modified_icalcomp to.
4571 * The @users list should be freed with e_client_util_free_string_slist() and
4572 * the @modified_icalcomp should be freed with icalcomponent_free().
4574 * Returns: %TRUE if successful, %FALSE otherwise.
4579 e_cal_client_send_objects_finish (ECalClient *client,
4580 GAsyncResult *result,
4582 icalcomponent **modified_icalcomp,
4586 gchar **out_strv = NULL;
4588 g_return_val_if_fail (users != NULL, FALSE);
4589 g_return_val_if_fail (modified_icalcomp != NULL, FALSE);
4591 res = e_client_proxy_call_finish_strv (E_CLIENT (client), result, &out_strv, error, e_cal_client_send_objects);
4593 return complete_send_objects (res, out_strv, users, modified_icalcomp, error);
4597 * e_cal_client_send_objects_sync:
4598 * @client: an #ECalClient
4599 * @icalcomp: An icalcomponent to be sent
4600 * @users: (out) (element-type utf8): List of users to send
4601 * the @modified_icalcomp to
4602 * @modified_icalcomp: (out): Return value for the icalcomponent to be sent
4603 * @cancellable: (allow-none): a #GCancellable; can be %NULL
4604 * @error: (out): a #GError to set an error, if any
4606 * Requests a calendar backend to send meeting information stored in @icalcomp.
4607 * The backend can modify this component and request a send to users in the @users list.
4608 * The @users list should be freed with e_client_util_free_string_slist() and
4609 * the @modified_icalcomp should be freed with icalcomponent_free().
4611 * Returns: %TRUE if successful, %FALSE otherwise.
4616 e_cal_client_send_objects_sync (ECalClient *client,
4617 /* const */ icalcomponent *icalcomp,
4619 icalcomponent **modified_icalcomp,
4620 GCancellable *cancellable,
4624 gchar **out_strv = NULL, *comp_str, *gdbus_comp = NULL;
4626 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
4627 g_return_val_if_fail (icalcomp != NULL, FALSE);
4628 g_return_val_if_fail (users != NULL, FALSE);
4629 g_return_val_if_fail (modified_icalcomp != NULL, FALSE);
4631 if (client->priv->dbus_proxy == NULL) {
4632 set_proxy_gone_error (error);
4636 comp_str = icalcomponent_as_ical_string_r (icalcomp);
4638 res = e_client_proxy_call_sync_string__strv (E_CLIENT (client), e_util_ensure_gdbus_string (comp_str, &gdbus_comp), &out_strv, cancellable, error, e_gdbus_cal_call_send_objects_sync);
4641 g_free (gdbus_comp);
4643 return complete_send_objects (res, out_strv, users, modified_icalcomp, error);
4647 * e_cal_client_get_attachment_uris:
4648 * @client: an #ECalClient
4649 * @uid: Unique identifier for a calendar component
4650 * @rid: Recurrence identifier
4651 * @cancellable: a #GCancellable; can be %NULL
4652 * @callback: callback to call when a result is ready
4653 * @user_data: user data for the @callback
4655 * Queries a calendar for a specified component's object attachment uris.
4656 * The call is finished by e_cal_client_get_attachment_uris_finish() from
4662 e_cal_client_get_attachment_uris (ECalClient *client,
4665 GCancellable *cancellable,
4666 GAsyncReadyCallback callback,
4671 g_return_if_fail (uid != NULL);
4673 strv = e_gdbus_cal_encode_get_attachment_uris (uid, rid);
4675 e_client_proxy_call_strv (
4676 E_CLIENT (client), (const gchar * const *) strv, cancellable, callback, user_data, e_cal_client_get_attachment_uris,
4677 e_gdbus_cal_call_get_attachment_uris,
4678 NULL, NULL, NULL, e_gdbus_cal_call_get_attachment_uris_finish, NULL);
4684 * e_cal_client_get_attachment_uris_finish:
4685 * @client: an #ECalClient
4686 * @result: a #GAsyncResult
4687 * @attachment_uris: (out) (element-type utf8): Return the list of attachment
4689 * @error: (out): a #GError to set an error, if any
4691 * Finishes previous call of e_cal_client_get_attachment_uris() and
4692 * sets @attachment_uris to uris for component's attachments.
4693 * The list should be freed with e_client_util_free_string_slist().
4695 * Returns: %TRUE if successful, %FALSE otherwise.
4700 e_cal_client_get_attachment_uris_finish (ECalClient *client,
4701 GAsyncResult *result,
4702 GSList **attachment_uris,
4706 gchar **out_strv = NULL;
4708 g_return_val_if_fail (attachment_uris != NULL, FALSE);
4710 res = e_client_proxy_call_finish_strv (E_CLIENT (client), result, &out_strv, error, e_cal_client_get_attachment_uris);
4712 if (res && out_strv) {
4713 *attachment_uris = e_client_util_strv_to_slist ((const gchar * const *) out_strv);
4715 *attachment_uris = NULL;
4718 g_strfreev (out_strv);
4724 * e_cal_client_get_attachment_uris_sync:
4725 * @client: an #ECalClient
4726 * @uid: Unique identifier for a calendar component
4727 * @rid: Recurrence identifier
4728 * @attachment_uris: (out) (element-type utf8): Return the list of attachment
4730 * @cancellable: (allow-none): a #GCancellable; can be %NULL
4731 * @error: (out): a #GError to set an error, if any
4733 * Queries a calendar for a specified component's object attachment URIs.
4734 * The list should be freed with e_client_util_free_string_slist().
4736 * Returns: %TRUE if successful, %FALSE otherwise.
4741 e_cal_client_get_attachment_uris_sync (ECalClient *client,
4744 GSList **attachment_uris,
4745 GCancellable *cancellable,
4749 gchar **strv, **out_strv = NULL;
4751 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
4752 g_return_val_if_fail (uid != NULL, FALSE);
4753 g_return_val_if_fail (attachment_uris != NULL, FALSE);
4755 if (client->priv->dbus_proxy == NULL) {
4756 set_proxy_gone_error (error);
4760 strv = e_gdbus_cal_encode_get_attachment_uris (uid, rid);
4762 res = e_client_proxy_call_sync_strv__strv (E_CLIENT (client), (const gchar * const *) strv, &out_strv, cancellable, error, e_gdbus_cal_call_get_attachment_uris_sync);
4766 if (res && out_strv) {
4767 *attachment_uris = e_client_util_strv_to_slist ((const gchar * const *) out_strv);
4769 *attachment_uris = NULL;
4772 g_strfreev (out_strv);
4778 * e_cal_client_discard_alarm:
4779 * @client: an #ECalClient
4780 * @uid: Unique identifier for a calendar component
4781 * @rid: Recurrence identifier
4782 * @auid: Alarm identifier to remove
4783 * @cancellable: a #GCancellable; can be %NULL
4784 * @callback: callback to call when a result is ready
4785 * @user_data: user data for the @callback
4787 * Removes alarm @auid from a given component identified by @uid and @rid.
4788 * The call is finished by e_cal_client_discard_alarm_finish() from
4794 e_cal_client_discard_alarm (ECalClient *client,
4798 GCancellable *cancellable,
4799 GAsyncReadyCallback callback,
4804 g_return_if_fail (uid != NULL);
4805 g_return_if_fail (auid != NULL);
4807 strv = e_gdbus_cal_encode_discard_alarm (uid, rid, auid);
4809 e_client_proxy_call_strv (
4810 E_CLIENT (client), (const gchar * const *) strv, cancellable, callback, user_data, e_cal_client_discard_alarm,
4811 e_gdbus_cal_call_discard_alarm,
4812 e_gdbus_cal_call_discard_alarm_finish, NULL, NULL, NULL, NULL);
4818 * e_cal_client_discard_alarm_finish:
4819 * @client: an #ECalClient
4820 * @result: a #GAsyncResult
4821 * @error: (out): a #GError to set an error, if any
4823 * Finishes previous call of e_cal_client_discard_alarm().
4825 * Returns: %TRUE if successful, %FALSE otherwise.
4830 e_cal_client_discard_alarm_finish (ECalClient *client,
4831 GAsyncResult *result,
4834 return e_client_proxy_call_finish_void (E_CLIENT (client), result, error, e_cal_client_discard_alarm);
4838 * e_cal_client_discard_alarm_sync:
4839 * @client: an #ECalClient
4840 * @uid: Unique identifier for a calendar component
4841 * @rid: Recurrence identifier
4842 * @auid: Alarm identifier to remove
4843 * @cancellable: a #GCancellable; can be %NULL
4844 * @error: (out): a #GError to set an error, if any
4846 * Removes alarm @auid from a given component identified by @uid and @rid.
4848 * Returns: %TRUE if successful, %FALSE otherwise.
4853 e_cal_client_discard_alarm_sync (ECalClient *client,
4857 GCancellable *cancellable,
4863 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
4864 g_return_val_if_fail (uid != NULL, FALSE);
4865 g_return_val_if_fail (auid != NULL, FALSE);
4867 if (client->priv->dbus_proxy == NULL) {
4868 set_proxy_gone_error (error);
4872 strv = e_gdbus_cal_encode_discard_alarm (uid, rid, auid);
4874 res = e_client_proxy_call_sync_strv__void (E_CLIENT (client), (const gchar * const *) strv, cancellable, error, e_gdbus_cal_call_discard_alarm_sync);
4882 * e_cal_client_get_view:
4883 * @client: an #ECalClient
4884 * @sexp: an S-expression representing the query.
4885 * @cancellable: a #GCancellable; can be %NULL
4886 * @callback: callback to call when a result is ready
4887 * @user_data: user data for the @callback
4889 * Query @client with @sexp, creating an #ECalClientView.
4890 * The call is finished by e_cal_client_get_view_finish()
4891 * from the @callback.
4896 e_cal_client_get_view (ECalClient *client,
4898 GCancellable *cancellable,
4899 GAsyncReadyCallback callback,
4902 gchar *gdbus_sexp = NULL;
4904 g_return_if_fail (sexp != NULL);
4906 e_client_proxy_call_string (
4907 E_CLIENT (client), e_util_ensure_gdbus_string (sexp, &gdbus_sexp), cancellable, callback, user_data, e_cal_client_get_view,
4908 e_gdbus_cal_call_get_view,
4909 NULL, NULL, e_gdbus_cal_call_get_view_finish, NULL, NULL);
4911 g_free (gdbus_sexp);
4915 complete_get_view (ECalClient *client,
4918 ECalClientView **view,
4921 g_return_val_if_fail (view != NULL, FALSE);
4923 if (view_path && res && cal_factory) {
4924 GDBusConnection *connection;
4925 GError *local_error = NULL;
4927 connection = g_dbus_proxy_get_connection (
4928 G_DBUS_PROXY (cal_factory));
4930 *view = g_initable_new (
4931 E_TYPE_CAL_CLIENT_VIEW,
4934 "connection", connection,
4935 "object-path", view_path,
4938 if (local_error != NULL) {
4939 unwrap_dbus_error (local_error, error);
4947 if (!*view && error && !*error)
4948 g_set_error_literal (error, E_CLIENT_ERROR, E_CLIENT_ERROR_DBUS_ERROR, _("Cannot get connection to view"));
4956 * e_cal_client_get_view_finish:
4957 * @client: an #ECalClient
4958 * @result: a #GAsyncResult
4959 * @view: (out) an #ECalClientView
4960 * @error: (out): a #GError to set an error, if any
4962 * Finishes previous call of e_cal_client_get_view().
4963 * If successful, then the @view is set to newly allocated #ECalClientView,
4964 * which should be freed with g_object_unref().
4966 * Returns: %TRUE if successful, %FALSE otherwise.
4971 e_cal_client_get_view_finish (ECalClient *client,
4972 GAsyncResult *result,
4973 ECalClientView **view,
4977 gchar *view_path = NULL;
4979 g_return_val_if_fail (view != NULL, FALSE);
4981 res = e_client_proxy_call_finish_string (E_CLIENT (client), result, &view_path, error, e_cal_client_get_view);
4983 return complete_get_view (client, res, view_path, view, error);
4987 * e_cal_client_get_view_sync:
4988 * @client: an #ECalClient
4989 * @sexp: an S-expression representing the query.
4990 * @view: (out) an #ECalClientView
4991 * @cancellable: a #GCancellable; can be %NULL
4992 * @error: (out): a #GError to set an error, if any
4994 * Query @client with @sexp, creating an #ECalClientView.
4995 * If successful, then the @view is set to newly allocated #ECalClientView,
4996 * which should be freed with g_object_unref().
4998 * Returns: %TRUE if successful, %FALSE otherwise.
5003 e_cal_client_get_view_sync (ECalClient *client,
5005 ECalClientView **view,
5006 GCancellable *cancellable,
5010 gchar *gdbus_sexp = NULL;
5011 gchar *view_path = NULL;
5013 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
5014 g_return_val_if_fail (sexp != NULL, FALSE);
5015 g_return_val_if_fail (view != NULL, FALSE);
5017 if (client->priv->dbus_proxy == NULL) {
5018 set_proxy_gone_error (error);
5022 res = e_client_proxy_call_sync_string__string (E_CLIENT (client), e_util_ensure_gdbus_string (sexp, &gdbus_sexp), &view_path, cancellable, error, e_gdbus_cal_call_get_view_sync);
5024 g_free (gdbus_sexp);
5026 return complete_get_view (client, res, view_path, view, error);
5030 cal_client_get_timezone_from_cache_finish (ECalClient *client,
5031 GAsyncResult *result,
5032 icaltimezone **zone,
5035 GSimpleAsyncResult *simple;
5036 GError *local_error = NULL;
5038 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
5039 g_return_val_if_fail (result != NULL, FALSE);
5040 g_return_val_if_fail (zone != NULL, FALSE);
5041 g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (client), e_timezone_cache_get_timezone), FALSE);
5043 simple = G_SIMPLE_ASYNC_RESULT (result);
5045 if (g_simple_async_result_propagate_error (simple, &local_error)) {
5046 e_client_unwrap_dbus_error (E_CLIENT (client), local_error, error);
5050 *zone = g_simple_async_result_get_op_res_gpointer (simple);
5052 return *zone != NULL;
5056 * e_cal_client_get_timezone:
5057 * @client: an #ECalClient
5058 * @tzid: ID of the timezone to retrieve
5059 * @cancellable: a #GCancellable; can be %NULL
5060 * @callback: callback to call when a result is ready
5061 * @user_data: user data for the @callback
5063 * Retrieves a timezone object from the calendar backend.
5064 * The call is finished by e_cal_client_get_timezone_finish() from
5070 e_cal_client_get_timezone (ECalClient *client,
5072 GCancellable *cancellable,
5073 GAsyncReadyCallback callback,
5076 gchar *gdbus_tzid = NULL;
5079 g_return_if_fail (tzid != NULL);
5081 zone = e_timezone_cache_get_timezone (
5082 E_TIMEZONE_CACHE (client), tzid);
5084 e_client_finish_async_without_dbus (E_CLIENT (client), cancellable, callback, user_data, e_timezone_cache_get_timezone, zone, NULL);
5086 e_client_proxy_call_string (
5087 E_CLIENT (client), e_util_ensure_gdbus_string (tzid, &gdbus_tzid), cancellable, callback, user_data, e_cal_client_get_timezone,
5088 e_gdbus_cal_call_get_timezone,
5089 NULL, NULL, e_gdbus_cal_call_get_timezone_finish, NULL, NULL);
5091 g_free (gdbus_tzid);
5096 complete_get_timezone (ECalClient *client,
5099 icaltimezone **zone,
5102 g_return_val_if_fail (zone != NULL, FALSE);
5106 if (res && out_string) {
5107 icalcomponent *icalcomp;
5109 icalcomp = icalparser_parse_string (out_string);
5111 *zone = icaltimezone_new ();
5112 if (!icaltimezone_set_component (*zone, icalcomp)) {
5113 icaltimezone_free (*zone, 1);
5114 icalcomponent_free (icalcomp);
5116 g_propagate_error (error, e_cal_client_error_create (E_CAL_CLIENT_ERROR_INVALID_OBJECT, NULL));
5120 tzid = icaltimezone_get_tzid (*zone);
5122 /* Add the timezone to the cache directly,
5123 * otherwise we'd have to free this struct
5124 * and fetch the cached copy. */
5125 g_mutex_lock (&client->priv->zone_cache_lock);
5126 g_hash_table_insert (
5127 client->priv->zone_cache,
5128 g_strdup (tzid), *zone);
5129 g_mutex_unlock (&client->priv->zone_cache_lock);
5133 g_propagate_error (error, e_cal_client_error_create (E_CAL_CLIENT_ERROR_INVALID_OBJECT, NULL));
5139 g_free (out_string);
5145 * e_cal_client_get_timezone_finish:
5146 * @client: an #ECalClient
5147 * @result: a #GAsyncResult
5148 * @zone: (out): Return value for the timezone
5149 * @error: (out): a #GError to set an error, if any
5151 * Finishes previous call of e_cal_client_get_timezone() and
5152 * sets @zone to a retrieved timezone object from the calendar backend.
5153 * This object is owned by the @client, thus do not free it.
5155 * Returns: %TRUE if successful, %FALSE otherwise.
5160 e_cal_client_get_timezone_finish (ECalClient *client,
5161 GAsyncResult *result,
5162 icaltimezone **zone,
5166 gchar *out_string = NULL;
5168 g_return_val_if_fail (zone != NULL, FALSE);
5170 if (g_simple_async_result_get_source_tag (G_SIMPLE_ASYNC_RESULT (result)) == e_timezone_cache_get_timezone) {
5171 res = cal_client_get_timezone_from_cache_finish (client, result, zone, error);
5173 res = e_client_proxy_call_finish_string (E_CLIENT (client), result, &out_string, error, e_cal_client_get_timezone);
5174 res = complete_get_timezone (client, res, out_string, zone, error);
5181 * e_cal_client_get_timezone_sync:
5182 * @client: an #ECalClient
5183 * @tzid: ID of the timezone to retrieve
5184 * @zone: (out): Return value for the timezone
5185 * @cancellable: a #GCancellable; can be %NULL
5186 * @error: (out): a #GError to set an error, if any
5188 * Retrieves a timezone object from the calendar backend.
5189 * This object is owned by the @client, thus do not free it.
5191 * Returns: %TRUE if successful, %FALSE otherwise.
5196 e_cal_client_get_timezone_sync (ECalClient *client,
5198 icaltimezone **zone,
5199 GCancellable *cancellable,
5203 gchar *gdbus_tzid = NULL, *out_string = NULL;
5205 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
5206 g_return_val_if_fail (tzid != NULL, FALSE);
5207 g_return_val_if_fail (zone != NULL, FALSE);
5209 if (client->priv->dbus_proxy == NULL) {
5210 set_proxy_gone_error (error);
5214 *zone = e_timezone_cache_get_timezone (
5215 E_TIMEZONE_CACHE (client), tzid);
5219 res = e_client_proxy_call_sync_string__string (E_CLIENT (client), e_util_ensure_gdbus_string (tzid, &gdbus_tzid), &out_string, cancellable, error, e_gdbus_cal_call_get_timezone_sync);
5221 g_free (gdbus_tzid);
5223 return complete_get_timezone (client, res, out_string, zone, error);
5227 * e_cal_client_add_timezone:
5228 * @client: an #ECalClient
5229 * @zone: The timezone to add
5230 * @cancellable: a #GCancellable; can be %NULL
5231 * @callback: callback to call when a result is ready
5232 * @user_data: user data for the @callback
5234 * Add a VTIMEZONE object to the given calendar client.
5235 * The call is finished by e_cal_client_add_timezone_finish() from
5241 e_cal_client_add_timezone (ECalClient *client,
5242 /* const */ icaltimezone *zone,
5243 GCancellable *cancellable,
5244 GAsyncReadyCallback callback,
5247 icalcomponent *icalcomp;
5248 gchar *zone_str, *gdbus_zone = NULL;
5250 g_return_if_fail (zone != NULL);
5252 if (zone == icaltimezone_get_utc_timezone ())
5255 icalcomp = icaltimezone_get_component (zone);
5256 g_return_if_fail (icalcomp != NULL);
5258 zone_str = icalcomponent_as_ical_string_r (icalcomp);
5260 e_client_proxy_call_string (
5261 E_CLIENT (client), e_util_ensure_gdbus_string (zone_str, &gdbus_zone), cancellable, callback, user_data, e_cal_client_add_timezone,
5262 e_gdbus_cal_call_add_timezone,
5263 e_gdbus_cal_call_add_timezone_finish, NULL, NULL, NULL, NULL);
5266 g_free (gdbus_zone);
5270 * e_cal_client_add_timezone_finish:
5271 * @client: an #ECalClient
5272 * @result: a #GAsyncResult
5273 * @error: (out): a #GError to set an error, if any
5275 * Finishes previous call of e_cal_client_add_timezone().
5277 * Returns: %TRUE if successful, %FALSE otherwise.
5282 e_cal_client_add_timezone_finish (ECalClient *client,
5283 GAsyncResult *result,
5286 return e_client_proxy_call_finish_void (E_CLIENT (client), result, error, e_cal_client_add_timezone);
5290 * e_cal_client_add_timezone_sync:
5291 * @client: an #ECalClient
5292 * @zone: The timezone to add
5293 * @cancellable: a #GCancellable; can be %NULL
5294 * @error: (out): a #GError to set an error, if any
5296 * Add a VTIMEZONE object to the given calendar client.
5298 * Returns: %TRUE if successful, %FALSE otherwise.
5303 e_cal_client_add_timezone_sync (ECalClient *client,
5304 /* const */ icaltimezone *zone,
5305 GCancellable *cancellable,
5309 icalcomponent *icalcomp;
5310 gchar *zone_str, *gdbus_zone = NULL;
5312 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
5313 g_return_val_if_fail (zone != NULL, FALSE);
5315 if (zone == icaltimezone_get_utc_timezone ())
5318 icalcomp = icaltimezone_get_component (zone);
5320 g_propagate_error (error, e_client_error_create (E_CLIENT_ERROR_INVALID_ARG, NULL));
5324 if (client->priv->dbus_proxy == NULL) {
5325 set_proxy_gone_error (error);
5329 zone_str = icalcomponent_as_ical_string_r (icalcomp);
5331 res = e_client_proxy_call_sync_string__void (E_CLIENT (client), e_util_ensure_gdbus_string (zone_str, &gdbus_zone), cancellable, error, e_gdbus_cal_call_add_timezone_sync);
5334 g_free (gdbus_zone);