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 /* Private D-Bus classes. */
30 #include <e-dbus-calendar.h>
31 #include <e-dbus-calendar-factory.h>
33 #include <libedataserver/e-client-private.h>
35 #include "e-cal-client.h"
36 #include "e-cal-component.h"
37 #include "e-cal-check-timezones.h"
38 #include "e-cal-enumtypes.h"
39 #include "e-cal-time-util.h"
40 #include "e-cal-types.h"
41 #include "e-timezone-cache.h"
43 #define E_CAL_CLIENT_GET_PRIVATE(obj) \
44 (G_TYPE_INSTANCE_GET_PRIVATE \
45 ((obj), E_TYPE_CAL_CLIENT, ECalClientPrivate))
47 /* Set this to a sufficiently large value
48 * to cover most long-running operations. */
49 #define DBUS_PROXY_TIMEOUT_MS (3 * 60 * 1000) /* 3 minutes */
51 typedef struct _AsyncContext AsyncContext;
52 typedef struct _SignalClosure SignalClosure;
53 typedef struct _ConnectClosure ConnectClosure;
54 typedef struct _RunInThreadClosure RunInThreadClosure;
56 struct _ECalClientPrivate {
57 EDBusCalendar *dbus_proxy;
58 GMainContext *main_context;
61 ECalClientSourceType source_type;
62 icaltimezone *default_zone;
64 GMutex zone_cache_lock;
65 GHashTable *zone_cache;
67 gulong dbus_proxy_error_handler_id;
68 gulong dbus_proxy_notify_handler_id;
69 gulong dbus_proxy_free_busy_data_handler_id;
72 struct _AsyncContext {
73 ECalClientView *client_view;
74 icalcomponent *in_comp;
75 icalcomponent *out_comp;
90 struct _SignalClosure {
94 gchar **free_busy_data;
95 icaltimezone *cached_zone;
98 struct _ConnectClosure {
100 GCancellable *cancellable;
103 struct _RunInThreadClosure {
104 GSimpleAsyncThreadFunc func;
105 GSimpleAsyncResult *simple;
106 GCancellable *cancellable;
119 /* Forward Declarations */
120 static void e_cal_client_initable_init
121 (GInitableIface *interface);
122 static void e_cal_client_async_initable_init
123 (GAsyncInitableIface *interface);
124 static void e_cal_client_timezone_cache_init
125 (ETimezoneCacheInterface *interface);
127 static guint signals[LAST_SIGNAL];
129 G_DEFINE_TYPE_WITH_CODE (
133 G_IMPLEMENT_INTERFACE (
135 e_cal_client_initable_init)
136 G_IMPLEMENT_INTERFACE (
137 G_TYPE_ASYNC_INITABLE,
138 e_cal_client_async_initable_init)
139 G_IMPLEMENT_INTERFACE (
140 E_TYPE_TIMEZONE_CACHE,
141 e_cal_client_timezone_cache_init))
144 async_context_free (AsyncContext *async_context)
146 if (async_context->client_view != NULL)
147 g_object_unref (async_context->client_view);
149 if (async_context->in_comp != NULL)
150 icalcomponent_free (async_context->in_comp);
152 if (async_context->out_comp != NULL)
153 icalcomponent_free (async_context->out_comp);
155 if (async_context->zone != NULL)
156 icaltimezone_free (async_context->zone, 1);
159 async_context->comp_list,
160 (GDestroyNotify) icalcomponent_free);
163 async_context->object_list,
164 (GDestroyNotify) g_object_unref);
167 async_context->string_list,
168 (GDestroyNotify) g_free);
170 g_free (async_context->sexp);
171 g_free (async_context->tzid);
172 g_free (async_context->uid);
173 g_free (async_context->rid);
174 g_free (async_context->auid);
176 g_slice_free (AsyncContext, async_context);
180 signal_closure_free (SignalClosure *signal_closure)
182 g_object_unref (signal_closure->client);
184 g_free (signal_closure->property_name);
185 g_free (signal_closure->error_message);
187 g_strfreev (signal_closure->free_busy_data);
189 /* The icaltimezone is cached in ECalClient's internal
190 * "zone_cache" hash table and must not be freed here. */
192 g_slice_free (SignalClosure, signal_closure);
196 connect_closure_free (ConnectClosure *connect_closure)
198 if (connect_closure->source != NULL)
199 g_object_unref (connect_closure->source);
201 if (connect_closure->cancellable != NULL)
202 g_object_unref (connect_closure->cancellable);
204 g_slice_free (ConnectClosure, connect_closure);
208 run_in_thread_closure_free (RunInThreadClosure *run_in_thread_closure)
210 if (run_in_thread_closure->simple != NULL)
211 g_object_unref (run_in_thread_closure->simple);
213 if (run_in_thread_closure->cancellable != NULL)
214 g_object_unref (run_in_thread_closure->cancellable);
216 g_slice_free (RunInThreadClosure, run_in_thread_closure);
220 free_zone_cb (gpointer zone)
222 icaltimezone_free (zone, 1);
226 * Well-known calendar backend properties:
227 * @CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS: Contains default calendar's email
228 * address suggested by the backend.
229 * @CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS: Contains default alarm email
230 * address suggested by the backend.
231 * @CAL_BACKEND_PROPERTY_DEFAULT_OBJECT: Contains iCal component string
232 * of an #icalcomponent with the default values for properties needed.
233 * Preferred way of retrieving this property is by
234 * calling e_cal_client_get_default_object().
236 * See also: @CLIENT_BACKEND_PROPERTY_OPENED, @CLIENT_BACKEND_PROPERTY_OPENING,
237 * @CLIENT_BACKEND_PROPERTY_ONLINE, @CLIENT_BACKEND_PROPERTY_READONLY
238 * @CLIENT_BACKEND_PROPERTY_CACHE_DIR, @CLIENT_BACKEND_PROPERTY_CAPABILITIES
241 G_DEFINE_QUARK (e-cal-client-error-quark, e_cal_client_error)
244 * e_cal_client_error_to_string:
246 * FIXME: Document me.
251 e_cal_client_error_to_string (ECalClientError code)
254 case E_CAL_CLIENT_ERROR_NO_SUCH_CALENDAR:
255 return _("No such calendar");
256 case E_CAL_CLIENT_ERROR_OBJECT_NOT_FOUND:
257 return _("Object not found");
258 case E_CAL_CLIENT_ERROR_INVALID_OBJECT:
259 return _("Invalid object");
260 case E_CAL_CLIENT_ERROR_UNKNOWN_USER:
261 return _("Unknown user");
262 case E_CAL_CLIENT_ERROR_OBJECT_ID_ALREADY_EXISTS:
263 return _("Object ID already exists");
264 case E_CAL_CLIENT_ERROR_INVALID_RANGE:
265 return _("Invalid range");
268 return _("Unknown error");
272 * e_cal_client_error_create:
273 * @code: an #ECalClientError code to create
274 * @custom_msg: custom message to use for the error; can be %NULL
276 * Returns: a new #GError containing an E_CAL_CLIENT_ERROR of the given
277 * @code. If the @custom_msg is NULL, then the error message is
278 * the one returned from e_cal_client_error_to_string() for the @code,
279 * otherwise the given message is used.
281 * Returned pointer should be freed with g_error_free().
286 e_cal_client_error_create (ECalClientError code,
287 const gchar *custom_msg)
289 return g_error_new_literal (E_CAL_CLIENT_ERROR, code, custom_msg ? custom_msg : e_cal_client_error_to_string (code));
293 * If the specified GError is a remote error, then create a new error
294 * representing the remote error. If the error is anything else, then
298 unwrap_dbus_error (GError *error,
299 GError **client_error)
301 #define err(a,b) "org.gnome.evolution.dataserver.Calendar." a, b
302 static EClientErrorsList cal_errors[] = {
303 { err ("Success", -1) },
304 { err ("ObjectNotFound", E_CAL_CLIENT_ERROR_OBJECT_NOT_FOUND) },
305 { err ("InvalidObject", E_CAL_CLIENT_ERROR_INVALID_OBJECT) },
306 { err ("ObjectIdAlreadyExists", E_CAL_CLIENT_ERROR_OBJECT_ID_ALREADY_EXISTS) },
307 { err ("NoSuchCal", E_CAL_CLIENT_ERROR_NO_SUCH_CALENDAR) },
308 { err ("UnknownUser", E_CAL_CLIENT_ERROR_UNKNOWN_USER) },
309 { err ("InvalidRange", E_CAL_CLIENT_ERROR_INVALID_RANGE) },
311 { err ("Busy", E_CLIENT_ERROR_BUSY) },
312 { err ("InvalidArg", E_CLIENT_ERROR_INVALID_ARG) },
313 { err ("RepositoryOffline", E_CLIENT_ERROR_REPOSITORY_OFFLINE) },
314 { err ("OfflineUnavailable", E_CLIENT_ERROR_OFFLINE_UNAVAILABLE) },
315 { err ("PermissionDenied", E_CLIENT_ERROR_PERMISSION_DENIED) },
316 { err ("AuthenticationFailed", E_CLIENT_ERROR_AUTHENTICATION_FAILED) },
317 { err ("AuthenticationRequired", E_CLIENT_ERROR_AUTHENTICATION_REQUIRED) },
318 { err ("CouldNotCancel", E_CLIENT_ERROR_COULD_NOT_CANCEL) },
319 { err ("NotSupported", E_CLIENT_ERROR_NOT_SUPPORTED) },
320 { err ("UnsupportedAuthenticationMethod", E_CLIENT_ERROR_UNSUPPORTED_AUTHENTICATION_METHOD) },
321 { err ("TLSNotAvailable", E_CLIENT_ERROR_TLS_NOT_AVAILABLE) },
322 { err ("SearchSizeLimitExceeded", E_CLIENT_ERROR_SEARCH_SIZE_LIMIT_EXCEEDED) },
323 { err ("SearchTimeLimitExceeded", E_CLIENT_ERROR_SEARCH_TIME_LIMIT_EXCEEDED) },
324 { err ("InvalidQuery", E_CLIENT_ERROR_INVALID_QUERY) },
325 { err ("QueryRefused", E_CLIENT_ERROR_QUERY_REFUSED) },
326 { err ("NotOpened", E_CLIENT_ERROR_NOT_OPENED) },
327 { err ("UnsupportedField", E_CLIENT_ERROR_OTHER_ERROR) },
328 { err ("UnsupportedMethod", E_CLIENT_ERROR_OTHER_ERROR) },
329 { err ("InvalidServerVersion", E_CLIENT_ERROR_OTHER_ERROR) },
330 { err ("OtherError", E_CLIENT_ERROR_OTHER_ERROR) }
337 if (!e_client_util_unwrap_dbus_error (error, client_error, cal_errors, G_N_ELEMENTS (cal_errors), E_CAL_CLIENT_ERROR, TRUE))
338 e_client_util_unwrap_dbus_error (error, client_error, cl_errors, G_N_ELEMENTS (cl_errors), E_CLIENT_ERROR, FALSE);
344 set_proxy_gone_error (GError **error)
346 /* do not translate this string, it should ideally never happen */
347 g_set_error_literal (error, E_CLIENT_ERROR, E_CLIENT_ERROR_DBUS_ERROR, "D-Bus calendar proxy gone");
350 static volatile gint active_cal_clients = 0;
351 static guint cal_connection_closed_id = 0;
352 static EDBusCalendarFactory *cal_factory = NULL;
353 static GRecMutex cal_factory_lock;
354 #define LOCK_FACTORY() g_rec_mutex_lock (&cal_factory_lock)
355 #define UNLOCK_FACTORY() g_rec_mutex_unlock (&cal_factory_lock)
357 static void gdbus_cal_factory_closed_cb (GDBusConnection *connection, gboolean remote_peer_vanished, GError *error, gpointer user_data);
360 gdbus_cal_factory_disconnect (GDBusConnection *connection)
364 if (!connection && cal_factory)
365 connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (cal_factory));
367 if (connection && cal_connection_closed_id) {
368 g_dbus_connection_signal_unsubscribe (connection, cal_connection_closed_id);
369 g_signal_handlers_disconnect_by_func (connection, gdbus_cal_factory_closed_cb, NULL);
372 if (cal_factory != NULL)
373 g_object_unref (cal_factory);
375 cal_connection_closed_id = 0;
382 gdbus_cal_factory_closed_cb (GDBusConnection *connection,
383 gboolean remote_peer_vanished,
391 gdbus_cal_factory_disconnect (connection);
394 unwrap_dbus_error (g_error_copy (error), &err);
397 g_debug ("GDBus connection is closed%s: %s", remote_peer_vanished ? ", remote peer vanished" : "", err->message);
399 } else if (active_cal_clients > 0) {
400 g_debug ("GDBus connection is closed%s", remote_peer_vanished ? ", remote peer vanished" : "");
407 gdbus_cal_factory_connection_gone_cb (GDBusConnection *connection,
408 const gchar *sender_name,
409 const gchar *object_path,
410 const gchar *interface_name,
411 const gchar *signal_name,
412 GVariant *parameters,
415 /* signal subscription takes care of correct parameters,
416 * thus just do what is to be done here */
417 gdbus_cal_factory_closed_cb (connection, TRUE, NULL, user_data);
421 gdbus_cal_factory_activate (GCancellable *cancellable,
424 GDBusConnection *connection;
428 if (G_LIKELY (cal_factory != NULL)) {
433 cal_factory = e_dbus_calendar_factory_proxy_new_for_bus_sync (
435 G_DBUS_PROXY_FLAGS_NONE,
436 CALENDAR_DBUS_SERVICE_NAME,
437 "/org/gnome/evolution/dataserver/CalendarFactory",
440 if (cal_factory == NULL) {
445 connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (cal_factory));
446 cal_connection_closed_id = g_dbus_connection_signal_subscribe (
449 "org.freedesktop.DBus", /* interface */
450 "NameOwnerChanged", /* member */
451 "/org/freedesktop/DBus", /* object_path */
452 "org.gnome.evolution.dataserver.Calendar", /* arg0 */
453 G_DBUS_SIGNAL_FLAGS_NONE,
454 gdbus_cal_factory_connection_gone_cb, NULL, NULL);
457 connection, "closed",
458 G_CALLBACK (gdbus_cal_factory_closed_cb), NULL);
466 cal_client_dbus_thread (gpointer user_data)
468 GMainContext *main_context = user_data;
469 GMainLoop *main_loop;
471 g_main_context_push_thread_default (main_context);
473 main_loop = g_main_loop_new (main_context, FALSE);
474 g_main_loop_run (main_loop);
475 g_main_loop_unref (main_loop);
477 g_main_context_pop_thread_default (main_context);
479 g_main_context_unref (main_context);
485 cal_client_dbus_thread_init (gpointer unused)
487 GMainContext *main_context;
489 main_context = g_main_context_new ();
491 /* This thread terminates when the process itself terminates, so
492 * no need to worry about unreferencing the returned GThread. */
494 "cal-client-dbus-thread",
495 cal_client_dbus_thread,
496 g_main_context_ref (main_context));
501 static GMainContext *
502 cal_client_ref_dbus_main_context (void)
504 static GOnce cal_client_dbus_thread_once = G_ONCE_INIT;
507 &cal_client_dbus_thread_once,
508 cal_client_dbus_thread_init, NULL);
510 return g_main_context_ref (cal_client_dbus_thread_once.retval);
514 cal_client_run_in_dbus_thread_idle_cb (gpointer user_data)
516 RunInThreadClosure *closure = user_data;
517 GObject *source_object;
518 GAsyncResult *result;
520 result = G_ASYNC_RESULT (closure->simple);
521 source_object = g_async_result_get_source_object (result);
526 closure->cancellable);
528 if (source_object != NULL)
529 g_object_unref (source_object);
531 g_simple_async_result_complete_in_idle (closure->simple);
537 cal_client_run_in_dbus_thread (GSimpleAsyncResult *simple,
538 GSimpleAsyncThreadFunc func,
540 GCancellable *cancellable)
542 RunInThreadClosure *closure;
543 GMainContext *main_context;
544 GSource *idle_source;
546 main_context = cal_client_ref_dbus_main_context ();
548 closure = g_slice_new0 (RunInThreadClosure);
549 closure->func = func;
550 closure->simple = g_object_ref (simple);
552 if (G_IS_CANCELLABLE (cancellable))
553 closure->cancellable = g_object_ref (cancellable);
555 idle_source = g_idle_source_new ();
556 g_source_set_priority (idle_source, io_priority);
557 g_source_set_callback (
558 idle_source, cal_client_run_in_dbus_thread_idle_cb,
559 closure, (GDestroyNotify) run_in_thread_closure_free);
560 g_source_attach (idle_source, main_context);
561 g_source_unref (idle_source);
563 g_main_context_unref (main_context);
566 static void gdbus_cal_client_disconnect (ECalClient *client);
569 * Called when the calendar server dies.
572 gdbus_cal_client_closed_cb (GDBusConnection *connection,
573 gboolean remote_peer_vanished,
579 g_assert (E_IS_CAL_CLIENT (client));
582 unwrap_dbus_error (g_error_copy (error), &err);
585 g_debug (G_STRLOC ": ECalClient GDBus connection is closed%s: %s", remote_peer_vanished ? ", remote peer vanished" : "", err->message);
588 g_debug (G_STRLOC ": ECalClient GDBus connection is closed%s", remote_peer_vanished ? ", remote peer vanished" : "");
591 gdbus_cal_client_disconnect (client);
593 e_client_emit_backend_died (E_CLIENT (client));
597 gdbus_cal_client_connection_gone_cb (GDBusConnection *connection,
598 const gchar *sender_name,
599 const gchar *object_path,
600 const gchar *interface_name,
601 const gchar *signal_name,
602 GVariant *parameters,
605 /* signal subscription takes care of correct parameters,
606 * thus just do what is to be done here */
607 gdbus_cal_client_closed_cb (connection, TRUE, NULL, user_data);
611 gdbus_cal_client_disconnect (ECalClient *client)
613 g_return_if_fail (E_IS_CAL_CLIENT (client));
615 /* Ensure that everything relevant is NULL */
618 if (client->priv->dbus_proxy != NULL) {
619 GDBusConnection *connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (client->priv->dbus_proxy));
621 g_signal_handlers_disconnect_by_func (connection, gdbus_cal_client_closed_cb, client);
622 g_dbus_connection_signal_unsubscribe (connection, client->priv->gone_signal_id);
623 client->priv->gone_signal_id = 0;
625 e_dbus_calendar_call_close_sync (
626 client->priv->dbus_proxy, NULL, NULL);
627 g_object_unref (client->priv->dbus_proxy);
628 client->priv->dbus_proxy = NULL;
635 cal_client_emit_backend_error_idle_cb (gpointer user_data)
637 SignalClosure *signal_closure = user_data;
639 g_signal_emit_by_name (
640 signal_closure->client,
642 signal_closure->error_message);
648 cal_client_emit_backend_property_changed_idle_cb (gpointer user_data)
650 SignalClosure *signal_closure = user_data;
651 gchar *prop_value = NULL;
653 /* XXX Despite appearances, this function does not block. */
654 e_client_get_backend_property_sync (
655 signal_closure->client,
656 signal_closure->property_name,
657 &prop_value, NULL, NULL);
659 if (prop_value != NULL) {
660 g_signal_emit_by_name (
661 signal_closure->client,
662 "backend-property-changed",
663 signal_closure->property_name,
672 cal_client_emit_free_busy_data_idle_cb (gpointer user_data)
674 SignalClosure *signal_closure = user_data;
679 strv = signal_closure->free_busy_data;
681 for (ii = 0; strv[ii] != NULL; ii++) {
683 icalcomponent *icalcomp;
684 icalcomponent_kind kind;
686 icalcomp = icalcomponent_new_from_string (strv[ii]);
687 if (icalcomp == NULL)
690 kind = icalcomponent_isa (icalcomp);
691 if (kind != ICAL_VFREEBUSY_COMPONENT) {
692 icalcomponent_free (icalcomp);
696 comp = e_cal_component_new ();
697 if (!e_cal_component_set_icalcomponent (comp, icalcomp)) {
698 icalcomponent_free (icalcomp);
699 g_object_unref (comp);
703 list = g_slist_prepend (list, comp);
706 list = g_slist_reverse (list);
709 signal_closure->client,
710 signals[FREE_BUSY_DATA], 0, list);
712 g_slist_free_full (list, (GDestroyNotify) g_object_unref);
718 cal_client_emit_timezone_added_idle_cb (gpointer user_data)
720 SignalClosure *signal_closure = user_data;
722 g_signal_emit_by_name (
723 signal_closure->client,
725 signal_closure->cached_zone);
731 cal_client_dbus_proxy_error_cb (EDBusCalendar *dbus_proxy,
732 const gchar *error_message,
733 ECalClient *cal_client)
735 GSource *idle_source;
736 SignalClosure *signal_closure;
738 signal_closure = g_slice_new0 (SignalClosure);
739 signal_closure->client = g_object_ref (cal_client);
740 signal_closure->error_message = g_strdup (error_message);
742 idle_source = g_idle_source_new ();
743 g_source_set_callback (
745 cal_client_emit_backend_error_idle_cb,
747 (GDestroyNotify) signal_closure_free);
748 g_source_attach (idle_source, cal_client->priv->main_context);
749 g_source_unref (idle_source);
753 cal_client_dbus_proxy_notify_cb (EDBusCalendar *dbus_proxy,
755 ECalClient *cal_client)
757 const gchar *backend_prop_name = NULL;
759 if (g_str_equal (pspec->name, "alarm-email-address")) {
760 backend_prop_name = CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS;
763 if (g_str_equal (pspec->name, "cache-dir")) {
764 backend_prop_name = CLIENT_BACKEND_PROPERTY_CACHE_DIR;
767 if (g_str_equal (pspec->name, "cal-email-address")) {
768 backend_prop_name = CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS;
771 if (g_str_equal (pspec->name, "capabilities")) {
775 backend_prop_name = CLIENT_BACKEND_PROPERTY_CAPABILITIES;
777 strv = e_dbus_calendar_dup_capabilities (dbus_proxy);
779 csv = g_strjoinv (",", strv);
782 e_client_set_capabilities (E_CLIENT (cal_client), csv);
786 if (g_str_equal (pspec->name, "default-object")) {
787 backend_prop_name = CAL_BACKEND_PROPERTY_DEFAULT_OBJECT;
790 if (g_str_equal (pspec->name, "online")) {
793 backend_prop_name = CLIENT_BACKEND_PROPERTY_ONLINE;
795 online = e_dbus_calendar_get_online (dbus_proxy);
796 e_client_set_online (E_CLIENT (cal_client), online);
799 if (g_str_equal (pspec->name, "revision")) {
800 backend_prop_name = CLIENT_BACKEND_PROPERTY_REVISION;
803 if (g_str_equal (pspec->name, "writable")) {
806 backend_prop_name = CLIENT_BACKEND_PROPERTY_READONLY;
808 writable = e_dbus_calendar_get_writable (dbus_proxy);
809 e_client_set_readonly (E_CLIENT (cal_client), !writable);
812 if (backend_prop_name != NULL) {
813 GSource *idle_source;
814 SignalClosure *signal_closure;
816 signal_closure = g_slice_new0 (SignalClosure);
817 signal_closure->client = g_object_ref (cal_client);
818 signal_closure->property_name = g_strdup (backend_prop_name);
820 idle_source = g_idle_source_new ();
821 g_source_set_callback (
823 cal_client_emit_backend_property_changed_idle_cb,
825 (GDestroyNotify) signal_closure_free);
826 g_source_attach (idle_source, cal_client->priv->main_context);
827 g_source_unref (idle_source);
832 cal_client_dbus_proxy_free_busy_data_cb (EDBusCalendar *dbus_proxy,
833 gchar **free_busy_data,
834 ECalClient *cal_client)
836 GSource *idle_source;
837 SignalClosure *signal_closure;
839 signal_closure = g_slice_new0 (SignalClosure);
840 signal_closure->client = g_object_ref (cal_client);
841 signal_closure->free_busy_data = g_strdupv (free_busy_data);
843 idle_source = g_idle_source_new ();
844 g_source_set_callback (
846 cal_client_emit_free_busy_data_idle_cb,
848 (GDestroyNotify) signal_closure_free);
849 g_source_attach (idle_source, cal_client->priv->main_context);
850 g_source_unref (idle_source);
854 cal_client_set_source_type (ECalClient *cal_client,
855 ECalClientSourceType source_type)
857 cal_client->priv->source_type = source_type;
861 cal_client_set_property (GObject *object,
866 switch (property_id) {
867 case PROP_SOURCE_TYPE:
868 cal_client_set_source_type (
869 E_CAL_CLIENT (object),
870 g_value_get_enum (value));
874 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
878 cal_client_get_property (GObject *object,
883 switch (property_id) {
884 case PROP_SOURCE_TYPE:
887 e_cal_client_get_source_type (
888 E_CAL_CLIENT (object)));
892 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
896 cal_client_dispose (GObject *object)
898 ECalClientPrivate *priv;
900 priv = E_CAL_CLIENT_GET_PRIVATE (object);
902 e_client_cancel_all (E_CLIENT (object));
904 if (priv->dbus_proxy_error_handler_id > 0) {
905 g_signal_handler_disconnect (
907 priv->dbus_proxy_error_handler_id);
908 priv->dbus_proxy_error_handler_id = 0;
911 if (priv->dbus_proxy_notify_handler_id > 0) {
912 g_signal_handler_disconnect (
914 priv->dbus_proxy_notify_handler_id);
915 priv->dbus_proxy_notify_handler_id = 0;
918 if (priv->dbus_proxy_free_busy_data_handler_id > 0) {
919 g_signal_handler_disconnect (
921 priv->dbus_proxy_free_busy_data_handler_id);
922 priv->dbus_proxy_free_busy_data_handler_id = 0;
925 gdbus_cal_client_disconnect (E_CAL_CLIENT (object));
927 if (priv->main_context != NULL) {
928 g_main_context_unref (priv->main_context);
929 priv->main_context = NULL;
932 /* Chain up to parent's dispose() method. */
933 G_OBJECT_CLASS (e_cal_client_parent_class)->dispose (object);
937 cal_client_finalize (GObject *object)
940 ECalClientPrivate *priv;
942 client = E_CAL_CLIENT (object);
946 if (priv->default_zone && priv->default_zone != icaltimezone_get_utc_timezone ())
947 icaltimezone_free (priv->default_zone, 1);
949 g_mutex_lock (&priv->zone_cache_lock);
950 g_hash_table_destroy (priv->zone_cache);
951 g_mutex_unlock (&priv->zone_cache_lock);
953 g_mutex_clear (&priv->zone_cache_lock);
955 /* Chain up to parent's finalize() method. */
956 G_OBJECT_CLASS (e_cal_client_parent_class)->finalize (object);
958 if (g_atomic_int_dec_and_test (&active_cal_clients))
959 gdbus_cal_factory_disconnect (NULL);
963 cal_client_get_dbus_proxy (EClient *client)
965 ECalClientPrivate *priv;
967 priv = E_CAL_CLIENT_GET_PRIVATE (client);
969 return G_DBUS_PROXY (priv->dbus_proxy);
973 cal_client_unwrap_dbus_error (EClient *client,
977 unwrap_dbus_error (dbus_error, out_error);
981 cal_client_get_backend_property_sync (EClient *client,
982 const gchar *prop_name,
984 GCancellable *cancellable,
987 ECalClient *cal_client;
988 EDBusCalendar *dbus_proxy;
991 cal_client = E_CAL_CLIENT (client);
992 dbus_proxy = cal_client->priv->dbus_proxy;
994 if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_OPENED)) {
995 *prop_value = g_strdup ("TRUE");
999 if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_OPENING)) {
1000 *prop_value = g_strdup ("FALSE");
1004 if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_ONLINE)) {
1005 if (e_dbus_calendar_get_online (dbus_proxy))
1006 *prop_value = g_strdup ("TRUE");
1008 *prop_value = g_strdup ("FALSE");
1012 if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_READONLY)) {
1013 if (e_dbus_calendar_get_writable (dbus_proxy))
1014 *prop_value = g_strdup ("FALSE");
1016 *prop_value = g_strdup ("TRUE");
1020 if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CACHE_DIR)) {
1021 *prop_value = e_dbus_calendar_dup_cache_dir (dbus_proxy);
1025 if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_REVISION)) {
1026 *prop_value = e_dbus_calendar_dup_revision (dbus_proxy);
1030 if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CAPABILITIES)) {
1031 strv = e_dbus_calendar_dup_capabilities (dbus_proxy);
1033 *prop_value = g_strjoinv (",", strv);
1035 *prop_value = g_strdup ("");
1040 if (g_str_equal (prop_name, CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS)) {
1041 *prop_value = e_dbus_calendar_dup_alarm_email_address (dbus_proxy);
1044 if (g_str_equal (prop_name, CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS)) {
1045 *prop_value = e_dbus_calendar_dup_cal_email_address (dbus_proxy);
1048 if (g_str_equal (prop_name, CAL_BACKEND_PROPERTY_DEFAULT_OBJECT)) {
1049 *prop_value = e_dbus_calendar_dup_default_object (dbus_proxy);
1053 error, E_CLIENT_ERROR, E_CLIENT_ERROR_NOT_SUPPORTED,
1054 _("Unknown calendar property '%s'"), prop_name);
1060 cal_client_set_backend_property_sync (EClient *client,
1061 const gchar *prop_name,
1062 const gchar *prop_value,
1063 GCancellable *cancellable,
1067 error, E_CLIENT_ERROR,
1068 E_CLIENT_ERROR_NOT_SUPPORTED,
1069 _("Cannot change value of calendar property '%s'"),
1076 cal_client_open_sync (EClient *client,
1077 gboolean only_if_exists,
1078 GCancellable *cancellable,
1081 ECalClient *cal_client;
1083 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
1085 cal_client = E_CAL_CLIENT (client);
1087 if (cal_client->priv->dbus_proxy == NULL) {
1088 set_proxy_gone_error (error);
1092 return e_dbus_calendar_call_open_sync (
1093 cal_client->priv->dbus_proxy, cancellable, error);
1097 cal_client_refresh_sync (EClient *client,
1098 GCancellable *cancellable,
1101 ECalClient *cal_client;
1103 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
1105 cal_client = E_CAL_CLIENT (client);
1107 if (cal_client->priv->dbus_proxy == NULL) {
1108 set_proxy_gone_error (error);
1112 return e_dbus_calendar_call_refresh_sync (
1113 cal_client->priv->dbus_proxy, cancellable, error);
1117 cal_client_init_in_dbus_thread (GSimpleAsyncResult *simple,
1118 GObject *source_object,
1119 GCancellable *cancellable)
1121 ECalClientPrivate *priv;
1124 GDBusConnection *connection;
1126 gchar *object_path = NULL;
1128 GError *error = NULL;
1130 priv = E_CAL_CLIENT_GET_PRIVATE (source_object);
1132 client = E_CLIENT (source_object);
1133 source = e_client_get_source (client);
1134 uid = e_source_get_uid (source);
1137 gdbus_cal_factory_activate (cancellable, &error);
1140 if (error != NULL) {
1141 unwrap_dbus_error (error, &error);
1142 g_simple_async_result_take_error (simple, error);
1146 switch (e_cal_client_get_source_type (E_CAL_CLIENT (client))) {
1147 case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
1148 e_dbus_calendar_factory_call_open_calendar_sync (
1149 cal_factory, uid, &object_path,
1150 cancellable, &error);
1152 case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
1153 e_dbus_calendar_factory_call_open_task_list_sync (
1154 cal_factory, uid, &object_path,
1155 cancellable, &error);
1157 case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
1158 e_dbus_calendar_factory_call_open_memo_list_sync (
1159 cal_factory, uid, &object_path,
1160 cancellable, &error);
1163 g_return_if_reached ();
1168 ((object_path != NULL) && (error == NULL)) ||
1169 ((object_path == NULL) && (error != NULL)));
1171 if (object_path == NULL) {
1172 unwrap_dbus_error (error, &error);
1173 g_simple_async_result_take_error (simple, error);
1177 connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (cal_factory));
1179 priv->dbus_proxy = e_dbus_calendar_proxy_new_sync (
1181 G_DBUS_PROXY_FLAGS_NONE,
1182 CALENDAR_DBUS_SERVICE_NAME,
1184 cancellable, &error);
1186 g_free (object_path);
1190 ((priv->dbus_proxy != NULL) && (error == NULL)) ||
1191 ((priv->dbus_proxy == NULL) && (error != NULL)));
1193 if (error != NULL) {
1194 unwrap_dbus_error (error, &error);
1195 g_simple_async_result_take_error (simple, error);
1199 g_dbus_proxy_set_default_timeout (
1200 G_DBUS_PROXY (priv->dbus_proxy), DBUS_PROXY_TIMEOUT_MS);
1202 priv->gone_signal_id = g_dbus_connection_signal_subscribe (
1204 "org.freedesktop.DBus", /* sender */
1205 "org.freedesktop.DBus", /* interface */
1206 "NameOwnerChanged", /* member */
1207 "/org/freedesktop/DBus", /* object_path */
1208 "org.gnome.evolution.dataserver.Calendar", /* arg0 */
1209 G_DBUS_SIGNAL_FLAGS_NONE,
1210 gdbus_cal_client_connection_gone_cb, client, NULL);
1213 connection, "closed",
1214 G_CALLBACK (gdbus_cal_client_closed_cb), client);
1216 handler_id = g_signal_connect_object (
1217 priv->dbus_proxy, "error",
1218 G_CALLBACK (cal_client_dbus_proxy_error_cb),
1220 priv->dbus_proxy_error_handler_id = handler_id;
1222 handler_id = g_signal_connect_object (
1223 priv->dbus_proxy, "notify",
1224 G_CALLBACK (cal_client_dbus_proxy_notify_cb),
1226 priv->dbus_proxy_notify_handler_id = handler_id;
1228 handler_id = g_signal_connect_object (
1229 priv->dbus_proxy, "free-busy-data",
1230 G_CALLBACK (cal_client_dbus_proxy_free_busy_data_cb),
1232 priv->dbus_proxy_free_busy_data_handler_id = handler_id;
1234 /* Initialize our public-facing GObject properties. */
1235 g_object_notify (G_OBJECT (priv->dbus_proxy), "online");
1236 g_object_notify (G_OBJECT (priv->dbus_proxy), "writable");
1237 g_object_notify (G_OBJECT (priv->dbus_proxy), "capabilities");
1241 cal_client_initable_init (GInitable *initable,
1242 GCancellable *cancellable,
1245 EAsyncClosure *closure;
1246 GAsyncResult *result;
1249 closure = e_async_closure_new ();
1251 g_async_initable_init_async (
1252 G_ASYNC_INITABLE (initable),
1253 G_PRIORITY_DEFAULT, cancellable,
1254 e_async_closure_callback, closure);
1256 result = e_async_closure_wait (closure);
1258 success = g_async_initable_init_finish (
1259 G_ASYNC_INITABLE (initable), result, error);
1261 e_async_closure_free (closure);
1267 cal_client_initable_init_async (GAsyncInitable *initable,
1269 GCancellable *cancellable,
1270 GAsyncReadyCallback callback,
1273 GSimpleAsyncResult *simple;
1275 simple = g_simple_async_result_new (
1276 G_OBJECT (initable), callback, user_data,
1277 cal_client_initable_init_async);
1279 g_simple_async_result_set_check_cancellable (simple, cancellable);
1281 cal_client_run_in_dbus_thread (
1282 simple, cal_client_init_in_dbus_thread,
1283 io_priority, cancellable);
1285 g_object_unref (simple);
1289 cal_client_initable_init_finish (GAsyncInitable *initable,
1290 GAsyncResult *result,
1293 GSimpleAsyncResult *simple;
1295 g_return_val_if_fail (
1296 g_simple_async_result_is_valid (
1297 result, G_OBJECT (initable),
1298 cal_client_initable_init_async), FALSE);
1300 simple = G_SIMPLE_ASYNC_RESULT (result);
1302 /* Assume success unless a GError is set. */
1303 return !g_simple_async_result_propagate_error (simple, error);
1307 cal_client_add_cached_timezone (ETimezoneCache *cache,
1310 ECalClientPrivate *priv;
1313 priv = E_CAL_CLIENT_GET_PRIVATE (cache);
1315 g_mutex_lock (&priv->zone_cache_lock);
1317 tzid = icaltimezone_get_tzid (zone);
1319 /* Avoid replacing an existing cache entry. We don't want to
1320 * invalidate any icaltimezone pointers that may have already
1321 * been returned through e_timezone_cache_get_timezone(). */
1322 if (!g_hash_table_contains (priv->zone_cache, tzid)) {
1323 GSource *idle_source;
1324 SignalClosure *signal_closure;
1326 icalcomponent *icalcomp;
1327 icaltimezone *cached_zone;
1329 cached_zone = icaltimezone_new ();
1330 icalcomp = icaltimezone_get_component (zone);
1331 icalcomp = icalcomponent_new_clone (icalcomp);
1332 icaltimezone_set_component (cached_zone, icalcomp);
1334 g_hash_table_insert (
1336 g_strdup (tzid), cached_zone);
1338 /* The closure's client reference will keep the
1339 * internally cached icaltimezone alive for the
1340 * duration of the idle callback. */
1341 signal_closure = g_slice_new0 (SignalClosure);
1342 signal_closure->client = g_object_ref (cache);
1343 signal_closure->cached_zone = cached_zone;
1345 idle_source = g_idle_source_new ();
1346 g_source_set_callback (
1348 cal_client_emit_timezone_added_idle_cb,
1350 (GDestroyNotify) g_object_unref);
1351 g_source_attach (idle_source, priv->main_context);
1352 g_source_unref (idle_source);
1355 g_mutex_unlock (&priv->zone_cache_lock);
1358 static icaltimezone *
1359 cal_client_get_cached_timezone (ETimezoneCache *cache,
1362 ECalClientPrivate *priv;
1363 icaltimezone *zone = NULL;
1364 icaltimezone *builtin_zone = NULL;
1365 icalcomponent *icalcomp;
1367 const gchar *builtin_tzid;
1369 priv = E_CAL_CLIENT_GET_PRIVATE (cache);
1371 if (g_str_equal (tzid, "UTC"))
1372 return icaltimezone_get_utc_timezone ();
1374 g_mutex_lock (&priv->zone_cache_lock);
1376 /* See if we already have it in the cache. */
1377 zone = g_hash_table_lookup (priv->zone_cache, tzid);
1382 /* Try to replace the original time zone with a more complete
1383 * and/or potentially updated built-in time zone. Note this also
1384 * applies to TZIDs which match built-in time zones exactly: they
1385 * are extracted via icaltimezone_get_builtin_timezone_from_tzid()
1386 * below without a roundtrip to the backend. */
1388 builtin_tzid = e_cal_match_tzid (tzid);
1390 if (builtin_tzid != NULL)
1391 builtin_zone = icaltimezone_get_builtin_timezone_from_tzid (
1394 if (builtin_zone == NULL)
1397 /* Use the built-in time zone *and* rename it. Likely the caller
1398 * is asking for a specific TZID because it has an event with such
1399 * a TZID. Returning an icaltimezone with a different TZID would
1400 * lead to broken VCALENDARs in the caller. */
1402 icalcomp = icaltimezone_get_component (builtin_zone);
1403 icalcomp = icalcomponent_new_clone (icalcomp);
1405 prop = icalcomponent_get_first_property (
1406 icalcomp, ICAL_ANY_PROPERTY);
1408 while (prop != NULL) {
1409 if (icalproperty_isa (prop) == ICAL_TZID_PROPERTY) {
1410 icalproperty_set_value_from_string (prop, tzid, "NO");
1414 prop = icalcomponent_get_next_property (
1415 icalcomp, ICAL_ANY_PROPERTY);
1418 if (icalcomp != NULL) {
1419 zone = icaltimezone_new ();
1420 if (icaltimezone_set_component (zone, icalcomp)) {
1421 tzid = icaltimezone_get_tzid (zone);
1422 g_hash_table_insert (
1424 g_strdup (tzid), zone);
1426 icalcomponent_free (icalcomp);
1427 icaltimezone_free (zone, 1);
1433 g_mutex_unlock (&priv->zone_cache_lock);
1439 cal_client_list_cached_timezones (ETimezoneCache *cache)
1441 ECalClientPrivate *priv;
1444 priv = E_CAL_CLIENT_GET_PRIVATE (cache);
1446 g_mutex_lock (&priv->zone_cache_lock);
1448 list = g_hash_table_get_values (priv->zone_cache);
1450 g_mutex_unlock (&priv->zone_cache_lock);
1456 e_cal_client_class_init (ECalClientClass *class)
1458 GObjectClass *object_class;
1459 EClientClass *client_class;
1461 g_type_class_add_private (class, sizeof (ECalClientPrivate));
1463 object_class = G_OBJECT_CLASS (class);
1464 object_class->set_property = cal_client_set_property;
1465 object_class->get_property = cal_client_get_property;
1466 object_class->dispose = cal_client_dispose;
1467 object_class->finalize = cal_client_finalize;
1469 client_class = E_CLIENT_CLASS (class);
1470 client_class->get_dbus_proxy = cal_client_get_dbus_proxy;
1471 client_class->unwrap_dbus_error = cal_client_unwrap_dbus_error;
1472 client_class->get_backend_property_sync = cal_client_get_backend_property_sync;
1473 client_class->set_backend_property_sync = cal_client_set_backend_property_sync;
1474 client_class->open_sync = cal_client_open_sync;
1475 client_class->refresh_sync = cal_client_refresh_sync;
1477 g_object_class_install_property (
1483 "The iCalendar data type",
1484 E_TYPE_CAL_CLIENT_SOURCE_TYPE,
1485 E_CAL_CLIENT_SOURCE_TYPE_EVENTS,
1487 G_PARAM_CONSTRUCT_ONLY |
1488 G_PARAM_STATIC_STRINGS));
1490 signals[FREE_BUSY_DATA] = g_signal_new (
1492 G_OBJECT_CLASS_TYPE (class),
1494 G_STRUCT_OFFSET (ECalClientClass, free_busy_data),
1496 g_cclosure_marshal_VOID__POINTER,
1502 e_cal_client_initable_init (GInitableIface *interface)
1504 interface->init = cal_client_initable_init;
1508 e_cal_client_async_initable_init (GAsyncInitableIface *interface)
1510 interface->init_async = cal_client_initable_init_async;
1511 interface->init_finish = cal_client_initable_init_finish;
1515 e_cal_client_timezone_cache_init (ETimezoneCacheInterface *interface)
1517 interface->add_timezone = cal_client_add_cached_timezone;
1518 interface->get_timezone = cal_client_get_cached_timezone;
1519 interface->list_timezones = cal_client_list_cached_timezones;
1523 e_cal_client_init (ECalClient *client)
1525 GHashTable *zone_cache;
1527 zone_cache = g_hash_table_new_full (
1528 (GHashFunc) g_str_hash,
1529 (GEqualFunc) g_str_equal,
1530 (GDestroyNotify) g_free,
1531 (GDestroyNotify) free_zone_cb);
1533 g_atomic_int_inc (&active_cal_clients);
1535 client->priv = E_CAL_CLIENT_GET_PRIVATE (client);
1536 client->priv->source_type = E_CAL_CLIENT_SOURCE_TYPE_LAST;
1537 client->priv->default_zone = icaltimezone_get_utc_timezone ();
1538 g_mutex_init (&client->priv->zone_cache_lock);
1539 client->priv->zone_cache = zone_cache;
1541 /* This is so the D-Bus thread can schedule signal emissions
1542 * on the thread-default context for this thread. */
1543 client->priv->main_context = g_main_context_ref_thread_default ();
1547 * e_cal_client_connect_sync:
1548 * @source: an #ESource
1549 * @source_type: source type of the calendar
1550 * @cancellable: (allow-none): optional #GCancellable object, or %NULL
1551 * @error: return location for a #GError, or %NULL
1553 * Creates a new #ECalClient for @source and @source_type. If an error
1554 * occurs, the function will set @error and return %FALSE.
1556 * Unlike with e_cal_client_new(), there is no need to call
1557 * e_client_open_sync() after obtaining the #ECalClient.
1559 * For error handling convenience, any error message returned by this
1560 * function will have a descriptive prefix that includes the display
1563 * Returns: a new #ECalClient, or %NULL
1568 e_cal_client_connect_sync (ESource *source,
1569 ECalClientSourceType source_type,
1570 GCancellable *cancellable,
1576 g_return_val_if_fail (E_IS_SOURCE (source), NULL);
1577 g_return_val_if_fail (
1578 source_type == E_CAL_CLIENT_SOURCE_TYPE_EVENTS ||
1579 source_type == E_CAL_CLIENT_SOURCE_TYPE_TASKS ||
1580 source_type == E_CAL_CLIENT_SOURCE_TYPE_MEMOS, NULL);
1582 client = g_object_new (
1585 "source-type", source_type, NULL);
1587 success = g_initable_init (
1588 G_INITABLE (client), cancellable, error);
1591 success = e_dbus_calendar_call_open_sync (
1592 client->priv->dbus_proxy, cancellable, error);
1596 error,_("Unable to connect to '%s': "),
1597 e_source_get_display_name (source));
1598 g_object_unref (client);
1602 return E_CLIENT (client);
1605 /* Helper for e_cal_client_connect() */
1607 cal_client_connect_open_cb (GObject *source_object,
1608 GAsyncResult *result,
1611 GSimpleAsyncResult *simple;
1612 GError *error = NULL;
1614 simple = G_SIMPLE_ASYNC_RESULT (user_data);
1616 e_dbus_calendar_call_open_finish (
1617 E_DBUS_CALENDAR (source_object), result, &error);
1620 g_simple_async_result_take_error (simple, error);
1622 g_simple_async_result_complete (simple);
1624 g_object_unref (simple);
1627 /* Helper for e_cal_client_connect() */
1629 cal_client_connect_init_cb (GObject *source_object,
1630 GAsyncResult *result,
1633 GSimpleAsyncResult *simple;
1634 ECalClientPrivate *priv;
1635 ConnectClosure *closure;
1636 GError *error = NULL;
1638 simple = G_SIMPLE_ASYNC_RESULT (user_data);
1640 g_async_initable_init_finish (
1641 G_ASYNC_INITABLE (source_object), result, &error);
1643 if (error != NULL) {
1644 g_simple_async_result_take_error (simple, error);
1645 g_simple_async_result_complete (simple);
1649 /* Note, we're repurposing some function parameters. */
1651 result = G_ASYNC_RESULT (simple);
1652 source_object = g_async_result_get_source_object (result);
1653 closure = g_simple_async_result_get_op_res_gpointer (simple);
1655 priv = E_CAL_CLIENT_GET_PRIVATE (source_object);
1657 e_dbus_calendar_call_open (
1659 closure->cancellable,
1660 cal_client_connect_open_cb,
1661 g_object_ref (simple));
1663 g_object_unref (source_object);
1666 g_object_unref (simple);
1670 * e_cal_client_connect:
1671 * @source: an #ESource
1672 * @source_type: source tpe of the calendar
1673 * @cancellable: (allow-none): optional #GCancellable object, or %NULL
1674 * @callback: (scope async): a #GAsyncReadyCallback to call when the request
1676 * @user_data: (closure): data to pass to the callback function
1678 * Asynchronously creates a new #ECalClient for @source and @source_type.
1680 * Unlike with e_cal_client_new(), there is no need to call e_client_open()
1681 * after obtaining the #ECalClient.
1683 * When the operation is finished, @callback will be called. You can then
1684 * call e_cal_client_connect_finish() to get the result of the operation.
1689 e_cal_client_connect (ESource *source,
1690 ECalClientSourceType source_type,
1691 GCancellable *cancellable,
1692 GAsyncReadyCallback callback,
1695 GSimpleAsyncResult *simple;
1696 ConnectClosure *closure;
1699 g_return_if_fail (E_IS_SOURCE (source));
1701 source_type == E_CAL_CLIENT_SOURCE_TYPE_EVENTS ||
1702 source_type == E_CAL_CLIENT_SOURCE_TYPE_TASKS ||
1703 source_type == E_CAL_CLIENT_SOURCE_TYPE_MEMOS);
1705 /* Two things with this: 1) instantiate the client object
1706 * immediately to make sure the thread-default GMainContext
1707 * gets plucked, and 2) do not call the D-Bus open() method
1708 * from our designated D-Bus thread -- it may take a long
1709 * time and block other clients from receiving signals. */
1711 closure = g_slice_new0 (ConnectClosure);
1712 closure->source = g_object_ref (source);
1714 if (G_IS_CANCELLABLE (cancellable))
1715 closure->cancellable = g_object_ref (cancellable);
1717 client = g_object_new (
1720 "source-type", source_type, NULL);
1722 simple = g_simple_async_result_new (
1723 G_OBJECT (client), callback,
1724 user_data, e_cal_client_connect);
1726 g_simple_async_result_set_check_cancellable (simple, cancellable);
1728 g_simple_async_result_set_op_res_gpointer (
1729 simple, closure, (GDestroyNotify) connect_closure_free);
1731 g_async_initable_init_async (
1732 G_ASYNC_INITABLE (client),
1733 G_PRIORITY_DEFAULT, cancellable,
1734 cal_client_connect_init_cb,
1735 g_object_ref (simple));
1737 g_object_unref (simple);
1738 g_object_unref (client);
1742 * e_cal_client_connect_finish:
1743 * @result: a #GAsyncResult
1744 * @error: return location for a #GError, or %NULL
1746 * Finishes the operation started with e_cal_client_connect(). If an
1747 * error occurs in connecting to the D-Bus service, the function sets
1748 * @error and returns %NULL.
1750 * For error handling convenience, any error message returned by this
1751 * function will have a descriptive prefix that includes the display
1752 * name of the #ESource passed to e_cal_client_connect().
1754 * Returns: a new #ECalClient, or %NULL
1759 e_cal_client_connect_finish (GAsyncResult *result,
1762 GSimpleAsyncResult *simple;
1763 ConnectClosure *closure;
1764 gpointer source_tag;
1766 g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), NULL);
1768 simple = G_SIMPLE_ASYNC_RESULT (result);
1769 closure = g_simple_async_result_get_op_res_gpointer (simple);
1771 source_tag = g_simple_async_result_get_source_tag (simple);
1772 g_return_val_if_fail (source_tag == e_cal_client_connect, NULL);
1774 if (g_simple_async_result_propagate_error (simple, error)) {
1776 error, _("Unable to connect to '%s': "),
1777 e_source_get_display_name (closure->source));
1781 return E_CLIENT (g_async_result_get_source_object (result));
1786 * @source: An #ESource pointer
1787 * @source_type: source type of the calendar
1788 * @error: A #GError pointer
1790 * Creates a new #ECalClient corresponding to the given source. There are
1791 * only two operations that are valid on this calendar at this point:
1792 * e_client_open(), and e_client_remove().
1794 * Returns: a new but unopened #ECalClient.
1798 * Deprecated: 3.8: It covertly makes synchronous D-Bus calls, with no
1799 * way to cancel. Use e_cal_client_connect() instead,
1800 * which combines e_cal_client_new() and e_client_open()
1804 e_cal_client_new (ESource *source,
1805 ECalClientSourceType source_type,
1808 g_return_val_if_fail (E_IS_SOURCE (source), NULL);
1809 g_return_val_if_fail (
1810 source_type == E_CAL_CLIENT_SOURCE_TYPE_EVENTS ||
1811 source_type == E_CAL_CLIENT_SOURCE_TYPE_TASKS ||
1812 source_type == E_CAL_CLIENT_SOURCE_TYPE_MEMOS, NULL);
1814 return g_initable_new (
1815 E_TYPE_CAL_CLIENT, NULL, error,
1817 "source-type", source_type, NULL);
1821 * e_cal_client_get_source_type:
1822 * @client: A calendar client.
1824 * Gets the source type of the calendar client.
1826 * Returns: an #ECalClientSourceType value corresponding
1827 * to the source type of the calendar client.
1831 ECalClientSourceType
1832 e_cal_client_get_source_type (ECalClient *client)
1834 g_return_val_if_fail (
1835 E_IS_CAL_CLIENT (client),
1836 E_CAL_CLIENT_SOURCE_TYPE_LAST);
1838 return client->priv->source_type;
1842 * e_cal_client_get_local_attachment_store:
1843 * @client: A calendar client.
1845 * Queries the URL where the calendar attachments are
1846 * serialized in the local filesystem. This enable clients
1847 * to operate with the reference to attachments rather than the data itself
1848 * unless it specifically uses the attachments for open/sending
1851 * Returns: The URL where the attachments are serialized in the
1857 e_cal_client_get_local_attachment_store (ECalClient *client)
1859 g_return_val_if_fail (E_IS_CAL_CLIENT (client), NULL);
1861 return e_dbus_calendar_get_cache_dir (client->priv->dbus_proxy);
1864 /* icaltimezone_copy does a shallow copy while icaltimezone_free tries to free the entire
1865 * the contents inside the structure with libical 0.43. Use this, till eds allows older libical.
1867 static icaltimezone *
1868 copy_timezone (icaltimezone *ozone)
1870 icaltimezone *zone = NULL;
1873 tzid = icaltimezone_get_tzid (ozone);
1875 if (g_strcmp0 (tzid, "UTC") != 0) {
1876 icalcomponent *comp;
1878 comp = icaltimezone_get_component (ozone);
1880 zone = icaltimezone_new ();
1881 icaltimezone_set_component (zone, icalcomponent_new_clone (comp));
1886 zone = icaltimezone_get_utc_timezone ();
1892 * e_cal_client_set_default_timezone:
1893 * @client: A calendar client.
1894 * @zone: A timezone object.
1896 * Sets the default timezone to use to resolve DATE and floating DATE-TIME
1897 * values. This will typically be from the user's timezone setting. Call this
1898 * before using any other object fetching functions.
1903 e_cal_client_set_default_timezone (ECalClient *client,
1906 g_return_if_fail (E_IS_CAL_CLIENT (client));
1907 g_return_if_fail (zone != NULL);
1909 if (client->priv->default_zone != icaltimezone_get_utc_timezone ())
1910 icaltimezone_free (client->priv->default_zone, 1);
1912 if (zone == icaltimezone_get_utc_timezone ())
1913 client->priv->default_zone = zone;
1915 client->priv->default_zone = copy_timezone (zone);
1919 * e_cal_client_get_default_timezone:
1920 * @client: A calendar client.
1922 * Returns: Default timezone previously set with e_cal_client_set_default_timezone().
1923 * Returned pointer is owned by the @client and should not be freed.
1928 e_cal_client_get_default_timezone (ECalClient *client)
1930 g_return_val_if_fail (E_IS_CAL_CLIENT (client), NULL);
1932 return client->priv->default_zone;
1936 * e_cal_client_check_one_alarm_only:
1937 * @client: A calendar client.
1939 * Checks if a calendar supports only one alarm per component.
1941 * Returns: TRUE if the calendar allows only one alarm, FALSE otherwise.
1946 e_cal_client_check_one_alarm_only (ECalClient *client)
1948 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
1950 return e_client_check_capability (
1952 CAL_STATIC_CAPABILITY_ONE_ALARM_ONLY);
1956 * e_cal_client_check_save_schedules:
1957 * @client: A calendar client.
1959 * Checks whether the calendar saves schedules.
1961 * Returns: TRUE if it saves schedules, FALSE otherwise.
1966 e_cal_client_check_save_schedules (ECalClient *client)
1968 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
1970 return e_client_check_capability (
1972 CAL_STATIC_CAPABILITY_SAVE_SCHEDULES);
1976 * e_cal_client_check_organizer_must_attend:
1977 * @client: A calendar client.
1979 * Checks if a calendar forces organizers of meetings to be also attendees.
1981 * Returns: TRUE if the calendar forces organizers to attend meetings,
1987 e_cal_client_check_organizer_must_attend (ECalClient *client)
1989 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
1991 return e_client_check_capability (
1993 CAL_STATIC_CAPABILITY_ORGANIZER_MUST_ATTEND);
1997 * e_cal_client_check_organizer_must_accept:
1998 * @client: A calendar client.
2000 * Checks whether a calendar requires organizer to accept their attendance to
2003 * Returns: TRUE if the calendar requires organizers to accept, FALSE
2009 e_cal_client_check_organizer_must_accept (ECalClient *client)
2011 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
2013 return e_client_check_capability (
2015 CAL_STATIC_CAPABILITY_ORGANIZER_MUST_ACCEPT);
2019 * e_cal_client_check_recurrences_no_master:
2020 * @client: A calendar client.
2022 * Checks if the calendar has a master object for recurrences.
2024 * Returns: TRUE if the calendar has a master object for recurrences,
2030 e_cal_client_check_recurrences_no_master (ECalClient *client)
2032 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
2034 return e_client_check_capability (
2036 CAL_STATIC_CAPABILITY_RECURRENCES_NO_MASTER);
2040 * e_cal_client_free_icalcomp_slist:
2041 * @icalcomps: (element-type icalcomponent): list of icalcomponent objects
2043 * Frees each element of the @icalcomps list and the list itself.
2044 * Each element is an object of type #icalcomponent.
2049 e_cal_client_free_icalcomp_slist (GSList *icalcomps)
2051 g_slist_foreach (icalcomps, (GFunc) icalcomponent_free, NULL);
2052 g_slist_free (icalcomps);
2056 * e_cal_client_free_ecalcomp_slist:
2057 * @ecalcomps: (element-type ECalComponent): list of #ECalComponent objects
2059 * Frees each element of the @ecalcomps list and the list itself.
2060 * Each element is an object of type #ECalComponent.
2065 e_cal_client_free_ecalcomp_slist (GSList *ecalcomps)
2067 g_slist_foreach (ecalcomps, (GFunc) g_object_unref, NULL);
2068 g_slist_free (ecalcomps);
2072 * e_cal_client_resolve_tzid_cb:
2073 * @tzid: ID of the timezone to resolve.
2074 * @data: Closure data for the callback, in this case #ECalClient.
2076 * Resolves TZIDs for the recurrence generator.
2078 * Returns: The timezone identified by the @tzid argument, or %NULL if
2079 * it could not be found.
2084 e_cal_client_resolve_tzid_cb (const gchar *tzid,
2087 ECalClient *client = data;
2088 icaltimezone *zone = NULL;
2089 GError *error = NULL;
2091 g_return_val_if_fail (E_IS_CAL_CLIENT (client), NULL);
2093 e_cal_client_get_timezone_sync (client, tzid, &zone, NULL, &error);
2096 g_debug ("%s: Failed to find '%s' timezone: %s", G_STRFUNC, tzid, error->message);
2097 g_error_free (error);
2103 struct comp_instance {
2104 ECalComponent *comp;
2109 struct instances_info {
2111 icaltimezone *start_zone;
2112 icaltimezone *end_zone;
2115 /* Called from cal_recur_generate_instances(); adds an instance to the list */
2117 add_instance (ECalComponent *comp,
2123 struct comp_instance *ci;
2124 icalcomponent *icalcomp;
2125 struct instances_info *instances_hold;
2127 instances_hold = data;
2128 list = instances_hold->instances;
2130 ci = g_new (struct comp_instance, 1);
2132 icalcomp = icalcomponent_new_clone (e_cal_component_get_icalcomponent (comp));
2134 /* add the instance to the list */
2135 ci->comp = e_cal_component_new ();
2136 e_cal_component_set_icalcomponent (ci->comp, icalcomp);
2138 /* make sure we return an instance */
2139 if (e_cal_util_component_has_recurrences (icalcomp) &&
2140 !(icalcomponent_get_first_property (icalcomp, ICAL_RECURRENCEID_PROPERTY))) {
2141 ECalComponentRange *range;
2142 struct icaltimetype itt;
2143 ECalComponentDateTime dtstart, dtend;
2145 /* update DTSTART */
2146 dtstart.value = NULL;
2147 dtstart.tzid = NULL;
2149 e_cal_component_get_dtstart (comp, &dtstart);
2151 if (instances_hold->start_zone) {
2152 itt = icaltime_from_timet_with_zone (start, dtstart.value && dtstart.value->is_date, instances_hold->start_zone);
2153 g_free ((gchar *) dtstart.tzid);
2154 dtstart.tzid = g_strdup (icaltimezone_get_tzid (instances_hold->start_zone));
2156 itt = icaltime_from_timet (start, dtstart.value && dtstart.value->is_date);
2158 g_free ((gchar *) dtstart.tzid);
2159 dtstart.tzid = NULL;
2163 g_free (dtstart.value);
2164 dtstart.value = &itt;
2165 e_cal_component_set_dtstart (ci->comp, &dtstart);
2167 /* set the RECUR-ID for the instance */
2168 range = g_new0 (ECalComponentRange, 1);
2169 range->type = E_CAL_COMPONENT_RANGE_SINGLE;
2170 range->datetime = dtstart;
2172 e_cal_component_set_recurid (ci->comp, range);
2175 g_free ((gchar *) dtstart.tzid);
2181 e_cal_component_get_dtend (comp, &dtend);
2183 if (instances_hold->end_zone) {
2184 itt = icaltime_from_timet_with_zone (end, dtend.value && dtend.value->is_date, instances_hold->end_zone);
2185 g_free ((gchar *) dtend.tzid);
2186 dtend.tzid = g_strdup (icaltimezone_get_tzid (instances_hold->end_zone));
2188 itt = icaltime_from_timet (end, dtend.value && dtend.value->is_date);
2190 g_free ((gchar *) dtend.tzid);
2195 g_free (dtend.value);
2197 e_cal_component_set_dtend (ci->comp, &dtend);
2199 g_free ((gchar *) dtend.tzid);
2205 *list = g_slist_prepend (*list, ci);
2210 /* Used from g_slist_sort(); compares two struct comp_instance structures */
2212 compare_comp_instance (gconstpointer a,
2215 const struct comp_instance *cia, *cib;
2221 diff = cia->start - cib->start;
2222 return (diff < 0) ? -1 : (diff > 0) ? 1 : 0;
2226 process_detached_instances (GSList *instances,
2227 GSList *detached_instances)
2229 struct comp_instance *ci, *cid;
2230 GSList *dl, *unprocessed_instances = NULL;
2232 for (dl = detached_instances; dl != NULL; dl = dl->next) {
2236 ECalComponentRange recur_id, instance_recur_id;
2239 recur_id.type = E_CAL_COMPONENT_RANGE_SINGLE;
2240 instance_recur_id.type = E_CAL_COMPONENT_RANGE_SINGLE;
2243 e_cal_component_get_uid (cid->comp, &uid);
2244 e_cal_component_get_recurid (cid->comp, &recur_id);
2246 /* search for coincident instances already expanded */
2247 for (il = instances; il != NULL; il = il->next) {
2248 const gchar *instance_uid;
2252 e_cal_component_get_uid (ci->comp, &instance_uid);
2253 e_cal_component_get_recurid (ci->comp, &instance_recur_id);
2254 if (strcmp (uid, instance_uid) == 0) {
2255 gchar *i_rid = NULL, *d_rid = NULL;
2257 i_rid = e_cal_component_get_recurid_as_string (ci->comp);
2258 d_rid = e_cal_component_get_recurid_as_string (cid->comp);
2260 if (i_rid && d_rid && strcmp (i_rid, d_rid) == 0) {
2261 g_object_unref (ci->comp);
2262 ci->comp = g_object_ref (cid->comp);
2263 ci->start = cid->start;
2268 if (!instance_recur_id.datetime.value ||
2269 !recur_id.datetime.value) {
2271 * Prevent obvious segfault by ignoring missing
2272 * recurrency ids. Real problem might be elsewhere,
2273 * but anything is better than crashing...
2277 G_LOG_LEVEL_CRITICAL,
2278 "UID %s: instance RECURRENCE-ID %s + detached instance RECURRENCE-ID %s: cannot compare",
2283 e_cal_component_free_datetime (&instance_recur_id.datetime);
2288 cmp = icaltime_compare (
2289 *instance_recur_id.datetime.value,
2290 *recur_id.datetime.value);
2291 if ((recur_id.type == E_CAL_COMPONENT_RANGE_THISPRIOR && cmp <= 0) ||
2292 (recur_id.type == E_CAL_COMPONENT_RANGE_THISFUTURE && cmp >= 0)) {
2293 ECalComponent *comp;
2295 comp = e_cal_component_new ();
2296 e_cal_component_set_icalcomponent (
2298 icalcomponent_new_clone (e_cal_component_get_icalcomponent (cid->comp)));
2299 e_cal_component_set_recurid (comp, &instance_recur_id);
2301 /* replace the generated instances */
2302 g_object_unref (ci->comp);
2309 e_cal_component_free_datetime (&instance_recur_id.datetime);
2312 e_cal_component_free_datetime (&recur_id.datetime);
2315 unprocessed_instances = g_slist_prepend (unprocessed_instances, cid);
2318 /* add the unprocessed instances (ie, detached instances with no master object */
2319 while (unprocessed_instances != NULL) {
2320 cid = unprocessed_instances->data;
2321 ci = g_new0 (struct comp_instance, 1);
2322 ci->comp = g_object_ref (cid->comp);
2323 ci->start = cid->start;
2325 instances = g_slist_append (instances, ci);
2327 unprocessed_instances = g_slist_remove (unprocessed_instances, cid);
2334 generate_instances (ECalClient *client,
2338 GCancellable *cancellable,
2339 ECalRecurInstanceFn cb,
2342 GSList *instances, *detached_instances = NULL;
2344 ECalClientPrivate *priv;
2346 priv = client->priv;
2350 for (l = objects; l && !g_cancellable_is_cancelled (cancellable); l = l->next) {
2351 ECalComponent *comp;
2352 icaltimezone *default_zone;
2354 if (priv->default_zone)
2355 default_zone = priv->default_zone;
2357 default_zone = icaltimezone_get_utc_timezone ();
2360 if (e_cal_component_is_instance (comp)) {
2361 struct comp_instance *ci;
2362 ECalComponentDateTime dtstart, dtend;
2363 icaltimezone *start_zone = NULL, *end_zone = NULL;
2365 /* keep the detached instances apart */
2366 ci = g_new0 (struct comp_instance, 1);
2367 ci->comp = g_object_ref (comp);
2369 e_cal_component_get_dtstart (comp, &dtstart);
2370 e_cal_component_get_dtend (comp, &dtend);
2372 /* For DATE-TIME values with a TZID, we use
2373 * e_cal_resolve_tzid_cb to resolve the TZID.
2374 * For DATE values and DATE-TIME values without a
2375 * TZID (i.e. floating times) we use the default
2377 if (dtstart.tzid && dtstart.value && !dtstart.value->is_date) {
2378 start_zone = e_cal_client_resolve_tzid_cb (dtstart.tzid, client);
2380 start_zone = default_zone;
2382 start_zone = default_zone;
2385 if (dtend.tzid && dtend.value && !dtend.value->is_date) {
2386 end_zone = e_cal_client_resolve_tzid_cb (dtend.tzid, client);
2388 end_zone = default_zone;
2390 end_zone = default_zone;
2393 ci->start = icaltime_as_timet_with_zone (*dtstart.value, start_zone);
2396 ci->end = icaltime_as_timet_with_zone (*dtend.value, end_zone);
2397 else if (icaltime_is_date (*dtstart.value))
2398 ci->end = time_day_end (ci->start);
2400 ci->end = ci->start;
2402 e_cal_component_free_datetime (&dtstart);
2403 e_cal_component_free_datetime (&dtend);
2405 if (ci->start <= end && ci->end >= start) {
2406 detached_instances = g_slist_prepend (detached_instances, ci);
2408 /* it doesn't fit to our time range, thus skip it */
2409 g_object_unref (G_OBJECT (ci->comp));
2413 ECalComponentDateTime datetime;
2414 icaltimezone *start_zone = NULL, *end_zone = NULL;
2415 struct instances_info *instances_hold;
2417 /* Get the start timezone */
2418 e_cal_component_get_dtstart (comp, &datetime);
2420 e_cal_client_get_timezone_sync (client, datetime.tzid, &start_zone, cancellable, NULL);
2423 e_cal_component_free_datetime (&datetime);
2425 /* Get the end timezone */
2426 e_cal_component_get_dtend (comp, &datetime);
2428 e_cal_client_get_timezone_sync (client, datetime.tzid, &end_zone, cancellable, NULL);
2431 e_cal_component_free_datetime (&datetime);
2433 instances_hold = g_new0 (struct instances_info, 1);
2434 instances_hold->instances = &instances;
2435 instances_hold->start_zone = start_zone;
2436 instances_hold->end_zone = end_zone;
2438 e_cal_recur_generate_instances (
2439 comp, start, end, add_instance, instances_hold,
2440 e_cal_client_resolve_tzid_cb, client,
2443 g_free (instances_hold);
2447 g_slist_foreach (objects, (GFunc) g_object_unref, NULL);
2448 g_slist_free (objects);
2450 /* Generate instances and spew them out */
2452 if (!g_cancellable_is_cancelled (cancellable)) {
2453 instances = g_slist_sort (instances, compare_comp_instance);
2454 instances = process_detached_instances (instances, detached_instances);
2457 for (l = instances; l && !g_cancellable_is_cancelled (cancellable); l = l->next) {
2458 struct comp_instance *ci;
2463 result = (* cb) (ci->comp, ci->start, ci->end, cb_data);
2471 for (l = instances; l; l = l->next) {
2472 struct comp_instance *ci;
2475 g_object_unref (G_OBJECT (ci->comp));
2479 g_slist_free (instances);
2481 for (l = detached_instances; l; l = l->next) {
2482 struct comp_instance *ci;
2485 g_object_unref (G_OBJECT (ci->comp));
2489 g_slist_free (detached_instances);
2493 get_objects_sync (ECalClient *client,
2498 GSList *objects = NULL;
2500 /* Generate objects */
2502 GError *error = NULL;
2504 if (!e_cal_client_get_objects_for_uid_sync (client, uid, &objects, NULL, &error)) {
2505 unwrap_dbus_error (error, &error);
2506 g_message ("Failed to get recurrence objects for uid %s \n", error ? error->message : "Unknown error");
2507 g_clear_error (&error);
2511 gchar *iso_start, *iso_end;
2514 iso_start = isodate_from_time_t (start);
2518 iso_end = isodate_from_time_t (end);
2524 query = g_strdup_printf (
2525 "(occur-in-time-range? (make-time \"%s\") (make-time \"%s\"))",
2526 iso_start, iso_end);
2529 if (!e_cal_client_get_object_list_as_comps_sync (client, query, &objects, NULL, NULL)) {
2539 struct get_objects_async_data
2541 GCancellable *cancellable;
2545 ECalRecurInstanceFn cb;
2547 GDestroyNotify destroy_cb_data;
2551 void (* ready_cb) (struct get_objects_async_data *goad, GSList *objects);
2552 icaltimezone *start_zone;
2553 icaltimezone *end_zone;
2554 ECalComponent *comp;
2558 free_get_objects_async_data (struct get_objects_async_data *goad)
2563 if (goad->cancellable)
2564 g_object_unref (goad->cancellable);
2565 if (goad->destroy_cb_data)
2566 goad->destroy_cb_data (goad->cb_data);
2568 g_object_unref (goad->client);
2570 g_object_unref (goad->comp);
2571 g_free (goad->query);
2577 got_objects_for_uid_cb (GObject *source_object,
2578 GAsyncResult *result,
2581 struct get_objects_async_data *goad = user_data;
2582 GSList *objects = NULL;
2583 GError *error = NULL;
2585 g_return_if_fail (source_object != NULL);
2586 g_return_if_fail (result != NULL);
2587 g_return_if_fail (goad != NULL);
2588 g_return_if_fail (goad->client == E_CAL_CLIENT (source_object));
2590 if (!e_cal_client_get_objects_for_uid_finish (goad->client, result, &objects, &error)) {
2591 if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED) ||
2592 g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
2593 free_get_objects_async_data (goad);
2594 g_clear_error (&error);
2598 g_clear_error (&error);
2602 g_return_if_fail (goad->ready_cb != NULL);
2604 /* takes care of the objects and goad */
2605 goad->ready_cb (goad, objects);
2609 got_object_list_as_comps_cb (GObject *source_object,
2610 GAsyncResult *result,
2613 struct get_objects_async_data *goad = user_data;
2614 GSList *objects = NULL;
2615 GError *error = NULL;
2617 g_return_if_fail (source_object != NULL);
2618 g_return_if_fail (result != NULL);
2619 g_return_if_fail (goad != NULL);
2620 g_return_if_fail (goad->client == E_CAL_CLIENT (source_object));
2622 if (!e_cal_client_get_object_list_as_comps_finish (goad->client, result, &objects, &error)) {
2623 if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED) ||
2624 g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
2625 free_get_objects_async_data (goad);
2626 g_clear_error (&error);
2630 g_clear_error (&error);
2634 g_return_if_fail (goad->ready_cb != NULL);
2636 /* takes care of the objects and goad */
2637 goad->ready_cb (goad, objects);
2640 /* ready_cb may take care of both arguments, goad and objects; objects can be also NULL */
2642 get_objects_async (void (*ready_cb) (struct get_objects_async_data *goad,
2644 struct get_objects_async_data *goad)
2646 g_return_if_fail (ready_cb != NULL);
2647 g_return_if_fail (goad != NULL);
2649 goad->ready_cb = ready_cb;
2651 if (goad->uid && *goad->uid) {
2652 e_cal_client_get_objects_for_uid (goad->client, goad->uid, goad->cancellable, got_objects_for_uid_cb, goad);
2654 gchar *iso_start, *iso_end;
2656 iso_start = isodate_from_time_t (goad->start);
2658 free_get_objects_async_data (goad);
2662 iso_end = isodate_from_time_t (goad->end);
2665 free_get_objects_async_data (goad);
2669 goad->query = g_strdup_printf ("(occur-in-time-range? (make-time \"%s\") (make-time \"%s\"))", iso_start, iso_end);
2674 e_cal_client_get_object_list_as_comps (goad->client, goad->query, goad->cancellable, got_object_list_as_comps_cb, goad);
2679 generate_instances_got_objects_cb (struct get_objects_async_data *goad,
2682 g_return_if_fail (goad != NULL);
2684 /* generate_instaces () frees 'objects' slist */
2686 generate_instances (goad->client, goad->start, goad->end, objects, goad->cancellable, goad->cb, goad->cb_data);
2688 free_get_objects_async_data (goad);
2692 * e_cal_client_generate_instances:
2693 * @client: A calendar client.
2694 * @start: Start time for query.
2695 * @end: End time for query.
2696 * @cancellable: a #GCancellable; can be %NULL
2697 * @cb: Callback for each generated instance.
2698 * @cb_data: Closure data for the callback.
2699 * @destroy_cb_data: Function to call when the processing is done, to free @cb_data; can be %NULL.
2701 * Does a combination of e_cal_client_get_object_list() and
2702 * e_cal_client_recur_generate_instances(). Unlike e_cal_client_generate_instances_sync(),
2703 * this returns immediately and the @cb callback is called asynchronously.
2705 * The callback function should do a g_object_ref() of the calendar component
2706 * it gets passed if it intends to keep it around, since it will be unref'ed
2707 * as soon as the callback returns.
2712 e_cal_client_generate_instances (ECalClient *client,
2715 GCancellable *cancellable,
2716 ECalRecurInstanceFn cb,
2718 GDestroyNotify destroy_cb_data)
2720 struct get_objects_async_data *goad;
2721 GCancellable *use_cancellable;
2723 g_return_if_fail (E_IS_CAL_CLIENT (client));
2725 g_return_if_fail (start >= 0);
2726 g_return_if_fail (end >= 0);
2727 g_return_if_fail (cb != NULL);
2729 use_cancellable = cancellable;
2730 if (!use_cancellable)
2731 use_cancellable = g_cancellable_new ();
2733 goad = g_new0 (struct get_objects_async_data, 1);
2734 goad->cancellable = g_object_ref (use_cancellable);
2735 goad->client = g_object_ref (client);
2736 goad->start = start;
2739 goad->cb_data = cb_data;
2740 goad->destroy_cb_data = destroy_cb_data;
2742 get_objects_async (generate_instances_got_objects_cb, goad);
2744 if (use_cancellable != cancellable)
2745 g_object_unref (use_cancellable);
2749 * e_cal_client_generate_instances_sync:
2750 * @client: A calendar client
2751 * @start: Start time for query
2752 * @end: End time for query
2753 * @cb: (closure cb_data) (scope call): Callback for each generated instance
2754 * @cb_data: (closure): Closure data for the callback
2756 * Does a combination of e_cal_client_get_object_list() and
2757 * e_cal_client_recur_generate_instances().
2759 * The callback function should do a g_object_ref() of the calendar component
2760 * it gets passed if it intends to keep it around, since it will be unreffed
2761 * as soon as the callback returns.
2766 e_cal_client_generate_instances_sync (ECalClient *client,
2769 ECalRecurInstanceFn cb,
2772 GSList *objects = NULL;
2774 g_return_if_fail (E_IS_CAL_CLIENT (client));
2776 g_return_if_fail (start >= 0);
2777 g_return_if_fail (end >= 0);
2778 g_return_if_fail (cb != NULL);
2780 objects = get_objects_sync (client, start, end, NULL);
2784 /* generate_instaces frees 'objects' slist */
2785 generate_instances (client, start, end, objects, NULL, cb, cb_data);
2788 /* also frees 'instances' GSList */
2790 process_instances (ECalComponent *comp,
2792 ECalRecurInstanceFn cb,
2798 g_return_if_fail (comp != NULL);
2799 g_return_if_fail (cb != NULL);
2801 rid = e_cal_component_get_recurid_as_string (comp);
2803 /* Reverse the instances list because the add_instance() function is prepending */
2804 instances = g_slist_reverse (instances);
2806 /* now only return back the instances for the given object */
2808 while (instances != NULL) {
2809 struct comp_instance *ci;
2810 gchar *instance_rid = NULL;
2812 ci = instances->data;
2815 instance_rid = e_cal_component_get_recurid_as_string (ci->comp);
2818 if (instance_rid && *instance_rid && strcmp (rid, instance_rid) == 0)
2819 result = (* cb) (ci->comp, ci->start, ci->end, cb_data);
2821 result = (* cb) (ci->comp, ci->start, ci->end, cb_data);
2824 /* remove instance from list */
2825 instances = g_slist_remove (instances, ci);
2826 g_object_unref (ci->comp);
2828 g_free (instance_rid);
2836 generate_instances_for_object_got_objects_cb (struct get_objects_async_data *goad,
2839 struct instances_info *instances_hold;
2840 GSList *instances = NULL;
2842 g_return_if_fail (goad != NULL);
2844 instances_hold = g_new0 (struct instances_info, 1);
2845 instances_hold->instances = &instances;
2846 instances_hold->start_zone = goad->start_zone;
2847 instances_hold->end_zone = goad->end_zone;
2849 /* generate all instances in the given time range */
2850 generate_instances (goad->client, goad->start, goad->end, objects, goad->cancellable, add_instance, instances_hold);
2852 /* it also frees 'instances' GSList */
2853 process_instances (goad->comp, *(instances_hold->instances), goad->cb, goad->cb_data);
2856 free_get_objects_async_data (goad);
2857 g_free (instances_hold);
2861 * e_cal_client_generate_instances_for_object:
2862 * @client: A calendar client.
2863 * @icalcomp: Object to generate instances from.
2864 * @start: Start time for query.
2865 * @end: End time for query.
2866 * @cancellable: a #GCancellable; can be %NULL
2867 * @cb: Callback for each generated instance.
2868 * @cb_data: Closure data for the callback.
2869 * @destroy_cb_data: Function to call when the processing is done, to free @cb_data; can be %NULL.
2871 * Does a combination of e_cal_client_get_object_list() and
2872 * e_cal_client_recur_generate_instances(), like e_cal_client_generate_instances(), but
2873 * for a single object. Unlike e_cal_client_generate_instances_for_object_sync(),
2874 * this returns immediately and the @cb callback is called asynchronously.
2876 * The callback function should do a g_object_ref() of the calendar component
2877 * it gets passed if it intends to keep it around, since it will be unref'ed
2878 * as soon as the callback returns.
2883 e_cal_client_generate_instances_for_object (ECalClient *client,
2884 icalcomponent *icalcomp,
2887 GCancellable *cancellable,
2888 ECalRecurInstanceFn cb,
2890 GDestroyNotify destroy_cb_data)
2892 ECalComponent *comp;
2894 ECalComponentDateTime datetime;
2895 icaltimezone *start_zone = NULL, *end_zone = NULL;
2896 gboolean is_single_instance = FALSE;
2897 struct get_objects_async_data *goad;
2898 GCancellable *use_cancellable;
2900 g_return_if_fail (E_IS_CAL_CLIENT (client));
2902 g_return_if_fail (start >= 0);
2903 g_return_if_fail (end >= 0);
2904 g_return_if_fail (cb != NULL);
2906 comp = e_cal_component_new ();
2907 e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (icalcomp));
2909 if (!e_cal_component_has_recurrences (comp))
2910 is_single_instance = TRUE;
2912 /* If the backend stores it as individual instances and does not
2913 * have a master object - do not expand */
2914 if (is_single_instance || e_client_check_capability (E_CLIENT (client), CAL_STATIC_CAPABILITY_RECURRENCES_NO_MASTER)) {
2915 /* return the same instance */
2916 (* cb) (comp, icaltime_as_timet_with_zone (icalcomponent_get_dtstart (icalcomp), client->priv->default_zone),
2917 icaltime_as_timet_with_zone (icalcomponent_get_dtend (icalcomp), client->priv->default_zone), cb_data);
2918 g_object_unref (comp);
2920 if (destroy_cb_data)
2921 destroy_cb_data (cb_data);
2925 e_cal_component_get_uid (comp, &uid);
2927 /* Get the start timezone */
2928 e_cal_component_get_dtstart (comp, &datetime);
2930 e_cal_client_get_timezone_sync (client, datetime.tzid, &start_zone, NULL, NULL);
2933 e_cal_component_free_datetime (&datetime);
2935 /* Get the end timezone */
2936 e_cal_component_get_dtend (comp, &datetime);
2938 e_cal_client_get_timezone_sync (client, datetime.tzid, &end_zone, NULL, NULL);
2941 e_cal_component_free_datetime (&datetime);
2943 use_cancellable = cancellable;
2944 if (!use_cancellable)
2945 use_cancellable = g_cancellable_new ();
2947 goad = g_new0 (struct get_objects_async_data, 1);
2948 goad->cancellable = g_object_ref (use_cancellable);
2949 goad->client = g_object_ref (client);
2950 goad->start = start;
2953 goad->cb_data = cb_data;
2954 goad->destroy_cb_data = destroy_cb_data;
2955 goad->start_zone = start_zone;
2956 goad->end_zone = end_zone;
2958 goad->uid = g_strdup (uid);
2960 get_objects_async (generate_instances_for_object_got_objects_cb, goad);
2962 if (use_cancellable != cancellable)
2963 g_object_unref (use_cancellable);
2967 * e_cal_client_generate_instances_for_object_sync:
2968 * @client: A calendar client
2969 * @icalcomp: Object to generate instances from
2970 * @start: Start time for query
2971 * @end: End time for query
2972 * @cb: (closure cb_data) (scope call): Callback for each generated instance
2973 * @cb_data: (closure): Closure data for the callback
2975 * Does a combination of e_cal_client_get_object_list() and
2976 * e_cal_client_recur_generate_instances(), like e_cal_client_generate_instances_sync(), but
2977 * for a single object.
2979 * The callback function should do a g_object_ref() of the calendar component
2980 * it gets passed if it intends to keep it around, since it will be unref'ed
2981 * as soon as the callback returns.
2986 e_cal_client_generate_instances_for_object_sync (ECalClient *client,
2987 icalcomponent *icalcomp,
2990 ECalRecurInstanceFn cb,
2993 ECalComponent *comp;
2995 GSList *instances = NULL;
2996 ECalComponentDateTime datetime;
2997 icaltimezone *start_zone = NULL, *end_zone = NULL;
2998 struct instances_info *instances_hold;
2999 gboolean is_single_instance = FALSE;
3001 g_return_if_fail (E_IS_CAL_CLIENT (client));
3003 g_return_if_fail (start >= 0);
3004 g_return_if_fail (end >= 0);
3005 g_return_if_fail (cb != NULL);
3007 comp = e_cal_component_new ();
3008 e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (icalcomp));
3010 if (!e_cal_component_has_recurrences (comp))
3011 is_single_instance = TRUE;
3013 /* If the backend stores it as individual instances and does not
3014 * have a master object - do not expand */
3015 if (is_single_instance || e_client_check_capability (E_CLIENT (client), CAL_STATIC_CAPABILITY_RECURRENCES_NO_MASTER)) {
3016 /* return the same instance */
3017 (* cb) (comp, icaltime_as_timet_with_zone (icalcomponent_get_dtstart (icalcomp), client->priv->default_zone),
3018 icaltime_as_timet_with_zone (icalcomponent_get_dtend (icalcomp), client->priv->default_zone), cb_data);
3019 g_object_unref (comp);
3023 e_cal_component_get_uid (comp, &uid);
3025 /* Get the start timezone */
3026 e_cal_component_get_dtstart (comp, &datetime);
3028 e_cal_client_get_timezone_sync (client, datetime.tzid, &start_zone, NULL, NULL);
3031 e_cal_component_free_datetime (&datetime);
3033 /* Get the end timezone */
3034 e_cal_component_get_dtend (comp, &datetime);
3036 e_cal_client_get_timezone_sync (client, datetime.tzid, &end_zone, NULL, NULL);
3039 e_cal_component_free_datetime (&datetime);
3041 instances_hold = g_new0 (struct instances_info, 1);
3042 instances_hold->instances = &instances;
3043 instances_hold->start_zone = start_zone;
3044 instances_hold->end_zone = end_zone;
3046 /* generate all instances in the given time range */
3047 generate_instances (client, start, end, get_objects_sync (client, start, end, uid), NULL, add_instance, instances_hold);
3049 /* it also frees 'instances' GSList */
3050 process_instances (comp, *(instances_hold->instances), cb, cb_data);
3053 g_object_unref (comp);
3054 g_free (instances_hold);
3057 typedef struct _ForeachTZIDCallbackData ForeachTZIDCallbackData;
3058 struct _ForeachTZIDCallbackData {
3060 GHashTable *timezone_hash;
3064 /* This adds the VTIMEZONE given by the TZID parameter to the GHashTable in
3067 foreach_tzid_callback (icalparameter *param,
3070 ForeachTZIDCallbackData *data = cbdata;
3072 icaltimezone *zone = NULL;
3073 icalcomponent *vtimezone_comp;
3074 gchar *vtimezone_as_string;
3076 /* Get the TZID string from the parameter. */
3077 tzid = icalparameter_get_tzid (param);
3081 /* Check if we've already added it to the GHashTable. */
3082 if (g_hash_table_lookup (data->timezone_hash, tzid))
3085 if (!e_cal_client_get_timezone_sync (data->client, tzid, &zone, NULL, NULL) || !zone) {
3086 data->success = FALSE;
3090 /* Convert it to a string and add it to the hash. */
3091 vtimezone_comp = icaltimezone_get_component (zone);
3092 if (!vtimezone_comp)
3095 vtimezone_as_string = icalcomponent_as_ical_string_r (vtimezone_comp);
3097 g_hash_table_insert (data->timezone_hash, (gchar *) tzid, vtimezone_as_string);
3100 /* This appends the value string to the GString given in data. */
3102 append_timezone_string (gpointer key,
3106 GString *vcal_string = data;
3108 g_string_append (vcal_string, value);
3112 /* This simply frees the hash values. */
3114 free_timezone_string (gpointer key,
3122 * e_cal_client_get_component_as_string:
3123 * @client: A calendar client.
3124 * @icalcomp: A calendar component object.
3126 * Gets a calendar component as an iCalendar string, with a toplevel
3127 * VCALENDAR component and all VTIMEZONEs needed for the component.
3129 * Returns: the component as a complete iCalendar string, or NULL on
3130 * failure. The string should be freed with g_free().
3135 e_cal_client_get_component_as_string (ECalClient *client,
3136 icalcomponent *icalcomp)
3138 GHashTable *timezone_hash;
3139 GString *vcal_string;
3140 ForeachTZIDCallbackData cbdata;
3143 g_return_val_if_fail (E_IS_CAL_CLIENT (client), NULL);
3144 g_return_val_if_fail (icalcomp != NULL, NULL);
3146 timezone_hash = g_hash_table_new (g_str_hash, g_str_equal);
3148 /* Add any timezones needed to the hash. We use a hash since we only
3149 * want to add each timezone once at most. */
3150 cbdata.client = client;
3151 cbdata.timezone_hash = timezone_hash;
3152 cbdata.success = TRUE;
3153 icalcomponent_foreach_tzid (icalcomp, foreach_tzid_callback, &cbdata);
3154 if (!cbdata.success) {
3155 g_hash_table_foreach (timezone_hash, free_timezone_string, NULL);
3159 /* Create the start of a VCALENDAR, to add the VTIMEZONES to,
3160 * and remember its length so we know if any VTIMEZONEs get added. */
3161 vcal_string = g_string_new (NULL);
3165 "PRODID:-//Ximian//NONSGML Evolution Calendar//EN\n"
3167 "METHOD:PUBLISH\n");
3169 /* Now concatenate all the timezone strings. This also frees the
3170 * timezone strings as it goes. */
3171 g_hash_table_foreach (timezone_hash, append_timezone_string, vcal_string);
3173 /* Get the string for the VEVENT/VTODO. */
3174 obj_string = icalcomponent_as_ical_string_r (icalcomp);
3176 /* If there were any timezones to send, create a complete VCALENDAR,
3177 * else just send the VEVENT/VTODO string. */
3178 g_string_append (vcal_string, obj_string);
3179 g_string_append (vcal_string, "END:VCALENDAR\n");
3180 g_free (obj_string);
3182 obj_string = g_string_free (vcal_string, FALSE);
3184 g_hash_table_destroy (timezone_hash);
3189 /* Helper for e_cal_client_get_default_object() */
3191 cal_client_get_default_object_thread (GSimpleAsyncResult *simple,
3192 GObject *source_object,
3193 GCancellable *cancellable)
3195 AsyncContext *async_context;
3196 GError *error = NULL;
3198 async_context = g_simple_async_result_get_op_res_gpointer (simple);
3200 e_cal_client_get_default_object_sync (
3201 E_CAL_CLIENT (source_object),
3202 &async_context->out_comp,
3203 cancellable, &error);
3206 g_simple_async_result_take_error (simple, error);
3210 * e_cal_client_get_default_object:
3211 * @client: an #ECalClient
3212 * @cancellable: a #GCancellable; can be %NULL
3213 * @callback: callback to call when a result is ready
3214 * @user_data: user data for the @callback
3216 * Retrives an #icalcomponent from the backend that contains the default
3217 * values for properties needed. The call is finished
3218 * by e_cal_client_get_default_object_finish() from the @callback.
3223 e_cal_client_get_default_object (ECalClient *client,
3224 GCancellable *cancellable,
3225 GAsyncReadyCallback callback,
3228 GSimpleAsyncResult *simple;
3229 AsyncContext *async_context;
3231 g_return_if_fail (E_IS_CAL_CLIENT (client));
3233 async_context = g_slice_new0 (AsyncContext);
3235 simple = g_simple_async_result_new (
3236 G_OBJECT (client), callback, user_data,
3237 e_cal_client_get_default_object);
3239 g_simple_async_result_set_check_cancellable (simple, cancellable);
3241 g_simple_async_result_set_op_res_gpointer (
3242 simple, async_context, (GDestroyNotify) async_context_free);
3244 g_simple_async_result_run_in_thread (
3245 simple, cal_client_get_default_object_thread,
3246 G_PRIORITY_DEFAULT, cancellable);
3248 g_object_unref (simple);
3252 * e_cal_client_get_default_object_finish:
3253 * @client: an #ECalClient
3254 * @result: a #GAsyncResult
3255 * @out_icalcomp: (out): Return value for the default calendar object.
3256 * @error: (out): a #GError to set an error, if any
3258 * Finishes previous call of e_cal_client_get_default_object() and
3259 * sets @out_icalcomp to an #icalcomponent from the backend that contains
3260 * the default values for properties needed. This @out_icalcomp should be
3261 * freed with icalcomponent_free().
3263 * Returns: %TRUE if successful, %FALSE otherwise.
3268 e_cal_client_get_default_object_finish (ECalClient *client,
3269 GAsyncResult *result,
3270 icalcomponent **out_icalcomp,
3273 GSimpleAsyncResult *simple;
3274 AsyncContext *async_context;
3276 g_return_val_if_fail (
3277 g_simple_async_result_is_valid (
3278 result, G_OBJECT (client),
3279 e_cal_client_get_default_object), FALSE);
3281 simple = G_SIMPLE_ASYNC_RESULT (result);
3282 async_context = g_simple_async_result_get_op_res_gpointer (simple);
3284 if (g_simple_async_result_propagate_error (simple, error))
3287 g_return_val_if_fail (async_context->out_comp != NULL, FALSE);
3289 if (out_icalcomp != NULL) {
3290 *out_icalcomp = async_context->out_comp;
3291 async_context->out_comp = NULL;
3298 * e_cal_client_get_default_object_sync:
3299 * @client: an #ECalClient
3300 * @out_icalcomp: (out): Return value for the default calendar object.
3301 * @cancellable: a #GCancellable; can be %NULL
3302 * @error: (out): a #GError to set an error, if any
3304 * Retrives an #icalcomponent from the backend that contains the default
3305 * values for properties needed. This @out_icalcomp should be freed with
3306 * icalcomponent_free().
3308 * Returns: %TRUE if successful, %FALSE otherwise.
3313 e_cal_client_get_default_object_sync (ECalClient *client,
3314 icalcomponent **out_icalcomp,
3315 GCancellable *cancellable,
3318 icalcomponent *icalcomp = NULL;
3321 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
3322 g_return_val_if_fail (out_icalcomp != NULL, FALSE);
3324 if (client->priv->dbus_proxy == NULL) {
3325 set_proxy_gone_error (error);
3329 string = e_dbus_calendar_dup_default_object (client->priv->dbus_proxy);
3330 if (string != NULL) {
3331 icalcomp = icalparser_parse_string (string);
3335 if (icalcomp == NULL) {
3337 error, e_cal_client_error_create (
3338 E_CAL_CLIENT_ERROR_INVALID_OBJECT, NULL));
3342 if (icalcomponent_get_uid (icalcomp) != NULL) {
3345 /* Make sure the UID is always unique. */
3346 new_uid = e_cal_component_gen_uid ();
3347 icalcomponent_set_uid (icalcomp, new_uid);
3351 *out_icalcomp = icalcomp;
3356 /* Helper for e_cal_client_get_object() */
3358 cal_client_get_object_thread (GSimpleAsyncResult *simple,
3359 GObject *source_object,
3360 GCancellable *cancellable)
3362 AsyncContext *async_context;
3363 GError *error = NULL;
3365 async_context = g_simple_async_result_get_op_res_gpointer (simple);
3367 e_cal_client_get_object_sync (
3368 E_CAL_CLIENT (source_object),
3371 &async_context->out_comp,
3372 cancellable, &error);
3375 g_simple_async_result_take_error (simple, error);
3379 * e_cal_client_get_object:
3380 * @client: an #ECalClient
3381 * @uid: Unique identifier for a calendar component.
3382 * @rid: Recurrence identifier.
3383 * @cancellable: a #GCancellable; can be %NULL
3384 * @callback: callback to call when a result is ready
3385 * @user_data: user data for the @callback
3387 * Queries a calendar for a calendar component object based on its unique
3388 * identifier. The call is finished by e_cal_client_get_object_finish()
3389 * from the @callback.
3391 * Use e_cal_client_get_objects_for_uid() to get list of all
3392 * objects for the given uid, which includes master object and
3393 * all detached instances.
3398 e_cal_client_get_object (ECalClient *client,
3401 GCancellable *cancellable,
3402 GAsyncReadyCallback callback,
3405 GSimpleAsyncResult *simple;
3406 AsyncContext *async_context;
3408 g_return_if_fail (E_IS_CAL_CLIENT (client));
3409 g_return_if_fail (uid != NULL);
3410 /* rid is optional */
3412 async_context = g_slice_new0 (AsyncContext);
3413 async_context->uid = g_strdup (uid);
3414 async_context->rid = g_strdup (rid);
3416 simple = g_simple_async_result_new (
3417 G_OBJECT (client), callback, user_data,
3418 e_cal_client_get_object);
3420 g_simple_async_result_set_check_cancellable (simple, cancellable);
3422 g_simple_async_result_set_op_res_gpointer (
3423 simple, async_context, (GDestroyNotify) async_context_free);
3425 g_simple_async_result_run_in_thread (
3426 simple, cal_client_get_object_thread,
3427 G_PRIORITY_DEFAULT, cancellable);
3429 g_object_unref (simple);
3433 * e_cal_client_get_object_finish:
3434 * @client: an #ECalClient
3435 * @result: a #GAsyncResult
3436 * @out_icalcomp: (out): Return value for the calendar component object.
3437 * @error: (out): a #GError to set an error, if any
3439 * Finishes previous call of e_cal_client_get_object() and
3440 * sets @out_icalcomp to queried component. This function always returns
3441 * master object for a case of @rid being NULL or an empty string.
3442 * This component should be freed with icalcomponent_free().
3444 * Use e_cal_client_get_objects_for_uid() to get list of all
3445 * objects for the given uid, which includes master object and
3446 * all detached instances.
3448 * Returns: %TRUE if successful, %FALSE otherwise.
3453 e_cal_client_get_object_finish (ECalClient *client,
3454 GAsyncResult *result,
3455 icalcomponent **out_icalcomp,
3458 GSimpleAsyncResult *simple;
3459 AsyncContext *async_context;
3461 g_return_val_if_fail (
3462 g_simple_async_result_is_valid (
3463 result, G_OBJECT (client),
3464 e_cal_client_get_object), FALSE);
3466 simple = G_SIMPLE_ASYNC_RESULT (result);
3467 async_context = g_simple_async_result_get_op_res_gpointer (simple);
3469 if (g_simple_async_result_propagate_error (simple, error))
3472 g_return_val_if_fail (async_context->out_comp != NULL, FALSE);
3474 if (out_icalcomp != NULL) {
3475 *out_icalcomp = async_context->out_comp;
3476 async_context->out_comp = NULL;
3483 * e_cal_client_get_object_sync:
3484 * @client: an #ECalClient
3485 * @uid: Unique identifier for a calendar component.
3486 * @rid: Recurrence identifier.
3487 * @out_icalcomp: (out): Return value for the calendar component object.
3488 * @cancellable: a #GCancellable; can be %NULL
3489 * @error: (out): a #GError to set an error, if any
3491 * Queries a calendar for a calendar component object based
3492 * on its unique identifier. This function always returns
3493 * master object for a case of @rid being NULL or an empty string.
3494 * This component should be freed with icalcomponent_free().
3496 * Use e_cal_client_get_objects_for_uid_sync() to get list of all
3497 * objects for the given uid, which includes master object and
3498 * all detached instances.
3500 * Returns: %TRUE if successful, %FALSE otherwise.
3505 e_cal_client_get_object_sync (ECalClient *client,
3508 icalcomponent **out_icalcomp,
3509 GCancellable *cancellable,
3512 icalcomponent *icalcomp = NULL;
3513 icalcomponent_kind kind;
3516 gchar *string = NULL;
3519 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
3520 g_return_val_if_fail (uid != NULL, FALSE);
3521 g_return_val_if_fail (out_icalcomp != NULL, FALSE);
3526 if (client->priv->dbus_proxy == NULL) {
3527 set_proxy_gone_error (error);
3531 utf8_uid = e_util_utf8_make_valid (uid);
3532 utf8_rid = e_util_utf8_make_valid (rid);
3534 success = e_dbus_calendar_call_get_object_sync (
3535 client->priv->dbus_proxy, utf8_uid, utf8_rid,
3536 &string, cancellable, error);
3542 g_return_val_if_fail (
3543 (success && (string != NULL)) ||
3544 (!success && (string == NULL)), FALSE);
3549 icalcomp = icalparser_parse_string (string);
3553 if (icalcomp == NULL) {
3555 error, e_cal_client_error_create (
3556 E_CAL_CLIENT_ERROR_INVALID_OBJECT, NULL));
3560 switch (e_cal_client_get_source_type (client)) {
3561 case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
3562 kind = ICAL_VEVENT_COMPONENT;
3564 case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
3565 kind = ICAL_VTODO_COMPONENT;
3567 case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
3568 kind = ICAL_VJOURNAL_COMPONENT;
3571 g_warn_if_reached ();
3572 kind = ICAL_VEVENT_COMPONENT;
3576 if (icalcomponent_isa (icalcomp) == kind) {
3577 *out_icalcomp = icalcomp;
3579 } else if (icalcomponent_isa (icalcomp) == ICAL_VCALENDAR_COMPONENT) {
3580 icalcomponent *subcomponent;
3582 for (subcomponent = icalcomponent_get_first_component (icalcomp, kind);
3583 subcomponent != NULL;
3584 subcomponent = icalcomponent_get_next_component (icalcomp, kind)) {
3585 struct icaltimetype recurrenceid;
3587 if (icalcomponent_get_uid (subcomponent) == NULL)
3591 icalcomponent_get_recurrenceid (subcomponent);
3593 if (icaltime_is_null_time (recurrenceid))
3596 if (!icaltime_is_valid_time (recurrenceid))
3600 if (subcomponent == NULL)
3601 subcomponent = icalcomponent_get_first_component (icalcomp, kind);
3602 if (subcomponent != NULL)
3603 subcomponent = icalcomponent_new_clone (subcomponent);
3605 /* XXX Shouldn't we set an error is this is still NULL? */
3606 *out_icalcomp = subcomponent;
3608 icalcomponent_free (icalcomp);
3614 /* Helper for e_cal_client_get_objects_for_uid() */
3616 cal_client_get_objects_for_uid_thread (GSimpleAsyncResult *simple,
3617 GObject *source_object,
3618 GCancellable *cancellable)
3620 AsyncContext *async_context;
3621 GError *error = NULL;
3623 async_context = g_simple_async_result_get_op_res_gpointer (simple);
3625 e_cal_client_get_objects_for_uid_sync (
3626 E_CAL_CLIENT (source_object),
3628 &async_context->object_list,
3629 cancellable, &error);
3632 g_simple_async_result_take_error (simple, error);
3636 * e_cal_client_get_objects_for_uid:
3637 * @client: an #ECalClient
3638 * @uid: Unique identifier for a calendar component
3639 * @cancellable: a #GCancellable; can be %NULL
3640 * @callback: callback to call when a result is ready
3641 * @user_data: user data for the @callback
3643 * Queries a calendar for all calendar components with the given unique
3644 * ID. This will return any recurring event and all its detached recurrences.
3645 * For non-recurring events, it will just return the object with that ID.
3646 * The call is finished by e_cal_client_get_objects_for_uid_finish() from
3652 e_cal_client_get_objects_for_uid (ECalClient *client,
3654 GCancellable *cancellable,
3655 GAsyncReadyCallback callback,
3658 GSimpleAsyncResult *simple;
3659 AsyncContext *async_context;
3661 g_return_if_fail (E_IS_CAL_CLIENT (client));
3662 g_return_if_fail (uid != NULL);
3664 async_context = g_slice_new0 (AsyncContext);
3665 async_context->uid = g_strdup (uid);
3667 simple = g_simple_async_result_new (
3668 G_OBJECT (client), callback, user_data,
3669 e_cal_client_get_objects_for_uid);
3671 g_simple_async_result_set_check_cancellable (simple, cancellable);
3673 g_simple_async_result_set_op_res_gpointer (
3674 simple, async_context, (GDestroyNotify) async_context_free);
3676 g_simple_async_result_run_in_thread (
3677 simple, cal_client_get_objects_for_uid_thread,
3678 G_PRIORITY_DEFAULT, cancellable);
3680 g_object_unref (simple);
3684 * e_cal_client_get_objects_for_uid_finish:
3685 * @client: an #ECalClient
3686 * @result: a #GAsyncResult
3687 * @out_ecalcomps: (out) (transfer full) (element-type ECalComponent):
3688 * Return location for the list of objects obtained from the
3690 * @error: (out): a #GError to set an error, if any
3692 * Finishes previous call of e_cal_client_get_objects_for_uid() and
3693 * sets @out_ecalcomps to a list of #ECalComponent<!-- -->s corresponding to
3694 * found components for a given uid of the same type as this client.
3695 * This list should be freed with e_cal_client_free_ecalcomp_slist().
3697 * Returns: %TRUE if successful, %FALSE otherwise.
3702 e_cal_client_get_objects_for_uid_finish (ECalClient *client,
3703 GAsyncResult *result,
3704 GSList **out_ecalcomps,
3707 GSimpleAsyncResult *simple;
3708 AsyncContext *async_context;
3710 g_return_val_if_fail (
3711 g_simple_async_result_is_valid (
3712 result, G_OBJECT (client),
3713 e_cal_client_get_objects_for_uid), FALSE);
3715 simple = G_SIMPLE_ASYNC_RESULT (result);
3716 async_context = g_simple_async_result_get_op_res_gpointer (simple);
3718 if (g_simple_async_result_propagate_error (simple, error))
3721 if (out_ecalcomps != NULL) {
3722 *out_ecalcomps = async_context->object_list;
3723 async_context->object_list = NULL;
3730 * e_cal_client_get_objects_for_uid_sync:
3731 * @client: an #ECalClient
3732 * @uid: Unique identifier for a calendar component
3733 * @out_ecalcomps: (out) (transfer full) (element-type ECalComponent):
3734 * Return location for the list of objects obtained from the
3736 * @cancellable: (allow-none): a #GCancellable; can be %NULL
3737 * @error: (out): a #GError to set an error, if any
3739 * Queries a calendar for all calendar components with the given unique
3740 * ID. This will return any recurring event and all its detached recurrences.
3741 * For non-recurring events, it will just return the object with that ID.
3742 * This list should be freed with e_cal_client_free_ecalcomp_slist().
3744 * Returns: %TRUE if successful, %FALSE otherwise.
3749 e_cal_client_get_objects_for_uid_sync (ECalClient *client,
3751 GSList **out_ecalcomps,
3752 GCancellable *cancellable,
3755 icalcomponent *icalcomp;
3756 icalcomponent_kind kind;
3758 gchar *string = NULL;
3761 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
3762 g_return_val_if_fail (uid != NULL, FALSE);
3763 g_return_val_if_fail (out_ecalcomps != NULL, FALSE);
3765 if (client->priv->dbus_proxy == NULL) {
3766 set_proxy_gone_error (error);
3770 utf8_uid = e_util_utf8_make_valid (uid);
3772 success = e_dbus_calendar_call_get_object_sync (
3773 client->priv->dbus_proxy, utf8_uid, "",
3774 &string, cancellable, error);
3779 g_return_val_if_fail (
3780 (success && (string != NULL)) ||
3781 (!success && (string == NULL)), FALSE);
3786 icalcomp = icalparser_parse_string (string);
3790 if (icalcomp == NULL) {
3792 error, e_cal_client_error_create (
3793 E_CAL_CLIENT_ERROR_INVALID_OBJECT, NULL));
3797 switch (e_cal_client_get_source_type (client)) {
3798 case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
3799 kind = ICAL_VEVENT_COMPONENT;
3801 case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
3802 kind = ICAL_VTODO_COMPONENT;
3804 case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
3805 kind = ICAL_VJOURNAL_COMPONENT;
3808 g_warn_if_reached ();
3809 kind = ICAL_VEVENT_COMPONENT;
3813 if (icalcomponent_isa (icalcomp) == kind) {
3814 ECalComponent *comp;
3816 comp = e_cal_component_new ();
3817 e_cal_component_set_icalcomponent (comp, icalcomp);
3818 *out_ecalcomps = g_slist_append (NULL, comp);
3820 } else if (icalcomponent_isa (icalcomp) == ICAL_VCALENDAR_COMPONENT) {
3822 icalcomponent *subcomponent;
3824 subcomponent = icalcomponent_get_first_component (
3827 while (subcomponent != NULL) {
3828 ECalComponent *comp;
3829 icalcomponent *clone;
3831 comp = e_cal_component_new ();
3832 clone = icalcomponent_new_clone (subcomponent);
3833 e_cal_component_set_icalcomponent (comp, clone);
3834 tmp = g_slist_prepend (tmp, comp);
3836 subcomponent = icalcomponent_get_next_component (
3840 *out_ecalcomps = g_slist_reverse (tmp);
3842 icalcomponent_free (icalcomp);
3848 /* Helper for e_cal_client_get_object_list() */
3850 cal_client_get_object_list_thread (GSimpleAsyncResult *simple,
3851 GObject *source_object,
3852 GCancellable *cancellable)
3854 AsyncContext *async_context;
3855 GError *error = NULL;
3857 async_context = g_simple_async_result_get_op_res_gpointer (simple);
3859 e_cal_client_get_object_list_sync (
3860 E_CAL_CLIENT (source_object),
3861 async_context->sexp,
3862 &async_context->comp_list,
3863 cancellable, &error);
3866 g_simple_async_result_take_error (simple, error);
3870 * e_cal_client_get_object_list:
3871 * @client: an #ECalClient
3872 * @sexp: an S-expression representing the query
3873 * @cancellable: a #GCancellable; can be %NULL
3874 * @callback: callback to call when a result is ready
3875 * @user_data: user data for the @callback
3877 * Gets a list of objects from the calendar that match the query specified
3878 * by the @sexp argument, returning matching objects as a list of #icalcomponent-s.
3879 * The call is finished by e_cal_client_get_object_list_finish() from
3885 e_cal_client_get_object_list (ECalClient *client,
3887 GCancellable *cancellable,
3888 GAsyncReadyCallback callback,
3891 GSimpleAsyncResult *simple;
3892 AsyncContext *async_context;
3894 g_return_if_fail (E_IS_CAL_CLIENT (client));
3895 g_return_if_fail (sexp != NULL);
3897 async_context = g_slice_new0 (AsyncContext);
3898 async_context->sexp = g_strdup (sexp);
3900 simple = g_simple_async_result_new (
3901 G_OBJECT (client), callback, user_data,
3902 e_cal_client_get_object_list);
3904 g_simple_async_result_set_check_cancellable (simple, cancellable);
3906 g_simple_async_result_set_op_res_gpointer (
3907 simple, async_context, (GDestroyNotify) async_context_free);
3909 g_simple_async_result_run_in_thread (
3910 simple, cal_client_get_object_list_thread,
3911 G_PRIORITY_DEFAULT, cancellable);
3913 g_object_unref (simple);
3917 * e_cal_client_get_object_list_finish:
3918 * @client: an #ECalClient
3919 * @result: a #GAsyncResult
3920 * @out_icalcomps: (out) (element-type icalcomponent): list of matching
3921 * #icalcomponent<!-- -->s
3922 * @error: (out): a #GError to set an error, if any
3924 * Finishes previous call of e_cal_client_get_object_list() and
3925 * sets @out_icalcomps to a matching list of #icalcomponent-s.
3926 * This list should be freed with e_cal_client_free_icalcomp_slist().
3928 * Returns: %TRUE if successful, %FALSE otherwise.
3933 e_cal_client_get_object_list_finish (ECalClient *client,
3934 GAsyncResult *result,
3935 GSList **out_icalcomps,
3938 GSimpleAsyncResult *simple;
3939 AsyncContext *async_context;
3941 g_return_val_if_fail (
3942 g_simple_async_result_is_valid (
3943 result, G_OBJECT (client),
3944 e_cal_client_get_object_list), FALSE);
3946 simple = G_SIMPLE_ASYNC_RESULT (result);
3947 async_context = g_simple_async_result_get_op_res_gpointer (simple);
3949 if (g_simple_async_result_propagate_error (simple, error))
3952 if (out_icalcomps != NULL) {
3953 *out_icalcomps = async_context->comp_list;
3954 async_context->comp_list = NULL;
3961 * e_cal_client_get_object_list_sync:
3962 * @client: an #ECalClient
3963 * @sexp: an S-expression representing the query
3964 * @out_icalcomps: (out) (element-type icalcomponent): list of matching
3965 * #icalcomponent<!-- -->s
3966 * @cancellable: (allow-none): a #GCancellable; can be %NULL
3967 * @error: (out): a #GError to set an error, if any
3969 * Gets a list of objects from the calendar that match the query specified
3970 * by the @sexp argument. The objects will be returned in the @out_icalcomps
3971 * argument, which is a list of #icalcomponent.
3972 * This list should be freed with e_cal_client_free_icalcomp_slist().
3974 * Returns: %TRUE if successful, %FALSE otherwise.
3979 e_cal_client_get_object_list_sync (ECalClient *client,
3981 GSList **out_icalcomps,
3982 GCancellable *cancellable,
3987 gchar **strv = NULL;
3991 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
3992 g_return_val_if_fail (sexp != NULL, FALSE);
3993 g_return_val_if_fail (out_icalcomps != NULL, FALSE);
3995 if (client->priv->dbus_proxy == NULL) {
3996 set_proxy_gone_error (error);
4000 utf8_sexp = e_util_utf8_make_valid (sexp);
4002 success = e_dbus_calendar_call_get_object_list_sync (
4003 client->priv->dbus_proxy, utf8_sexp,
4004 &strv, cancellable, error);
4009 g_return_val_if_fail (
4010 (success && (strv != NULL)) ||
4011 (!success && (strv == NULL)), FALSE);
4016 for (ii = 0; strv[ii] != NULL; ii++) {
4017 icalcomponent *icalcomp;
4019 icalcomp = icalcomponent_new_from_string (strv[ii]);
4020 if (icalcomp == NULL)
4023 tmp = g_slist_prepend (tmp, icalcomp);
4026 *out_icalcomps = g_slist_reverse (tmp);
4031 /* Helper for e_cal_client_get_object_list_as_comps() */
4033 cal_client_get_object_list_as_comps_thread (GSimpleAsyncResult *simple,
4034 GObject *source_object,
4035 GCancellable *cancellable)
4037 AsyncContext *async_context;
4038 GError *error = NULL;
4040 async_context = g_simple_async_result_get_op_res_gpointer (simple);
4042 e_cal_client_get_object_list_as_comps_sync (
4043 E_CAL_CLIENT (source_object),
4044 async_context->sexp,
4045 &async_context->object_list,
4046 cancellable, &error);
4049 g_simple_async_result_take_error (simple, error);
4053 * e_cal_client_get_object_list_as_comps:
4054 * @client: an #ECalClient
4055 * @sexp: an S-expression representing the query
4056 * @cancellable: a #GCancellable; can be %NULL
4057 * @callback: callback to call when a result is ready
4058 * @user_data: user data for the @callback
4060 * Gets a list of objects from the calendar that match the query specified
4061 * by the @sexp argument, returning matching objects as a list of #ECalComponent-s.
4062 * The call is finished by e_cal_client_get_object_list_as_comps_finish() from
4068 e_cal_client_get_object_list_as_comps (ECalClient *client,
4070 GCancellable *cancellable,
4071 GAsyncReadyCallback callback,
4074 GSimpleAsyncResult *simple;
4075 AsyncContext *async_context;
4077 g_return_if_fail (E_IS_CAL_CLIENT (client));
4078 g_return_if_fail (sexp != NULL);
4080 async_context = g_slice_new0 (AsyncContext);
4081 async_context->sexp = g_strdup (sexp);
4083 simple = g_simple_async_result_new (
4084 G_OBJECT (client), callback, user_data,
4085 e_cal_client_get_object_list_as_comps);
4087 g_simple_async_result_set_check_cancellable (simple, cancellable);
4089 g_simple_async_result_set_op_res_gpointer (
4090 simple, async_context, (GDestroyNotify) async_context_free);
4092 g_simple_async_result_run_in_thread (
4093 simple, cal_client_get_object_list_as_comps_thread,
4094 G_PRIORITY_DEFAULT, cancellable);
4096 g_object_unref (simple);
4100 * e_cal_client_get_object_list_as_comps_finish:
4101 * @client: an #ECalClient
4102 * @result: a #GAsyncResult
4103 * @out_ecalcomps: (out) (element-type ECalComponent): list of matching
4104 * #ECalComponent<!-- -->s
4105 * @error: (out): a #GError to set an error, if any
4107 * Finishes previous call of e_cal_client_get_object_list_as_comps() and
4108 * sets @out_ecalcomps to a matching list of #ECalComponent-s.
4109 * This list should be freed with e_cal_client_free_ecalcomp_slist().
4111 * Returns: %TRUE if successful, %FALSE otherwise.
4116 e_cal_client_get_object_list_as_comps_finish (ECalClient *client,
4117 GAsyncResult *result,
4118 GSList **out_ecalcomps,
4121 GSimpleAsyncResult *simple;
4122 AsyncContext *async_context;
4124 g_return_val_if_fail (
4125 g_simple_async_result_is_valid (
4126 result, G_OBJECT (client),
4127 e_cal_client_get_object_list), FALSE);
4129 simple = G_SIMPLE_ASYNC_RESULT (result);
4130 async_context = g_simple_async_result_get_op_res_gpointer (simple);
4132 if (g_simple_async_result_propagate_error (simple, error))
4135 if (out_ecalcomps != NULL) {
4136 *out_ecalcomps = async_context->object_list;
4137 async_context->object_list = NULL;
4144 * e_cal_client_get_object_list_as_comps_sync:
4145 * @client: an #ECalClient
4146 * @sexp: an S-expression representing the query
4147 * @out_ecalcomps: (out) (element-type ECalComponent): list of matching
4148 * #ECalComponent<!-- -->s
4149 * @cancellable: (allow-none): a #GCancellable; can be %NULL
4150 * @error: (out): a #GError to set an error, if any
4152 * Gets a list of objects from the calendar that match the query specified
4153 * by the @sexp argument. The objects will be returned in the @out_ecalcomps
4154 * argument, which is a list of #ECalComponent.
4155 * This list should be freed with e_cal_client_free_ecalcomp_slist().
4157 * Returns: %TRUE if successful, %FALSE otherwise.
4162 e_cal_client_get_object_list_as_comps_sync (ECalClient *client,
4164 GSList **out_ecalcomps,
4165 GCancellable *cancellable,
4168 GSList *list = NULL;
4170 GQueue trash = G_QUEUE_INIT;
4173 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
4174 g_return_val_if_fail (sexp != NULL, FALSE);
4175 g_return_val_if_fail (out_ecalcomps != NULL, FALSE);
4177 success = e_cal_client_get_object_list_sync (
4178 client, sexp, &list, cancellable, error);
4181 g_warn_if_fail (list == NULL);
4185 /* Convert the icalcomponent list to an ECalComponent list. */
4186 for (link = list; link != NULL; link = g_slist_next (link)) {
4187 ECalComponent *comp;
4188 icalcomponent *icalcomp = link->data;
4190 comp = e_cal_component_new ();
4192 /* This takes ownership of the icalcomponent, if it works. */
4193 if (e_cal_component_set_icalcomponent (comp, icalcomp)) {
4194 link->data = g_object_ref (comp);
4196 /* On failure, free resources and add
4197 * the GSList link to the trash queue. */
4198 icalcomponent_free (icalcomp);
4199 g_queue_push_tail (&trash, link);
4203 g_object_unref (comp);
4206 /* Delete GSList links we failed to convert. */
4207 while ((link = g_queue_pop_head (&trash)) != NULL)
4208 list = g_slist_delete_link (list, link);
4210 *out_ecalcomps = list;
4215 /* Helper for e_cal_client_get_free_busy() */
4217 cal_client_get_free_busy_thread (GSimpleAsyncResult *simple,
4218 GObject *source_object,
4219 GCancellable *cancellable)
4221 AsyncContext *async_context;
4222 GError *error = NULL;
4224 async_context = g_simple_async_result_get_op_res_gpointer (simple);
4226 e_cal_client_get_free_busy_sync (
4227 E_CAL_CLIENT (source_object),
4228 async_context->start,
4230 async_context->string_list,
4231 cancellable, &error);
4234 g_simple_async_result_take_error (simple, error);
4238 * e_cal_client_get_free_busy:
4239 * @client: an #ECalClient
4240 * @start: Start time for query
4241 * @end: End time for query
4242 * @users: (element-type utf8): List of users to retrieve free/busy information for
4243 * @cancellable: (allow-none): a #GCancellable; can be %NULL
4244 * @callback: callback to call when a result is ready
4245 * @user_data: user data for the @callback
4247 * Begins retrieval of free/busy information from the calendar server
4248 * as a list of #ECalComponent-s. Connect to "free-busy-data" signal
4249 * to receive chunks of free/busy components.
4250 * The call is finished by e_cal_client_get_free_busy_finish() from
4256 e_cal_client_get_free_busy (ECalClient *client,
4259 const GSList *users,
4260 GCancellable *cancellable,
4261 GAsyncReadyCallback callback,
4264 GSimpleAsyncResult *simple;
4265 AsyncContext *async_context;
4267 g_return_if_fail (E_IS_CAL_CLIENT (client));
4268 g_return_if_fail (start > 0);
4269 g_return_if_fail (end > 0);
4271 async_context = g_slice_new0 (AsyncContext);
4272 async_context->start = start;
4273 async_context->end = end;
4274 async_context->string_list = g_slist_copy_deep (
4275 (GSList *) users, (GCopyFunc) g_strdup, NULL);
4277 simple = g_simple_async_result_new (
4278 G_OBJECT (client), callback, user_data,
4279 e_cal_client_get_free_busy);
4281 g_simple_async_result_set_check_cancellable (simple, cancellable);
4283 g_simple_async_result_set_op_res_gpointer (
4284 simple, async_context, (GDestroyNotify) async_context_free);
4286 g_simple_async_result_run_in_thread (
4287 simple, cal_client_get_free_busy_thread,
4288 G_PRIORITY_DEFAULT, cancellable);
4290 g_object_unref (simple);
4294 * e_cal_client_get_free_busy_finish:
4295 * @client: an #ECalClient
4296 * @result: a #GAsyncResult
4297 * @error: (out): a #GError to set an error, if any
4299 * Finishes previous call of e_cal_client_get_free_busy().
4300 * All VFREEBUSY #ECalComponent-s were received by "free-busy-data" signal.
4302 * Returns: %TRUE if successful, %FALSE otherwise.
4307 e_cal_client_get_free_busy_finish (ECalClient *client,
4308 GAsyncResult *result,
4311 GSimpleAsyncResult *simple;
4313 g_return_val_if_fail (
4314 g_simple_async_result_is_valid (
4315 result, G_OBJECT (client),
4316 e_cal_client_get_free_busy), FALSE);
4318 simple = G_SIMPLE_ASYNC_RESULT (result);
4320 /* Assume success unless a GError is set. */
4321 return !g_simple_async_result_propagate_error (simple, error);
4325 * e_cal_client_get_free_busy_sync:
4326 * @client: an #ECalClient
4327 * @start: Start time for query
4328 * @end: End time for query
4329 * @users: (element-type utf8): List of users to retrieve free/busy information for
4330 * @cancellable: (allow-none): a #GCancellable; can be %NULL
4331 * @error: (out): a #GError to set an error, if any
4333 * Gets free/busy information from the calendar server.
4334 * All VFREEBUSY #ECalComponent-s were received by "free-busy-data" signal.
4336 * Returns: %TRUE if successful, %FALSE otherwise.
4341 e_cal_client_get_free_busy_sync (ECalClient *client,
4344 const GSList *users,
4345 GCancellable *cancellable,
4352 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
4353 g_return_val_if_fail (start > 0, FALSE);
4354 g_return_val_if_fail (end > 0, FALSE);
4356 if (client->priv->dbus_proxy == NULL) {
4357 set_proxy_gone_error (error);
4361 strv = g_new0 (gchar *, g_slist_length ((GSList *) users) + 1);
4362 while (users != NULL) {
4363 strv[ii++] = e_util_utf8_make_valid (users->data);
4364 users = g_slist_next (users);
4367 success = e_dbus_calendar_call_get_free_busy_sync (
4368 client->priv->dbus_proxy,
4369 (gint64) start, (gint64) end,
4370 (const gchar * const *) strv,
4371 cancellable, error);
4378 /* Helper for e_cal_client_create_object() */
4380 cal_client_create_object_thread (GSimpleAsyncResult *simple,
4381 GObject *source_object,
4382 GCancellable *cancellable)
4384 AsyncContext *async_context;
4385 GError *error = NULL;
4387 async_context = g_simple_async_result_get_op_res_gpointer (simple);
4389 e_cal_client_create_object_sync (
4390 E_CAL_CLIENT (source_object),
4391 async_context->in_comp,
4392 &async_context->uid,
4393 cancellable, &error);
4396 g_simple_async_result_take_error (simple, error);
4400 * e_cal_client_create_object:
4401 * @client: an #ECalClient
4402 * @icalcomp: The component to create
4403 * @cancellable: a #GCancellable; can be %NULL
4404 * @callback: callback to call when a result is ready
4405 * @user_data: user data for the @callback
4407 * Requests the calendar backend to create the object specified by the @icalcomp
4408 * argument. Some backends would assign a specific UID to the newly created object,
4409 * but this function does not modify the original @icalcomp if its UID changes.
4410 * The call is finished by e_cal_client_create_object_finish() from
4416 e_cal_client_create_object (ECalClient *client,
4417 icalcomponent *icalcomp,
4418 GCancellable *cancellable,
4419 GAsyncReadyCallback callback,
4422 GSimpleAsyncResult *simple;
4423 AsyncContext *async_context;
4425 g_return_if_fail (E_IS_CAL_CLIENT (client));
4426 g_return_if_fail (icalcomp != NULL);
4428 async_context = g_slice_new0 (AsyncContext);
4429 async_context->in_comp = icalcomponent_new_clone (icalcomp);
4431 simple = g_simple_async_result_new (
4432 G_OBJECT (client), callback, user_data,
4433 e_cal_client_create_object);
4435 g_simple_async_result_set_op_res_gpointer (
4436 simple, async_context, (GDestroyNotify) async_context_free);
4438 g_simple_async_result_run_in_thread (
4439 simple, cal_client_create_object_thread,
4440 G_PRIORITY_DEFAULT, cancellable);
4442 g_object_unref (simple);
4446 * e_cal_client_create_object_finish:
4447 * @client: an #ECalClient
4448 * @result: a #GAsyncResult
4449 * @out_uid: (out): Return value for the UID assigned to the new component
4450 * by the calendar backend
4451 * @error: (out): a #GError to set an error, if any
4453 * Finishes previous call of e_cal_client_create_object() and
4454 * sets @out_uid to newly assigned UID for the created object.
4455 * This @out_uid should be freed with g_free().
4457 * Returns: %TRUE if successful, %FALSE otherwise.
4462 e_cal_client_create_object_finish (ECalClient *client,
4463 GAsyncResult *result,
4467 GSimpleAsyncResult *simple;
4468 AsyncContext *async_context;
4470 g_return_val_if_fail (
4471 g_simple_async_result_is_valid (
4472 result, G_OBJECT (client),
4473 e_cal_client_create_object), FALSE);
4475 simple = G_SIMPLE_ASYNC_RESULT (result);
4476 async_context = g_simple_async_result_get_op_res_gpointer (simple);
4478 if (g_simple_async_result_propagate_error (simple, error))
4481 g_return_val_if_fail (async_context->uid != NULL, FALSE);
4483 if (out_uid != NULL) {
4484 *out_uid = async_context->uid;
4485 async_context->uid = NULL;
4492 * e_cal_client_create_object_sync:
4493 * @client: an #ECalClient
4494 * @icalcomp: The component to create
4495 * @out_uid: (out): Return value for the UID assigned to the new component
4496 * by the calendar backend
4497 * @cancellable: a #GCancellable; can be %NULL
4498 * @error: (out): a #GError to set an error, if any
4500 * Requests the calendar backend to create the object specified by the
4501 * @icalcomp argument. Some backends would assign a specific UID to the newly
4502 * created object, in those cases that UID would be returned in the @out_uid
4503 * argument. This function does not modify the original @icalcomp if its UID
4504 * changes. Returned @out_uid should be freed with g_free().
4506 * Returns: %TRUE if successful, %FALSE otherwise.
4511 e_cal_client_create_object_sync (ECalClient *client,
4512 icalcomponent *icalcomp,
4514 GCancellable *cancellable,
4517 GSList link = { icalcomp, NULL };
4518 GSList *string_list = NULL;
4521 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
4522 g_return_val_if_fail (icalcomp != NULL, FALSE);
4524 success = e_cal_client_create_objects_sync (
4525 client, &link, &string_list, cancellable, error);
4528 g_return_val_if_fail (
4529 (success && (string_list != NULL)) ||
4530 (!success && (string_list == NULL)), FALSE);
4532 if (out_uid != NULL && string_list != NULL)
4533 *out_uid = g_strdup (string_list->data);
4535 g_slist_free_full (string_list, (GDestroyNotify) g_free);
4540 /* Helper for e_cal_client_create_objects() */
4542 cal_client_create_objects_thread (GSimpleAsyncResult *simple,
4543 GObject *source_object,
4544 GCancellable *cancellable)
4546 AsyncContext *async_context;
4547 GError *error = NULL;
4549 async_context = g_simple_async_result_get_op_res_gpointer (simple);
4551 e_cal_client_create_objects_sync (
4552 E_CAL_CLIENT (source_object),
4553 async_context->comp_list,
4554 &async_context->string_list,
4555 cancellable, &error);
4558 g_simple_async_result_take_error (simple, error);
4562 * e_cal_client_create_objects:
4563 * @client: an #ECalClient
4564 * @icalcomps: (element-type icalcomponent): The components to create
4565 * @cancellable: (allow-none): a #GCancellable; can be %NULL
4566 * @callback: callback to call when a result is ready
4567 * @user_data: user data for the @callback
4569 * Requests the calendar backend to create the objects specified by the @icalcomps
4570 * argument. Some backends would assign a specific UID to the newly created object,
4571 * but this function does not modify the original @icalcomps if their UID changes.
4572 * The call is finished by e_cal_client_create_objects_finish() from
4578 e_cal_client_create_objects (ECalClient *client,
4580 GCancellable *cancellable,
4581 GAsyncReadyCallback callback,
4584 GSimpleAsyncResult *simple;
4585 AsyncContext *async_context;
4587 g_return_if_fail (E_IS_CAL_CLIENT (client));
4588 g_return_if_fail (icalcomps != NULL);
4590 async_context = g_slice_new0 (AsyncContext);
4591 async_context->comp_list = g_slist_copy_deep (
4592 icalcomps, (GCopyFunc) icalcomponent_new_clone, NULL);
4594 simple = g_simple_async_result_new (
4595 G_OBJECT (client), callback, user_data,
4596 e_cal_client_create_objects);
4598 g_simple_async_result_set_check_cancellable (simple, cancellable);
4600 g_simple_async_result_set_op_res_gpointer (
4601 simple, async_context, (GDestroyNotify) async_context_free);
4603 g_simple_async_result_run_in_thread (
4604 simple, cal_client_create_objects_thread,
4605 G_PRIORITY_DEFAULT, cancellable);
4607 g_object_unref (simple);
4611 * e_cal_client_create_objects_finish:
4612 * @client: an #ECalClient
4613 * @result: a #GAsyncResult
4614 * @out_uids: (out) (element-type utf8): Return value for the UIDs assigned
4615 * to the new components by the calendar backend
4616 * @error: (out): a #GError to set an error, if any
4618 * Finishes previous call of e_cal_client_create_objects() and
4619 * sets @out_uids to newly assigned UIDs for the created objects.
4620 * This @out_uids should be freed with e_client_util_free_string_slist().
4622 * Returns: %TRUE if successful, %FALSE otherwise.
4627 e_cal_client_create_objects_finish (ECalClient *client,
4628 GAsyncResult *result,
4632 GSimpleAsyncResult *simple;
4633 AsyncContext *async_context;
4635 g_return_val_if_fail (
4636 g_simple_async_result_is_valid (
4637 result, G_OBJECT (client),
4638 e_cal_client_create_objects), FALSE);
4640 simple = G_SIMPLE_ASYNC_RESULT (result);
4641 async_context = g_simple_async_result_get_op_res_gpointer (simple);
4643 if (g_simple_async_result_propagate_error (simple, error))
4646 if (out_uids != NULL) {
4647 *out_uids = async_context->string_list;
4648 async_context->string_list = NULL;
4655 * e_cal_client_create_objects_sync:
4656 * @client: an #ECalClient
4657 * @icalcomps: (element-type icalcomponent): The components to create
4658 * @out_uids: (out) (element-type utf8): Return value for the UIDs assigned
4659 * to the new components by the calendar backend
4660 * @cancellable: (allow-none): a #GCancellable; can be %NULL
4661 * @error: (out): a #GError to set an error, if any
4663 * Requests the calendar backend to create the objects specified by the
4664 * @icalcomps argument. Some backends would assign a specific UID to the
4665 * newly created objects, in those cases these UIDs would be returned in
4666 * the @out_uids argument. This function does not modify the original
4667 * @icalcomps if their UID changes. Returned @out_uids should be freed
4668 * with e_client_util_free_string_slist().
4670 * Returns: %TRUE if successful, %FALSE otherwise.
4675 e_cal_client_create_objects_sync (ECalClient *client,
4678 GCancellable *cancellable,
4682 gchar **uids = NULL;
4686 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
4687 g_return_val_if_fail (icalcomps != NULL, FALSE);
4688 g_return_val_if_fail (out_uids != NULL, FALSE);
4690 if (client->priv->dbus_proxy == NULL) {
4691 set_proxy_gone_error (error);
4695 strv = g_new0 (gchar *, g_slist_length (icalcomps) + 1);
4696 while (icalcomps != NULL) {
4699 ical_string = icalcomponent_as_ical_string_r (icalcomps->data);
4700 strv[ii++] = e_util_utf8_make_valid (ical_string);
4701 g_free (ical_string);
4703 icalcomps = g_slist_next (icalcomps);
4706 success = e_dbus_calendar_call_create_objects_sync (
4707 client->priv->dbus_proxy,
4708 (const gchar * const *) strv,
4709 &uids, cancellable, error);
4714 g_return_val_if_fail (
4715 (success && (uids != NULL)) ||
4716 (!success && (uids == NULL)), FALSE);
4721 /* Steal the string array elements. */
4722 for (ii = 0; uids[ii] != NULL; ii++) {
4723 tmp = g_slist_prepend (tmp, uids[ii]);
4727 *out_uids = g_slist_reverse (tmp);
4735 /* Helper for e_cal_client_modify_object() */
4737 cal_client_modify_object_thread (GSimpleAsyncResult *simple,
4738 GObject *source_object,
4739 GCancellable *cancellable)
4741 AsyncContext *async_context;
4742 GError *error = NULL;
4744 async_context = g_simple_async_result_get_op_res_gpointer (simple);
4746 e_cal_client_modify_object_sync (
4747 E_CAL_CLIENT (source_object),
4748 async_context->in_comp,
4750 cancellable, &error);
4753 g_simple_async_result_take_error (simple, error);
4757 * e_cal_client_modify_object:
4758 * @client: an #ECalClient
4759 * @icalcomp: Component to modify
4760 * @mod: Type of modification
4761 * @cancellable: a #GCancellable; can be %NULL
4762 * @callback: callback to call when a result is ready
4763 * @user_data: user data for the @callback
4765 * Requests the calendar backend to modify an existing object. If the object
4766 * does not exist on the calendar, an error will be returned.
4768 * For recurrent appointments, the @mod argument specifies what to modify,
4769 * if all instances (E_CAL_OBJ_MOD_ALL), a single instance (E_CAL_OBJ_MOD_THIS),
4770 * or a specific set of instances (E_CAL_OBJ_MOD_THIS_AND_PRIOR and
4771 * E_CAL_OBJ_MOD_THIS_AND_FUTURE).
4773 * The call is finished by e_cal_client_modify_object_finish() from
4779 e_cal_client_modify_object (ECalClient *client,
4780 icalcomponent *icalcomp,
4782 GCancellable *cancellable,
4783 GAsyncReadyCallback callback,
4786 GSimpleAsyncResult *simple;
4787 AsyncContext *async_context;
4789 g_return_if_fail (E_IS_CAL_CLIENT (client));
4790 g_return_if_fail (icalcomp != NULL);
4792 async_context = g_slice_new0 (AsyncContext);
4793 async_context->in_comp = icalcomponent_new_clone (icalcomp);
4794 async_context->mod = mod;
4796 simple = g_simple_async_result_new (
4797 G_OBJECT (client), callback, user_data,
4798 e_cal_client_modify_object);
4800 g_simple_async_result_set_check_cancellable (simple, cancellable);
4802 g_simple_async_result_set_op_res_gpointer (
4803 simple, async_context, (GDestroyNotify) async_context_free);
4805 g_simple_async_result_run_in_thread (
4806 simple, cal_client_modify_object_thread,
4807 G_PRIORITY_DEFAULT, cancellable);
4809 g_object_unref (simple);
4813 * e_cal_client_modify_object_finish:
4814 * @client: an #ECalClient
4815 * @result: a #GAsyncResult
4816 * @error: (out): a #GError to set an error, if any
4818 * Finishes previous call of e_cal_client_modify_object().
4820 * Returns: %TRUE if successful, %FALSE otherwise.
4825 e_cal_client_modify_object_finish (ECalClient *client,
4826 GAsyncResult *result,
4829 GSimpleAsyncResult *simple;
4831 g_return_val_if_fail (
4832 g_simple_async_result_is_valid (
4833 result, G_OBJECT (client),
4834 e_cal_client_modify_object), FALSE);
4836 simple = G_SIMPLE_ASYNC_RESULT (result);
4838 /* Assume success unless a GError is set. */
4839 return !g_simple_async_result_propagate_error (simple, error);
4843 * e_cal_client_modify_object_sync:
4844 * @client: an #ECalClient
4845 * @icalcomp: Component to modify
4846 * @mod: Type of modification
4847 * @cancellable: a #GCancellable; can be %NULL
4848 * @error: (out): a #GError to set an error, if any
4850 * Requests the calendar backend to modify an existing object. If the object
4851 * does not exist on the calendar, an error will be returned.
4853 * For recurrent appointments, the @mod argument specifies what to modify,
4854 * if all instances (E_CAL_OBJ_MOD_ALL), a single instance (E_CAL_OBJ_MOD_THIS),
4855 * or a specific set of instances (E_CAL_OBJ_MOD_THISNADPRIOR and
4856 * E_CAL_OBJ_MOD_THIS_AND_FUTURE).
4858 * Returns: %TRUE if successful, %FALSE otherwise.
4863 e_cal_client_modify_object_sync (ECalClient *client,
4864 icalcomponent *icalcomp,
4866 GCancellable *cancellable,
4869 GSList link = { icalcomp, NULL };
4871 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
4872 g_return_val_if_fail (icalcomp != NULL, FALSE);
4874 return e_cal_client_modify_objects_sync (
4875 client, &link, mod, cancellable, error);
4878 /* Helper for e_cal_client_modify_objects() */
4880 cal_client_modify_objects_thread (GSimpleAsyncResult *simple,
4881 GObject *source_object,
4882 GCancellable *cancellable)
4884 AsyncContext *async_context;
4885 GError *error = NULL;
4887 async_context = g_simple_async_result_get_op_res_gpointer (simple);
4889 e_cal_client_modify_objects_sync (
4890 E_CAL_CLIENT (source_object),
4891 async_context->comp_list,
4893 cancellable, &error);
4896 g_simple_async_result_take_error (simple, error);
4900 * e_cal_client_modify_objects:
4901 * @client: an #ECalClient
4902 * @comps: (element-type icalcomponent): Components to modify
4903 * @mod: Type of modification
4904 * @cancellable: (allow-none): a #GCancellable; can be %NULL
4905 * @callback: callback to call when a result is ready
4906 * @user_data: user data for the @callback
4908 * Requests the calendar backend to modify existing objects. If an object
4909 * does not exist on the calendar, an error will be returned.
4911 * For recurrent appointments, the @mod argument specifies what to modify,
4912 * if all instances (E_CAL_OBJ_MOD_ALL), a single instance (E_CAL_OBJ_MOD_THIS),
4913 * or a specific set of instances (E_CAL_OBJ_MOD_THISNADPRIOR and
4914 * E_CAL_OBJ_MOD_THIS_AND_FUTURE).
4916 * The call is finished by e_cal_client_modify_objects_finish() from
4922 e_cal_client_modify_objects (ECalClient *client,
4925 GCancellable *cancellable,
4926 GAsyncReadyCallback callback,
4929 GSimpleAsyncResult *simple;
4930 AsyncContext *async_context;
4932 g_return_if_fail (E_IS_CAL_CLIENT (client));
4933 g_return_if_fail (comps != NULL);
4935 async_context = g_slice_new0 (AsyncContext);
4936 async_context->comp_list = g_slist_copy_deep (
4937 comps, (GCopyFunc) icalcomponent_new_clone, NULL);
4938 async_context->mod = mod;
4940 simple = g_simple_async_result_new (
4941 G_OBJECT (client), callback, user_data,
4942 e_cal_client_modify_objects);
4944 g_simple_async_result_set_check_cancellable (simple, cancellable);
4946 g_simple_async_result_set_op_res_gpointer (
4947 simple, async_context, (GDestroyNotify) async_context_free);
4949 g_simple_async_result_run_in_thread (
4950 simple, cal_client_modify_objects_thread,
4951 G_PRIORITY_DEFAULT, cancellable);
4953 g_object_unref (simple);
4957 * e_cal_client_modify_objects_finish:
4958 * @client: an #ECalClient
4959 * @result: a #GAsyncResult
4960 * @error: (out): a #GError to set an error, if any
4962 * Finishes previous call of e_cal_client_modify_objects().
4964 * Returns: %TRUE if successful, %FALSE otherwise.
4969 e_cal_client_modify_objects_finish (ECalClient *client,
4970 GAsyncResult *result,
4973 GSimpleAsyncResult *simple;
4975 g_return_val_if_fail (
4976 g_simple_async_result_is_valid (
4977 result, G_OBJECT (client),
4978 e_cal_client_modify_objects), FALSE);
4980 simple = G_SIMPLE_ASYNC_RESULT (result);
4982 /* Assume success unless a GError is set. */
4983 return !g_simple_async_result_propagate_error (simple, error);
4987 * e_cal_client_modify_objects_sync:
4988 * @client: an #ECalClient
4989 * @comps: (element-type icalcomponent): Components to modify
4990 * @mod: Type of modification
4991 * @cancellable: (allow-none): a #GCancellable; can be %NULL
4992 * @error: (out): a #GError to set an error, if any
4994 * Requests the calendar backend to modify existing objects. If an object
4995 * does not exist on the calendar, an error will be returned.
4997 * For recurrent appointments, the @mod argument specifies what to modify,
4998 * if all instances (E_CAL_OBJ_MOD_ALL), a single instance (E_CAL_OBJ_MOD_THIS),
4999 * or a specific set of instances (E_CAL_OBJ_MOD_THISNADPRIOR and
5000 * E_CAL_OBJ_MOD_THIS_AND_FUTURE).
5002 * Returns: %TRUE if successful, %FALSE otherwise.
5007 e_cal_client_modify_objects_sync (ECalClient *client,
5010 GCancellable *cancellable,
5013 GEnumClass *enum_class;
5014 GEnumValue *enum_value;
5019 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
5020 g_return_val_if_fail (comps != NULL, FALSE);
5022 if (client->priv->dbus_proxy == NULL) {
5023 set_proxy_gone_error (error);
5027 enum_class = g_type_class_ref (E_TYPE_CAL_OBJ_MOD_TYPE);
5028 enum_value = g_enum_get_value (enum_class, mod);
5029 g_return_val_if_fail (enum_value != NULL, FALSE);
5031 strv = g_new0 (gchar *, g_slist_length (comps) + 1);
5032 while (comps != NULL) {
5035 ical_string = icalcomponent_as_ical_string_r (comps->data);
5036 strv[ii++] = e_util_utf8_make_valid (ical_string);
5037 g_free (ical_string);
5040 success = e_dbus_calendar_call_modify_objects_sync (
5041 client->priv->dbus_proxy,
5042 (const gchar * const *) strv,
5043 enum_value->value_nick,
5044 cancellable, error);
5048 g_type_class_unref (enum_class);
5053 /* Helper for e_cal_client_remove_object() */
5055 cal_client_remove_object_thread (GSimpleAsyncResult *simple,
5056 GObject *source_object,
5057 GCancellable *cancellable)
5059 AsyncContext *async_context;
5060 GError *error = NULL;
5062 async_context = g_simple_async_result_get_op_res_gpointer (simple);
5064 e_cal_client_remove_object_sync (
5065 E_CAL_CLIENT (source_object),
5069 cancellable, &error);
5072 g_simple_async_result_take_error (simple, error);
5076 * e_cal_client_remove_object:
5077 * @client: an #ECalClient
5078 * @uid: UID of the object to remove
5079 * @rid: Recurrence ID of the specific recurrence to remove
5080 * @mod: Type of the removal
5081 * @cancellable: a #GCancellable; can be %NULL
5082 * @callback: callback to call when a result is ready
5083 * @user_data: user data for the @callback
5085 * This function allows the removal of instances of a recurrent
5086 * appointment. By using a combination of the @uid, @rid and @mod
5087 * arguments, you can remove specific instances. If what you want
5088 * is to remove all instances, use #NULL @rid and E_CAL_OBJ_MOD_ALL
5091 * The call is finished by e_cal_client_remove_object_finish() from
5097 e_cal_client_remove_object (ECalClient *client,
5101 GCancellable *cancellable,
5102 GAsyncReadyCallback callback,
5105 GSimpleAsyncResult *simple;
5106 AsyncContext *async_context;
5108 g_return_if_fail (E_IS_CAL_CLIENT (client));
5109 g_return_if_fail (uid != NULL);
5110 /* rid is optional */
5112 async_context = g_slice_new0 (AsyncContext);
5113 async_context->uid = g_strdup (uid);
5114 async_context->rid = g_strdup (rid);
5115 async_context->mod = mod;
5117 simple = g_simple_async_result_new (
5118 G_OBJECT (client), callback, user_data,
5119 e_cal_client_remove_object);
5121 g_simple_async_result_set_check_cancellable (simple, cancellable);
5123 g_simple_async_result_set_op_res_gpointer (
5124 simple, async_context, (GDestroyNotify) async_context_free);
5126 g_simple_async_result_run_in_thread (
5127 simple, cal_client_remove_object_thread,
5128 G_PRIORITY_DEFAULT, cancellable);
5130 g_object_unref (simple);
5134 * e_cal_client_remove_object_finish:
5135 * @client: an #ECalClient
5136 * @result: a #GAsyncResult
5137 * @error: (out): a #GError to set an error, if any
5139 * Finishes previous call of e_cal_client_remove_object().
5141 * Returns: %TRUE if successful, %FALSE otherwise.
5146 e_cal_client_remove_object_finish (ECalClient *client,
5147 GAsyncResult *result,
5150 GSimpleAsyncResult *simple;
5152 g_return_val_if_fail (
5153 g_simple_async_result_is_valid (
5154 result, G_OBJECT (client),
5155 e_cal_client_remove_object), FALSE);
5157 simple = G_SIMPLE_ASYNC_RESULT (result);
5159 /* Assume success unless a GError is set. */
5160 return !g_simple_async_result_propagate_error (simple, error);
5164 * e_cal_client_remove_object_sync:
5165 * @client: an #ECalClient
5166 * @uid: UID of the object to remove
5167 * @rid: Recurrence ID of the specific recurrence to remove
5168 * @mod: Type of the removal
5169 * @cancellable: a #GCancellable; can be %NULL
5170 * @error: (out): a #GError to set an error, if any
5172 * This function allows the removal of instances of a recurrent
5173 * appointment. By using a combination of the @uid, @rid and @mod
5174 * arguments, you can remove specific instances. If what you want
5175 * is to remove all instances, use #NULL @rid and E_CAL_OBJ_MODE_THIS
5178 * Returns: %TRUE if successful, %FALSE otherwise.
5183 e_cal_client_remove_object_sync (ECalClient *client,
5187 GCancellable *cancellable,
5190 ECalComponentId id = { (gchar *) uid, (gchar *) rid };
5191 GSList link = { &id, NULL };
5193 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
5194 g_return_val_if_fail (uid != NULL, FALSE);
5196 if (client->priv->dbus_proxy == NULL) {
5197 set_proxy_gone_error (error);
5201 return e_cal_client_remove_objects_sync (
5202 client, &link, mod, cancellable, error);
5205 /* Helper for e_cal_client_remove_objects() */
5207 cal_client_remove_objects_thread (GSimpleAsyncResult *simple,
5208 GObject *source_object,
5209 GCancellable *cancellable)
5211 AsyncContext *async_context;
5212 GError *error = NULL;
5214 async_context = g_simple_async_result_get_op_res_gpointer (simple);
5216 e_cal_client_remove_objects_sync (
5217 E_CAL_CLIENT (source_object),
5218 async_context->string_list,
5220 cancellable, &error);
5223 g_simple_async_result_take_error (simple, error);
5227 * e_cal_client_remove_objects:
5228 * @client: an #ECalClient
5229 * @ids: (element-type ECalComponentId): A list of #ECalComponentId objects
5230 * identifying the objects to remove
5231 * @mod: Type of the removal
5232 * @cancellable: a #GCancellable; can be %NULL
5233 * @callback: callback to call when a result is ready
5234 * @user_data: user data for the @callback
5236 * This function allows the removal of instances of recurrent
5237 * appointments. #ECalComponentId objects can identify specific instances (if rid is not NULL).
5238 * If what you want is to remove all instances, use a #NULL rid in the #ECalComponentId and E_CAL_OBJ_MOD_ALL
5241 * The call is finished by e_cal_client_remove_objects_finish() from
5247 e_cal_client_remove_objects (ECalClient *client,
5250 GCancellable *cancellable,
5251 GAsyncReadyCallback callback,
5254 GSimpleAsyncResult *simple;
5255 AsyncContext *async_context;
5257 g_return_if_fail (E_IS_CAL_CLIENT (client));
5258 g_return_if_fail (ids != NULL);
5260 async_context = g_slice_new0 (AsyncContext);
5261 async_context->string_list = g_slist_copy_deep (
5262 (GSList *) ids, (GCopyFunc) g_strdup, NULL);
5263 async_context->mod = mod;
5265 simple = g_simple_async_result_new (
5266 G_OBJECT (client), callback, user_data,
5267 e_cal_client_remove_objects);
5269 g_simple_async_result_set_check_cancellable (simple, cancellable);
5271 g_simple_async_result_set_op_res_gpointer (
5272 simple, async_context, (GDestroyNotify) async_context_free);
5274 g_simple_async_result_run_in_thread (
5275 simple, cal_client_remove_objects_thread,
5276 G_PRIORITY_DEFAULT, cancellable);
5278 g_object_unref (simple);
5282 * e_cal_client_remove_objects_finish:
5283 * @client: an #ECalClient
5284 * @result: a #GAsyncResult
5285 * @error: (out): a #GError to set an error, if any
5287 * Finishes previous call of e_cal_client_remove_objects().
5289 * Returns: %TRUE if successful, %FALSE otherwise.
5294 e_cal_client_remove_objects_finish (ECalClient *client,
5295 GAsyncResult *result,
5298 GSimpleAsyncResult *simple;
5300 g_return_val_if_fail (
5301 g_simple_async_result_is_valid (
5302 result, G_OBJECT (client),
5303 e_cal_client_remove_objects), FALSE);
5305 simple = G_SIMPLE_ASYNC_RESULT (result);
5307 /* Assume success unless a GError is set. */
5308 return !g_simple_async_result_propagate_error (simple, error);
5312 * e_cal_client_remove_objects_sync:
5313 * @client: an #ECalClient
5314 * @ids: (element-type ECalComponentId): a list of #ECalComponentId objects
5315 * identifying the objects to remove
5316 * @mod: Type of the removal
5317 * @cancellable: (allow-none): a #GCancellable; can be %NULL
5318 * @error: (out): a #GError to set an error, if any
5320 * This function allows the removal of instances of recurrent
5321 * appointments. #ECalComponentId objects can identify specific instances
5322 * (if rid is not %NULL). If what you want is to remove all instances, use
5323 * a %NULL rid in the #ECalComponentId and E_CAL_OBJ_MOD_ALL for the @mod.
5325 * Returns: %TRUE if successful, %FALSE otherwise.
5330 e_cal_client_remove_objects_sync (ECalClient *client,
5333 GCancellable *cancellable,
5336 GVariantBuilder builder;
5337 GEnumClass *enum_class;
5338 GEnumValue *enum_value;
5341 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
5342 g_return_val_if_fail (ids != NULL, FALSE);
5344 if (client->priv->dbus_proxy == NULL) {
5345 set_proxy_gone_error (error);
5349 enum_class = g_type_class_ref (E_TYPE_CAL_OBJ_MOD_TYPE);
5350 enum_value = g_enum_get_value (enum_class, mod);
5351 g_return_val_if_fail (enum_value != NULL, FALSE);
5353 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
5354 while (ids != NULL) {
5355 ECalComponentId *id = ids->data;
5359 if (id->uid == NULL || *id->uid == '\0')
5362 utf8_uid = e_util_utf8_make_valid (id->uid);
5363 if (id->rid != NULL)
5364 utf8_rid = e_util_utf8_make_valid (id->rid);
5366 utf8_rid = g_strdup ("");
5368 g_variant_builder_add (&builder, "(ss)", utf8_uid, utf8_rid);
5374 success = e_dbus_calendar_call_remove_objects_sync (
5375 client->priv->dbus_proxy,
5376 g_variant_builder_end (&builder),
5377 enum_value->value_nick,
5378 cancellable, error);
5380 g_type_class_unref (enum_class);
5385 /* Helper for e_cal_client_receive_objects() */
5387 cal_client_receive_objects_thread (GSimpleAsyncResult *simple,
5388 GObject *source_object,
5389 GCancellable *cancellable)
5391 AsyncContext *async_context;
5392 GError *error = NULL;
5394 async_context = g_simple_async_result_get_op_res_gpointer (simple);
5396 e_cal_client_receive_objects_sync (
5397 E_CAL_CLIENT (source_object),
5398 async_context->in_comp,
5399 cancellable, &error);
5402 g_simple_async_result_take_error (simple, error);
5406 * e_cal_client_receive_objects:
5407 * @client: an #ECalClient
5408 * @icalcomp: An #icalcomponent
5409 * @cancellable: a #GCancellable; can be %NULL
5410 * @callback: callback to call when a result is ready
5411 * @user_data: user data for the @callback
5413 * Makes the backend receive the set of iCalendar objects specified in the
5414 * @icalcomp argument. This is used for iTIP confirmation/cancellation
5415 * messages for scheduled meetings.
5417 * The call is finished by e_cal_client_receive_objects_finish() from
5423 e_cal_client_receive_objects (ECalClient *client,
5424 icalcomponent *icalcomp,
5425 GCancellable *cancellable,
5426 GAsyncReadyCallback callback,
5429 GSimpleAsyncResult *simple;
5430 AsyncContext *async_context;
5432 g_return_if_fail (E_IS_CAL_CLIENT (client));
5433 g_return_if_fail (icalcomp != NULL);
5435 async_context = g_slice_new0 (AsyncContext);
5436 async_context->in_comp = icalcomponent_new_clone (icalcomp);
5438 simple = g_simple_async_result_new (
5439 G_OBJECT (client), callback, user_data,
5440 e_cal_client_receive_objects);
5442 g_simple_async_result_set_check_cancellable (simple, cancellable);
5444 g_simple_async_result_set_op_res_gpointer (
5445 simple, async_context, (GDestroyNotify) async_context_free);
5447 g_simple_async_result_run_in_thread (
5448 simple, cal_client_receive_objects_thread,
5449 G_PRIORITY_DEFAULT, cancellable);
5451 g_object_unref (simple);
5455 * e_cal_client_receive_objects_finish:
5456 * @client: an #ECalClient
5457 * @result: a #GAsyncResult
5458 * @error: (out): a #GError to set an error, if any
5460 * Finishes previous call of e_cal_client_receive_objects().
5462 * Returns: %TRUE if successful, %FALSE otherwise.
5467 e_cal_client_receive_objects_finish (ECalClient *client,
5468 GAsyncResult *result,
5471 GSimpleAsyncResult *simple;
5473 g_return_val_if_fail (
5474 g_simple_async_result_is_valid (
5475 result, G_OBJECT (client),
5476 e_cal_client_receive_objects), FALSE);
5478 simple = G_SIMPLE_ASYNC_RESULT (result);
5480 /* Assume success unless a GError is set. */
5481 return !g_simple_async_result_propagate_error (simple, error);
5485 * e_cal_client_receive_objects_sync:
5486 * @client: an #ECalClient
5487 * @icalcomp: An #icalcomponent
5488 * @cancellable: a #GCancellable; can be %NULL
5489 * @error: (out): a #GError to set an error, if any
5491 * Makes the backend receive the set of iCalendar objects specified in the
5492 * @icalcomp argument. This is used for iTIP confirmation/cancellation
5493 * messages for scheduled meetings.
5495 * Returns: %TRUE if successful, %FALSE otherwise.
5500 e_cal_client_receive_objects_sync (ECalClient *client,
5501 icalcomponent *icalcomp,
5502 GCancellable *cancellable,
5506 gchar *utf8_ical_string;
5509 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
5511 if (client->priv->dbus_proxy == NULL) {
5512 set_proxy_gone_error (error);
5516 ical_string = icalcomponent_as_ical_string_r (icalcomp);
5517 utf8_ical_string = e_util_utf8_make_valid (ical_string);
5519 success = e_dbus_calendar_call_receive_objects_sync (
5520 client->priv->dbus_proxy,
5521 utf8_ical_string, cancellable, error);
5523 g_free (utf8_ical_string);
5524 g_free (ical_string);
5529 /* Helper for e_cal_client_send_objects() */
5531 cal_client_send_objects_thread (GSimpleAsyncResult *simple,
5532 GObject *source_object,
5533 GCancellable *cancellable)
5535 AsyncContext *async_context;
5536 GError *error = NULL;
5538 async_context = g_simple_async_result_get_op_res_gpointer (simple);
5540 e_cal_client_send_objects_sync (
5541 E_CAL_CLIENT (source_object),
5542 async_context->in_comp,
5543 &async_context->string_list,
5544 &async_context->out_comp,
5545 cancellable, &error);
5548 g_simple_async_result_take_error (simple, error);
5552 * e_cal_client_send_objects:
5553 * @client: an #ECalClient
5554 * @icalcomp: An icalcomponent to be sent
5555 * @cancellable: a #GCancellable; can be %NULL
5556 * @callback: callback to call when a result is ready
5557 * @user_data: user data for the @callback
5559 * Requests a calendar backend to send meeting information stored in @icalcomp.
5560 * The backend can modify this component and request a send to particular users.
5561 * The call is finished by e_cal_client_send_objects_finish() from
5567 e_cal_client_send_objects (ECalClient *client,
5568 icalcomponent *icalcomp,
5569 GCancellable *cancellable,
5570 GAsyncReadyCallback callback,
5573 GSimpleAsyncResult *simple;
5574 AsyncContext *async_context;
5576 g_return_if_fail (E_IS_CAL_CLIENT (client));
5577 g_return_if_fail (icalcomp != NULL);
5579 async_context = g_slice_new0 (AsyncContext);
5580 async_context->in_comp = icalcomponent_new_clone (icalcomp);
5582 simple = g_simple_async_result_new (
5583 G_OBJECT (client), callback, user_data,
5584 e_cal_client_send_objects);
5586 g_simple_async_result_set_check_cancellable (simple, cancellable);
5588 g_simple_async_result_set_op_res_gpointer (
5589 simple, async_context, (GDestroyNotify) async_context_free);
5591 g_simple_async_result_run_in_thread (
5592 simple, cal_client_send_objects_thread,
5593 G_PRIORITY_DEFAULT, cancellable);
5595 g_object_unref (simple);
5599 * e_cal_client_send_objects_finish:
5600 * @client: an #ECalClient
5601 * @result: a #GAsyncResult
5602 * @out_users: (out) (element-type utf8): List of users to send
5603 * the @out_modified_icalcomp to
5604 * @out_modified_icalcomp: (out): Return value for the icalcomponent to be sent
5605 * @error: (out): a #GError to set an error, if any
5607 * Finishes previous call of e_cal_client_send_objects() and
5608 * populates @out_users with a list of users to send @out_modified_icalcomp to.
5610 * The @out_users list should be freed with e_client_util_free_string_slist()
5611 * and the @out_modified_icalcomp should be freed with icalcomponent_free().
5613 * Returns: %TRUE if successful, %FALSE otherwise.
5618 e_cal_client_send_objects_finish (ECalClient *client,
5619 GAsyncResult *result,
5621 icalcomponent **out_modified_icalcomp,
5624 GSimpleAsyncResult *simple;
5625 AsyncContext *async_context;
5627 g_return_val_if_fail (
5628 g_simple_async_result_is_valid (
5629 result, G_OBJECT (client),
5630 e_cal_client_send_objects), FALSE);
5632 simple = G_SIMPLE_ASYNC_RESULT (result);
5633 async_context = g_simple_async_result_get_op_res_gpointer (simple);
5635 if (g_simple_async_result_propagate_error (simple, error))
5638 g_return_val_if_fail (async_context->out_comp != NULL, FALSE);
5640 if (out_users != NULL) {
5641 *out_users = async_context->string_list;
5642 async_context->string_list = NULL;
5645 if (out_modified_icalcomp != NULL) {
5646 *out_modified_icalcomp = async_context->out_comp;
5647 async_context->out_comp = NULL;
5654 * e_cal_client_send_objects_sync:
5655 * @client: an #ECalClient
5656 * @icalcomp: An icalcomponent to be sent
5657 * @out_users: (out) (element-type utf8): List of users to send the
5658 * @out_modified_icalcomp to
5659 * @out_modified_icalcomp: (out): Return value for the icalcomponent to be sent
5660 * @cancellable: (allow-none): a #GCancellable; can be %NULL
5661 * @error: (out): a #GError to set an error, if any
5663 * Requests a calendar backend to send meeting information stored in @icalcomp.
5664 * The backend can modify this component and request a send to users in the
5667 * The @out_users list should be freed with e_client_util_free_string_slist()
5668 * and the @out_modified_icalcomp should be freed with icalcomponent_free().
5670 * Returns: %TRUE if successful, %FALSE otherwise.
5675 e_cal_client_send_objects_sync (ECalClient *client,
5676 icalcomponent *icalcomp,
5678 icalcomponent **out_modified_icalcomp,
5679 GCancellable *cancellable,
5683 gchar *utf8_ical_string;
5684 gchar **users = NULL;
5685 gchar *out_ical_string = NULL;
5688 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
5689 g_return_val_if_fail (icalcomp != NULL, FALSE);
5690 g_return_val_if_fail (out_users != NULL, FALSE);
5691 g_return_val_if_fail (out_modified_icalcomp != NULL, FALSE);
5693 if (client->priv->dbus_proxy == NULL) {
5694 set_proxy_gone_error (error);
5698 ical_string = icalcomponent_as_ical_string_r (icalcomp);
5699 utf8_ical_string = e_util_utf8_make_valid (ical_string);
5701 success = e_dbus_calendar_call_send_objects_sync (
5702 client->priv->dbus_proxy, utf8_ical_string,
5703 &users, &out_ical_string, cancellable, error);
5705 g_free (utf8_ical_string);
5706 g_free (ical_string);
5709 g_return_val_if_fail (
5710 (success && (out_ical_string != NULL)) ||
5711 (!success && (out_ical_string == NULL)), FALSE);
5714 g_warn_if_fail (users == NULL);
5718 icalcomp = icalparser_parse_string (out_ical_string);
5720 g_free (out_ical_string);
5722 if (icalcomp != NULL) {
5723 *out_modified_icalcomp = icalcomp;
5726 error, e_cal_client_error_create (
5727 E_CAL_CLIENT_ERROR_INVALID_OBJECT, NULL));
5732 if (users != NULL) {
5736 for (ii = 0; users[ii] != NULL; ii++) {
5737 tmp = g_slist_prepend (tmp, users[ii]);
5741 *out_users = g_slist_reverse (tmp);
5749 /* Helper for e_cal_client_get_attachment_uris() */
5751 cal_client_get_attachment_uris_thread (GSimpleAsyncResult *simple,
5752 GObject *source_object,
5753 GCancellable *cancellable)
5755 AsyncContext *async_context;
5756 GError *error = NULL;
5758 async_context = g_simple_async_result_get_op_res_gpointer (simple);
5760 e_cal_client_get_attachment_uris_sync (
5761 E_CAL_CLIENT (source_object),
5764 &async_context->string_list,
5765 cancellable, &error);
5768 g_simple_async_result_take_error (simple, error);
5772 * e_cal_client_get_attachment_uris:
5773 * @client: an #ECalClient
5774 * @uid: Unique identifier for a calendar component
5775 * @rid: Recurrence identifier
5776 * @cancellable: a #GCancellable; can be %NULL
5777 * @callback: callback to call when a result is ready
5778 * @user_data: user data for the @callback
5780 * Queries a calendar for a specified component's object attachment uris.
5781 * The call is finished by e_cal_client_get_attachment_uris_finish() from
5787 e_cal_client_get_attachment_uris (ECalClient *client,
5790 GCancellable *cancellable,
5791 GAsyncReadyCallback callback,
5794 GSimpleAsyncResult *simple;
5795 AsyncContext *async_context;
5797 g_return_if_fail (E_CAL_CLIENT (client));
5798 g_return_if_fail (uid != NULL);
5799 /* rid is optional */
5801 async_context = g_slice_new0 (AsyncContext);
5802 async_context->uid = g_strdup (uid);
5803 async_context->rid = g_strdup (rid);
5805 simple = g_simple_async_result_new (
5806 G_OBJECT (client), callback, user_data,
5807 e_cal_client_get_attachment_uris);
5809 g_simple_async_result_set_check_cancellable (simple, cancellable);
5811 g_simple_async_result_run_in_thread (
5812 simple, cal_client_get_attachment_uris_thread,
5813 G_PRIORITY_DEFAULT, cancellable);
5815 g_object_unref (simple);
5819 * e_cal_client_get_attachment_uris_finish:
5820 * @client: an #ECalClient
5821 * @result: a #GAsyncResult
5822 * @out_attachment_uris: (out) (element-type utf8): Return location for the
5823 * list of attachment URIs
5824 * @error: (out): a #GError to set an error, if any
5826 * Finishes previous call of e_cal_client_get_attachment_uris() and
5827 * sets @out_attachment_uris to uris for component's attachments.
5828 * The list should be freed with e_client_util_free_string_slist().
5830 * Returns: %TRUE if successful, %FALSE otherwise.
5835 e_cal_client_get_attachment_uris_finish (ECalClient *client,
5836 GAsyncResult *result,
5837 GSList **out_attachment_uris,
5840 GSimpleAsyncResult *simple;
5841 AsyncContext *async_context;
5843 g_return_val_if_fail (
5844 g_simple_async_result_is_valid (
5845 result, G_OBJECT (client),
5846 e_cal_client_get_attachment_uris), FALSE);
5848 simple = G_SIMPLE_ASYNC_RESULT (result);
5849 async_context = g_simple_async_result_get_op_res_gpointer (simple);
5851 if (g_simple_async_result_propagate_error (simple, error))
5854 if (out_attachment_uris != NULL) {
5855 *out_attachment_uris = async_context->string_list;
5856 async_context->string_list = NULL;
5863 * e_cal_client_get_attachment_uris_sync:
5864 * @client: an #ECalClient
5865 * @uid: Unique identifier for a calendar component
5866 * @rid: Recurrence identifier
5867 * @out_attachment_uris: (out) (element-type utf8): Return location for the
5868 * list of attachment URIs
5869 * @cancellable: (allow-none): a #GCancellable; can be %NULL
5870 * @error: (out): a #GError to set an error, if any
5872 * Queries a calendar for a specified component's object attachment URIs.
5873 * The list should be freed with e_client_util_free_string_slist().
5875 * Returns: %TRUE if successful, %FALSE otherwise.
5880 e_cal_client_get_attachment_uris_sync (ECalClient *client,
5883 GSList **out_attachment_uris,
5884 GCancellable *cancellable,
5889 gchar **uris = NULL;
5892 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
5893 g_return_val_if_fail (uid != NULL, FALSE);
5894 g_return_val_if_fail (out_attachment_uris != NULL, FALSE);
5899 if (client->priv->dbus_proxy == NULL) {
5900 set_proxy_gone_error (error);
5904 utf8_uid = e_util_utf8_make_valid (uid);
5905 utf8_rid = e_util_utf8_make_valid (rid);
5907 success = e_dbus_calendar_call_get_attachment_uris_sync (
5908 client->priv->dbus_proxy, utf8_uid,
5909 utf8_rid, &uris, cancellable, error);
5915 g_return_val_if_fail (
5916 (success && (uris != NULL)) ||
5917 (!success && (uris == NULL)), FALSE);
5923 for (ii = 0; uris[ii] != NULL; ii++) {
5924 tmp = g_slist_prepend (tmp, uris[ii]);
5928 *out_attachment_uris = g_slist_reverse (tmp);
5934 /* Helper for e_cal_client_discard_alarm() */
5936 cal_client_discard_alarm_thread (GSimpleAsyncResult *simple,
5937 GObject *source_object,
5938 GCancellable *cancellable)
5940 AsyncContext *async_context;
5941 GError *error = NULL;
5943 async_context = g_simple_async_result_get_op_res_gpointer (simple);
5945 e_cal_client_discard_alarm_sync (
5946 E_CAL_CLIENT (source_object),
5949 async_context->auid,
5950 cancellable, &error);
5953 g_simple_async_result_take_error (simple, error);
5957 * e_cal_client_discard_alarm:
5958 * @client: an #ECalClient
5959 * @uid: Unique identifier for a calendar component
5960 * @rid: Recurrence identifier
5961 * @auid: Alarm identifier to remove
5962 * @cancellable: a #GCancellable; can be %NULL
5963 * @callback: callback to call when a result is ready
5964 * @user_data: user data for the @callback
5966 * Removes alarm @auid from a given component identified by @uid and @rid.
5967 * The call is finished by e_cal_client_discard_alarm_finish() from
5973 e_cal_client_discard_alarm (ECalClient *client,
5977 GCancellable *cancellable,
5978 GAsyncReadyCallback callback,
5981 GSimpleAsyncResult *simple;
5982 AsyncContext *async_context;
5984 g_return_if_fail (E_IS_CAL_CLIENT (client));
5985 g_return_if_fail (uid != NULL);
5986 /* rid is optional */
5987 g_return_if_fail (auid != NULL);
5989 async_context = g_slice_new0 (AsyncContext);
5990 async_context->uid = g_strdup (uid);
5991 async_context->rid = NULL;
5992 async_context->auid = g_strdup (auid);
5994 simple = g_simple_async_result_new (
5995 G_OBJECT (client), callback, user_data,
5996 e_cal_client_discard_alarm);
5998 g_simple_async_result_set_check_cancellable (simple, cancellable);
6000 g_simple_async_result_set_op_res_gpointer (
6001 simple, async_context, (GDestroyNotify) async_context_free);
6003 g_simple_async_result_run_in_thread (
6004 simple, cal_client_discard_alarm_thread,
6005 G_PRIORITY_DEFAULT, cancellable);
6007 g_object_unref (simple);
6011 * e_cal_client_discard_alarm_finish:
6012 * @client: an #ECalClient
6013 * @result: a #GAsyncResult
6014 * @error: (out): a #GError to set an error, if any
6016 * Finishes previous call of e_cal_client_discard_alarm().
6018 * Returns: %TRUE if successful, %FALSE otherwise.
6023 e_cal_client_discard_alarm_finish (ECalClient *client,
6024 GAsyncResult *result,
6027 GSimpleAsyncResult *simple;
6029 g_return_val_if_fail (
6030 g_simple_async_result_is_valid (
6031 result, G_OBJECT (client),
6032 e_cal_client_discard_alarm), FALSE);
6034 simple = G_SIMPLE_ASYNC_RESULT (result);
6036 /* Assume success unless a GError is set. */
6037 return !g_simple_async_result_propagate_error (simple, error);
6041 * e_cal_client_discard_alarm_sync:
6042 * @client: an #ECalClient
6043 * @uid: Unique identifier for a calendar component
6044 * @rid: Recurrence identifier
6045 * @auid: Alarm identifier to remove
6046 * @cancellable: a #GCancellable; can be %NULL
6047 * @error: (out): a #GError to set an error, if any
6049 * Removes alarm @auid from a given component identified by @uid and @rid.
6051 * Returns: %TRUE if successful, %FALSE otherwise.
6056 e_cal_client_discard_alarm_sync (ECalClient *client,
6060 GCancellable *cancellable,
6068 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
6069 g_return_val_if_fail (uid != NULL, FALSE);
6070 g_return_val_if_fail (auid != NULL, FALSE);
6075 if (client->priv->dbus_proxy == NULL) {
6076 set_proxy_gone_error (error);
6080 utf8_uid = e_util_utf8_make_valid (uid);
6081 utf8_rid = e_util_utf8_make_valid (rid);
6082 utf8_auid = e_util_utf8_make_valid (auid);
6084 success = e_dbus_calendar_call_discard_alarm_sync (
6085 client->priv->dbus_proxy, utf8_uid,
6086 utf8_rid, utf8_auid, cancellable, error);
6095 /* Helper for e_cal_client_get_view() */
6097 cal_client_get_view_thread (GSimpleAsyncResult *simple,
6098 GObject *source_object,
6099 GCancellable *cancellable)
6101 AsyncContext *async_context;
6102 GError *error = NULL;
6104 async_context = g_simple_async_result_get_op_res_gpointer (simple);
6106 e_cal_client_get_view_sync (
6107 E_CAL_CLIENT (source_object),
6108 async_context->sexp,
6109 &async_context->client_view,
6110 cancellable, &error);
6113 g_simple_async_result_take_error (simple, error);
6117 * e_cal_client_get_view:
6118 * @client: an #ECalClient
6119 * @sexp: an S-expression representing the query.
6120 * @cancellable: a #GCancellable; can be %NULL
6121 * @callback: callback to call when a result is ready
6122 * @user_data: user data for the @callback
6124 * Query @client with @sexp, creating an #ECalClientView.
6125 * The call is finished by e_cal_client_get_view_finish()
6126 * from the @callback.
6131 e_cal_client_get_view (ECalClient *client,
6133 GCancellable *cancellable,
6134 GAsyncReadyCallback callback,
6137 GSimpleAsyncResult *simple;
6138 AsyncContext *async_context;
6140 g_return_if_fail (E_IS_CAL_CLIENT (client));
6141 g_return_if_fail (sexp != NULL);
6143 async_context = g_slice_new0 (AsyncContext);
6144 async_context->sexp = g_strdup (sexp);
6146 simple = g_simple_async_result_new (
6147 G_OBJECT (client), callback, user_data,
6148 e_cal_client_get_view);
6150 g_simple_async_result_set_check_cancellable (simple, cancellable);
6152 g_simple_async_result_set_op_res_gpointer (
6153 simple, async_context, (GDestroyNotify) async_context_free);
6155 g_simple_async_result_run_in_thread (
6156 simple, cal_client_get_view_thread,
6157 G_PRIORITY_DEFAULT, cancellable);
6159 g_object_unref (simple);
6163 * e_cal_client_get_view_finish:
6164 * @client: an #ECalClient
6165 * @result: a #GAsyncResult
6166 * @out_view: (out) an #ECalClientView
6167 * @error: (out): a #GError to set an error, if any
6169 * Finishes previous call of e_cal_client_get_view().
6170 * If successful, then the @out_view is set to newly allocated #ECalClientView,
6171 * which should be freed with g_object_unref().
6173 * Returns: %TRUE if successful, %FALSE otherwise.
6178 e_cal_client_get_view_finish (ECalClient *client,
6179 GAsyncResult *result,
6180 ECalClientView **out_view,
6183 GSimpleAsyncResult *simple;
6184 AsyncContext *async_context;
6186 g_return_val_if_fail (
6187 g_simple_async_result_is_valid (
6188 result, G_OBJECT (client),
6189 e_cal_client_get_view), FALSE);
6191 simple = G_SIMPLE_ASYNC_RESULT (result);
6192 async_context = g_simple_async_result_get_op_res_gpointer (simple);
6194 if (g_simple_async_result_propagate_error (simple, error))
6197 g_return_val_if_fail (async_context->client_view != NULL, FALSE);
6199 if (out_view != NULL)
6200 *out_view = g_object_ref (async_context->client_view);
6206 * e_cal_client_get_view_sync:
6207 * @client: an #ECalClient
6208 * @sexp: an S-expression representing the query.
6209 * @out_view: (out) an #ECalClientView
6210 * @cancellable: a #GCancellable; can be %NULL
6211 * @error: (out): a #GError to set an error, if any
6213 * Query @client with @sexp, creating an #ECalClientView.
6214 * If successful, then the @out_view is set to newly allocated #ECalClientView,
6215 * which should be freed with g_object_unref().
6217 * Returns: %TRUE if successful, %FALSE otherwise.
6222 e_cal_client_get_view_sync (ECalClient *client,
6224 ECalClientView **out_view,
6225 GCancellable *cancellable,
6229 gchar *object_path = NULL;
6232 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
6233 g_return_val_if_fail (sexp != NULL, FALSE);
6234 g_return_val_if_fail (out_view != NULL, FALSE);
6236 if (client->priv->dbus_proxy == NULL) {
6237 set_proxy_gone_error (error);
6241 utf8_sexp = e_util_utf8_make_valid (sexp);
6243 success = e_dbus_calendar_call_get_view_sync (
6244 client->priv->dbus_proxy, utf8_sexp,
6245 &object_path, cancellable, error);
6250 g_return_val_if_fail (
6251 (success && (object_path != NULL)) ||
6252 (!success && (object_path == NULL)), FALSE);
6254 if (object_path != NULL) {
6255 GDBusConnection *connection;
6256 ECalClientView *client_view;
6258 connection = g_dbus_proxy_get_connection (
6259 G_DBUS_PROXY (client->priv->dbus_proxy));
6261 client_view = g_initable_new (
6262 E_TYPE_CAL_CLIENT_VIEW,
6265 "connection", connection,
6266 "object-path", object_path,
6269 /* XXX Would have been easier to return the
6270 * EBookClientView directly rather than
6271 * through an "out" parameter. */
6272 if (client_view != NULL)
6273 *out_view = client_view;
6277 g_free (object_path);
6283 /* Helper for e_cal_client_get_timezone() */
6285 cal_client_get_timezone_thread (GSimpleAsyncResult *simple,
6286 GObject *source_object,
6287 GCancellable *cancellable)
6289 AsyncContext *async_context;
6290 GError *error = NULL;
6292 async_context = g_simple_async_result_get_op_res_gpointer (simple);
6294 e_cal_client_get_timezone_sync (
6295 E_CAL_CLIENT (source_object),
6296 async_context->tzid,
6297 &async_context->zone,
6298 cancellable, &error);
6301 g_simple_async_result_take_error (simple, error);
6305 * e_cal_client_get_timezone:
6306 * @client: an #ECalClient
6307 * @tzid: ID of the timezone to retrieve
6308 * @cancellable: a #GCancellable; can be %NULL
6309 * @callback: callback to call when a result is ready
6310 * @user_data: user data for the @callback
6312 * Retrieves a timezone object from the calendar backend.
6313 * The call is finished by e_cal_client_get_timezone_finish() from
6319 e_cal_client_get_timezone (ECalClient *client,
6321 GCancellable *cancellable,
6322 GAsyncReadyCallback callback,
6325 GSimpleAsyncResult *simple;
6326 AsyncContext *async_context;
6328 g_return_if_fail (E_IS_CAL_CLIENT (client));
6329 g_return_if_fail (tzid != NULL);
6331 async_context = g_slice_new0 (AsyncContext);
6332 async_context->tzid = g_strdup (tzid);
6334 simple = g_simple_async_result_new (
6335 G_OBJECT (client), callback, user_data,
6336 e_cal_client_get_timezone);
6338 g_simple_async_result_set_check_cancellable (simple, cancellable);
6340 g_simple_async_result_set_op_res_gpointer (
6341 simple, async_context, (GDestroyNotify) async_context_free);
6343 g_simple_async_result_run_in_thread (
6344 simple, cal_client_get_timezone_thread,
6345 G_PRIORITY_DEFAULT, cancellable);
6347 g_object_unref (simple);
6351 * e_cal_client_get_timezone_finish:
6352 * @client: an #ECalClient
6353 * @result: a #GAsyncResult
6354 * @out_zone: (out): Return value for the timezone
6355 * @error: (out): a #GError to set an error, if any
6357 * Finishes previous call of e_cal_client_get_timezone() and
6358 * sets @out_zone to a retrieved timezone object from the calendar backend.
6359 * This object is owned by the @client, thus do not free it.
6361 * Returns: %TRUE if successful, %FALSE otherwise.
6366 e_cal_client_get_timezone_finish (ECalClient *client,
6367 GAsyncResult *result,
6368 icaltimezone **out_zone,
6371 GSimpleAsyncResult *simple;
6372 AsyncContext *async_context;
6374 g_return_val_if_fail (
6375 g_simple_async_result_is_valid (
6376 result, G_OBJECT (client),
6377 e_cal_client_get_timezone), FALSE);
6379 simple = G_SIMPLE_ASYNC_RESULT (result);
6380 async_context = g_simple_async_result_get_op_res_gpointer (simple);
6382 if (g_simple_async_result_propagate_error (simple, error))
6385 g_return_val_if_fail (async_context->zone != NULL, FALSE);
6387 if (out_zone != NULL) {
6388 *out_zone = async_context->zone;
6389 async_context->zone = NULL;
6396 * e_cal_client_get_timezone_sync:
6397 * @client: an #ECalClient
6398 * @tzid: ID of the timezone to retrieve
6399 * @out_zone: (out): Return value for the timezone
6400 * @cancellable: a #GCancellable; can be %NULL
6401 * @error: (out): a #GError to set an error, if any
6403 * Retrieves a timezone object from the calendar backend.
6404 * This object is owned by the @client, thus do not free it.
6406 * Returns: %TRUE if successful, %FALSE otherwise.
6411 e_cal_client_get_timezone_sync (ECalClient *client,
6413 icaltimezone **out_zone,
6414 GCancellable *cancellable,
6417 icalcomponent *icalcomp;
6420 gchar *string = NULL;
6423 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
6424 g_return_val_if_fail (tzid != NULL, FALSE);
6425 g_return_val_if_fail (out_zone != NULL, FALSE);
6427 if (client->priv->dbus_proxy == NULL) {
6428 set_proxy_gone_error (error);
6432 zone = e_timezone_cache_get_timezone (
6433 E_TIMEZONE_CACHE (client), tzid);
6439 utf8_tzid = e_util_utf8_make_valid (tzid);
6441 success = e_dbus_calendar_call_get_timezone_sync (
6442 client->priv->dbus_proxy, utf8_tzid,
6443 &string, cancellable, error);
6448 g_return_val_if_fail (
6449 (success && (string != NULL)) ||
6450 (!success && (string == NULL)), FALSE);
6455 icalcomp = icalparser_parse_string (string);
6459 if (icalcomp == NULL) {
6461 error, e_cal_client_error_create (
6462 E_CAL_CLIENT_ERROR_INVALID_OBJECT, NULL));
6466 zone = icaltimezone_new ();
6467 if (!icaltimezone_set_component (zone, icalcomp)) {
6469 error, e_cal_client_error_create (
6470 E_CAL_CLIENT_ERROR_INVALID_OBJECT, NULL));
6471 icalcomponent_free (icalcomp);
6472 icaltimezone_free (zone, 1);
6476 /* Add the timezone to the cache directly,
6477 * otherwise we'd have to free this struct
6478 * and fetch the cached copy. */
6479 g_mutex_lock (&client->priv->zone_cache_lock);
6480 g_hash_table_insert (
6481 client->priv->zone_cache, g_strdup (tzid), zone);
6482 g_mutex_unlock (&client->priv->zone_cache_lock);
6489 /* Helper for e_cal_client_add_timezone() */
6491 cal_client_add_timezone_thread (GSimpleAsyncResult *simple,
6492 GObject *source_object,
6493 GCancellable *cancellable)
6495 AsyncContext *async_context;
6496 GError *error = NULL;
6498 async_context = g_simple_async_result_get_op_res_gpointer (simple);
6500 e_cal_client_add_timezone_sync (
6501 E_CAL_CLIENT (source_object),
6502 async_context->zone,
6503 cancellable, &error);
6506 g_simple_async_result_take_error (simple, error);
6510 * e_cal_client_add_timezone:
6511 * @client: an #ECalClient
6512 * @zone: The timezone to add
6513 * @cancellable: a #GCancellable; can be %NULL
6514 * @callback: callback to call when a result is ready
6515 * @user_data: user data for the @callback
6517 * Add a VTIMEZONE object to the given calendar client.
6518 * The call is finished by e_cal_client_add_timezone_finish() from
6524 e_cal_client_add_timezone (ECalClient *client,
6526 GCancellable *cancellable,
6527 GAsyncReadyCallback callback,
6530 GSimpleAsyncResult *simple;
6531 AsyncContext *async_context;
6532 icalcomponent *icalcomp;
6534 g_return_if_fail (E_IS_CAL_CLIENT (client));
6535 g_return_if_fail (zone != NULL);
6537 icalcomp = icaltimezone_get_component (zone);
6538 g_return_if_fail (icalcomp != NULL);
6540 async_context = g_slice_new0 (AsyncContext);
6541 async_context->zone = icaltimezone_new ();
6543 icalcomp = icalcomponent_new_clone (icalcomp);
6544 icaltimezone_set_component (async_context->zone, icalcomp);
6546 simple = g_simple_async_result_new (
6547 G_OBJECT (client), callback, user_data,
6548 e_cal_client_add_timezone);
6550 g_simple_async_result_set_check_cancellable (simple, cancellable);
6552 g_simple_async_result_set_op_res_gpointer (
6553 simple, async_context, (GDestroyNotify) async_context_free);
6555 if (zone == icaltimezone_get_utc_timezone ())
6556 g_simple_async_result_complete_in_idle (simple);
6558 g_simple_async_result_run_in_thread (
6559 simple, cal_client_add_timezone_thread,
6560 G_PRIORITY_DEFAULT, cancellable);
6562 g_object_unref (simple);
6566 * e_cal_client_add_timezone_finish:
6567 * @client: an #ECalClient
6568 * @result: a #GAsyncResult
6569 * @error: (out): a #GError to set an error, if any
6571 * Finishes previous call of e_cal_client_add_timezone().
6573 * Returns: %TRUE if successful, %FALSE otherwise.
6578 e_cal_client_add_timezone_finish (ECalClient *client,
6579 GAsyncResult *result,
6582 GSimpleAsyncResult *simple;
6584 g_return_val_if_fail (
6585 g_simple_async_result_is_valid (
6586 result, G_OBJECT (client),
6587 e_cal_client_add_timezone), FALSE);
6589 simple = G_SIMPLE_ASYNC_RESULT (result);
6591 /* Assume success unless a GError is set. */
6592 return !g_simple_async_result_propagate_error (simple, error);
6596 * e_cal_client_add_timezone_sync:
6597 * @client: an #ECalClient
6598 * @zone: The timezone to add
6599 * @cancellable: a #GCancellable; can be %NULL
6600 * @error: (out): a #GError to set an error, if any
6602 * Add a VTIMEZONE object to the given calendar client.
6604 * Returns: %TRUE if successful, %FALSE otherwise.
6609 e_cal_client_add_timezone_sync (ECalClient *client,
6611 GCancellable *cancellable,
6614 icalcomponent *icalcomp;
6616 gchar *utf8_zone_str;
6619 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
6620 g_return_val_if_fail (zone != NULL, FALSE);
6622 if (zone == icaltimezone_get_utc_timezone ())
6625 icalcomp = icaltimezone_get_component (zone);
6626 if (icalcomp == NULL) {
6628 error, e_client_error_create (
6629 E_CLIENT_ERROR_INVALID_ARG, NULL));
6633 if (client->priv->dbus_proxy == NULL) {
6634 set_proxy_gone_error (error);
6638 zone_str = icalcomponent_as_ical_string_r (icalcomp);
6639 utf8_zone_str = e_util_utf8_make_valid (zone_str);
6641 success = e_dbus_calendar_call_add_timezone_sync (
6642 client->priv->dbus_proxy, utf8_zone_str, cancellable, error);
6645 g_free (utf8_zone_str);