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().
285 * Deprecated: 3.8: Just use the #GError API directly.
288 e_cal_client_error_create (ECalClientError code,
289 const gchar *custom_msg)
291 return g_error_new_literal (E_CAL_CLIENT_ERROR, code, custom_msg ? custom_msg : e_cal_client_error_to_string (code));
295 * If the specified GError is a remote error, then create a new error
296 * representing the remote error. If the error is anything else, then
300 unwrap_dbus_error (GError *error,
301 GError **client_error)
303 #define err(a,b) "org.gnome.evolution.dataserver.Calendar." a, b
304 static EClientErrorsList cal_errors[] = {
305 { err ("Success", -1) },
306 { err ("ObjectNotFound", E_CAL_CLIENT_ERROR_OBJECT_NOT_FOUND) },
307 { err ("InvalidObject", E_CAL_CLIENT_ERROR_INVALID_OBJECT) },
308 { err ("ObjectIdAlreadyExists", E_CAL_CLIENT_ERROR_OBJECT_ID_ALREADY_EXISTS) },
309 { err ("NoSuchCal", E_CAL_CLIENT_ERROR_NO_SUCH_CALENDAR) },
310 { err ("UnknownUser", E_CAL_CLIENT_ERROR_UNKNOWN_USER) },
311 { err ("InvalidRange", E_CAL_CLIENT_ERROR_INVALID_RANGE) },
313 { err ("Busy", E_CLIENT_ERROR_BUSY) },
314 { err ("InvalidArg", E_CLIENT_ERROR_INVALID_ARG) },
315 { err ("RepositoryOffline", E_CLIENT_ERROR_REPOSITORY_OFFLINE) },
316 { err ("OfflineUnavailable", E_CLIENT_ERROR_OFFLINE_UNAVAILABLE) },
317 { err ("PermissionDenied", E_CLIENT_ERROR_PERMISSION_DENIED) },
318 { err ("AuthenticationFailed", E_CLIENT_ERROR_AUTHENTICATION_FAILED) },
319 { err ("AuthenticationRequired", E_CLIENT_ERROR_AUTHENTICATION_REQUIRED) },
320 { err ("CouldNotCancel", E_CLIENT_ERROR_COULD_NOT_CANCEL) },
321 { err ("NotSupported", E_CLIENT_ERROR_NOT_SUPPORTED) },
322 { err ("UnsupportedAuthenticationMethod", E_CLIENT_ERROR_UNSUPPORTED_AUTHENTICATION_METHOD) },
323 { err ("TLSNotAvailable", E_CLIENT_ERROR_TLS_NOT_AVAILABLE) },
324 { err ("SearchSizeLimitExceeded", E_CLIENT_ERROR_SEARCH_SIZE_LIMIT_EXCEEDED) },
325 { err ("SearchTimeLimitExceeded", E_CLIENT_ERROR_SEARCH_TIME_LIMIT_EXCEEDED) },
326 { err ("InvalidQuery", E_CLIENT_ERROR_INVALID_QUERY) },
327 { err ("QueryRefused", E_CLIENT_ERROR_QUERY_REFUSED) },
328 { err ("NotOpened", E_CLIENT_ERROR_NOT_OPENED) },
329 { err ("UnsupportedField", E_CLIENT_ERROR_OTHER_ERROR) },
330 { err ("UnsupportedMethod", E_CLIENT_ERROR_OTHER_ERROR) },
331 { err ("InvalidServerVersion", E_CLIENT_ERROR_OTHER_ERROR) },
332 { err ("OtherError", E_CLIENT_ERROR_OTHER_ERROR) }
339 if (!e_client_util_unwrap_dbus_error (error, client_error, cal_errors, G_N_ELEMENTS (cal_errors), E_CAL_CLIENT_ERROR, TRUE))
340 e_client_util_unwrap_dbus_error (error, client_error, cl_errors, G_N_ELEMENTS (cl_errors), E_CLIENT_ERROR, FALSE);
346 set_proxy_gone_error (GError **error)
348 /* do not translate this string, it should ideally never happen */
349 g_set_error_literal (error, E_CLIENT_ERROR, E_CLIENT_ERROR_DBUS_ERROR, "D-Bus calendar proxy gone");
352 static volatile gint active_cal_clients = 0;
353 static guint cal_connection_closed_id = 0;
354 static EDBusCalendarFactory *cal_factory = NULL;
355 static GRecMutex cal_factory_lock;
356 #define LOCK_FACTORY() g_rec_mutex_lock (&cal_factory_lock)
357 #define UNLOCK_FACTORY() g_rec_mutex_unlock (&cal_factory_lock)
359 static void gdbus_cal_factory_closed_cb (GDBusConnection *connection, gboolean remote_peer_vanished, GError *error, gpointer user_data);
362 gdbus_cal_factory_disconnect (GDBusConnection *connection)
366 if (!connection && cal_factory)
367 connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (cal_factory));
369 if (connection && cal_connection_closed_id) {
370 g_dbus_connection_signal_unsubscribe (connection, cal_connection_closed_id);
371 g_signal_handlers_disconnect_by_func (connection, gdbus_cal_factory_closed_cb, NULL);
374 if (cal_factory != NULL)
375 g_object_unref (cal_factory);
377 cal_connection_closed_id = 0;
384 gdbus_cal_factory_closed_cb (GDBusConnection *connection,
385 gboolean remote_peer_vanished,
393 gdbus_cal_factory_disconnect (connection);
396 unwrap_dbus_error (g_error_copy (error), &err);
399 g_debug ("GDBus connection is closed%s: %s", remote_peer_vanished ? ", remote peer vanished" : "", err->message);
401 } else if (active_cal_clients > 0) {
402 g_debug ("GDBus connection is closed%s", remote_peer_vanished ? ", remote peer vanished" : "");
409 gdbus_cal_factory_connection_gone_cb (GDBusConnection *connection,
410 const gchar *sender_name,
411 const gchar *object_path,
412 const gchar *interface_name,
413 const gchar *signal_name,
414 GVariant *parameters,
417 /* signal subscription takes care of correct parameters,
418 * thus just do what is to be done here */
419 gdbus_cal_factory_closed_cb (connection, TRUE, NULL, user_data);
423 gdbus_cal_factory_activate (GCancellable *cancellable,
426 GDBusConnection *connection;
430 if (G_LIKELY (cal_factory != NULL)) {
435 cal_factory = e_dbus_calendar_factory_proxy_new_for_bus_sync (
437 G_DBUS_PROXY_FLAGS_NONE,
438 CALENDAR_DBUS_SERVICE_NAME,
439 "/org/gnome/evolution/dataserver/CalendarFactory",
442 if (cal_factory == NULL) {
447 connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (cal_factory));
448 cal_connection_closed_id = g_dbus_connection_signal_subscribe (
451 "org.freedesktop.DBus", /* interface */
452 "NameOwnerChanged", /* member */
453 "/org/freedesktop/DBus", /* object_path */
454 "org.gnome.evolution.dataserver.Calendar", /* arg0 */
455 G_DBUS_SIGNAL_FLAGS_NONE,
456 gdbus_cal_factory_connection_gone_cb, NULL, NULL);
459 connection, "closed",
460 G_CALLBACK (gdbus_cal_factory_closed_cb), NULL);
468 cal_client_dbus_thread (gpointer user_data)
470 GMainContext *main_context = user_data;
471 GMainLoop *main_loop;
473 g_main_context_push_thread_default (main_context);
475 main_loop = g_main_loop_new (main_context, FALSE);
476 g_main_loop_run (main_loop);
477 g_main_loop_unref (main_loop);
479 g_main_context_pop_thread_default (main_context);
481 g_main_context_unref (main_context);
487 cal_client_dbus_thread_init (gpointer unused)
489 GMainContext *main_context;
491 main_context = g_main_context_new ();
493 /* This thread terminates when the process itself terminates, so
494 * no need to worry about unreferencing the returned GThread. */
496 "cal-client-dbus-thread",
497 cal_client_dbus_thread,
498 g_main_context_ref (main_context));
503 static GMainContext *
504 cal_client_ref_dbus_main_context (void)
506 static GOnce cal_client_dbus_thread_once = G_ONCE_INIT;
509 &cal_client_dbus_thread_once,
510 cal_client_dbus_thread_init, NULL);
512 return g_main_context_ref (cal_client_dbus_thread_once.retval);
516 cal_client_run_in_dbus_thread_idle_cb (gpointer user_data)
518 RunInThreadClosure *closure = user_data;
519 GObject *source_object;
520 GAsyncResult *result;
522 result = G_ASYNC_RESULT (closure->simple);
523 source_object = g_async_result_get_source_object (result);
528 closure->cancellable);
530 if (source_object != NULL)
531 g_object_unref (source_object);
533 g_simple_async_result_complete_in_idle (closure->simple);
539 cal_client_run_in_dbus_thread (GSimpleAsyncResult *simple,
540 GSimpleAsyncThreadFunc func,
542 GCancellable *cancellable)
544 RunInThreadClosure *closure;
545 GMainContext *main_context;
546 GSource *idle_source;
548 main_context = cal_client_ref_dbus_main_context ();
550 closure = g_slice_new0 (RunInThreadClosure);
551 closure->func = func;
552 closure->simple = g_object_ref (simple);
554 if (G_IS_CANCELLABLE (cancellable))
555 closure->cancellable = g_object_ref (cancellable);
557 idle_source = g_idle_source_new ();
558 g_source_set_priority (idle_source, io_priority);
559 g_source_set_callback (
560 idle_source, cal_client_run_in_dbus_thread_idle_cb,
561 closure, (GDestroyNotify) run_in_thread_closure_free);
562 g_source_attach (idle_source, main_context);
563 g_source_unref (idle_source);
565 g_main_context_unref (main_context);
568 static void gdbus_cal_client_disconnect (ECalClient *client);
571 * Called when the calendar server dies.
574 gdbus_cal_client_closed_cb (GDBusConnection *connection,
575 gboolean remote_peer_vanished,
581 g_assert (E_IS_CAL_CLIENT (client));
584 unwrap_dbus_error (g_error_copy (error), &err);
587 g_debug (G_STRLOC ": ECalClient GDBus connection is closed%s: %s", remote_peer_vanished ? ", remote peer vanished" : "", err->message);
590 g_debug (G_STRLOC ": ECalClient GDBus connection is closed%s", remote_peer_vanished ? ", remote peer vanished" : "");
593 gdbus_cal_client_disconnect (client);
595 e_client_emit_backend_died (E_CLIENT (client));
599 gdbus_cal_client_connection_gone_cb (GDBusConnection *connection,
600 const gchar *sender_name,
601 const gchar *object_path,
602 const gchar *interface_name,
603 const gchar *signal_name,
604 GVariant *parameters,
607 /* signal subscription takes care of correct parameters,
608 * thus just do what is to be done here */
609 gdbus_cal_client_closed_cb (connection, TRUE, NULL, user_data);
613 gdbus_cal_client_disconnect (ECalClient *client)
615 g_return_if_fail (E_IS_CAL_CLIENT (client));
617 /* Ensure that everything relevant is NULL */
620 if (client->priv->dbus_proxy != NULL) {
621 GDBusConnection *connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (client->priv->dbus_proxy));
623 g_signal_handlers_disconnect_by_func (connection, gdbus_cal_client_closed_cb, client);
624 g_dbus_connection_signal_unsubscribe (connection, client->priv->gone_signal_id);
625 client->priv->gone_signal_id = 0;
627 e_dbus_calendar_call_close_sync (
628 client->priv->dbus_proxy, NULL, NULL);
629 g_object_unref (client->priv->dbus_proxy);
630 client->priv->dbus_proxy = NULL;
637 cal_client_emit_backend_error_idle_cb (gpointer user_data)
639 SignalClosure *signal_closure = user_data;
641 g_signal_emit_by_name (
642 signal_closure->client,
644 signal_closure->error_message);
650 cal_client_emit_backend_property_changed_idle_cb (gpointer user_data)
652 SignalClosure *signal_closure = user_data;
653 gchar *prop_value = NULL;
655 /* XXX Despite appearances, this function does not block. */
656 e_client_get_backend_property_sync (
657 signal_closure->client,
658 signal_closure->property_name,
659 &prop_value, NULL, NULL);
661 if (prop_value != NULL) {
662 g_signal_emit_by_name (
663 signal_closure->client,
664 "backend-property-changed",
665 signal_closure->property_name,
674 cal_client_emit_free_busy_data_idle_cb (gpointer user_data)
676 SignalClosure *signal_closure = user_data;
681 strv = signal_closure->free_busy_data;
683 for (ii = 0; strv[ii] != NULL; ii++) {
685 icalcomponent *icalcomp;
686 icalcomponent_kind kind;
688 icalcomp = icalcomponent_new_from_string (strv[ii]);
689 if (icalcomp == NULL)
692 kind = icalcomponent_isa (icalcomp);
693 if (kind != ICAL_VFREEBUSY_COMPONENT) {
694 icalcomponent_free (icalcomp);
698 comp = e_cal_component_new ();
699 if (!e_cal_component_set_icalcomponent (comp, icalcomp)) {
700 icalcomponent_free (icalcomp);
701 g_object_unref (comp);
705 list = g_slist_prepend (list, comp);
708 list = g_slist_reverse (list);
711 signal_closure->client,
712 signals[FREE_BUSY_DATA], 0, list);
714 g_slist_free_full (list, (GDestroyNotify) g_object_unref);
720 cal_client_emit_timezone_added_idle_cb (gpointer user_data)
722 SignalClosure *signal_closure = user_data;
724 g_signal_emit_by_name (
725 signal_closure->client,
727 signal_closure->cached_zone);
733 cal_client_dbus_proxy_error_cb (EDBusCalendar *dbus_proxy,
734 const gchar *error_message,
735 ECalClient *cal_client)
737 GSource *idle_source;
738 SignalClosure *signal_closure;
740 signal_closure = g_slice_new0 (SignalClosure);
741 signal_closure->client = g_object_ref (cal_client);
742 signal_closure->error_message = g_strdup (error_message);
744 idle_source = g_idle_source_new ();
745 g_source_set_callback (
747 cal_client_emit_backend_error_idle_cb,
749 (GDestroyNotify) signal_closure_free);
750 g_source_attach (idle_source, cal_client->priv->main_context);
751 g_source_unref (idle_source);
755 cal_client_dbus_proxy_notify_cb (EDBusCalendar *dbus_proxy,
757 ECalClient *cal_client)
759 const gchar *backend_prop_name = NULL;
761 if (g_str_equal (pspec->name, "alarm-email-address")) {
762 backend_prop_name = CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS;
765 if (g_str_equal (pspec->name, "cache-dir")) {
766 backend_prop_name = CLIENT_BACKEND_PROPERTY_CACHE_DIR;
769 if (g_str_equal (pspec->name, "cal-email-address")) {
770 backend_prop_name = CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS;
773 if (g_str_equal (pspec->name, "capabilities")) {
777 backend_prop_name = CLIENT_BACKEND_PROPERTY_CAPABILITIES;
779 strv = e_dbus_calendar_dup_capabilities (dbus_proxy);
781 csv = g_strjoinv (",", strv);
784 e_client_set_capabilities (E_CLIENT (cal_client), csv);
788 if (g_str_equal (pspec->name, "default-object")) {
789 backend_prop_name = CAL_BACKEND_PROPERTY_DEFAULT_OBJECT;
792 if (g_str_equal (pspec->name, "online")) {
795 backend_prop_name = CLIENT_BACKEND_PROPERTY_ONLINE;
797 online = e_dbus_calendar_get_online (dbus_proxy);
798 e_client_set_online (E_CLIENT (cal_client), online);
801 if (g_str_equal (pspec->name, "revision")) {
802 backend_prop_name = CLIENT_BACKEND_PROPERTY_REVISION;
805 if (g_str_equal (pspec->name, "writable")) {
808 backend_prop_name = CLIENT_BACKEND_PROPERTY_READONLY;
810 writable = e_dbus_calendar_get_writable (dbus_proxy);
811 e_client_set_readonly (E_CLIENT (cal_client), !writable);
814 if (backend_prop_name != NULL) {
815 GSource *idle_source;
816 SignalClosure *signal_closure;
818 signal_closure = g_slice_new0 (SignalClosure);
819 signal_closure->client = g_object_ref (cal_client);
820 signal_closure->property_name = g_strdup (backend_prop_name);
822 idle_source = g_idle_source_new ();
823 g_source_set_callback (
825 cal_client_emit_backend_property_changed_idle_cb,
827 (GDestroyNotify) signal_closure_free);
828 g_source_attach (idle_source, cal_client->priv->main_context);
829 g_source_unref (idle_source);
834 cal_client_dbus_proxy_free_busy_data_cb (EDBusCalendar *dbus_proxy,
835 gchar **free_busy_data,
836 ECalClient *cal_client)
838 GSource *idle_source;
839 SignalClosure *signal_closure;
841 signal_closure = g_slice_new0 (SignalClosure);
842 signal_closure->client = g_object_ref (cal_client);
843 signal_closure->free_busy_data = g_strdupv (free_busy_data);
845 idle_source = g_idle_source_new ();
846 g_source_set_callback (
848 cal_client_emit_free_busy_data_idle_cb,
850 (GDestroyNotify) signal_closure_free);
851 g_source_attach (idle_source, cal_client->priv->main_context);
852 g_source_unref (idle_source);
856 cal_client_set_source_type (ECalClient *cal_client,
857 ECalClientSourceType source_type)
859 cal_client->priv->source_type = source_type;
863 cal_client_set_property (GObject *object,
868 switch (property_id) {
869 case PROP_SOURCE_TYPE:
870 cal_client_set_source_type (
871 E_CAL_CLIENT (object),
872 g_value_get_enum (value));
876 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
880 cal_client_get_property (GObject *object,
885 switch (property_id) {
886 case PROP_SOURCE_TYPE:
889 e_cal_client_get_source_type (
890 E_CAL_CLIENT (object)));
894 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
898 cal_client_dispose (GObject *object)
900 ECalClientPrivate *priv;
902 priv = E_CAL_CLIENT_GET_PRIVATE (object);
904 e_client_cancel_all (E_CLIENT (object));
906 if (priv->dbus_proxy_error_handler_id > 0) {
907 g_signal_handler_disconnect (
909 priv->dbus_proxy_error_handler_id);
910 priv->dbus_proxy_error_handler_id = 0;
913 if (priv->dbus_proxy_notify_handler_id > 0) {
914 g_signal_handler_disconnect (
916 priv->dbus_proxy_notify_handler_id);
917 priv->dbus_proxy_notify_handler_id = 0;
920 if (priv->dbus_proxy_free_busy_data_handler_id > 0) {
921 g_signal_handler_disconnect (
923 priv->dbus_proxy_free_busy_data_handler_id);
924 priv->dbus_proxy_free_busy_data_handler_id = 0;
927 gdbus_cal_client_disconnect (E_CAL_CLIENT (object));
929 if (priv->main_context != NULL) {
930 g_main_context_unref (priv->main_context);
931 priv->main_context = NULL;
934 /* Chain up to parent's dispose() method. */
935 G_OBJECT_CLASS (e_cal_client_parent_class)->dispose (object);
939 cal_client_finalize (GObject *object)
942 ECalClientPrivate *priv;
944 client = E_CAL_CLIENT (object);
948 if (priv->default_zone && priv->default_zone != icaltimezone_get_utc_timezone ())
949 icaltimezone_free (priv->default_zone, 1);
951 g_mutex_lock (&priv->zone_cache_lock);
952 g_hash_table_destroy (priv->zone_cache);
953 g_mutex_unlock (&priv->zone_cache_lock);
955 g_mutex_clear (&priv->zone_cache_lock);
957 /* Chain up to parent's finalize() method. */
958 G_OBJECT_CLASS (e_cal_client_parent_class)->finalize (object);
960 if (g_atomic_int_dec_and_test (&active_cal_clients))
961 gdbus_cal_factory_disconnect (NULL);
965 cal_client_get_dbus_proxy (EClient *client)
967 ECalClientPrivate *priv;
969 priv = E_CAL_CLIENT_GET_PRIVATE (client);
971 return G_DBUS_PROXY (priv->dbus_proxy);
975 cal_client_unwrap_dbus_error (EClient *client,
979 unwrap_dbus_error (dbus_error, out_error);
983 cal_client_get_backend_property_sync (EClient *client,
984 const gchar *prop_name,
986 GCancellable *cancellable,
989 ECalClient *cal_client;
990 EDBusCalendar *dbus_proxy;
993 cal_client = E_CAL_CLIENT (client);
994 dbus_proxy = cal_client->priv->dbus_proxy;
996 if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_OPENED)) {
997 *prop_value = g_strdup ("TRUE");
1001 if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_OPENING)) {
1002 *prop_value = g_strdup ("FALSE");
1006 if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_ONLINE)) {
1007 if (e_dbus_calendar_get_online (dbus_proxy))
1008 *prop_value = g_strdup ("TRUE");
1010 *prop_value = g_strdup ("FALSE");
1014 if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_READONLY)) {
1015 if (e_dbus_calendar_get_writable (dbus_proxy))
1016 *prop_value = g_strdup ("FALSE");
1018 *prop_value = g_strdup ("TRUE");
1022 if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CACHE_DIR)) {
1023 *prop_value = e_dbus_calendar_dup_cache_dir (dbus_proxy);
1027 if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_REVISION)) {
1028 *prop_value = e_dbus_calendar_dup_revision (dbus_proxy);
1032 if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CAPABILITIES)) {
1033 strv = e_dbus_calendar_dup_capabilities (dbus_proxy);
1035 *prop_value = g_strjoinv (",", strv);
1037 *prop_value = g_strdup ("");
1042 if (g_str_equal (prop_name, CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS)) {
1043 *prop_value = e_dbus_calendar_dup_alarm_email_address (dbus_proxy);
1046 if (g_str_equal (prop_name, CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS)) {
1047 *prop_value = e_dbus_calendar_dup_cal_email_address (dbus_proxy);
1050 if (g_str_equal (prop_name, CAL_BACKEND_PROPERTY_DEFAULT_OBJECT)) {
1051 *prop_value = e_dbus_calendar_dup_default_object (dbus_proxy);
1055 error, E_CLIENT_ERROR, E_CLIENT_ERROR_NOT_SUPPORTED,
1056 _("Unknown calendar property '%s'"), prop_name);
1062 cal_client_set_backend_property_sync (EClient *client,
1063 const gchar *prop_name,
1064 const gchar *prop_value,
1065 GCancellable *cancellable,
1069 error, E_CLIENT_ERROR,
1070 E_CLIENT_ERROR_NOT_SUPPORTED,
1071 _("Cannot change value of calendar property '%s'"),
1078 cal_client_open_sync (EClient *client,
1079 gboolean only_if_exists,
1080 GCancellable *cancellable,
1083 ECalClient *cal_client;
1085 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
1087 cal_client = E_CAL_CLIENT (client);
1089 if (cal_client->priv->dbus_proxy == NULL) {
1090 set_proxy_gone_error (error);
1094 return e_dbus_calendar_call_open_sync (
1095 cal_client->priv->dbus_proxy, cancellable, error);
1099 cal_client_refresh_sync (EClient *client,
1100 GCancellable *cancellable,
1103 ECalClient *cal_client;
1105 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
1107 cal_client = E_CAL_CLIENT (client);
1109 if (cal_client->priv->dbus_proxy == NULL) {
1110 set_proxy_gone_error (error);
1114 return e_dbus_calendar_call_refresh_sync (
1115 cal_client->priv->dbus_proxy, cancellable, error);
1119 cal_client_init_in_dbus_thread (GSimpleAsyncResult *simple,
1120 GObject *source_object,
1121 GCancellable *cancellable)
1123 ECalClientPrivate *priv;
1126 GDBusConnection *connection;
1128 gchar *object_path = NULL;
1130 GError *error = NULL;
1132 priv = E_CAL_CLIENT_GET_PRIVATE (source_object);
1134 client = E_CLIENT (source_object);
1135 source = e_client_get_source (client);
1136 uid = e_source_get_uid (source);
1139 gdbus_cal_factory_activate (cancellable, &error);
1142 if (error != NULL) {
1143 unwrap_dbus_error (error, &error);
1144 g_simple_async_result_take_error (simple, error);
1148 switch (e_cal_client_get_source_type (E_CAL_CLIENT (client))) {
1149 case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
1150 e_dbus_calendar_factory_call_open_calendar_sync (
1151 cal_factory, uid, &object_path,
1152 cancellable, &error);
1154 case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
1155 e_dbus_calendar_factory_call_open_task_list_sync (
1156 cal_factory, uid, &object_path,
1157 cancellable, &error);
1159 case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
1160 e_dbus_calendar_factory_call_open_memo_list_sync (
1161 cal_factory, uid, &object_path,
1162 cancellable, &error);
1165 g_return_if_reached ();
1170 ((object_path != NULL) && (error == NULL)) ||
1171 ((object_path == NULL) && (error != NULL)));
1173 if (object_path == NULL) {
1174 unwrap_dbus_error (error, &error);
1175 g_simple_async_result_take_error (simple, error);
1179 connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (cal_factory));
1181 priv->dbus_proxy = e_dbus_calendar_proxy_new_sync (
1183 G_DBUS_PROXY_FLAGS_NONE,
1184 CALENDAR_DBUS_SERVICE_NAME,
1186 cancellable, &error);
1188 g_free (object_path);
1192 ((priv->dbus_proxy != NULL) && (error == NULL)) ||
1193 ((priv->dbus_proxy == NULL) && (error != NULL)));
1195 if (error != NULL) {
1196 unwrap_dbus_error (error, &error);
1197 g_simple_async_result_take_error (simple, error);
1201 g_dbus_proxy_set_default_timeout (
1202 G_DBUS_PROXY (priv->dbus_proxy), DBUS_PROXY_TIMEOUT_MS);
1204 priv->gone_signal_id = g_dbus_connection_signal_subscribe (
1206 "org.freedesktop.DBus", /* sender */
1207 "org.freedesktop.DBus", /* interface */
1208 "NameOwnerChanged", /* member */
1209 "/org/freedesktop/DBus", /* object_path */
1210 "org.gnome.evolution.dataserver.Calendar", /* arg0 */
1211 G_DBUS_SIGNAL_FLAGS_NONE,
1212 gdbus_cal_client_connection_gone_cb, client, NULL);
1215 connection, "closed",
1216 G_CALLBACK (gdbus_cal_client_closed_cb), client);
1218 handler_id = g_signal_connect_object (
1219 priv->dbus_proxy, "error",
1220 G_CALLBACK (cal_client_dbus_proxy_error_cb),
1222 priv->dbus_proxy_error_handler_id = handler_id;
1224 handler_id = g_signal_connect_object (
1225 priv->dbus_proxy, "notify",
1226 G_CALLBACK (cal_client_dbus_proxy_notify_cb),
1228 priv->dbus_proxy_notify_handler_id = handler_id;
1230 handler_id = g_signal_connect_object (
1231 priv->dbus_proxy, "free-busy-data",
1232 G_CALLBACK (cal_client_dbus_proxy_free_busy_data_cb),
1234 priv->dbus_proxy_free_busy_data_handler_id = handler_id;
1236 /* Initialize our public-facing GObject properties. */
1237 g_object_notify (G_OBJECT (priv->dbus_proxy), "online");
1238 g_object_notify (G_OBJECT (priv->dbus_proxy), "writable");
1239 g_object_notify (G_OBJECT (priv->dbus_proxy), "capabilities");
1243 cal_client_initable_init (GInitable *initable,
1244 GCancellable *cancellable,
1247 EAsyncClosure *closure;
1248 GAsyncResult *result;
1251 closure = e_async_closure_new ();
1253 g_async_initable_init_async (
1254 G_ASYNC_INITABLE (initable),
1255 G_PRIORITY_DEFAULT, cancellable,
1256 e_async_closure_callback, closure);
1258 result = e_async_closure_wait (closure);
1260 success = g_async_initable_init_finish (
1261 G_ASYNC_INITABLE (initable), result, error);
1263 e_async_closure_free (closure);
1269 cal_client_initable_init_async (GAsyncInitable *initable,
1271 GCancellable *cancellable,
1272 GAsyncReadyCallback callback,
1275 GSimpleAsyncResult *simple;
1277 simple = g_simple_async_result_new (
1278 G_OBJECT (initable), callback, user_data,
1279 cal_client_initable_init_async);
1281 g_simple_async_result_set_check_cancellable (simple, cancellable);
1283 cal_client_run_in_dbus_thread (
1284 simple, cal_client_init_in_dbus_thread,
1285 io_priority, cancellable);
1287 g_object_unref (simple);
1291 cal_client_initable_init_finish (GAsyncInitable *initable,
1292 GAsyncResult *result,
1295 GSimpleAsyncResult *simple;
1297 g_return_val_if_fail (
1298 g_simple_async_result_is_valid (
1299 result, G_OBJECT (initable),
1300 cal_client_initable_init_async), FALSE);
1302 simple = G_SIMPLE_ASYNC_RESULT (result);
1304 /* Assume success unless a GError is set. */
1305 return !g_simple_async_result_propagate_error (simple, error);
1309 cal_client_add_cached_timezone (ETimezoneCache *cache,
1312 ECalClientPrivate *priv;
1315 priv = E_CAL_CLIENT_GET_PRIVATE (cache);
1317 g_mutex_lock (&priv->zone_cache_lock);
1319 tzid = icaltimezone_get_tzid (zone);
1321 /* Avoid replacing an existing cache entry. We don't want to
1322 * invalidate any icaltimezone pointers that may have already
1323 * been returned through e_timezone_cache_get_timezone(). */
1324 if (!g_hash_table_contains (priv->zone_cache, tzid)) {
1325 GSource *idle_source;
1326 SignalClosure *signal_closure;
1328 icalcomponent *icalcomp;
1329 icaltimezone *cached_zone;
1331 cached_zone = icaltimezone_new ();
1332 icalcomp = icaltimezone_get_component (zone);
1333 icalcomp = icalcomponent_new_clone (icalcomp);
1334 icaltimezone_set_component (cached_zone, icalcomp);
1336 g_hash_table_insert (
1338 g_strdup (tzid), cached_zone);
1340 /* The closure's client reference will keep the
1341 * internally cached icaltimezone alive for the
1342 * duration of the idle callback. */
1343 signal_closure = g_slice_new0 (SignalClosure);
1344 signal_closure->client = g_object_ref (cache);
1345 signal_closure->cached_zone = cached_zone;
1347 idle_source = g_idle_source_new ();
1348 g_source_set_callback (
1350 cal_client_emit_timezone_added_idle_cb,
1352 (GDestroyNotify) g_object_unref);
1353 g_source_attach (idle_source, priv->main_context);
1354 g_source_unref (idle_source);
1357 g_mutex_unlock (&priv->zone_cache_lock);
1360 static icaltimezone *
1361 cal_client_get_cached_timezone (ETimezoneCache *cache,
1364 ECalClientPrivate *priv;
1365 icaltimezone *zone = NULL;
1366 icaltimezone *builtin_zone = NULL;
1367 icalcomponent *icalcomp;
1369 const gchar *builtin_tzid;
1371 priv = E_CAL_CLIENT_GET_PRIVATE (cache);
1373 if (g_str_equal (tzid, "UTC"))
1374 return icaltimezone_get_utc_timezone ();
1376 g_mutex_lock (&priv->zone_cache_lock);
1378 /* See if we already have it in the cache. */
1379 zone = g_hash_table_lookup (priv->zone_cache, tzid);
1384 /* Try to replace the original time zone with a more complete
1385 * and/or potentially updated built-in time zone. Note this also
1386 * applies to TZIDs which match built-in time zones exactly: they
1387 * are extracted via icaltimezone_get_builtin_timezone_from_tzid()
1388 * below without a roundtrip to the backend. */
1390 builtin_tzid = e_cal_match_tzid (tzid);
1392 if (builtin_tzid != NULL)
1393 builtin_zone = icaltimezone_get_builtin_timezone_from_tzid (
1396 if (builtin_zone == NULL)
1399 /* Use the built-in time zone *and* rename it. Likely the caller
1400 * is asking for a specific TZID because it has an event with such
1401 * a TZID. Returning an icaltimezone with a different TZID would
1402 * lead to broken VCALENDARs in the caller. */
1404 icalcomp = icaltimezone_get_component (builtin_zone);
1405 icalcomp = icalcomponent_new_clone (icalcomp);
1407 prop = icalcomponent_get_first_property (
1408 icalcomp, ICAL_ANY_PROPERTY);
1410 while (prop != NULL) {
1411 if (icalproperty_isa (prop) == ICAL_TZID_PROPERTY) {
1412 icalproperty_set_value_from_string (prop, tzid, "NO");
1416 prop = icalcomponent_get_next_property (
1417 icalcomp, ICAL_ANY_PROPERTY);
1420 if (icalcomp != NULL) {
1421 zone = icaltimezone_new ();
1422 if (icaltimezone_set_component (zone, icalcomp)) {
1423 tzid = icaltimezone_get_tzid (zone);
1424 g_hash_table_insert (
1426 g_strdup (tzid), zone);
1428 icalcomponent_free (icalcomp);
1429 icaltimezone_free (zone, 1);
1435 g_mutex_unlock (&priv->zone_cache_lock);
1441 cal_client_list_cached_timezones (ETimezoneCache *cache)
1443 ECalClientPrivate *priv;
1446 priv = E_CAL_CLIENT_GET_PRIVATE (cache);
1448 g_mutex_lock (&priv->zone_cache_lock);
1450 list = g_hash_table_get_values (priv->zone_cache);
1452 g_mutex_unlock (&priv->zone_cache_lock);
1458 e_cal_client_class_init (ECalClientClass *class)
1460 GObjectClass *object_class;
1461 EClientClass *client_class;
1463 g_type_class_add_private (class, sizeof (ECalClientPrivate));
1465 object_class = G_OBJECT_CLASS (class);
1466 object_class->set_property = cal_client_set_property;
1467 object_class->get_property = cal_client_get_property;
1468 object_class->dispose = cal_client_dispose;
1469 object_class->finalize = cal_client_finalize;
1471 client_class = E_CLIENT_CLASS (class);
1472 client_class->get_dbus_proxy = cal_client_get_dbus_proxy;
1473 client_class->unwrap_dbus_error = cal_client_unwrap_dbus_error;
1474 client_class->get_backend_property_sync = cal_client_get_backend_property_sync;
1475 client_class->set_backend_property_sync = cal_client_set_backend_property_sync;
1476 client_class->open_sync = cal_client_open_sync;
1477 client_class->refresh_sync = cal_client_refresh_sync;
1479 g_object_class_install_property (
1485 "The iCalendar data type",
1486 E_TYPE_CAL_CLIENT_SOURCE_TYPE,
1487 E_CAL_CLIENT_SOURCE_TYPE_EVENTS,
1489 G_PARAM_CONSTRUCT_ONLY |
1490 G_PARAM_STATIC_STRINGS));
1492 signals[FREE_BUSY_DATA] = g_signal_new (
1494 G_OBJECT_CLASS_TYPE (class),
1496 G_STRUCT_OFFSET (ECalClientClass, free_busy_data),
1498 g_cclosure_marshal_VOID__POINTER,
1504 e_cal_client_initable_init (GInitableIface *interface)
1506 interface->init = cal_client_initable_init;
1510 e_cal_client_async_initable_init (GAsyncInitableIface *interface)
1512 interface->init_async = cal_client_initable_init_async;
1513 interface->init_finish = cal_client_initable_init_finish;
1517 e_cal_client_timezone_cache_init (ETimezoneCacheInterface *interface)
1519 interface->add_timezone = cal_client_add_cached_timezone;
1520 interface->get_timezone = cal_client_get_cached_timezone;
1521 interface->list_timezones = cal_client_list_cached_timezones;
1525 e_cal_client_init (ECalClient *client)
1527 GHashTable *zone_cache;
1529 zone_cache = g_hash_table_new_full (
1530 (GHashFunc) g_str_hash,
1531 (GEqualFunc) g_str_equal,
1532 (GDestroyNotify) g_free,
1533 (GDestroyNotify) free_zone_cb);
1535 g_atomic_int_inc (&active_cal_clients);
1537 client->priv = E_CAL_CLIENT_GET_PRIVATE (client);
1538 client->priv->source_type = E_CAL_CLIENT_SOURCE_TYPE_LAST;
1539 client->priv->default_zone = icaltimezone_get_utc_timezone ();
1540 g_mutex_init (&client->priv->zone_cache_lock);
1541 client->priv->zone_cache = zone_cache;
1543 /* This is so the D-Bus thread can schedule signal emissions
1544 * on the thread-default context for this thread. */
1545 client->priv->main_context = g_main_context_ref_thread_default ();
1549 * e_cal_client_connect_sync:
1550 * @source: an #ESource
1551 * @source_type: source type of the calendar
1552 * @cancellable: (allow-none): optional #GCancellable object, or %NULL
1553 * @error: return location for a #GError, or %NULL
1555 * Creates a new #ECalClient for @source and @source_type. If an error
1556 * occurs, the function will set @error and return %FALSE.
1558 * Unlike with e_cal_client_new(), there is no need to call
1559 * e_client_open_sync() after obtaining the #ECalClient.
1561 * For error handling convenience, any error message returned by this
1562 * function will have a descriptive prefix that includes the display
1565 * Returns: a new #ECalClient, or %NULL
1570 e_cal_client_connect_sync (ESource *source,
1571 ECalClientSourceType source_type,
1572 GCancellable *cancellable,
1578 g_return_val_if_fail (E_IS_SOURCE (source), NULL);
1579 g_return_val_if_fail (
1580 source_type == E_CAL_CLIENT_SOURCE_TYPE_EVENTS ||
1581 source_type == E_CAL_CLIENT_SOURCE_TYPE_TASKS ||
1582 source_type == E_CAL_CLIENT_SOURCE_TYPE_MEMOS, NULL);
1584 client = g_object_new (
1587 "source-type", source_type, NULL);
1589 success = g_initable_init (
1590 G_INITABLE (client), cancellable, error);
1593 success = e_dbus_calendar_call_open_sync (
1594 client->priv->dbus_proxy, cancellable, error);
1598 error,_("Unable to connect to '%s': "),
1599 e_source_get_display_name (source));
1600 g_object_unref (client);
1604 return E_CLIENT (client);
1607 /* Helper for e_cal_client_connect() */
1609 cal_client_connect_open_cb (GObject *source_object,
1610 GAsyncResult *result,
1613 GSimpleAsyncResult *simple;
1614 GError *error = NULL;
1616 simple = G_SIMPLE_ASYNC_RESULT (user_data);
1618 e_dbus_calendar_call_open_finish (
1619 E_DBUS_CALENDAR (source_object), result, &error);
1622 g_simple_async_result_take_error (simple, error);
1624 g_simple_async_result_complete (simple);
1626 g_object_unref (simple);
1629 /* Helper for e_cal_client_connect() */
1631 cal_client_connect_init_cb (GObject *source_object,
1632 GAsyncResult *result,
1635 GSimpleAsyncResult *simple;
1636 ECalClientPrivate *priv;
1637 ConnectClosure *closure;
1638 GError *error = NULL;
1640 simple = G_SIMPLE_ASYNC_RESULT (user_data);
1642 g_async_initable_init_finish (
1643 G_ASYNC_INITABLE (source_object), result, &error);
1645 if (error != NULL) {
1646 g_simple_async_result_take_error (simple, error);
1647 g_simple_async_result_complete (simple);
1651 /* Note, we're repurposing some function parameters. */
1653 result = G_ASYNC_RESULT (simple);
1654 source_object = g_async_result_get_source_object (result);
1655 closure = g_simple_async_result_get_op_res_gpointer (simple);
1657 priv = E_CAL_CLIENT_GET_PRIVATE (source_object);
1659 e_dbus_calendar_call_open (
1661 closure->cancellable,
1662 cal_client_connect_open_cb,
1663 g_object_ref (simple));
1665 g_object_unref (source_object);
1668 g_object_unref (simple);
1672 * e_cal_client_connect:
1673 * @source: an #ESource
1674 * @source_type: source tpe of the calendar
1675 * @cancellable: (allow-none): optional #GCancellable object, or %NULL
1676 * @callback: (scope async): a #GAsyncReadyCallback to call when the request
1678 * @user_data: (closure): data to pass to the callback function
1680 * Asynchronously creates a new #ECalClient for @source and @source_type.
1682 * Unlike with e_cal_client_new(), there is no need to call e_client_open()
1683 * after obtaining the #ECalClient.
1685 * When the operation is finished, @callback will be called. You can then
1686 * call e_cal_client_connect_finish() to get the result of the operation.
1691 e_cal_client_connect (ESource *source,
1692 ECalClientSourceType source_type,
1693 GCancellable *cancellable,
1694 GAsyncReadyCallback callback,
1697 GSimpleAsyncResult *simple;
1698 ConnectClosure *closure;
1701 g_return_if_fail (E_IS_SOURCE (source));
1703 source_type == E_CAL_CLIENT_SOURCE_TYPE_EVENTS ||
1704 source_type == E_CAL_CLIENT_SOURCE_TYPE_TASKS ||
1705 source_type == E_CAL_CLIENT_SOURCE_TYPE_MEMOS);
1707 /* Two things with this: 1) instantiate the client object
1708 * immediately to make sure the thread-default GMainContext
1709 * gets plucked, and 2) do not call the D-Bus open() method
1710 * from our designated D-Bus thread -- it may take a long
1711 * time and block other clients from receiving signals. */
1713 closure = g_slice_new0 (ConnectClosure);
1714 closure->source = g_object_ref (source);
1716 if (G_IS_CANCELLABLE (cancellable))
1717 closure->cancellable = g_object_ref (cancellable);
1719 client = g_object_new (
1722 "source-type", source_type, NULL);
1724 simple = g_simple_async_result_new (
1725 G_OBJECT (client), callback,
1726 user_data, e_cal_client_connect);
1728 g_simple_async_result_set_check_cancellable (simple, cancellable);
1730 g_simple_async_result_set_op_res_gpointer (
1731 simple, closure, (GDestroyNotify) connect_closure_free);
1733 g_async_initable_init_async (
1734 G_ASYNC_INITABLE (client),
1735 G_PRIORITY_DEFAULT, cancellable,
1736 cal_client_connect_init_cb,
1737 g_object_ref (simple));
1739 g_object_unref (simple);
1740 g_object_unref (client);
1744 * e_cal_client_connect_finish:
1745 * @result: a #GAsyncResult
1746 * @error: return location for a #GError, or %NULL
1748 * Finishes the operation started with e_cal_client_connect(). If an
1749 * error occurs in connecting to the D-Bus service, the function sets
1750 * @error and returns %NULL.
1752 * For error handling convenience, any error message returned by this
1753 * function will have a descriptive prefix that includes the display
1754 * name of the #ESource passed to e_cal_client_connect().
1756 * Returns: a new #ECalClient, or %NULL
1761 e_cal_client_connect_finish (GAsyncResult *result,
1764 GSimpleAsyncResult *simple;
1765 ConnectClosure *closure;
1766 gpointer source_tag;
1768 g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), NULL);
1770 simple = G_SIMPLE_ASYNC_RESULT (result);
1771 closure = g_simple_async_result_get_op_res_gpointer (simple);
1773 source_tag = g_simple_async_result_get_source_tag (simple);
1774 g_return_val_if_fail (source_tag == e_cal_client_connect, NULL);
1776 if (g_simple_async_result_propagate_error (simple, error)) {
1778 error, _("Unable to connect to '%s': "),
1779 e_source_get_display_name (closure->source));
1783 return E_CLIENT (g_async_result_get_source_object (result));
1788 * @source: An #ESource pointer
1789 * @source_type: source type of the calendar
1790 * @error: A #GError pointer
1792 * Creates a new #ECalClient corresponding to the given source. There are
1793 * only two operations that are valid on this calendar at this point:
1794 * e_client_open(), and e_client_remove().
1796 * Returns: a new but unopened #ECalClient.
1800 * Deprecated: 3.8: It covertly makes synchronous D-Bus calls, with no
1801 * way to cancel. Use e_cal_client_connect() instead,
1802 * which combines e_cal_client_new() and e_client_open()
1806 e_cal_client_new (ESource *source,
1807 ECalClientSourceType source_type,
1810 g_return_val_if_fail (E_IS_SOURCE (source), NULL);
1811 g_return_val_if_fail (
1812 source_type == E_CAL_CLIENT_SOURCE_TYPE_EVENTS ||
1813 source_type == E_CAL_CLIENT_SOURCE_TYPE_TASKS ||
1814 source_type == E_CAL_CLIENT_SOURCE_TYPE_MEMOS, NULL);
1816 return g_initable_new (
1817 E_TYPE_CAL_CLIENT, NULL, error,
1819 "source-type", source_type, NULL);
1823 * e_cal_client_get_source_type:
1824 * @client: A calendar client.
1826 * Gets the source type of the calendar client.
1828 * Returns: an #ECalClientSourceType value corresponding
1829 * to the source type of the calendar client.
1833 ECalClientSourceType
1834 e_cal_client_get_source_type (ECalClient *client)
1836 g_return_val_if_fail (
1837 E_IS_CAL_CLIENT (client),
1838 E_CAL_CLIENT_SOURCE_TYPE_LAST);
1840 return client->priv->source_type;
1844 * e_cal_client_get_local_attachment_store:
1845 * @client: A calendar client.
1847 * Queries the URL where the calendar attachments are
1848 * serialized in the local filesystem. This enable clients
1849 * to operate with the reference to attachments rather than the data itself
1850 * unless it specifically uses the attachments for open/sending
1853 * Returns: The URL where the attachments are serialized in the
1859 e_cal_client_get_local_attachment_store (ECalClient *client)
1861 g_return_val_if_fail (E_IS_CAL_CLIENT (client), NULL);
1863 return e_dbus_calendar_get_cache_dir (client->priv->dbus_proxy);
1866 /* icaltimezone_copy does a shallow copy while icaltimezone_free tries to free the entire
1867 * the contents inside the structure with libical 0.43. Use this, till eds allows older libical.
1869 static icaltimezone *
1870 copy_timezone (icaltimezone *ozone)
1872 icaltimezone *zone = NULL;
1875 tzid = icaltimezone_get_tzid (ozone);
1877 if (g_strcmp0 (tzid, "UTC") != 0) {
1878 icalcomponent *comp;
1880 comp = icaltimezone_get_component (ozone);
1882 zone = icaltimezone_new ();
1883 icaltimezone_set_component (zone, icalcomponent_new_clone (comp));
1888 zone = icaltimezone_get_utc_timezone ();
1894 * e_cal_client_set_default_timezone:
1895 * @client: A calendar client.
1896 * @zone: A timezone object.
1898 * Sets the default timezone to use to resolve DATE and floating DATE-TIME
1899 * values. This will typically be from the user's timezone setting. Call this
1900 * before using any other object fetching functions.
1905 e_cal_client_set_default_timezone (ECalClient *client,
1908 g_return_if_fail (E_IS_CAL_CLIENT (client));
1909 g_return_if_fail (zone != NULL);
1911 if (client->priv->default_zone != icaltimezone_get_utc_timezone ())
1912 icaltimezone_free (client->priv->default_zone, 1);
1914 if (zone == icaltimezone_get_utc_timezone ())
1915 client->priv->default_zone = zone;
1917 client->priv->default_zone = copy_timezone (zone);
1921 * e_cal_client_get_default_timezone:
1922 * @client: A calendar client.
1924 * Returns: Default timezone previously set with e_cal_client_set_default_timezone().
1925 * Returned pointer is owned by the @client and should not be freed.
1930 e_cal_client_get_default_timezone (ECalClient *client)
1932 g_return_val_if_fail (E_IS_CAL_CLIENT (client), NULL);
1934 return client->priv->default_zone;
1938 * e_cal_client_check_one_alarm_only:
1939 * @client: A calendar client.
1941 * Checks if a calendar supports only one alarm per component.
1943 * Returns: TRUE if the calendar allows only one alarm, FALSE otherwise.
1948 e_cal_client_check_one_alarm_only (ECalClient *client)
1950 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
1952 return e_client_check_capability (
1954 CAL_STATIC_CAPABILITY_ONE_ALARM_ONLY);
1958 * e_cal_client_check_save_schedules:
1959 * @client: A calendar client.
1961 * Checks whether the calendar saves schedules.
1963 * Returns: TRUE if it saves schedules, FALSE otherwise.
1968 e_cal_client_check_save_schedules (ECalClient *client)
1970 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
1972 return e_client_check_capability (
1974 CAL_STATIC_CAPABILITY_SAVE_SCHEDULES);
1978 * e_cal_client_check_organizer_must_attend:
1979 * @client: A calendar client.
1981 * Checks if a calendar forces organizers of meetings to be also attendees.
1983 * Returns: TRUE if the calendar forces organizers to attend meetings,
1989 e_cal_client_check_organizer_must_attend (ECalClient *client)
1991 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
1993 return e_client_check_capability (
1995 CAL_STATIC_CAPABILITY_ORGANIZER_MUST_ATTEND);
1999 * e_cal_client_check_organizer_must_accept:
2000 * @client: A calendar client.
2002 * Checks whether a calendar requires organizer to accept their attendance to
2005 * Returns: TRUE if the calendar requires organizers to accept, FALSE
2011 e_cal_client_check_organizer_must_accept (ECalClient *client)
2013 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
2015 return e_client_check_capability (
2017 CAL_STATIC_CAPABILITY_ORGANIZER_MUST_ACCEPT);
2021 * e_cal_client_check_recurrences_no_master:
2022 * @client: A calendar client.
2024 * Checks if the calendar has a master object for recurrences.
2026 * Returns: TRUE if the calendar has a master object for recurrences,
2032 e_cal_client_check_recurrences_no_master (ECalClient *client)
2034 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
2036 return e_client_check_capability (
2038 CAL_STATIC_CAPABILITY_RECURRENCES_NO_MASTER);
2042 * e_cal_client_free_icalcomp_slist:
2043 * @icalcomps: (element-type icalcomponent): list of icalcomponent objects
2045 * Frees each element of the @icalcomps list and the list itself.
2046 * Each element is an object of type #icalcomponent.
2051 e_cal_client_free_icalcomp_slist (GSList *icalcomps)
2053 g_slist_foreach (icalcomps, (GFunc) icalcomponent_free, NULL);
2054 g_slist_free (icalcomps);
2058 * e_cal_client_free_ecalcomp_slist:
2059 * @ecalcomps: (element-type ECalComponent): list of #ECalComponent objects
2061 * Frees each element of the @ecalcomps list and the list itself.
2062 * Each element is an object of type #ECalComponent.
2067 e_cal_client_free_ecalcomp_slist (GSList *ecalcomps)
2069 g_slist_foreach (ecalcomps, (GFunc) g_object_unref, NULL);
2070 g_slist_free (ecalcomps);
2074 * e_cal_client_resolve_tzid_cb:
2075 * @tzid: ID of the timezone to resolve.
2076 * @data: Closure data for the callback, in this case #ECalClient.
2078 * Resolves TZIDs for the recurrence generator.
2080 * Returns: The timezone identified by the @tzid argument, or %NULL if
2081 * it could not be found.
2086 e_cal_client_resolve_tzid_cb (const gchar *tzid,
2089 ECalClient *client = data;
2090 icaltimezone *zone = NULL;
2091 GError *error = NULL;
2093 g_return_val_if_fail (E_IS_CAL_CLIENT (client), NULL);
2095 e_cal_client_get_timezone_sync (client, tzid, &zone, NULL, &error);
2098 g_debug ("%s: Failed to find '%s' timezone: %s", G_STRFUNC, tzid, error->message);
2099 g_error_free (error);
2105 struct comp_instance {
2106 ECalComponent *comp;
2111 struct instances_info {
2113 icaltimezone *start_zone;
2114 icaltimezone *end_zone;
2117 /* Called from cal_recur_generate_instances(); adds an instance to the list */
2119 add_instance (ECalComponent *comp,
2125 struct comp_instance *ci;
2126 icalcomponent *icalcomp;
2127 struct instances_info *instances_hold;
2129 instances_hold = data;
2130 list = instances_hold->instances;
2132 ci = g_new (struct comp_instance, 1);
2134 icalcomp = icalcomponent_new_clone (e_cal_component_get_icalcomponent (comp));
2136 /* add the instance to the list */
2137 ci->comp = e_cal_component_new ();
2138 e_cal_component_set_icalcomponent (ci->comp, icalcomp);
2140 /* make sure we return an instance */
2141 if (e_cal_util_component_has_recurrences (icalcomp) &&
2142 !(icalcomponent_get_first_property (icalcomp, ICAL_RECURRENCEID_PROPERTY))) {
2143 ECalComponentRange *range;
2144 struct icaltimetype itt;
2145 ECalComponentDateTime dtstart, dtend;
2147 /* update DTSTART */
2148 dtstart.value = NULL;
2149 dtstart.tzid = NULL;
2151 e_cal_component_get_dtstart (comp, &dtstart);
2153 if (instances_hold->start_zone) {
2154 itt = icaltime_from_timet_with_zone (start, dtstart.value && dtstart.value->is_date, instances_hold->start_zone);
2155 g_free ((gchar *) dtstart.tzid);
2156 dtstart.tzid = g_strdup (icaltimezone_get_tzid (instances_hold->start_zone));
2158 itt = icaltime_from_timet (start, dtstart.value && dtstart.value->is_date);
2160 g_free ((gchar *) dtstart.tzid);
2161 dtstart.tzid = NULL;
2165 g_free (dtstart.value);
2166 dtstart.value = &itt;
2167 e_cal_component_set_dtstart (ci->comp, &dtstart);
2169 /* set the RECUR-ID for the instance */
2170 range = g_new0 (ECalComponentRange, 1);
2171 range->type = E_CAL_COMPONENT_RANGE_SINGLE;
2172 range->datetime = dtstart;
2174 e_cal_component_set_recurid (ci->comp, range);
2177 g_free ((gchar *) dtstart.tzid);
2183 e_cal_component_get_dtend (comp, &dtend);
2185 if (instances_hold->end_zone) {
2186 itt = icaltime_from_timet_with_zone (end, dtend.value && dtend.value->is_date, instances_hold->end_zone);
2187 g_free ((gchar *) dtend.tzid);
2188 dtend.tzid = g_strdup (icaltimezone_get_tzid (instances_hold->end_zone));
2190 itt = icaltime_from_timet (end, dtend.value && dtend.value->is_date);
2192 g_free ((gchar *) dtend.tzid);
2197 g_free (dtend.value);
2199 e_cal_component_set_dtend (ci->comp, &dtend);
2201 g_free ((gchar *) dtend.tzid);
2207 *list = g_slist_prepend (*list, ci);
2212 /* Used from g_slist_sort(); compares two struct comp_instance structures */
2214 compare_comp_instance (gconstpointer a,
2217 const struct comp_instance *cia, *cib;
2223 diff = cia->start - cib->start;
2224 return (diff < 0) ? -1 : (diff > 0) ? 1 : 0;
2228 process_detached_instances (GSList *instances,
2229 GSList *detached_instances)
2231 struct comp_instance *ci, *cid;
2232 GSList *dl, *unprocessed_instances = NULL;
2234 for (dl = detached_instances; dl != NULL; dl = dl->next) {
2238 ECalComponentRange recur_id, instance_recur_id;
2241 recur_id.type = E_CAL_COMPONENT_RANGE_SINGLE;
2242 instance_recur_id.type = E_CAL_COMPONENT_RANGE_SINGLE;
2245 e_cal_component_get_uid (cid->comp, &uid);
2246 e_cal_component_get_recurid (cid->comp, &recur_id);
2248 /* search for coincident instances already expanded */
2249 for (il = instances; il != NULL; il = il->next) {
2250 const gchar *instance_uid;
2254 e_cal_component_get_uid (ci->comp, &instance_uid);
2255 e_cal_component_get_recurid (ci->comp, &instance_recur_id);
2256 if (strcmp (uid, instance_uid) == 0) {
2257 gchar *i_rid = NULL, *d_rid = NULL;
2259 i_rid = e_cal_component_get_recurid_as_string (ci->comp);
2260 d_rid = e_cal_component_get_recurid_as_string (cid->comp);
2262 if (i_rid && d_rid && strcmp (i_rid, d_rid) == 0) {
2263 g_object_unref (ci->comp);
2264 ci->comp = g_object_ref (cid->comp);
2265 ci->start = cid->start;
2270 if (!instance_recur_id.datetime.value ||
2271 !recur_id.datetime.value) {
2273 * Prevent obvious segfault by ignoring missing
2274 * recurrency ids. Real problem might be elsewhere,
2275 * but anything is better than crashing...
2279 G_LOG_LEVEL_CRITICAL,
2280 "UID %s: instance RECURRENCE-ID %s + detached instance RECURRENCE-ID %s: cannot compare",
2285 e_cal_component_free_datetime (&instance_recur_id.datetime);
2290 cmp = icaltime_compare (
2291 *instance_recur_id.datetime.value,
2292 *recur_id.datetime.value);
2293 if ((recur_id.type == E_CAL_COMPONENT_RANGE_THISPRIOR && cmp <= 0) ||
2294 (recur_id.type == E_CAL_COMPONENT_RANGE_THISFUTURE && cmp >= 0)) {
2295 ECalComponent *comp;
2297 comp = e_cal_component_new ();
2298 e_cal_component_set_icalcomponent (
2300 icalcomponent_new_clone (e_cal_component_get_icalcomponent (cid->comp)));
2301 e_cal_component_set_recurid (comp, &instance_recur_id);
2303 /* replace the generated instances */
2304 g_object_unref (ci->comp);
2311 e_cal_component_free_datetime (&instance_recur_id.datetime);
2314 e_cal_component_free_datetime (&recur_id.datetime);
2317 unprocessed_instances = g_slist_prepend (unprocessed_instances, cid);
2320 /* add the unprocessed instances (ie, detached instances with no master object */
2321 while (unprocessed_instances != NULL) {
2322 cid = unprocessed_instances->data;
2323 ci = g_new0 (struct comp_instance, 1);
2324 ci->comp = g_object_ref (cid->comp);
2325 ci->start = cid->start;
2327 instances = g_slist_append (instances, ci);
2329 unprocessed_instances = g_slist_remove (unprocessed_instances, cid);
2336 generate_instances (ECalClient *client,
2340 GCancellable *cancellable,
2341 ECalRecurInstanceFn cb,
2344 GSList *instances, *detached_instances = NULL;
2346 ECalClientPrivate *priv;
2348 priv = client->priv;
2352 for (l = objects; l && !g_cancellable_is_cancelled (cancellable); l = l->next) {
2353 ECalComponent *comp;
2354 icaltimezone *default_zone;
2356 if (priv->default_zone)
2357 default_zone = priv->default_zone;
2359 default_zone = icaltimezone_get_utc_timezone ();
2362 if (e_cal_component_is_instance (comp)) {
2363 struct comp_instance *ci;
2364 ECalComponentDateTime dtstart, dtend;
2365 icaltimezone *start_zone = NULL, *end_zone = NULL;
2367 /* keep the detached instances apart */
2368 ci = g_new0 (struct comp_instance, 1);
2369 ci->comp = g_object_ref (comp);
2371 e_cal_component_get_dtstart (comp, &dtstart);
2372 e_cal_component_get_dtend (comp, &dtend);
2374 /* For DATE-TIME values with a TZID, we use
2375 * e_cal_resolve_tzid_cb to resolve the TZID.
2376 * For DATE values and DATE-TIME values without a
2377 * TZID (i.e. floating times) we use the default
2379 if (dtstart.tzid && dtstart.value && !dtstart.value->is_date) {
2380 start_zone = e_cal_client_resolve_tzid_cb (dtstart.tzid, client);
2382 start_zone = default_zone;
2384 start_zone = default_zone;
2387 if (dtend.tzid && dtend.value && !dtend.value->is_date) {
2388 end_zone = e_cal_client_resolve_tzid_cb (dtend.tzid, client);
2390 end_zone = default_zone;
2392 end_zone = default_zone;
2395 ci->start = icaltime_as_timet_with_zone (*dtstart.value, start_zone);
2398 ci->end = icaltime_as_timet_with_zone (*dtend.value, end_zone);
2399 else if (icaltime_is_date (*dtstart.value))
2400 ci->end = time_day_end (ci->start);
2402 ci->end = ci->start;
2404 e_cal_component_free_datetime (&dtstart);
2405 e_cal_component_free_datetime (&dtend);
2407 if (ci->start <= end && ci->end >= start) {
2408 detached_instances = g_slist_prepend (detached_instances, ci);
2410 /* it doesn't fit to our time range, thus skip it */
2411 g_object_unref (G_OBJECT (ci->comp));
2415 ECalComponentDateTime datetime;
2416 icaltimezone *start_zone = NULL, *end_zone = NULL;
2417 struct instances_info *instances_hold;
2419 /* Get the start timezone */
2420 e_cal_component_get_dtstart (comp, &datetime);
2422 e_cal_client_get_timezone_sync (client, datetime.tzid, &start_zone, cancellable, NULL);
2425 e_cal_component_free_datetime (&datetime);
2427 /* Get the end timezone */
2428 e_cal_component_get_dtend (comp, &datetime);
2430 e_cal_client_get_timezone_sync (client, datetime.tzid, &end_zone, cancellable, NULL);
2433 e_cal_component_free_datetime (&datetime);
2435 instances_hold = g_new0 (struct instances_info, 1);
2436 instances_hold->instances = &instances;
2437 instances_hold->start_zone = start_zone;
2438 instances_hold->end_zone = end_zone;
2440 e_cal_recur_generate_instances (
2441 comp, start, end, add_instance, instances_hold,
2442 e_cal_client_resolve_tzid_cb, client,
2445 g_free (instances_hold);
2449 g_slist_foreach (objects, (GFunc) g_object_unref, NULL);
2450 g_slist_free (objects);
2452 /* Generate instances and spew them out */
2454 if (!g_cancellable_is_cancelled (cancellable)) {
2455 instances = g_slist_sort (instances, compare_comp_instance);
2456 instances = process_detached_instances (instances, detached_instances);
2459 for (l = instances; l && !g_cancellable_is_cancelled (cancellable); l = l->next) {
2460 struct comp_instance *ci;
2465 result = (* cb) (ci->comp, ci->start, ci->end, cb_data);
2473 for (l = instances; l; l = l->next) {
2474 struct comp_instance *ci;
2477 g_object_unref (G_OBJECT (ci->comp));
2481 g_slist_free (instances);
2483 for (l = detached_instances; l; l = l->next) {
2484 struct comp_instance *ci;
2487 g_object_unref (G_OBJECT (ci->comp));
2491 g_slist_free (detached_instances);
2495 get_objects_sync (ECalClient *client,
2500 GSList *objects = NULL;
2502 /* Generate objects */
2504 GError *error = NULL;
2506 if (!e_cal_client_get_objects_for_uid_sync (client, uid, &objects, NULL, &error)) {
2507 unwrap_dbus_error (error, &error);
2508 g_message ("Failed to get recurrence objects for uid %s \n", error ? error->message : "Unknown error");
2509 g_clear_error (&error);
2513 gchar *iso_start, *iso_end;
2516 iso_start = isodate_from_time_t (start);
2520 iso_end = isodate_from_time_t (end);
2526 query = g_strdup_printf (
2527 "(occur-in-time-range? (make-time \"%s\") (make-time \"%s\"))",
2528 iso_start, iso_end);
2531 if (!e_cal_client_get_object_list_as_comps_sync (client, query, &objects, NULL, NULL)) {
2541 struct get_objects_async_data
2543 GCancellable *cancellable;
2547 ECalRecurInstanceFn cb;
2549 GDestroyNotify destroy_cb_data;
2553 void (* ready_cb) (struct get_objects_async_data *goad, GSList *objects);
2554 icaltimezone *start_zone;
2555 icaltimezone *end_zone;
2556 ECalComponent *comp;
2560 free_get_objects_async_data (struct get_objects_async_data *goad)
2565 if (goad->cancellable)
2566 g_object_unref (goad->cancellable);
2567 if (goad->destroy_cb_data)
2568 goad->destroy_cb_data (goad->cb_data);
2570 g_object_unref (goad->client);
2572 g_object_unref (goad->comp);
2573 g_free (goad->query);
2579 got_objects_for_uid_cb (GObject *source_object,
2580 GAsyncResult *result,
2583 struct get_objects_async_data *goad = user_data;
2584 GSList *objects = NULL;
2585 GError *error = NULL;
2587 g_return_if_fail (source_object != NULL);
2588 g_return_if_fail (result != NULL);
2589 g_return_if_fail (goad != NULL);
2590 g_return_if_fail (goad->client == E_CAL_CLIENT (source_object));
2592 if (!e_cal_client_get_objects_for_uid_finish (goad->client, result, &objects, &error)) {
2593 if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED) ||
2594 g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
2595 free_get_objects_async_data (goad);
2596 g_clear_error (&error);
2600 g_clear_error (&error);
2604 g_return_if_fail (goad->ready_cb != NULL);
2606 /* takes care of the objects and goad */
2607 goad->ready_cb (goad, objects);
2611 got_object_list_as_comps_cb (GObject *source_object,
2612 GAsyncResult *result,
2615 struct get_objects_async_data *goad = user_data;
2616 GSList *objects = NULL;
2617 GError *error = NULL;
2619 g_return_if_fail (source_object != NULL);
2620 g_return_if_fail (result != NULL);
2621 g_return_if_fail (goad != NULL);
2622 g_return_if_fail (goad->client == E_CAL_CLIENT (source_object));
2624 if (!e_cal_client_get_object_list_as_comps_finish (goad->client, result, &objects, &error)) {
2625 if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED) ||
2626 g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
2627 free_get_objects_async_data (goad);
2628 g_clear_error (&error);
2632 g_clear_error (&error);
2636 g_return_if_fail (goad->ready_cb != NULL);
2638 /* takes care of the objects and goad */
2639 goad->ready_cb (goad, objects);
2642 /* ready_cb may take care of both arguments, goad and objects; objects can be also NULL */
2644 get_objects_async (void (*ready_cb) (struct get_objects_async_data *goad,
2646 struct get_objects_async_data *goad)
2648 g_return_if_fail (ready_cb != NULL);
2649 g_return_if_fail (goad != NULL);
2651 goad->ready_cb = ready_cb;
2653 if (goad->uid && *goad->uid) {
2654 e_cal_client_get_objects_for_uid (goad->client, goad->uid, goad->cancellable, got_objects_for_uid_cb, goad);
2656 gchar *iso_start, *iso_end;
2658 iso_start = isodate_from_time_t (goad->start);
2660 free_get_objects_async_data (goad);
2664 iso_end = isodate_from_time_t (goad->end);
2667 free_get_objects_async_data (goad);
2671 goad->query = g_strdup_printf ("(occur-in-time-range? (make-time \"%s\") (make-time \"%s\"))", iso_start, iso_end);
2676 e_cal_client_get_object_list_as_comps (goad->client, goad->query, goad->cancellable, got_object_list_as_comps_cb, goad);
2681 generate_instances_got_objects_cb (struct get_objects_async_data *goad,
2684 g_return_if_fail (goad != NULL);
2686 /* generate_instaces () frees 'objects' slist */
2688 generate_instances (goad->client, goad->start, goad->end, objects, goad->cancellable, goad->cb, goad->cb_data);
2690 free_get_objects_async_data (goad);
2694 * e_cal_client_generate_instances:
2695 * @client: A calendar client.
2696 * @start: Start time for query.
2697 * @end: End time for query.
2698 * @cancellable: a #GCancellable; can be %NULL
2699 * @cb: Callback for each generated instance.
2700 * @cb_data: Closure data for the callback.
2701 * @destroy_cb_data: Function to call when the processing is done, to free @cb_data; can be %NULL.
2703 * Does a combination of e_cal_client_get_object_list() and
2704 * e_cal_client_recur_generate_instances(). Unlike e_cal_client_generate_instances_sync(),
2705 * this returns immediately and the @cb callback is called asynchronously.
2707 * The callback function should do a g_object_ref() of the calendar component
2708 * it gets passed if it intends to keep it around, since it will be unref'ed
2709 * as soon as the callback returns.
2714 e_cal_client_generate_instances (ECalClient *client,
2717 GCancellable *cancellable,
2718 ECalRecurInstanceFn cb,
2720 GDestroyNotify destroy_cb_data)
2722 struct get_objects_async_data *goad;
2723 GCancellable *use_cancellable;
2725 g_return_if_fail (E_IS_CAL_CLIENT (client));
2727 g_return_if_fail (start >= 0);
2728 g_return_if_fail (end >= 0);
2729 g_return_if_fail (cb != NULL);
2731 use_cancellable = cancellable;
2732 if (!use_cancellable)
2733 use_cancellable = g_cancellable_new ();
2735 goad = g_new0 (struct get_objects_async_data, 1);
2736 goad->cancellable = g_object_ref (use_cancellable);
2737 goad->client = g_object_ref (client);
2738 goad->start = start;
2741 goad->cb_data = cb_data;
2742 goad->destroy_cb_data = destroy_cb_data;
2744 get_objects_async (generate_instances_got_objects_cb, goad);
2746 if (use_cancellable != cancellable)
2747 g_object_unref (use_cancellable);
2751 * e_cal_client_generate_instances_sync:
2752 * @client: A calendar client
2753 * @start: Start time for query
2754 * @end: End time for query
2755 * @cb: (closure cb_data) (scope call): Callback for each generated instance
2756 * @cb_data: (closure): Closure data for the callback
2758 * Does a combination of e_cal_client_get_object_list() and
2759 * e_cal_client_recur_generate_instances().
2761 * The callback function should do a g_object_ref() of the calendar component
2762 * it gets passed if it intends to keep it around, since it will be unreffed
2763 * as soon as the callback returns.
2768 e_cal_client_generate_instances_sync (ECalClient *client,
2771 ECalRecurInstanceFn cb,
2774 GSList *objects = NULL;
2776 g_return_if_fail (E_IS_CAL_CLIENT (client));
2778 g_return_if_fail (start >= 0);
2779 g_return_if_fail (end >= 0);
2780 g_return_if_fail (cb != NULL);
2782 objects = get_objects_sync (client, start, end, NULL);
2786 /* generate_instaces frees 'objects' slist */
2787 generate_instances (client, start, end, objects, NULL, cb, cb_data);
2790 /* also frees 'instances' GSList */
2792 process_instances (ECalComponent *comp,
2794 ECalRecurInstanceFn cb,
2800 g_return_if_fail (comp != NULL);
2801 g_return_if_fail (cb != NULL);
2803 rid = e_cal_component_get_recurid_as_string (comp);
2805 /* Reverse the instances list because the add_instance() function is prepending */
2806 instances = g_slist_reverse (instances);
2808 /* now only return back the instances for the given object */
2810 while (instances != NULL) {
2811 struct comp_instance *ci;
2812 gchar *instance_rid = NULL;
2814 ci = instances->data;
2817 instance_rid = e_cal_component_get_recurid_as_string (ci->comp);
2820 if (instance_rid && *instance_rid && strcmp (rid, instance_rid) == 0)
2821 result = (* cb) (ci->comp, ci->start, ci->end, cb_data);
2823 result = (* cb) (ci->comp, ci->start, ci->end, cb_data);
2826 /* remove instance from list */
2827 instances = g_slist_remove (instances, ci);
2828 g_object_unref (ci->comp);
2830 g_free (instance_rid);
2838 generate_instances_for_object_got_objects_cb (struct get_objects_async_data *goad,
2841 struct instances_info *instances_hold;
2842 GSList *instances = NULL;
2844 g_return_if_fail (goad != NULL);
2846 instances_hold = g_new0 (struct instances_info, 1);
2847 instances_hold->instances = &instances;
2848 instances_hold->start_zone = goad->start_zone;
2849 instances_hold->end_zone = goad->end_zone;
2851 /* generate all instances in the given time range */
2852 generate_instances (goad->client, goad->start, goad->end, objects, goad->cancellable, add_instance, instances_hold);
2854 /* it also frees 'instances' GSList */
2855 process_instances (goad->comp, *(instances_hold->instances), goad->cb, goad->cb_data);
2858 free_get_objects_async_data (goad);
2859 g_free (instances_hold);
2863 * e_cal_client_generate_instances_for_object:
2864 * @client: A calendar client.
2865 * @icalcomp: Object to generate instances from.
2866 * @start: Start time for query.
2867 * @end: End time for query.
2868 * @cancellable: a #GCancellable; can be %NULL
2869 * @cb: Callback for each generated instance.
2870 * @cb_data: Closure data for the callback.
2871 * @destroy_cb_data: Function to call when the processing is done, to free @cb_data; can be %NULL.
2873 * Does a combination of e_cal_client_get_object_list() and
2874 * e_cal_client_recur_generate_instances(), like e_cal_client_generate_instances(), but
2875 * for a single object. Unlike e_cal_client_generate_instances_for_object_sync(),
2876 * this returns immediately and the @cb callback is called asynchronously.
2878 * The callback function should do a g_object_ref() of the calendar component
2879 * it gets passed if it intends to keep it around, since it will be unref'ed
2880 * as soon as the callback returns.
2885 e_cal_client_generate_instances_for_object (ECalClient *client,
2886 icalcomponent *icalcomp,
2889 GCancellable *cancellable,
2890 ECalRecurInstanceFn cb,
2892 GDestroyNotify destroy_cb_data)
2894 ECalComponent *comp;
2896 ECalComponentDateTime datetime;
2897 icaltimezone *start_zone = NULL, *end_zone = NULL;
2898 gboolean is_single_instance = FALSE;
2899 struct get_objects_async_data *goad;
2900 GCancellable *use_cancellable;
2902 g_return_if_fail (E_IS_CAL_CLIENT (client));
2904 g_return_if_fail (start >= 0);
2905 g_return_if_fail (end >= 0);
2906 g_return_if_fail (cb != NULL);
2908 comp = e_cal_component_new ();
2909 e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (icalcomp));
2911 if (!e_cal_component_has_recurrences (comp))
2912 is_single_instance = TRUE;
2914 /* If the backend stores it as individual instances and does not
2915 * have a master object - do not expand */
2916 if (is_single_instance || e_client_check_capability (E_CLIENT (client), CAL_STATIC_CAPABILITY_RECURRENCES_NO_MASTER)) {
2917 /* return the same instance */
2918 (* cb) (comp, icaltime_as_timet_with_zone (icalcomponent_get_dtstart (icalcomp), client->priv->default_zone),
2919 icaltime_as_timet_with_zone (icalcomponent_get_dtend (icalcomp), client->priv->default_zone), cb_data);
2920 g_object_unref (comp);
2922 if (destroy_cb_data)
2923 destroy_cb_data (cb_data);
2927 e_cal_component_get_uid (comp, &uid);
2929 /* Get the start timezone */
2930 e_cal_component_get_dtstart (comp, &datetime);
2932 e_cal_client_get_timezone_sync (client, datetime.tzid, &start_zone, NULL, NULL);
2935 e_cal_component_free_datetime (&datetime);
2937 /* Get the end timezone */
2938 e_cal_component_get_dtend (comp, &datetime);
2940 e_cal_client_get_timezone_sync (client, datetime.tzid, &end_zone, NULL, NULL);
2943 e_cal_component_free_datetime (&datetime);
2945 use_cancellable = cancellable;
2946 if (!use_cancellable)
2947 use_cancellable = g_cancellable_new ();
2949 goad = g_new0 (struct get_objects_async_data, 1);
2950 goad->cancellable = g_object_ref (use_cancellable);
2951 goad->client = g_object_ref (client);
2952 goad->start = start;
2955 goad->cb_data = cb_data;
2956 goad->destroy_cb_data = destroy_cb_data;
2957 goad->start_zone = start_zone;
2958 goad->end_zone = end_zone;
2960 goad->uid = g_strdup (uid);
2962 get_objects_async (generate_instances_for_object_got_objects_cb, goad);
2964 if (use_cancellable != cancellable)
2965 g_object_unref (use_cancellable);
2969 * e_cal_client_generate_instances_for_object_sync:
2970 * @client: A calendar client
2971 * @icalcomp: Object to generate instances from
2972 * @start: Start time for query
2973 * @end: End time for query
2974 * @cb: (closure cb_data) (scope call): Callback for each generated instance
2975 * @cb_data: (closure): Closure data for the callback
2977 * Does a combination of e_cal_client_get_object_list() and
2978 * e_cal_client_recur_generate_instances(), like e_cal_client_generate_instances_sync(), but
2979 * for a single object.
2981 * The callback function should do a g_object_ref() of the calendar component
2982 * it gets passed if it intends to keep it around, since it will be unref'ed
2983 * as soon as the callback returns.
2988 e_cal_client_generate_instances_for_object_sync (ECalClient *client,
2989 icalcomponent *icalcomp,
2992 ECalRecurInstanceFn cb,
2995 ECalComponent *comp;
2997 GSList *instances = NULL;
2998 ECalComponentDateTime datetime;
2999 icaltimezone *start_zone = NULL, *end_zone = NULL;
3000 struct instances_info *instances_hold;
3001 gboolean is_single_instance = FALSE;
3003 g_return_if_fail (E_IS_CAL_CLIENT (client));
3005 g_return_if_fail (start >= 0);
3006 g_return_if_fail (end >= 0);
3007 g_return_if_fail (cb != NULL);
3009 comp = e_cal_component_new ();
3010 e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (icalcomp));
3012 if (!e_cal_component_has_recurrences (comp))
3013 is_single_instance = TRUE;
3015 /* If the backend stores it as individual instances and does not
3016 * have a master object - do not expand */
3017 if (is_single_instance || e_client_check_capability (E_CLIENT (client), CAL_STATIC_CAPABILITY_RECURRENCES_NO_MASTER)) {
3018 /* return the same instance */
3019 (* cb) (comp, icaltime_as_timet_with_zone (icalcomponent_get_dtstart (icalcomp), client->priv->default_zone),
3020 icaltime_as_timet_with_zone (icalcomponent_get_dtend (icalcomp), client->priv->default_zone), cb_data);
3021 g_object_unref (comp);
3025 e_cal_component_get_uid (comp, &uid);
3027 /* Get the start timezone */
3028 e_cal_component_get_dtstart (comp, &datetime);
3030 e_cal_client_get_timezone_sync (client, datetime.tzid, &start_zone, NULL, NULL);
3033 e_cal_component_free_datetime (&datetime);
3035 /* Get the end timezone */
3036 e_cal_component_get_dtend (comp, &datetime);
3038 e_cal_client_get_timezone_sync (client, datetime.tzid, &end_zone, NULL, NULL);
3041 e_cal_component_free_datetime (&datetime);
3043 instances_hold = g_new0 (struct instances_info, 1);
3044 instances_hold->instances = &instances;
3045 instances_hold->start_zone = start_zone;
3046 instances_hold->end_zone = end_zone;
3048 /* generate all instances in the given time range */
3049 generate_instances (client, start, end, get_objects_sync (client, start, end, uid), NULL, add_instance, instances_hold);
3051 /* it also frees 'instances' GSList */
3052 process_instances (comp, *(instances_hold->instances), cb, cb_data);
3055 g_object_unref (comp);
3056 g_free (instances_hold);
3059 typedef struct _ForeachTZIDCallbackData ForeachTZIDCallbackData;
3060 struct _ForeachTZIDCallbackData {
3062 GHashTable *timezone_hash;
3066 /* This adds the VTIMEZONE given by the TZID parameter to the GHashTable in
3069 foreach_tzid_callback (icalparameter *param,
3072 ForeachTZIDCallbackData *data = cbdata;
3074 icaltimezone *zone = NULL;
3075 icalcomponent *vtimezone_comp;
3076 gchar *vtimezone_as_string;
3078 /* Get the TZID string from the parameter. */
3079 tzid = icalparameter_get_tzid (param);
3083 /* Check if we've already added it to the GHashTable. */
3084 if (g_hash_table_lookup (data->timezone_hash, tzid))
3087 if (!e_cal_client_get_timezone_sync (data->client, tzid, &zone, NULL, NULL) || !zone) {
3088 data->success = FALSE;
3092 /* Convert it to a string and add it to the hash. */
3093 vtimezone_comp = icaltimezone_get_component (zone);
3094 if (!vtimezone_comp)
3097 vtimezone_as_string = icalcomponent_as_ical_string_r (vtimezone_comp);
3099 g_hash_table_insert (data->timezone_hash, (gchar *) tzid, vtimezone_as_string);
3102 /* This appends the value string to the GString given in data. */
3104 append_timezone_string (gpointer key,
3108 GString *vcal_string = data;
3110 g_string_append (vcal_string, value);
3114 /* This simply frees the hash values. */
3116 free_timezone_string (gpointer key,
3124 * e_cal_client_get_component_as_string:
3125 * @client: A calendar client.
3126 * @icalcomp: A calendar component object.
3128 * Gets a calendar component as an iCalendar string, with a toplevel
3129 * VCALENDAR component and all VTIMEZONEs needed for the component.
3131 * Returns: the component as a complete iCalendar string, or NULL on
3132 * failure. The string should be freed with g_free().
3137 e_cal_client_get_component_as_string (ECalClient *client,
3138 icalcomponent *icalcomp)
3140 GHashTable *timezone_hash;
3141 GString *vcal_string;
3142 ForeachTZIDCallbackData cbdata;
3145 g_return_val_if_fail (E_IS_CAL_CLIENT (client), NULL);
3146 g_return_val_if_fail (icalcomp != NULL, NULL);
3148 timezone_hash = g_hash_table_new (g_str_hash, g_str_equal);
3150 /* Add any timezones needed to the hash. We use a hash since we only
3151 * want to add each timezone once at most. */
3152 cbdata.client = client;
3153 cbdata.timezone_hash = timezone_hash;
3154 cbdata.success = TRUE;
3155 icalcomponent_foreach_tzid (icalcomp, foreach_tzid_callback, &cbdata);
3156 if (!cbdata.success) {
3157 g_hash_table_foreach (timezone_hash, free_timezone_string, NULL);
3161 /* Create the start of a VCALENDAR, to add the VTIMEZONES to,
3162 * and remember its length so we know if any VTIMEZONEs get added. */
3163 vcal_string = g_string_new (NULL);
3167 "PRODID:-//Ximian//NONSGML Evolution Calendar//EN\n"
3169 "METHOD:PUBLISH\n");
3171 /* Now concatenate all the timezone strings. This also frees the
3172 * timezone strings as it goes. */
3173 g_hash_table_foreach (timezone_hash, append_timezone_string, vcal_string);
3175 /* Get the string for the VEVENT/VTODO. */
3176 obj_string = icalcomponent_as_ical_string_r (icalcomp);
3178 /* If there were any timezones to send, create a complete VCALENDAR,
3179 * else just send the VEVENT/VTODO string. */
3180 g_string_append (vcal_string, obj_string);
3181 g_string_append (vcal_string, "END:VCALENDAR\n");
3182 g_free (obj_string);
3184 obj_string = g_string_free (vcal_string, FALSE);
3186 g_hash_table_destroy (timezone_hash);
3191 /* Helper for e_cal_client_get_default_object() */
3193 cal_client_get_default_object_thread (GSimpleAsyncResult *simple,
3194 GObject *source_object,
3195 GCancellable *cancellable)
3197 AsyncContext *async_context;
3198 GError *error = NULL;
3200 async_context = g_simple_async_result_get_op_res_gpointer (simple);
3202 e_cal_client_get_default_object_sync (
3203 E_CAL_CLIENT (source_object),
3204 &async_context->out_comp,
3205 cancellable, &error);
3208 g_simple_async_result_take_error (simple, error);
3212 * e_cal_client_get_default_object:
3213 * @client: an #ECalClient
3214 * @cancellable: a #GCancellable; can be %NULL
3215 * @callback: callback to call when a result is ready
3216 * @user_data: user data for the @callback
3218 * Retrives an #icalcomponent from the backend that contains the default
3219 * values for properties needed. The call is finished
3220 * by e_cal_client_get_default_object_finish() from the @callback.
3225 e_cal_client_get_default_object (ECalClient *client,
3226 GCancellable *cancellable,
3227 GAsyncReadyCallback callback,
3230 GSimpleAsyncResult *simple;
3231 AsyncContext *async_context;
3233 g_return_if_fail (E_IS_CAL_CLIENT (client));
3235 async_context = g_slice_new0 (AsyncContext);
3237 simple = g_simple_async_result_new (
3238 G_OBJECT (client), callback, user_data,
3239 e_cal_client_get_default_object);
3241 g_simple_async_result_set_check_cancellable (simple, cancellable);
3243 g_simple_async_result_set_op_res_gpointer (
3244 simple, async_context, (GDestroyNotify) async_context_free);
3246 g_simple_async_result_run_in_thread (
3247 simple, cal_client_get_default_object_thread,
3248 G_PRIORITY_DEFAULT, cancellable);
3250 g_object_unref (simple);
3254 * e_cal_client_get_default_object_finish:
3255 * @client: an #ECalClient
3256 * @result: a #GAsyncResult
3257 * @out_icalcomp: (out): Return value for the default calendar object.
3258 * @error: (out): a #GError to set an error, if any
3260 * Finishes previous call of e_cal_client_get_default_object() and
3261 * sets @out_icalcomp to an #icalcomponent from the backend that contains
3262 * the default values for properties needed. This @out_icalcomp should be
3263 * freed with icalcomponent_free().
3265 * Returns: %TRUE if successful, %FALSE otherwise.
3270 e_cal_client_get_default_object_finish (ECalClient *client,
3271 GAsyncResult *result,
3272 icalcomponent **out_icalcomp,
3275 GSimpleAsyncResult *simple;
3276 AsyncContext *async_context;
3278 g_return_val_if_fail (
3279 g_simple_async_result_is_valid (
3280 result, G_OBJECT (client),
3281 e_cal_client_get_default_object), FALSE);
3283 simple = G_SIMPLE_ASYNC_RESULT (result);
3284 async_context = g_simple_async_result_get_op_res_gpointer (simple);
3286 if (g_simple_async_result_propagate_error (simple, error))
3289 g_return_val_if_fail (async_context->out_comp != NULL, FALSE);
3291 if (out_icalcomp != NULL) {
3292 *out_icalcomp = async_context->out_comp;
3293 async_context->out_comp = NULL;
3300 * e_cal_client_get_default_object_sync:
3301 * @client: an #ECalClient
3302 * @out_icalcomp: (out): Return value for the default calendar object.
3303 * @cancellable: a #GCancellable; can be %NULL
3304 * @error: (out): a #GError to set an error, if any
3306 * Retrives an #icalcomponent from the backend that contains the default
3307 * values for properties needed. This @out_icalcomp should be freed with
3308 * icalcomponent_free().
3310 * Returns: %TRUE if successful, %FALSE otherwise.
3315 e_cal_client_get_default_object_sync (ECalClient *client,
3316 icalcomponent **out_icalcomp,
3317 GCancellable *cancellable,
3320 icalcomponent *icalcomp = NULL;
3323 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
3324 g_return_val_if_fail (out_icalcomp != NULL, FALSE);
3326 if (client->priv->dbus_proxy == NULL) {
3327 set_proxy_gone_error (error);
3331 string = e_dbus_calendar_dup_default_object (client->priv->dbus_proxy);
3332 if (string != NULL) {
3333 icalcomp = icalparser_parse_string (string);
3337 if (icalcomp == NULL) {
3338 g_set_error_literal (
3339 error, E_CAL_CLIENT_ERROR,
3340 E_CAL_CLIENT_ERROR_INVALID_OBJECT,
3341 e_cal_client_error_to_string (
3342 E_CAL_CLIENT_ERROR_INVALID_OBJECT));
3346 if (icalcomponent_get_uid (icalcomp) != NULL) {
3349 /* Make sure the UID is always unique. */
3350 new_uid = e_cal_component_gen_uid ();
3351 icalcomponent_set_uid (icalcomp, new_uid);
3355 *out_icalcomp = icalcomp;
3360 /* Helper for e_cal_client_get_object() */
3362 cal_client_get_object_thread (GSimpleAsyncResult *simple,
3363 GObject *source_object,
3364 GCancellable *cancellable)
3366 AsyncContext *async_context;
3367 GError *error = NULL;
3369 async_context = g_simple_async_result_get_op_res_gpointer (simple);
3371 e_cal_client_get_object_sync (
3372 E_CAL_CLIENT (source_object),
3375 &async_context->out_comp,
3376 cancellable, &error);
3379 g_simple_async_result_take_error (simple, error);
3383 * e_cal_client_get_object:
3384 * @client: an #ECalClient
3385 * @uid: Unique identifier for a calendar component.
3386 * @rid: Recurrence identifier.
3387 * @cancellable: a #GCancellable; can be %NULL
3388 * @callback: callback to call when a result is ready
3389 * @user_data: user data for the @callback
3391 * Queries a calendar for a calendar component object based on its unique
3392 * identifier. The call is finished by e_cal_client_get_object_finish()
3393 * from the @callback.
3395 * Use e_cal_client_get_objects_for_uid() to get list of all
3396 * objects for the given uid, which includes master object and
3397 * all detached instances.
3402 e_cal_client_get_object (ECalClient *client,
3405 GCancellable *cancellable,
3406 GAsyncReadyCallback callback,
3409 GSimpleAsyncResult *simple;
3410 AsyncContext *async_context;
3412 g_return_if_fail (E_IS_CAL_CLIENT (client));
3413 g_return_if_fail (uid != NULL);
3414 /* rid is optional */
3416 async_context = g_slice_new0 (AsyncContext);
3417 async_context->uid = g_strdup (uid);
3418 async_context->rid = g_strdup (rid);
3420 simple = g_simple_async_result_new (
3421 G_OBJECT (client), callback, user_data,
3422 e_cal_client_get_object);
3424 g_simple_async_result_set_check_cancellable (simple, cancellable);
3426 g_simple_async_result_set_op_res_gpointer (
3427 simple, async_context, (GDestroyNotify) async_context_free);
3429 g_simple_async_result_run_in_thread (
3430 simple, cal_client_get_object_thread,
3431 G_PRIORITY_DEFAULT, cancellable);
3433 g_object_unref (simple);
3437 * e_cal_client_get_object_finish:
3438 * @client: an #ECalClient
3439 * @result: a #GAsyncResult
3440 * @out_icalcomp: (out): Return value for the calendar component object.
3441 * @error: (out): a #GError to set an error, if any
3443 * Finishes previous call of e_cal_client_get_object() and
3444 * sets @out_icalcomp to queried component. This function always returns
3445 * master object for a case of @rid being NULL or an empty string.
3446 * This component should be freed with icalcomponent_free().
3448 * Use e_cal_client_get_objects_for_uid() to get list of all
3449 * objects for the given uid, which includes master object and
3450 * all detached instances.
3452 * Returns: %TRUE if successful, %FALSE otherwise.
3457 e_cal_client_get_object_finish (ECalClient *client,
3458 GAsyncResult *result,
3459 icalcomponent **out_icalcomp,
3462 GSimpleAsyncResult *simple;
3463 AsyncContext *async_context;
3465 g_return_val_if_fail (
3466 g_simple_async_result_is_valid (
3467 result, G_OBJECT (client),
3468 e_cal_client_get_object), FALSE);
3470 simple = G_SIMPLE_ASYNC_RESULT (result);
3471 async_context = g_simple_async_result_get_op_res_gpointer (simple);
3473 if (g_simple_async_result_propagate_error (simple, error))
3476 g_return_val_if_fail (async_context->out_comp != NULL, FALSE);
3478 if (out_icalcomp != NULL) {
3479 *out_icalcomp = async_context->out_comp;
3480 async_context->out_comp = NULL;
3487 * e_cal_client_get_object_sync:
3488 * @client: an #ECalClient
3489 * @uid: Unique identifier for a calendar component.
3490 * @rid: Recurrence identifier.
3491 * @out_icalcomp: (out): Return value for the calendar component object.
3492 * @cancellable: a #GCancellable; can be %NULL
3493 * @error: (out): a #GError to set an error, if any
3495 * Queries a calendar for a calendar component object based
3496 * on its unique identifier. This function always returns
3497 * master object for a case of @rid being NULL or an empty string.
3498 * This component should be freed with icalcomponent_free().
3500 * Use e_cal_client_get_objects_for_uid_sync() to get list of all
3501 * objects for the given uid, which includes master object and
3502 * all detached instances.
3504 * Returns: %TRUE if successful, %FALSE otherwise.
3509 e_cal_client_get_object_sync (ECalClient *client,
3512 icalcomponent **out_icalcomp,
3513 GCancellable *cancellable,
3516 icalcomponent *icalcomp = NULL;
3517 icalcomponent_kind kind;
3520 gchar *string = NULL;
3523 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
3524 g_return_val_if_fail (uid != NULL, FALSE);
3525 g_return_val_if_fail (out_icalcomp != NULL, FALSE);
3530 if (client->priv->dbus_proxy == NULL) {
3531 set_proxy_gone_error (error);
3535 utf8_uid = e_util_utf8_make_valid (uid);
3536 utf8_rid = e_util_utf8_make_valid (rid);
3538 success = e_dbus_calendar_call_get_object_sync (
3539 client->priv->dbus_proxy, utf8_uid, utf8_rid,
3540 &string, cancellable, error);
3546 g_return_val_if_fail (
3547 (success && (string != NULL)) ||
3548 (!success && (string == NULL)), FALSE);
3553 icalcomp = icalparser_parse_string (string);
3557 if (icalcomp == NULL) {
3558 g_set_error_literal (
3559 error, E_CAL_CLIENT_ERROR,
3560 E_CAL_CLIENT_ERROR_INVALID_OBJECT,
3561 e_cal_client_error_to_string (
3562 E_CAL_CLIENT_ERROR_INVALID_OBJECT));
3566 switch (e_cal_client_get_source_type (client)) {
3567 case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
3568 kind = ICAL_VEVENT_COMPONENT;
3570 case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
3571 kind = ICAL_VTODO_COMPONENT;
3573 case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
3574 kind = ICAL_VJOURNAL_COMPONENT;
3577 g_warn_if_reached ();
3578 kind = ICAL_VEVENT_COMPONENT;
3582 if (icalcomponent_isa (icalcomp) == kind) {
3583 *out_icalcomp = icalcomp;
3585 } else if (icalcomponent_isa (icalcomp) == ICAL_VCALENDAR_COMPONENT) {
3586 icalcomponent *subcomponent;
3588 for (subcomponent = icalcomponent_get_first_component (icalcomp, kind);
3589 subcomponent != NULL;
3590 subcomponent = icalcomponent_get_next_component (icalcomp, kind)) {
3591 struct icaltimetype recurrenceid;
3593 if (icalcomponent_get_uid (subcomponent) == NULL)
3597 icalcomponent_get_recurrenceid (subcomponent);
3599 if (icaltime_is_null_time (recurrenceid))
3602 if (!icaltime_is_valid_time (recurrenceid))
3606 if (subcomponent == NULL)
3607 subcomponent = icalcomponent_get_first_component (icalcomp, kind);
3608 if (subcomponent != NULL)
3609 subcomponent = icalcomponent_new_clone (subcomponent);
3611 /* XXX Shouldn't we set an error is this is still NULL? */
3612 *out_icalcomp = subcomponent;
3614 icalcomponent_free (icalcomp);
3620 /* Helper for e_cal_client_get_objects_for_uid() */
3622 cal_client_get_objects_for_uid_thread (GSimpleAsyncResult *simple,
3623 GObject *source_object,
3624 GCancellable *cancellable)
3626 AsyncContext *async_context;
3627 GError *error = NULL;
3629 async_context = g_simple_async_result_get_op_res_gpointer (simple);
3631 e_cal_client_get_objects_for_uid_sync (
3632 E_CAL_CLIENT (source_object),
3634 &async_context->object_list,
3635 cancellable, &error);
3638 g_simple_async_result_take_error (simple, error);
3642 * e_cal_client_get_objects_for_uid:
3643 * @client: an #ECalClient
3644 * @uid: Unique identifier for a calendar component
3645 * @cancellable: a #GCancellable; can be %NULL
3646 * @callback: callback to call when a result is ready
3647 * @user_data: user data for the @callback
3649 * Queries a calendar for all calendar components with the given unique
3650 * ID. This will return any recurring event and all its detached recurrences.
3651 * For non-recurring events, it will just return the object with that ID.
3652 * The call is finished by e_cal_client_get_objects_for_uid_finish() from
3658 e_cal_client_get_objects_for_uid (ECalClient *client,
3660 GCancellable *cancellable,
3661 GAsyncReadyCallback callback,
3664 GSimpleAsyncResult *simple;
3665 AsyncContext *async_context;
3667 g_return_if_fail (E_IS_CAL_CLIENT (client));
3668 g_return_if_fail (uid != NULL);
3670 async_context = g_slice_new0 (AsyncContext);
3671 async_context->uid = g_strdup (uid);
3673 simple = g_simple_async_result_new (
3674 G_OBJECT (client), callback, user_data,
3675 e_cal_client_get_objects_for_uid);
3677 g_simple_async_result_set_check_cancellable (simple, cancellable);
3679 g_simple_async_result_set_op_res_gpointer (
3680 simple, async_context, (GDestroyNotify) async_context_free);
3682 g_simple_async_result_run_in_thread (
3683 simple, cal_client_get_objects_for_uid_thread,
3684 G_PRIORITY_DEFAULT, cancellable);
3686 g_object_unref (simple);
3690 * e_cal_client_get_objects_for_uid_finish:
3691 * @client: an #ECalClient
3692 * @result: a #GAsyncResult
3693 * @out_ecalcomps: (out) (transfer full) (element-type ECalComponent):
3694 * Return location for the list of objects obtained from the
3696 * @error: (out): a #GError to set an error, if any
3698 * Finishes previous call of e_cal_client_get_objects_for_uid() and
3699 * sets @out_ecalcomps to a list of #ECalComponent<!-- -->s corresponding to
3700 * found components for a given uid of the same type as this client.
3701 * This list should be freed with e_cal_client_free_ecalcomp_slist().
3703 * Returns: %TRUE if successful, %FALSE otherwise.
3708 e_cal_client_get_objects_for_uid_finish (ECalClient *client,
3709 GAsyncResult *result,
3710 GSList **out_ecalcomps,
3713 GSimpleAsyncResult *simple;
3714 AsyncContext *async_context;
3716 g_return_val_if_fail (
3717 g_simple_async_result_is_valid (
3718 result, G_OBJECT (client),
3719 e_cal_client_get_objects_for_uid), FALSE);
3721 simple = G_SIMPLE_ASYNC_RESULT (result);
3722 async_context = g_simple_async_result_get_op_res_gpointer (simple);
3724 if (g_simple_async_result_propagate_error (simple, error))
3727 if (out_ecalcomps != NULL) {
3728 *out_ecalcomps = async_context->object_list;
3729 async_context->object_list = NULL;
3736 * e_cal_client_get_objects_for_uid_sync:
3737 * @client: an #ECalClient
3738 * @uid: Unique identifier for a calendar component
3739 * @out_ecalcomps: (out) (transfer full) (element-type ECalComponent):
3740 * Return location for the list of objects obtained from the
3742 * @cancellable: (allow-none): a #GCancellable; can be %NULL
3743 * @error: (out): a #GError to set an error, if any
3745 * Queries a calendar for all calendar components with the given unique
3746 * ID. This will return any recurring event and all its detached recurrences.
3747 * For non-recurring events, it will just return the object with that ID.
3748 * This list should be freed with e_cal_client_free_ecalcomp_slist().
3750 * Returns: %TRUE if successful, %FALSE otherwise.
3755 e_cal_client_get_objects_for_uid_sync (ECalClient *client,
3757 GSList **out_ecalcomps,
3758 GCancellable *cancellable,
3761 icalcomponent *icalcomp;
3762 icalcomponent_kind kind;
3764 gchar *string = NULL;
3767 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
3768 g_return_val_if_fail (uid != NULL, FALSE);
3769 g_return_val_if_fail (out_ecalcomps != NULL, FALSE);
3771 if (client->priv->dbus_proxy == NULL) {
3772 set_proxy_gone_error (error);
3776 utf8_uid = e_util_utf8_make_valid (uid);
3778 success = e_dbus_calendar_call_get_object_sync (
3779 client->priv->dbus_proxy, utf8_uid, "",
3780 &string, cancellable, error);
3785 g_return_val_if_fail (
3786 (success && (string != NULL)) ||
3787 (!success && (string == NULL)), FALSE);
3792 icalcomp = icalparser_parse_string (string);
3796 if (icalcomp == NULL) {
3797 g_set_error_literal (
3798 error, E_CAL_CLIENT_ERROR,
3799 E_CAL_CLIENT_ERROR_INVALID_OBJECT,
3800 e_cal_client_error_to_string (
3801 E_CAL_CLIENT_ERROR_INVALID_OBJECT));
3805 switch (e_cal_client_get_source_type (client)) {
3806 case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
3807 kind = ICAL_VEVENT_COMPONENT;
3809 case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
3810 kind = ICAL_VTODO_COMPONENT;
3812 case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
3813 kind = ICAL_VJOURNAL_COMPONENT;
3816 g_warn_if_reached ();
3817 kind = ICAL_VEVENT_COMPONENT;
3821 if (icalcomponent_isa (icalcomp) == kind) {
3822 ECalComponent *comp;
3824 comp = e_cal_component_new ();
3825 e_cal_component_set_icalcomponent (comp, icalcomp);
3826 *out_ecalcomps = g_slist_append (NULL, comp);
3828 } else if (icalcomponent_isa (icalcomp) == ICAL_VCALENDAR_COMPONENT) {
3830 icalcomponent *subcomponent;
3832 subcomponent = icalcomponent_get_first_component (
3835 while (subcomponent != NULL) {
3836 ECalComponent *comp;
3837 icalcomponent *clone;
3839 comp = e_cal_component_new ();
3840 clone = icalcomponent_new_clone (subcomponent);
3841 e_cal_component_set_icalcomponent (comp, clone);
3842 tmp = g_slist_prepend (tmp, comp);
3844 subcomponent = icalcomponent_get_next_component (
3848 *out_ecalcomps = g_slist_reverse (tmp);
3850 icalcomponent_free (icalcomp);
3856 /* Helper for e_cal_client_get_object_list() */
3858 cal_client_get_object_list_thread (GSimpleAsyncResult *simple,
3859 GObject *source_object,
3860 GCancellable *cancellable)
3862 AsyncContext *async_context;
3863 GError *error = NULL;
3865 async_context = g_simple_async_result_get_op_res_gpointer (simple);
3867 e_cal_client_get_object_list_sync (
3868 E_CAL_CLIENT (source_object),
3869 async_context->sexp,
3870 &async_context->comp_list,
3871 cancellable, &error);
3874 g_simple_async_result_take_error (simple, error);
3878 * e_cal_client_get_object_list:
3879 * @client: an #ECalClient
3880 * @sexp: an S-expression representing the query
3881 * @cancellable: a #GCancellable; can be %NULL
3882 * @callback: callback to call when a result is ready
3883 * @user_data: user data for the @callback
3885 * Gets a list of objects from the calendar that match the query specified
3886 * by the @sexp argument, returning matching objects as a list of #icalcomponent-s.
3887 * The call is finished by e_cal_client_get_object_list_finish() from
3893 e_cal_client_get_object_list (ECalClient *client,
3895 GCancellable *cancellable,
3896 GAsyncReadyCallback callback,
3899 GSimpleAsyncResult *simple;
3900 AsyncContext *async_context;
3902 g_return_if_fail (E_IS_CAL_CLIENT (client));
3903 g_return_if_fail (sexp != NULL);
3905 async_context = g_slice_new0 (AsyncContext);
3906 async_context->sexp = g_strdup (sexp);
3908 simple = g_simple_async_result_new (
3909 G_OBJECT (client), callback, user_data,
3910 e_cal_client_get_object_list);
3912 g_simple_async_result_set_check_cancellable (simple, cancellable);
3914 g_simple_async_result_set_op_res_gpointer (
3915 simple, async_context, (GDestroyNotify) async_context_free);
3917 g_simple_async_result_run_in_thread (
3918 simple, cal_client_get_object_list_thread,
3919 G_PRIORITY_DEFAULT, cancellable);
3921 g_object_unref (simple);
3925 * e_cal_client_get_object_list_finish:
3926 * @client: an #ECalClient
3927 * @result: a #GAsyncResult
3928 * @out_icalcomps: (out) (element-type icalcomponent): list of matching
3929 * #icalcomponent<!-- -->s
3930 * @error: (out): a #GError to set an error, if any
3932 * Finishes previous call of e_cal_client_get_object_list() and
3933 * sets @out_icalcomps to a matching list of #icalcomponent-s.
3934 * This list should be freed with e_cal_client_free_icalcomp_slist().
3936 * Returns: %TRUE if successful, %FALSE otherwise.
3941 e_cal_client_get_object_list_finish (ECalClient *client,
3942 GAsyncResult *result,
3943 GSList **out_icalcomps,
3946 GSimpleAsyncResult *simple;
3947 AsyncContext *async_context;
3949 g_return_val_if_fail (
3950 g_simple_async_result_is_valid (
3951 result, G_OBJECT (client),
3952 e_cal_client_get_object_list), FALSE);
3954 simple = G_SIMPLE_ASYNC_RESULT (result);
3955 async_context = g_simple_async_result_get_op_res_gpointer (simple);
3957 if (g_simple_async_result_propagate_error (simple, error))
3960 if (out_icalcomps != NULL) {
3961 *out_icalcomps = async_context->comp_list;
3962 async_context->comp_list = NULL;
3969 * e_cal_client_get_object_list_sync:
3970 * @client: an #ECalClient
3971 * @sexp: an S-expression representing the query
3972 * @out_icalcomps: (out) (element-type icalcomponent): list of matching
3973 * #icalcomponent<!-- -->s
3974 * @cancellable: (allow-none): a #GCancellable; can be %NULL
3975 * @error: (out): a #GError to set an error, if any
3977 * Gets a list of objects from the calendar that match the query specified
3978 * by the @sexp argument. The objects will be returned in the @out_icalcomps
3979 * argument, which is a list of #icalcomponent.
3980 * This list should be freed with e_cal_client_free_icalcomp_slist().
3982 * Returns: %TRUE if successful, %FALSE otherwise.
3987 e_cal_client_get_object_list_sync (ECalClient *client,
3989 GSList **out_icalcomps,
3990 GCancellable *cancellable,
3995 gchar **strv = NULL;
3999 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
4000 g_return_val_if_fail (sexp != NULL, FALSE);
4001 g_return_val_if_fail (out_icalcomps != NULL, FALSE);
4003 if (client->priv->dbus_proxy == NULL) {
4004 set_proxy_gone_error (error);
4008 utf8_sexp = e_util_utf8_make_valid (sexp);
4010 success = e_dbus_calendar_call_get_object_list_sync (
4011 client->priv->dbus_proxy, utf8_sexp,
4012 &strv, cancellable, error);
4017 g_return_val_if_fail (
4018 (success && (strv != NULL)) ||
4019 (!success && (strv == NULL)), FALSE);
4024 for (ii = 0; strv[ii] != NULL; ii++) {
4025 icalcomponent *icalcomp;
4027 icalcomp = icalcomponent_new_from_string (strv[ii]);
4028 if (icalcomp == NULL)
4031 tmp = g_slist_prepend (tmp, icalcomp);
4034 *out_icalcomps = g_slist_reverse (tmp);
4039 /* Helper for e_cal_client_get_object_list_as_comps() */
4041 cal_client_get_object_list_as_comps_thread (GSimpleAsyncResult *simple,
4042 GObject *source_object,
4043 GCancellable *cancellable)
4045 AsyncContext *async_context;
4046 GError *error = NULL;
4048 async_context = g_simple_async_result_get_op_res_gpointer (simple);
4050 e_cal_client_get_object_list_as_comps_sync (
4051 E_CAL_CLIENT (source_object),
4052 async_context->sexp,
4053 &async_context->object_list,
4054 cancellable, &error);
4057 g_simple_async_result_take_error (simple, error);
4061 * e_cal_client_get_object_list_as_comps:
4062 * @client: an #ECalClient
4063 * @sexp: an S-expression representing the query
4064 * @cancellable: a #GCancellable; can be %NULL
4065 * @callback: callback to call when a result is ready
4066 * @user_data: user data for the @callback
4068 * Gets a list of objects from the calendar that match the query specified
4069 * by the @sexp argument, returning matching objects as a list of #ECalComponent-s.
4070 * The call is finished by e_cal_client_get_object_list_as_comps_finish() from
4076 e_cal_client_get_object_list_as_comps (ECalClient *client,
4078 GCancellable *cancellable,
4079 GAsyncReadyCallback callback,
4082 GSimpleAsyncResult *simple;
4083 AsyncContext *async_context;
4085 g_return_if_fail (E_IS_CAL_CLIENT (client));
4086 g_return_if_fail (sexp != NULL);
4088 async_context = g_slice_new0 (AsyncContext);
4089 async_context->sexp = g_strdup (sexp);
4091 simple = g_simple_async_result_new (
4092 G_OBJECT (client), callback, user_data,
4093 e_cal_client_get_object_list_as_comps);
4095 g_simple_async_result_set_check_cancellable (simple, cancellable);
4097 g_simple_async_result_set_op_res_gpointer (
4098 simple, async_context, (GDestroyNotify) async_context_free);
4100 g_simple_async_result_run_in_thread (
4101 simple, cal_client_get_object_list_as_comps_thread,
4102 G_PRIORITY_DEFAULT, cancellable);
4104 g_object_unref (simple);
4108 * e_cal_client_get_object_list_as_comps_finish:
4109 * @client: an #ECalClient
4110 * @result: a #GAsyncResult
4111 * @out_ecalcomps: (out) (element-type ECalComponent): list of matching
4112 * #ECalComponent<!-- -->s
4113 * @error: (out): a #GError to set an error, if any
4115 * Finishes previous call of e_cal_client_get_object_list_as_comps() and
4116 * sets @out_ecalcomps to a matching list of #ECalComponent-s.
4117 * This list should be freed with e_cal_client_free_ecalcomp_slist().
4119 * Returns: %TRUE if successful, %FALSE otherwise.
4124 e_cal_client_get_object_list_as_comps_finish (ECalClient *client,
4125 GAsyncResult *result,
4126 GSList **out_ecalcomps,
4129 GSimpleAsyncResult *simple;
4130 AsyncContext *async_context;
4132 g_return_val_if_fail (
4133 g_simple_async_result_is_valid (
4134 result, G_OBJECT (client),
4135 e_cal_client_get_object_list), FALSE);
4137 simple = G_SIMPLE_ASYNC_RESULT (result);
4138 async_context = g_simple_async_result_get_op_res_gpointer (simple);
4140 if (g_simple_async_result_propagate_error (simple, error))
4143 if (out_ecalcomps != NULL) {
4144 *out_ecalcomps = async_context->object_list;
4145 async_context->object_list = NULL;
4152 * e_cal_client_get_object_list_as_comps_sync:
4153 * @client: an #ECalClient
4154 * @sexp: an S-expression representing the query
4155 * @out_ecalcomps: (out) (element-type ECalComponent): list of matching
4156 * #ECalComponent<!-- -->s
4157 * @cancellable: (allow-none): a #GCancellable; can be %NULL
4158 * @error: (out): a #GError to set an error, if any
4160 * Gets a list of objects from the calendar that match the query specified
4161 * by the @sexp argument. The objects will be returned in the @out_ecalcomps
4162 * argument, which is a list of #ECalComponent.
4163 * This list should be freed with e_cal_client_free_ecalcomp_slist().
4165 * Returns: %TRUE if successful, %FALSE otherwise.
4170 e_cal_client_get_object_list_as_comps_sync (ECalClient *client,
4172 GSList **out_ecalcomps,
4173 GCancellable *cancellable,
4176 GSList *list = NULL;
4178 GQueue trash = G_QUEUE_INIT;
4181 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
4182 g_return_val_if_fail (sexp != NULL, FALSE);
4183 g_return_val_if_fail (out_ecalcomps != NULL, FALSE);
4185 success = e_cal_client_get_object_list_sync (
4186 client, sexp, &list, cancellable, error);
4189 g_warn_if_fail (list == NULL);
4193 /* Convert the icalcomponent list to an ECalComponent list. */
4194 for (link = list; link != NULL; link = g_slist_next (link)) {
4195 ECalComponent *comp;
4196 icalcomponent *icalcomp = link->data;
4198 comp = e_cal_component_new ();
4200 /* This takes ownership of the icalcomponent, if it works. */
4201 if (e_cal_component_set_icalcomponent (comp, icalcomp)) {
4202 link->data = g_object_ref (comp);
4204 /* On failure, free resources and add
4205 * the GSList link to the trash queue. */
4206 icalcomponent_free (icalcomp);
4207 g_queue_push_tail (&trash, link);
4211 g_object_unref (comp);
4214 /* Delete GSList links we failed to convert. */
4215 while ((link = g_queue_pop_head (&trash)) != NULL)
4216 list = g_slist_delete_link (list, link);
4218 *out_ecalcomps = list;
4223 /* Helper for e_cal_client_get_free_busy() */
4225 cal_client_get_free_busy_thread (GSimpleAsyncResult *simple,
4226 GObject *source_object,
4227 GCancellable *cancellable)
4229 AsyncContext *async_context;
4230 GError *error = NULL;
4232 async_context = g_simple_async_result_get_op_res_gpointer (simple);
4234 e_cal_client_get_free_busy_sync (
4235 E_CAL_CLIENT (source_object),
4236 async_context->start,
4238 async_context->string_list,
4239 cancellable, &error);
4242 g_simple_async_result_take_error (simple, error);
4246 * e_cal_client_get_free_busy:
4247 * @client: an #ECalClient
4248 * @start: Start time for query
4249 * @end: End time for query
4250 * @users: (element-type utf8): List of users to retrieve free/busy information for
4251 * @cancellable: (allow-none): a #GCancellable; can be %NULL
4252 * @callback: callback to call when a result is ready
4253 * @user_data: user data for the @callback
4255 * Begins retrieval of free/busy information from the calendar server
4256 * as a list of #ECalComponent-s. Connect to "free-busy-data" signal
4257 * to receive chunks of free/busy components.
4258 * The call is finished by e_cal_client_get_free_busy_finish() from
4264 e_cal_client_get_free_busy (ECalClient *client,
4267 const GSList *users,
4268 GCancellable *cancellable,
4269 GAsyncReadyCallback callback,
4272 GSimpleAsyncResult *simple;
4273 AsyncContext *async_context;
4275 g_return_if_fail (E_IS_CAL_CLIENT (client));
4276 g_return_if_fail (start > 0);
4277 g_return_if_fail (end > 0);
4279 async_context = g_slice_new0 (AsyncContext);
4280 async_context->start = start;
4281 async_context->end = end;
4282 async_context->string_list = g_slist_copy_deep (
4283 (GSList *) users, (GCopyFunc) g_strdup, NULL);
4285 simple = g_simple_async_result_new (
4286 G_OBJECT (client), callback, user_data,
4287 e_cal_client_get_free_busy);
4289 g_simple_async_result_set_check_cancellable (simple, cancellable);
4291 g_simple_async_result_set_op_res_gpointer (
4292 simple, async_context, (GDestroyNotify) async_context_free);
4294 g_simple_async_result_run_in_thread (
4295 simple, cal_client_get_free_busy_thread,
4296 G_PRIORITY_DEFAULT, cancellable);
4298 g_object_unref (simple);
4302 * e_cal_client_get_free_busy_finish:
4303 * @client: an #ECalClient
4304 * @result: a #GAsyncResult
4305 * @error: (out): a #GError to set an error, if any
4307 * Finishes previous call of e_cal_client_get_free_busy().
4308 * All VFREEBUSY #ECalComponent-s were received by "free-busy-data" signal.
4310 * Returns: %TRUE if successful, %FALSE otherwise.
4315 e_cal_client_get_free_busy_finish (ECalClient *client,
4316 GAsyncResult *result,
4319 GSimpleAsyncResult *simple;
4321 g_return_val_if_fail (
4322 g_simple_async_result_is_valid (
4323 result, G_OBJECT (client),
4324 e_cal_client_get_free_busy), FALSE);
4326 simple = G_SIMPLE_ASYNC_RESULT (result);
4328 /* Assume success unless a GError is set. */
4329 return !g_simple_async_result_propagate_error (simple, error);
4333 * e_cal_client_get_free_busy_sync:
4334 * @client: an #ECalClient
4335 * @start: Start time for query
4336 * @end: End time for query
4337 * @users: (element-type utf8): List of users to retrieve free/busy information for
4338 * @cancellable: (allow-none): a #GCancellable; can be %NULL
4339 * @error: (out): a #GError to set an error, if any
4341 * Gets free/busy information from the calendar server.
4342 * All VFREEBUSY #ECalComponent-s were received by "free-busy-data" signal.
4344 * Returns: %TRUE if successful, %FALSE otherwise.
4349 e_cal_client_get_free_busy_sync (ECalClient *client,
4352 const GSList *users,
4353 GCancellable *cancellable,
4360 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
4361 g_return_val_if_fail (start > 0, FALSE);
4362 g_return_val_if_fail (end > 0, FALSE);
4364 if (client->priv->dbus_proxy == NULL) {
4365 set_proxy_gone_error (error);
4369 strv = g_new0 (gchar *, g_slist_length ((GSList *) users) + 1);
4370 while (users != NULL) {
4371 strv[ii++] = e_util_utf8_make_valid (users->data);
4372 users = g_slist_next (users);
4375 success = e_dbus_calendar_call_get_free_busy_sync (
4376 client->priv->dbus_proxy,
4377 (gint64) start, (gint64) end,
4378 (const gchar * const *) strv,
4379 cancellable, error);
4386 /* Helper for e_cal_client_create_object() */
4388 cal_client_create_object_thread (GSimpleAsyncResult *simple,
4389 GObject *source_object,
4390 GCancellable *cancellable)
4392 AsyncContext *async_context;
4393 GError *error = NULL;
4395 async_context = g_simple_async_result_get_op_res_gpointer (simple);
4397 e_cal_client_create_object_sync (
4398 E_CAL_CLIENT (source_object),
4399 async_context->in_comp,
4400 &async_context->uid,
4401 cancellable, &error);
4404 g_simple_async_result_take_error (simple, error);
4408 * e_cal_client_create_object:
4409 * @client: an #ECalClient
4410 * @icalcomp: The component to create
4411 * @cancellable: a #GCancellable; can be %NULL
4412 * @callback: callback to call when a result is ready
4413 * @user_data: user data for the @callback
4415 * Requests the calendar backend to create the object specified by the @icalcomp
4416 * argument. Some backends would assign a specific UID to the newly created object,
4417 * but this function does not modify the original @icalcomp if its UID changes.
4418 * The call is finished by e_cal_client_create_object_finish() from
4424 e_cal_client_create_object (ECalClient *client,
4425 icalcomponent *icalcomp,
4426 GCancellable *cancellable,
4427 GAsyncReadyCallback callback,
4430 GSimpleAsyncResult *simple;
4431 AsyncContext *async_context;
4433 g_return_if_fail (E_IS_CAL_CLIENT (client));
4434 g_return_if_fail (icalcomp != NULL);
4436 async_context = g_slice_new0 (AsyncContext);
4437 async_context->in_comp = icalcomponent_new_clone (icalcomp);
4439 simple = g_simple_async_result_new (
4440 G_OBJECT (client), callback, user_data,
4441 e_cal_client_create_object);
4443 g_simple_async_result_set_op_res_gpointer (
4444 simple, async_context, (GDestroyNotify) async_context_free);
4446 g_simple_async_result_run_in_thread (
4447 simple, cal_client_create_object_thread,
4448 G_PRIORITY_DEFAULT, cancellable);
4450 g_object_unref (simple);
4454 * e_cal_client_create_object_finish:
4455 * @client: an #ECalClient
4456 * @result: a #GAsyncResult
4457 * @out_uid: (out): Return value for the UID assigned to the new component
4458 * by the calendar backend
4459 * @error: (out): a #GError to set an error, if any
4461 * Finishes previous call of e_cal_client_create_object() and
4462 * sets @out_uid to newly assigned UID for the created object.
4463 * This @out_uid should be freed with g_free().
4465 * Returns: %TRUE if successful, %FALSE otherwise.
4470 e_cal_client_create_object_finish (ECalClient *client,
4471 GAsyncResult *result,
4475 GSimpleAsyncResult *simple;
4476 AsyncContext *async_context;
4478 g_return_val_if_fail (
4479 g_simple_async_result_is_valid (
4480 result, G_OBJECT (client),
4481 e_cal_client_create_object), FALSE);
4483 simple = G_SIMPLE_ASYNC_RESULT (result);
4484 async_context = g_simple_async_result_get_op_res_gpointer (simple);
4486 if (g_simple_async_result_propagate_error (simple, error))
4489 g_return_val_if_fail (async_context->uid != NULL, FALSE);
4491 if (out_uid != NULL) {
4492 *out_uid = async_context->uid;
4493 async_context->uid = NULL;
4500 * e_cal_client_create_object_sync:
4501 * @client: an #ECalClient
4502 * @icalcomp: The component to create
4503 * @out_uid: (out): Return value for the UID assigned to the new component
4504 * by the calendar backend
4505 * @cancellable: a #GCancellable; can be %NULL
4506 * @error: (out): a #GError to set an error, if any
4508 * Requests the calendar backend to create the object specified by the
4509 * @icalcomp argument. Some backends would assign a specific UID to the newly
4510 * created object, in those cases that UID would be returned in the @out_uid
4511 * argument. This function does not modify the original @icalcomp if its UID
4512 * changes. Returned @out_uid should be freed with g_free().
4514 * Returns: %TRUE if successful, %FALSE otherwise.
4519 e_cal_client_create_object_sync (ECalClient *client,
4520 icalcomponent *icalcomp,
4522 GCancellable *cancellable,
4525 GSList link = { icalcomp, NULL };
4526 GSList *string_list = NULL;
4529 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
4530 g_return_val_if_fail (icalcomp != NULL, FALSE);
4532 success = e_cal_client_create_objects_sync (
4533 client, &link, &string_list, cancellable, error);
4536 g_return_val_if_fail (
4537 (success && (string_list != NULL)) ||
4538 (!success && (string_list == NULL)), FALSE);
4540 if (out_uid != NULL && string_list != NULL)
4541 *out_uid = g_strdup (string_list->data);
4543 g_slist_free_full (string_list, (GDestroyNotify) g_free);
4548 /* Helper for e_cal_client_create_objects() */
4550 cal_client_create_objects_thread (GSimpleAsyncResult *simple,
4551 GObject *source_object,
4552 GCancellable *cancellable)
4554 AsyncContext *async_context;
4555 GError *error = NULL;
4557 async_context = g_simple_async_result_get_op_res_gpointer (simple);
4559 e_cal_client_create_objects_sync (
4560 E_CAL_CLIENT (source_object),
4561 async_context->comp_list,
4562 &async_context->string_list,
4563 cancellable, &error);
4566 g_simple_async_result_take_error (simple, error);
4570 * e_cal_client_create_objects:
4571 * @client: an #ECalClient
4572 * @icalcomps: (element-type icalcomponent): The components to create
4573 * @cancellable: (allow-none): a #GCancellable; can be %NULL
4574 * @callback: callback to call when a result is ready
4575 * @user_data: user data for the @callback
4577 * Requests the calendar backend to create the objects specified by the @icalcomps
4578 * argument. Some backends would assign a specific UID to the newly created object,
4579 * but this function does not modify the original @icalcomps if their UID changes.
4580 * The call is finished by e_cal_client_create_objects_finish() from
4586 e_cal_client_create_objects (ECalClient *client,
4588 GCancellable *cancellable,
4589 GAsyncReadyCallback callback,
4592 GSimpleAsyncResult *simple;
4593 AsyncContext *async_context;
4595 g_return_if_fail (E_IS_CAL_CLIENT (client));
4596 g_return_if_fail (icalcomps != NULL);
4598 async_context = g_slice_new0 (AsyncContext);
4599 async_context->comp_list = g_slist_copy_deep (
4600 icalcomps, (GCopyFunc) icalcomponent_new_clone, NULL);
4602 simple = g_simple_async_result_new (
4603 G_OBJECT (client), callback, user_data,
4604 e_cal_client_create_objects);
4606 g_simple_async_result_set_check_cancellable (simple, cancellable);
4608 g_simple_async_result_set_op_res_gpointer (
4609 simple, async_context, (GDestroyNotify) async_context_free);
4611 g_simple_async_result_run_in_thread (
4612 simple, cal_client_create_objects_thread,
4613 G_PRIORITY_DEFAULT, cancellable);
4615 g_object_unref (simple);
4619 * e_cal_client_create_objects_finish:
4620 * @client: an #ECalClient
4621 * @result: a #GAsyncResult
4622 * @out_uids: (out) (element-type utf8): Return value for the UIDs assigned
4623 * to the new components by the calendar backend
4624 * @error: (out): a #GError to set an error, if any
4626 * Finishes previous call of e_cal_client_create_objects() and
4627 * sets @out_uids to newly assigned UIDs for the created objects.
4628 * This @out_uids should be freed with e_client_util_free_string_slist().
4630 * Returns: %TRUE if successful, %FALSE otherwise.
4635 e_cal_client_create_objects_finish (ECalClient *client,
4636 GAsyncResult *result,
4640 GSimpleAsyncResult *simple;
4641 AsyncContext *async_context;
4643 g_return_val_if_fail (
4644 g_simple_async_result_is_valid (
4645 result, G_OBJECT (client),
4646 e_cal_client_create_objects), FALSE);
4648 simple = G_SIMPLE_ASYNC_RESULT (result);
4649 async_context = g_simple_async_result_get_op_res_gpointer (simple);
4651 if (g_simple_async_result_propagate_error (simple, error))
4654 if (out_uids != NULL) {
4655 *out_uids = async_context->string_list;
4656 async_context->string_list = NULL;
4663 * e_cal_client_create_objects_sync:
4664 * @client: an #ECalClient
4665 * @icalcomps: (element-type icalcomponent): The components to create
4666 * @out_uids: (out) (element-type utf8): Return value for the UIDs assigned
4667 * to the new components by the calendar backend
4668 * @cancellable: (allow-none): a #GCancellable; can be %NULL
4669 * @error: (out): a #GError to set an error, if any
4671 * Requests the calendar backend to create the objects specified by the
4672 * @icalcomps argument. Some backends would assign a specific UID to the
4673 * newly created objects, in those cases these UIDs would be returned in
4674 * the @out_uids argument. This function does not modify the original
4675 * @icalcomps if their UID changes. Returned @out_uids should be freed
4676 * with e_client_util_free_string_slist().
4678 * Returns: %TRUE if successful, %FALSE otherwise.
4683 e_cal_client_create_objects_sync (ECalClient *client,
4686 GCancellable *cancellable,
4690 gchar **uids = NULL;
4694 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
4695 g_return_val_if_fail (icalcomps != NULL, FALSE);
4696 g_return_val_if_fail (out_uids != NULL, FALSE);
4698 if (client->priv->dbus_proxy == NULL) {
4699 set_proxy_gone_error (error);
4703 strv = g_new0 (gchar *, g_slist_length (icalcomps) + 1);
4704 while (icalcomps != NULL) {
4707 ical_string = icalcomponent_as_ical_string_r (icalcomps->data);
4708 strv[ii++] = e_util_utf8_make_valid (ical_string);
4709 g_free (ical_string);
4711 icalcomps = g_slist_next (icalcomps);
4714 success = e_dbus_calendar_call_create_objects_sync (
4715 client->priv->dbus_proxy,
4716 (const gchar * const *) strv,
4717 &uids, cancellable, error);
4722 g_return_val_if_fail (
4723 (success && (uids != NULL)) ||
4724 (!success && (uids == NULL)), FALSE);
4729 /* Steal the string array elements. */
4730 for (ii = 0; uids[ii] != NULL; ii++) {
4731 tmp = g_slist_prepend (tmp, uids[ii]);
4735 *out_uids = g_slist_reverse (tmp);
4743 /* Helper for e_cal_client_modify_object() */
4745 cal_client_modify_object_thread (GSimpleAsyncResult *simple,
4746 GObject *source_object,
4747 GCancellable *cancellable)
4749 AsyncContext *async_context;
4750 GError *error = NULL;
4752 async_context = g_simple_async_result_get_op_res_gpointer (simple);
4754 e_cal_client_modify_object_sync (
4755 E_CAL_CLIENT (source_object),
4756 async_context->in_comp,
4758 cancellable, &error);
4761 g_simple_async_result_take_error (simple, error);
4765 * e_cal_client_modify_object:
4766 * @client: an #ECalClient
4767 * @icalcomp: Component to modify
4768 * @mod: Type of modification
4769 * @cancellable: a #GCancellable; can be %NULL
4770 * @callback: callback to call when a result is ready
4771 * @user_data: user data for the @callback
4773 * Requests the calendar backend to modify an existing object. If the object
4774 * does not exist on the calendar, an error will be returned.
4776 * For recurrent appointments, the @mod argument specifies what to modify,
4777 * if all instances (E_CAL_OBJ_MOD_ALL), a single instance (E_CAL_OBJ_MOD_THIS),
4778 * or a specific set of instances (E_CAL_OBJ_MOD_THIS_AND_PRIOR and
4779 * E_CAL_OBJ_MOD_THIS_AND_FUTURE).
4781 * The call is finished by e_cal_client_modify_object_finish() from
4787 e_cal_client_modify_object (ECalClient *client,
4788 icalcomponent *icalcomp,
4790 GCancellable *cancellable,
4791 GAsyncReadyCallback callback,
4794 GSimpleAsyncResult *simple;
4795 AsyncContext *async_context;
4797 g_return_if_fail (E_IS_CAL_CLIENT (client));
4798 g_return_if_fail (icalcomp != NULL);
4800 async_context = g_slice_new0 (AsyncContext);
4801 async_context->in_comp = icalcomponent_new_clone (icalcomp);
4802 async_context->mod = mod;
4804 simple = g_simple_async_result_new (
4805 G_OBJECT (client), callback, user_data,
4806 e_cal_client_modify_object);
4808 g_simple_async_result_set_check_cancellable (simple, cancellable);
4810 g_simple_async_result_set_op_res_gpointer (
4811 simple, async_context, (GDestroyNotify) async_context_free);
4813 g_simple_async_result_run_in_thread (
4814 simple, cal_client_modify_object_thread,
4815 G_PRIORITY_DEFAULT, cancellable);
4817 g_object_unref (simple);
4821 * e_cal_client_modify_object_finish:
4822 * @client: an #ECalClient
4823 * @result: a #GAsyncResult
4824 * @error: (out): a #GError to set an error, if any
4826 * Finishes previous call of e_cal_client_modify_object().
4828 * Returns: %TRUE if successful, %FALSE otherwise.
4833 e_cal_client_modify_object_finish (ECalClient *client,
4834 GAsyncResult *result,
4837 GSimpleAsyncResult *simple;
4839 g_return_val_if_fail (
4840 g_simple_async_result_is_valid (
4841 result, G_OBJECT (client),
4842 e_cal_client_modify_object), FALSE);
4844 simple = G_SIMPLE_ASYNC_RESULT (result);
4846 /* Assume success unless a GError is set. */
4847 return !g_simple_async_result_propagate_error (simple, error);
4851 * e_cal_client_modify_object_sync:
4852 * @client: an #ECalClient
4853 * @icalcomp: Component to modify
4854 * @mod: Type of modification
4855 * @cancellable: a #GCancellable; can be %NULL
4856 * @error: (out): a #GError to set an error, if any
4858 * Requests the calendar backend to modify an existing object. If the object
4859 * does not exist on the calendar, an error will be returned.
4861 * For recurrent appointments, the @mod argument specifies what to modify,
4862 * if all instances (E_CAL_OBJ_MOD_ALL), a single instance (E_CAL_OBJ_MOD_THIS),
4863 * or a specific set of instances (E_CAL_OBJ_MOD_THISNADPRIOR and
4864 * E_CAL_OBJ_MOD_THIS_AND_FUTURE).
4866 * Returns: %TRUE if successful, %FALSE otherwise.
4871 e_cal_client_modify_object_sync (ECalClient *client,
4872 icalcomponent *icalcomp,
4874 GCancellable *cancellable,
4877 GSList link = { icalcomp, NULL };
4879 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
4880 g_return_val_if_fail (icalcomp != NULL, FALSE);
4882 return e_cal_client_modify_objects_sync (
4883 client, &link, mod, cancellable, error);
4886 /* Helper for e_cal_client_modify_objects() */
4888 cal_client_modify_objects_thread (GSimpleAsyncResult *simple,
4889 GObject *source_object,
4890 GCancellable *cancellable)
4892 AsyncContext *async_context;
4893 GError *error = NULL;
4895 async_context = g_simple_async_result_get_op_res_gpointer (simple);
4897 e_cal_client_modify_objects_sync (
4898 E_CAL_CLIENT (source_object),
4899 async_context->comp_list,
4901 cancellable, &error);
4904 g_simple_async_result_take_error (simple, error);
4908 * e_cal_client_modify_objects:
4909 * @client: an #ECalClient
4910 * @comps: (element-type icalcomponent): Components to modify
4911 * @mod: Type of modification
4912 * @cancellable: (allow-none): a #GCancellable; can be %NULL
4913 * @callback: callback to call when a result is ready
4914 * @user_data: user data for the @callback
4916 * Requests the calendar backend to modify existing objects. If an object
4917 * does not exist on the calendar, an error will be returned.
4919 * For recurrent appointments, the @mod argument specifies what to modify,
4920 * if all instances (E_CAL_OBJ_MOD_ALL), a single instance (E_CAL_OBJ_MOD_THIS),
4921 * or a specific set of instances (E_CAL_OBJ_MOD_THISNADPRIOR and
4922 * E_CAL_OBJ_MOD_THIS_AND_FUTURE).
4924 * The call is finished by e_cal_client_modify_objects_finish() from
4930 e_cal_client_modify_objects (ECalClient *client,
4933 GCancellable *cancellable,
4934 GAsyncReadyCallback callback,
4937 GSimpleAsyncResult *simple;
4938 AsyncContext *async_context;
4940 g_return_if_fail (E_IS_CAL_CLIENT (client));
4941 g_return_if_fail (comps != NULL);
4943 async_context = g_slice_new0 (AsyncContext);
4944 async_context->comp_list = g_slist_copy_deep (
4945 comps, (GCopyFunc) icalcomponent_new_clone, NULL);
4946 async_context->mod = mod;
4948 simple = g_simple_async_result_new (
4949 G_OBJECT (client), callback, user_data,
4950 e_cal_client_modify_objects);
4952 g_simple_async_result_set_check_cancellable (simple, cancellable);
4954 g_simple_async_result_set_op_res_gpointer (
4955 simple, async_context, (GDestroyNotify) async_context_free);
4957 g_simple_async_result_run_in_thread (
4958 simple, cal_client_modify_objects_thread,
4959 G_PRIORITY_DEFAULT, cancellable);
4961 g_object_unref (simple);
4965 * e_cal_client_modify_objects_finish:
4966 * @client: an #ECalClient
4967 * @result: a #GAsyncResult
4968 * @error: (out): a #GError to set an error, if any
4970 * Finishes previous call of e_cal_client_modify_objects().
4972 * Returns: %TRUE if successful, %FALSE otherwise.
4977 e_cal_client_modify_objects_finish (ECalClient *client,
4978 GAsyncResult *result,
4981 GSimpleAsyncResult *simple;
4983 g_return_val_if_fail (
4984 g_simple_async_result_is_valid (
4985 result, G_OBJECT (client),
4986 e_cal_client_modify_objects), FALSE);
4988 simple = G_SIMPLE_ASYNC_RESULT (result);
4990 /* Assume success unless a GError is set. */
4991 return !g_simple_async_result_propagate_error (simple, error);
4995 * e_cal_client_modify_objects_sync:
4996 * @client: an #ECalClient
4997 * @comps: (element-type icalcomponent): Components to modify
4998 * @mod: Type of modification
4999 * @cancellable: (allow-none): a #GCancellable; can be %NULL
5000 * @error: (out): a #GError to set an error, if any
5002 * Requests the calendar backend to modify existing objects. If an object
5003 * does not exist on the calendar, an error will be returned.
5005 * For recurrent appointments, the @mod argument specifies what to modify,
5006 * if all instances (E_CAL_OBJ_MOD_ALL), a single instance (E_CAL_OBJ_MOD_THIS),
5007 * or a specific set of instances (E_CAL_OBJ_MOD_THISNADPRIOR and
5008 * E_CAL_OBJ_MOD_THIS_AND_FUTURE).
5010 * Returns: %TRUE if successful, %FALSE otherwise.
5015 e_cal_client_modify_objects_sync (ECalClient *client,
5018 GCancellable *cancellable,
5021 GEnumClass *enum_class;
5022 GEnumValue *enum_value;
5027 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
5028 g_return_val_if_fail (comps != NULL, FALSE);
5030 if (client->priv->dbus_proxy == NULL) {
5031 set_proxy_gone_error (error);
5035 enum_class = g_type_class_ref (E_TYPE_CAL_OBJ_MOD_TYPE);
5036 enum_value = g_enum_get_value (enum_class, mod);
5037 g_return_val_if_fail (enum_value != NULL, FALSE);
5039 strv = g_new0 (gchar *, g_slist_length (comps) + 1);
5040 while (comps != NULL) {
5043 ical_string = icalcomponent_as_ical_string_r (comps->data);
5044 strv[ii++] = e_util_utf8_make_valid (ical_string);
5045 g_free (ical_string);
5048 success = e_dbus_calendar_call_modify_objects_sync (
5049 client->priv->dbus_proxy,
5050 (const gchar * const *) strv,
5051 enum_value->value_nick,
5052 cancellable, error);
5056 g_type_class_unref (enum_class);
5061 /* Helper for e_cal_client_remove_object() */
5063 cal_client_remove_object_thread (GSimpleAsyncResult *simple,
5064 GObject *source_object,
5065 GCancellable *cancellable)
5067 AsyncContext *async_context;
5068 GError *error = NULL;
5070 async_context = g_simple_async_result_get_op_res_gpointer (simple);
5072 e_cal_client_remove_object_sync (
5073 E_CAL_CLIENT (source_object),
5077 cancellable, &error);
5080 g_simple_async_result_take_error (simple, error);
5084 * e_cal_client_remove_object:
5085 * @client: an #ECalClient
5086 * @uid: UID of the object to remove
5087 * @rid: Recurrence ID of the specific recurrence to remove
5088 * @mod: Type of the removal
5089 * @cancellable: a #GCancellable; can be %NULL
5090 * @callback: callback to call when a result is ready
5091 * @user_data: user data for the @callback
5093 * This function allows the removal of instances of a recurrent
5094 * appointment. By using a combination of the @uid, @rid and @mod
5095 * arguments, you can remove specific instances. If what you want
5096 * is to remove all instances, use #NULL @rid and E_CAL_OBJ_MOD_ALL
5099 * The call is finished by e_cal_client_remove_object_finish() from
5105 e_cal_client_remove_object (ECalClient *client,
5109 GCancellable *cancellable,
5110 GAsyncReadyCallback callback,
5113 GSimpleAsyncResult *simple;
5114 AsyncContext *async_context;
5116 g_return_if_fail (E_IS_CAL_CLIENT (client));
5117 g_return_if_fail (uid != NULL);
5118 /* rid is optional */
5120 async_context = g_slice_new0 (AsyncContext);
5121 async_context->uid = g_strdup (uid);
5122 async_context->rid = g_strdup (rid);
5123 async_context->mod = mod;
5125 simple = g_simple_async_result_new (
5126 G_OBJECT (client), callback, user_data,
5127 e_cal_client_remove_object);
5129 g_simple_async_result_set_check_cancellable (simple, cancellable);
5131 g_simple_async_result_set_op_res_gpointer (
5132 simple, async_context, (GDestroyNotify) async_context_free);
5134 g_simple_async_result_run_in_thread (
5135 simple, cal_client_remove_object_thread,
5136 G_PRIORITY_DEFAULT, cancellable);
5138 g_object_unref (simple);
5142 * e_cal_client_remove_object_finish:
5143 * @client: an #ECalClient
5144 * @result: a #GAsyncResult
5145 * @error: (out): a #GError to set an error, if any
5147 * Finishes previous call of e_cal_client_remove_object().
5149 * Returns: %TRUE if successful, %FALSE otherwise.
5154 e_cal_client_remove_object_finish (ECalClient *client,
5155 GAsyncResult *result,
5158 GSimpleAsyncResult *simple;
5160 g_return_val_if_fail (
5161 g_simple_async_result_is_valid (
5162 result, G_OBJECT (client),
5163 e_cal_client_remove_object), FALSE);
5165 simple = G_SIMPLE_ASYNC_RESULT (result);
5167 /* Assume success unless a GError is set. */
5168 return !g_simple_async_result_propagate_error (simple, error);
5172 * e_cal_client_remove_object_sync:
5173 * @client: an #ECalClient
5174 * @uid: UID of the object to remove
5175 * @rid: Recurrence ID of the specific recurrence to remove
5176 * @mod: Type of the removal
5177 * @cancellable: a #GCancellable; can be %NULL
5178 * @error: (out): a #GError to set an error, if any
5180 * This function allows the removal of instances of a recurrent
5181 * appointment. By using a combination of the @uid, @rid and @mod
5182 * arguments, you can remove specific instances. If what you want
5183 * is to remove all instances, use #NULL @rid and E_CAL_OBJ_MODE_THIS
5186 * Returns: %TRUE if successful, %FALSE otherwise.
5191 e_cal_client_remove_object_sync (ECalClient *client,
5195 GCancellable *cancellable,
5198 ECalComponentId id = { (gchar *) uid, (gchar *) rid };
5199 GSList link = { &id, NULL };
5201 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
5202 g_return_val_if_fail (uid != NULL, FALSE);
5204 if (client->priv->dbus_proxy == NULL) {
5205 set_proxy_gone_error (error);
5209 return e_cal_client_remove_objects_sync (
5210 client, &link, mod, cancellable, error);
5213 /* Helper for e_cal_client_remove_objects() */
5215 cal_client_remove_objects_thread (GSimpleAsyncResult *simple,
5216 GObject *source_object,
5217 GCancellable *cancellable)
5219 AsyncContext *async_context;
5220 GError *error = NULL;
5222 async_context = g_simple_async_result_get_op_res_gpointer (simple);
5224 e_cal_client_remove_objects_sync (
5225 E_CAL_CLIENT (source_object),
5226 async_context->string_list,
5228 cancellable, &error);
5231 g_simple_async_result_take_error (simple, error);
5235 * e_cal_client_remove_objects:
5236 * @client: an #ECalClient
5237 * @ids: (element-type ECalComponentId): A list of #ECalComponentId objects
5238 * identifying the objects to remove
5239 * @mod: Type of the removal
5240 * @cancellable: a #GCancellable; can be %NULL
5241 * @callback: callback to call when a result is ready
5242 * @user_data: user data for the @callback
5244 * This function allows the removal of instances of recurrent
5245 * appointments. #ECalComponentId objects can identify specific instances (if rid is not NULL).
5246 * If what you want is to remove all instances, use a #NULL rid in the #ECalComponentId and E_CAL_OBJ_MOD_ALL
5249 * The call is finished by e_cal_client_remove_objects_finish() from
5255 e_cal_client_remove_objects (ECalClient *client,
5258 GCancellable *cancellable,
5259 GAsyncReadyCallback callback,
5262 GSimpleAsyncResult *simple;
5263 AsyncContext *async_context;
5265 g_return_if_fail (E_IS_CAL_CLIENT (client));
5266 g_return_if_fail (ids != NULL);
5268 async_context = g_slice_new0 (AsyncContext);
5269 async_context->string_list = g_slist_copy_deep (
5270 (GSList *) ids, (GCopyFunc) g_strdup, NULL);
5271 async_context->mod = mod;
5273 simple = g_simple_async_result_new (
5274 G_OBJECT (client), callback, user_data,
5275 e_cal_client_remove_objects);
5277 g_simple_async_result_set_check_cancellable (simple, cancellable);
5279 g_simple_async_result_set_op_res_gpointer (
5280 simple, async_context, (GDestroyNotify) async_context_free);
5282 g_simple_async_result_run_in_thread (
5283 simple, cal_client_remove_objects_thread,
5284 G_PRIORITY_DEFAULT, cancellable);
5286 g_object_unref (simple);
5290 * e_cal_client_remove_objects_finish:
5291 * @client: an #ECalClient
5292 * @result: a #GAsyncResult
5293 * @error: (out): a #GError to set an error, if any
5295 * Finishes previous call of e_cal_client_remove_objects().
5297 * Returns: %TRUE if successful, %FALSE otherwise.
5302 e_cal_client_remove_objects_finish (ECalClient *client,
5303 GAsyncResult *result,
5306 GSimpleAsyncResult *simple;
5308 g_return_val_if_fail (
5309 g_simple_async_result_is_valid (
5310 result, G_OBJECT (client),
5311 e_cal_client_remove_objects), FALSE);
5313 simple = G_SIMPLE_ASYNC_RESULT (result);
5315 /* Assume success unless a GError is set. */
5316 return !g_simple_async_result_propagate_error (simple, error);
5320 * e_cal_client_remove_objects_sync:
5321 * @client: an #ECalClient
5322 * @ids: (element-type ECalComponentId): a list of #ECalComponentId objects
5323 * identifying the objects to remove
5324 * @mod: Type of the removal
5325 * @cancellable: (allow-none): a #GCancellable; can be %NULL
5326 * @error: (out): a #GError to set an error, if any
5328 * This function allows the removal of instances of recurrent
5329 * appointments. #ECalComponentId objects can identify specific instances
5330 * (if rid is not %NULL). If what you want is to remove all instances, use
5331 * a %NULL rid in the #ECalComponentId and E_CAL_OBJ_MOD_ALL for the @mod.
5333 * Returns: %TRUE if successful, %FALSE otherwise.
5338 e_cal_client_remove_objects_sync (ECalClient *client,
5341 GCancellable *cancellable,
5344 GVariantBuilder builder;
5345 GEnumClass *enum_class;
5346 GEnumValue *enum_value;
5349 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
5350 g_return_val_if_fail (ids != NULL, FALSE);
5352 if (client->priv->dbus_proxy == NULL) {
5353 set_proxy_gone_error (error);
5357 enum_class = g_type_class_ref (E_TYPE_CAL_OBJ_MOD_TYPE);
5358 enum_value = g_enum_get_value (enum_class, mod);
5359 g_return_val_if_fail (enum_value != NULL, FALSE);
5361 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
5362 while (ids != NULL) {
5363 ECalComponentId *id = ids->data;
5367 if (id->uid == NULL || *id->uid == '\0')
5370 utf8_uid = e_util_utf8_make_valid (id->uid);
5371 if (id->rid != NULL)
5372 utf8_rid = e_util_utf8_make_valid (id->rid);
5374 utf8_rid = g_strdup ("");
5376 g_variant_builder_add (&builder, "(ss)", utf8_uid, utf8_rid);
5382 success = e_dbus_calendar_call_remove_objects_sync (
5383 client->priv->dbus_proxy,
5384 g_variant_builder_end (&builder),
5385 enum_value->value_nick,
5386 cancellable, error);
5388 g_type_class_unref (enum_class);
5393 /* Helper for e_cal_client_receive_objects() */
5395 cal_client_receive_objects_thread (GSimpleAsyncResult *simple,
5396 GObject *source_object,
5397 GCancellable *cancellable)
5399 AsyncContext *async_context;
5400 GError *error = NULL;
5402 async_context = g_simple_async_result_get_op_res_gpointer (simple);
5404 e_cal_client_receive_objects_sync (
5405 E_CAL_CLIENT (source_object),
5406 async_context->in_comp,
5407 cancellable, &error);
5410 g_simple_async_result_take_error (simple, error);
5414 * e_cal_client_receive_objects:
5415 * @client: an #ECalClient
5416 * @icalcomp: An #icalcomponent
5417 * @cancellable: a #GCancellable; can be %NULL
5418 * @callback: callback to call when a result is ready
5419 * @user_data: user data for the @callback
5421 * Makes the backend receive the set of iCalendar objects specified in the
5422 * @icalcomp argument. This is used for iTIP confirmation/cancellation
5423 * messages for scheduled meetings.
5425 * The call is finished by e_cal_client_receive_objects_finish() from
5431 e_cal_client_receive_objects (ECalClient *client,
5432 icalcomponent *icalcomp,
5433 GCancellable *cancellable,
5434 GAsyncReadyCallback callback,
5437 GSimpleAsyncResult *simple;
5438 AsyncContext *async_context;
5440 g_return_if_fail (E_IS_CAL_CLIENT (client));
5441 g_return_if_fail (icalcomp != NULL);
5443 async_context = g_slice_new0 (AsyncContext);
5444 async_context->in_comp = icalcomponent_new_clone (icalcomp);
5446 simple = g_simple_async_result_new (
5447 G_OBJECT (client), callback, user_data,
5448 e_cal_client_receive_objects);
5450 g_simple_async_result_set_check_cancellable (simple, cancellable);
5452 g_simple_async_result_set_op_res_gpointer (
5453 simple, async_context, (GDestroyNotify) async_context_free);
5455 g_simple_async_result_run_in_thread (
5456 simple, cal_client_receive_objects_thread,
5457 G_PRIORITY_DEFAULT, cancellable);
5459 g_object_unref (simple);
5463 * e_cal_client_receive_objects_finish:
5464 * @client: an #ECalClient
5465 * @result: a #GAsyncResult
5466 * @error: (out): a #GError to set an error, if any
5468 * Finishes previous call of e_cal_client_receive_objects().
5470 * Returns: %TRUE if successful, %FALSE otherwise.
5475 e_cal_client_receive_objects_finish (ECalClient *client,
5476 GAsyncResult *result,
5479 GSimpleAsyncResult *simple;
5481 g_return_val_if_fail (
5482 g_simple_async_result_is_valid (
5483 result, G_OBJECT (client),
5484 e_cal_client_receive_objects), FALSE);
5486 simple = G_SIMPLE_ASYNC_RESULT (result);
5488 /* Assume success unless a GError is set. */
5489 return !g_simple_async_result_propagate_error (simple, error);
5493 * e_cal_client_receive_objects_sync:
5494 * @client: an #ECalClient
5495 * @icalcomp: An #icalcomponent
5496 * @cancellable: a #GCancellable; can be %NULL
5497 * @error: (out): a #GError to set an error, if any
5499 * Makes the backend receive the set of iCalendar objects specified in the
5500 * @icalcomp argument. This is used for iTIP confirmation/cancellation
5501 * messages for scheduled meetings.
5503 * Returns: %TRUE if successful, %FALSE otherwise.
5508 e_cal_client_receive_objects_sync (ECalClient *client,
5509 icalcomponent *icalcomp,
5510 GCancellable *cancellable,
5514 gchar *utf8_ical_string;
5517 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
5519 if (client->priv->dbus_proxy == NULL) {
5520 set_proxy_gone_error (error);
5524 ical_string = icalcomponent_as_ical_string_r (icalcomp);
5525 utf8_ical_string = e_util_utf8_make_valid (ical_string);
5527 success = e_dbus_calendar_call_receive_objects_sync (
5528 client->priv->dbus_proxy,
5529 utf8_ical_string, cancellable, error);
5531 g_free (utf8_ical_string);
5532 g_free (ical_string);
5537 /* Helper for e_cal_client_send_objects() */
5539 cal_client_send_objects_thread (GSimpleAsyncResult *simple,
5540 GObject *source_object,
5541 GCancellable *cancellable)
5543 AsyncContext *async_context;
5544 GError *error = NULL;
5546 async_context = g_simple_async_result_get_op_res_gpointer (simple);
5548 e_cal_client_send_objects_sync (
5549 E_CAL_CLIENT (source_object),
5550 async_context->in_comp,
5551 &async_context->string_list,
5552 &async_context->out_comp,
5553 cancellable, &error);
5556 g_simple_async_result_take_error (simple, error);
5560 * e_cal_client_send_objects:
5561 * @client: an #ECalClient
5562 * @icalcomp: An icalcomponent to be sent
5563 * @cancellable: a #GCancellable; can be %NULL
5564 * @callback: callback to call when a result is ready
5565 * @user_data: user data for the @callback
5567 * Requests a calendar backend to send meeting information stored in @icalcomp.
5568 * The backend can modify this component and request a send to particular users.
5569 * The call is finished by e_cal_client_send_objects_finish() from
5575 e_cal_client_send_objects (ECalClient *client,
5576 icalcomponent *icalcomp,
5577 GCancellable *cancellable,
5578 GAsyncReadyCallback callback,
5581 GSimpleAsyncResult *simple;
5582 AsyncContext *async_context;
5584 g_return_if_fail (E_IS_CAL_CLIENT (client));
5585 g_return_if_fail (icalcomp != NULL);
5587 async_context = g_slice_new0 (AsyncContext);
5588 async_context->in_comp = icalcomponent_new_clone (icalcomp);
5590 simple = g_simple_async_result_new (
5591 G_OBJECT (client), callback, user_data,
5592 e_cal_client_send_objects);
5594 g_simple_async_result_set_check_cancellable (simple, cancellable);
5596 g_simple_async_result_set_op_res_gpointer (
5597 simple, async_context, (GDestroyNotify) async_context_free);
5599 g_simple_async_result_run_in_thread (
5600 simple, cal_client_send_objects_thread,
5601 G_PRIORITY_DEFAULT, cancellable);
5603 g_object_unref (simple);
5607 * e_cal_client_send_objects_finish:
5608 * @client: an #ECalClient
5609 * @result: a #GAsyncResult
5610 * @out_users: (out) (element-type utf8): List of users to send
5611 * the @out_modified_icalcomp to
5612 * @out_modified_icalcomp: (out): Return value for the icalcomponent to be sent
5613 * @error: (out): a #GError to set an error, if any
5615 * Finishes previous call of e_cal_client_send_objects() and
5616 * populates @out_users with a list of users to send @out_modified_icalcomp to.
5618 * The @out_users list should be freed with e_client_util_free_string_slist()
5619 * and the @out_modified_icalcomp should be freed with icalcomponent_free().
5621 * Returns: %TRUE if successful, %FALSE otherwise.
5626 e_cal_client_send_objects_finish (ECalClient *client,
5627 GAsyncResult *result,
5629 icalcomponent **out_modified_icalcomp,
5632 GSimpleAsyncResult *simple;
5633 AsyncContext *async_context;
5635 g_return_val_if_fail (
5636 g_simple_async_result_is_valid (
5637 result, G_OBJECT (client),
5638 e_cal_client_send_objects), FALSE);
5640 simple = G_SIMPLE_ASYNC_RESULT (result);
5641 async_context = g_simple_async_result_get_op_res_gpointer (simple);
5643 if (g_simple_async_result_propagate_error (simple, error))
5646 g_return_val_if_fail (async_context->out_comp != NULL, FALSE);
5648 if (out_users != NULL) {
5649 *out_users = async_context->string_list;
5650 async_context->string_list = NULL;
5653 if (out_modified_icalcomp != NULL) {
5654 *out_modified_icalcomp = async_context->out_comp;
5655 async_context->out_comp = NULL;
5662 * e_cal_client_send_objects_sync:
5663 * @client: an #ECalClient
5664 * @icalcomp: An icalcomponent to be sent
5665 * @out_users: (out) (element-type utf8): List of users to send the
5666 * @out_modified_icalcomp to
5667 * @out_modified_icalcomp: (out): Return value for the icalcomponent to be sent
5668 * @cancellable: (allow-none): a #GCancellable; can be %NULL
5669 * @error: (out): a #GError to set an error, if any
5671 * Requests a calendar backend to send meeting information stored in @icalcomp.
5672 * The backend can modify this component and request a send to users in the
5675 * The @out_users list should be freed with e_client_util_free_string_slist()
5676 * and the @out_modified_icalcomp should be freed with icalcomponent_free().
5678 * Returns: %TRUE if successful, %FALSE otherwise.
5683 e_cal_client_send_objects_sync (ECalClient *client,
5684 icalcomponent *icalcomp,
5686 icalcomponent **out_modified_icalcomp,
5687 GCancellable *cancellable,
5691 gchar *utf8_ical_string;
5692 gchar **users = NULL;
5693 gchar *out_ical_string = NULL;
5696 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
5697 g_return_val_if_fail (icalcomp != NULL, FALSE);
5698 g_return_val_if_fail (out_users != NULL, FALSE);
5699 g_return_val_if_fail (out_modified_icalcomp != NULL, FALSE);
5701 if (client->priv->dbus_proxy == NULL) {
5702 set_proxy_gone_error (error);
5706 ical_string = icalcomponent_as_ical_string_r (icalcomp);
5707 utf8_ical_string = e_util_utf8_make_valid (ical_string);
5709 success = e_dbus_calendar_call_send_objects_sync (
5710 client->priv->dbus_proxy, utf8_ical_string,
5711 &users, &out_ical_string, cancellable, error);
5713 g_free (utf8_ical_string);
5714 g_free (ical_string);
5717 g_return_val_if_fail (
5718 (success && (out_ical_string != NULL)) ||
5719 (!success && (out_ical_string == NULL)), FALSE);
5722 g_warn_if_fail (users == NULL);
5726 icalcomp = icalparser_parse_string (out_ical_string);
5728 g_free (out_ical_string);
5730 if (icalcomp != NULL) {
5731 *out_modified_icalcomp = icalcomp;
5733 g_set_error_literal (
5734 error, E_CAL_CLIENT_ERROR,
5735 E_CAL_CLIENT_ERROR_INVALID_OBJECT,
5736 e_cal_client_error_to_string (
5737 E_CAL_CLIENT_ERROR_INVALID_OBJECT));
5742 if (users != NULL) {
5746 for (ii = 0; users[ii] != NULL; ii++) {
5747 tmp = g_slist_prepend (tmp, users[ii]);
5751 *out_users = g_slist_reverse (tmp);
5759 /* Helper for e_cal_client_get_attachment_uris() */
5761 cal_client_get_attachment_uris_thread (GSimpleAsyncResult *simple,
5762 GObject *source_object,
5763 GCancellable *cancellable)
5765 AsyncContext *async_context;
5766 GError *error = NULL;
5768 async_context = g_simple_async_result_get_op_res_gpointer (simple);
5770 e_cal_client_get_attachment_uris_sync (
5771 E_CAL_CLIENT (source_object),
5774 &async_context->string_list,
5775 cancellable, &error);
5778 g_simple_async_result_take_error (simple, error);
5782 * e_cal_client_get_attachment_uris:
5783 * @client: an #ECalClient
5784 * @uid: Unique identifier for a calendar component
5785 * @rid: Recurrence identifier
5786 * @cancellable: a #GCancellable; can be %NULL
5787 * @callback: callback to call when a result is ready
5788 * @user_data: user data for the @callback
5790 * Queries a calendar for a specified component's object attachment uris.
5791 * The call is finished by e_cal_client_get_attachment_uris_finish() from
5797 e_cal_client_get_attachment_uris (ECalClient *client,
5800 GCancellable *cancellable,
5801 GAsyncReadyCallback callback,
5804 GSimpleAsyncResult *simple;
5805 AsyncContext *async_context;
5807 g_return_if_fail (E_CAL_CLIENT (client));
5808 g_return_if_fail (uid != NULL);
5809 /* rid is optional */
5811 async_context = g_slice_new0 (AsyncContext);
5812 async_context->uid = g_strdup (uid);
5813 async_context->rid = g_strdup (rid);
5815 simple = g_simple_async_result_new (
5816 G_OBJECT (client), callback, user_data,
5817 e_cal_client_get_attachment_uris);
5819 g_simple_async_result_set_check_cancellable (simple, cancellable);
5821 g_simple_async_result_run_in_thread (
5822 simple, cal_client_get_attachment_uris_thread,
5823 G_PRIORITY_DEFAULT, cancellable);
5825 g_object_unref (simple);
5829 * e_cal_client_get_attachment_uris_finish:
5830 * @client: an #ECalClient
5831 * @result: a #GAsyncResult
5832 * @out_attachment_uris: (out) (element-type utf8): Return location for the
5833 * list of attachment URIs
5834 * @error: (out): a #GError to set an error, if any
5836 * Finishes previous call of e_cal_client_get_attachment_uris() and
5837 * sets @out_attachment_uris to uris for component's attachments.
5838 * The list should be freed with e_client_util_free_string_slist().
5840 * Returns: %TRUE if successful, %FALSE otherwise.
5845 e_cal_client_get_attachment_uris_finish (ECalClient *client,
5846 GAsyncResult *result,
5847 GSList **out_attachment_uris,
5850 GSimpleAsyncResult *simple;
5851 AsyncContext *async_context;
5853 g_return_val_if_fail (
5854 g_simple_async_result_is_valid (
5855 result, G_OBJECT (client),
5856 e_cal_client_get_attachment_uris), FALSE);
5858 simple = G_SIMPLE_ASYNC_RESULT (result);
5859 async_context = g_simple_async_result_get_op_res_gpointer (simple);
5861 if (g_simple_async_result_propagate_error (simple, error))
5864 if (out_attachment_uris != NULL) {
5865 *out_attachment_uris = async_context->string_list;
5866 async_context->string_list = NULL;
5873 * e_cal_client_get_attachment_uris_sync:
5874 * @client: an #ECalClient
5875 * @uid: Unique identifier for a calendar component
5876 * @rid: Recurrence identifier
5877 * @out_attachment_uris: (out) (element-type utf8): Return location for the
5878 * list of attachment URIs
5879 * @cancellable: (allow-none): a #GCancellable; can be %NULL
5880 * @error: (out): a #GError to set an error, if any
5882 * Queries a calendar for a specified component's object attachment URIs.
5883 * The list should be freed with e_client_util_free_string_slist().
5885 * Returns: %TRUE if successful, %FALSE otherwise.
5890 e_cal_client_get_attachment_uris_sync (ECalClient *client,
5893 GSList **out_attachment_uris,
5894 GCancellable *cancellable,
5899 gchar **uris = NULL;
5902 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
5903 g_return_val_if_fail (uid != NULL, FALSE);
5904 g_return_val_if_fail (out_attachment_uris != NULL, FALSE);
5909 if (client->priv->dbus_proxy == NULL) {
5910 set_proxy_gone_error (error);
5914 utf8_uid = e_util_utf8_make_valid (uid);
5915 utf8_rid = e_util_utf8_make_valid (rid);
5917 success = e_dbus_calendar_call_get_attachment_uris_sync (
5918 client->priv->dbus_proxy, utf8_uid,
5919 utf8_rid, &uris, cancellable, error);
5925 g_return_val_if_fail (
5926 (success && (uris != NULL)) ||
5927 (!success && (uris == NULL)), FALSE);
5933 for (ii = 0; uris[ii] != NULL; ii++) {
5934 tmp = g_slist_prepend (tmp, uris[ii]);
5938 *out_attachment_uris = g_slist_reverse (tmp);
5944 /* Helper for e_cal_client_discard_alarm() */
5946 cal_client_discard_alarm_thread (GSimpleAsyncResult *simple,
5947 GObject *source_object,
5948 GCancellable *cancellable)
5950 AsyncContext *async_context;
5951 GError *error = NULL;
5953 async_context = g_simple_async_result_get_op_res_gpointer (simple);
5955 e_cal_client_discard_alarm_sync (
5956 E_CAL_CLIENT (source_object),
5959 async_context->auid,
5960 cancellable, &error);
5963 g_simple_async_result_take_error (simple, error);
5967 * e_cal_client_discard_alarm:
5968 * @client: an #ECalClient
5969 * @uid: Unique identifier for a calendar component
5970 * @rid: Recurrence identifier
5971 * @auid: Alarm identifier to remove
5972 * @cancellable: a #GCancellable; can be %NULL
5973 * @callback: callback to call when a result is ready
5974 * @user_data: user data for the @callback
5976 * Removes alarm @auid from a given component identified by @uid and @rid.
5977 * The call is finished by e_cal_client_discard_alarm_finish() from
5983 e_cal_client_discard_alarm (ECalClient *client,
5987 GCancellable *cancellable,
5988 GAsyncReadyCallback callback,
5991 GSimpleAsyncResult *simple;
5992 AsyncContext *async_context;
5994 g_return_if_fail (E_IS_CAL_CLIENT (client));
5995 g_return_if_fail (uid != NULL);
5996 /* rid is optional */
5997 g_return_if_fail (auid != NULL);
5999 async_context = g_slice_new0 (AsyncContext);
6000 async_context->uid = g_strdup (uid);
6001 async_context->rid = NULL;
6002 async_context->auid = g_strdup (auid);
6004 simple = g_simple_async_result_new (
6005 G_OBJECT (client), callback, user_data,
6006 e_cal_client_discard_alarm);
6008 g_simple_async_result_set_check_cancellable (simple, cancellable);
6010 g_simple_async_result_set_op_res_gpointer (
6011 simple, async_context, (GDestroyNotify) async_context_free);
6013 g_simple_async_result_run_in_thread (
6014 simple, cal_client_discard_alarm_thread,
6015 G_PRIORITY_DEFAULT, cancellable);
6017 g_object_unref (simple);
6021 * e_cal_client_discard_alarm_finish:
6022 * @client: an #ECalClient
6023 * @result: a #GAsyncResult
6024 * @error: (out): a #GError to set an error, if any
6026 * Finishes previous call of e_cal_client_discard_alarm().
6028 * Returns: %TRUE if successful, %FALSE otherwise.
6033 e_cal_client_discard_alarm_finish (ECalClient *client,
6034 GAsyncResult *result,
6037 GSimpleAsyncResult *simple;
6039 g_return_val_if_fail (
6040 g_simple_async_result_is_valid (
6041 result, G_OBJECT (client),
6042 e_cal_client_discard_alarm), FALSE);
6044 simple = G_SIMPLE_ASYNC_RESULT (result);
6046 /* Assume success unless a GError is set. */
6047 return !g_simple_async_result_propagate_error (simple, error);
6051 * e_cal_client_discard_alarm_sync:
6052 * @client: an #ECalClient
6053 * @uid: Unique identifier for a calendar component
6054 * @rid: Recurrence identifier
6055 * @auid: Alarm identifier to remove
6056 * @cancellable: a #GCancellable; can be %NULL
6057 * @error: (out): a #GError to set an error, if any
6059 * Removes alarm @auid from a given component identified by @uid and @rid.
6061 * Returns: %TRUE if successful, %FALSE otherwise.
6066 e_cal_client_discard_alarm_sync (ECalClient *client,
6070 GCancellable *cancellable,
6078 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
6079 g_return_val_if_fail (uid != NULL, FALSE);
6080 g_return_val_if_fail (auid != NULL, FALSE);
6085 if (client->priv->dbus_proxy == NULL) {
6086 set_proxy_gone_error (error);
6090 utf8_uid = e_util_utf8_make_valid (uid);
6091 utf8_rid = e_util_utf8_make_valid (rid);
6092 utf8_auid = e_util_utf8_make_valid (auid);
6094 success = e_dbus_calendar_call_discard_alarm_sync (
6095 client->priv->dbus_proxy, utf8_uid,
6096 utf8_rid, utf8_auid, cancellable, error);
6105 /* Helper for e_cal_client_get_view() */
6107 cal_client_get_view_thread (GSimpleAsyncResult *simple,
6108 GObject *source_object,
6109 GCancellable *cancellable)
6111 AsyncContext *async_context;
6112 GError *error = NULL;
6114 async_context = g_simple_async_result_get_op_res_gpointer (simple);
6116 e_cal_client_get_view_sync (
6117 E_CAL_CLIENT (source_object),
6118 async_context->sexp,
6119 &async_context->client_view,
6120 cancellable, &error);
6123 g_simple_async_result_take_error (simple, error);
6127 * e_cal_client_get_view:
6128 * @client: an #ECalClient
6129 * @sexp: an S-expression representing the query.
6130 * @cancellable: a #GCancellable; can be %NULL
6131 * @callback: callback to call when a result is ready
6132 * @user_data: user data for the @callback
6134 * Query @client with @sexp, creating an #ECalClientView.
6135 * The call is finished by e_cal_client_get_view_finish()
6136 * from the @callback.
6141 e_cal_client_get_view (ECalClient *client,
6143 GCancellable *cancellable,
6144 GAsyncReadyCallback callback,
6147 GSimpleAsyncResult *simple;
6148 AsyncContext *async_context;
6150 g_return_if_fail (E_IS_CAL_CLIENT (client));
6151 g_return_if_fail (sexp != NULL);
6153 async_context = g_slice_new0 (AsyncContext);
6154 async_context->sexp = g_strdup (sexp);
6156 simple = g_simple_async_result_new (
6157 G_OBJECT (client), callback, user_data,
6158 e_cal_client_get_view);
6160 g_simple_async_result_set_check_cancellable (simple, cancellable);
6162 g_simple_async_result_set_op_res_gpointer (
6163 simple, async_context, (GDestroyNotify) async_context_free);
6165 g_simple_async_result_run_in_thread (
6166 simple, cal_client_get_view_thread,
6167 G_PRIORITY_DEFAULT, cancellable);
6169 g_object_unref (simple);
6173 * e_cal_client_get_view_finish:
6174 * @client: an #ECalClient
6175 * @result: a #GAsyncResult
6176 * @out_view: (out) an #ECalClientView
6177 * @error: (out): a #GError to set an error, if any
6179 * Finishes previous call of e_cal_client_get_view().
6180 * If successful, then the @out_view is set to newly allocated #ECalClientView,
6181 * which should be freed with g_object_unref().
6183 * Returns: %TRUE if successful, %FALSE otherwise.
6188 e_cal_client_get_view_finish (ECalClient *client,
6189 GAsyncResult *result,
6190 ECalClientView **out_view,
6193 GSimpleAsyncResult *simple;
6194 AsyncContext *async_context;
6196 g_return_val_if_fail (
6197 g_simple_async_result_is_valid (
6198 result, G_OBJECT (client),
6199 e_cal_client_get_view), FALSE);
6201 simple = G_SIMPLE_ASYNC_RESULT (result);
6202 async_context = g_simple_async_result_get_op_res_gpointer (simple);
6204 if (g_simple_async_result_propagate_error (simple, error))
6207 g_return_val_if_fail (async_context->client_view != NULL, FALSE);
6209 if (out_view != NULL)
6210 *out_view = g_object_ref (async_context->client_view);
6216 * e_cal_client_get_view_sync:
6217 * @client: an #ECalClient
6218 * @sexp: an S-expression representing the query.
6219 * @out_view: (out) an #ECalClientView
6220 * @cancellable: a #GCancellable; can be %NULL
6221 * @error: (out): a #GError to set an error, if any
6223 * Query @client with @sexp, creating an #ECalClientView.
6224 * If successful, then the @out_view is set to newly allocated #ECalClientView,
6225 * which should be freed with g_object_unref().
6227 * Returns: %TRUE if successful, %FALSE otherwise.
6232 e_cal_client_get_view_sync (ECalClient *client,
6234 ECalClientView **out_view,
6235 GCancellable *cancellable,
6239 gchar *object_path = NULL;
6242 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
6243 g_return_val_if_fail (sexp != NULL, FALSE);
6244 g_return_val_if_fail (out_view != NULL, FALSE);
6246 if (client->priv->dbus_proxy == NULL) {
6247 set_proxy_gone_error (error);
6251 utf8_sexp = e_util_utf8_make_valid (sexp);
6253 success = e_dbus_calendar_call_get_view_sync (
6254 client->priv->dbus_proxy, utf8_sexp,
6255 &object_path, cancellable, error);
6260 g_return_val_if_fail (
6261 (success && (object_path != NULL)) ||
6262 (!success && (object_path == NULL)), FALSE);
6264 if (object_path != NULL) {
6265 GDBusConnection *connection;
6266 ECalClientView *client_view;
6268 connection = g_dbus_proxy_get_connection (
6269 G_DBUS_PROXY (client->priv->dbus_proxy));
6271 client_view = g_initable_new (
6272 E_TYPE_CAL_CLIENT_VIEW,
6275 "connection", connection,
6276 "object-path", object_path,
6279 /* XXX Would have been easier to return the
6280 * EBookClientView directly rather than
6281 * through an "out" parameter. */
6282 if (client_view != NULL)
6283 *out_view = client_view;
6287 g_free (object_path);
6293 /* Helper for e_cal_client_get_timezone() */
6295 cal_client_get_timezone_thread (GSimpleAsyncResult *simple,
6296 GObject *source_object,
6297 GCancellable *cancellable)
6299 AsyncContext *async_context;
6300 GError *error = NULL;
6302 async_context = g_simple_async_result_get_op_res_gpointer (simple);
6304 e_cal_client_get_timezone_sync (
6305 E_CAL_CLIENT (source_object),
6306 async_context->tzid,
6307 &async_context->zone,
6308 cancellable, &error);
6311 g_simple_async_result_take_error (simple, error);
6315 * e_cal_client_get_timezone:
6316 * @client: an #ECalClient
6317 * @tzid: ID of the timezone to retrieve
6318 * @cancellable: a #GCancellable; can be %NULL
6319 * @callback: callback to call when a result is ready
6320 * @user_data: user data for the @callback
6322 * Retrieves a timezone object from the calendar backend.
6323 * The call is finished by e_cal_client_get_timezone_finish() from
6329 e_cal_client_get_timezone (ECalClient *client,
6331 GCancellable *cancellable,
6332 GAsyncReadyCallback callback,
6335 GSimpleAsyncResult *simple;
6336 AsyncContext *async_context;
6338 g_return_if_fail (E_IS_CAL_CLIENT (client));
6339 g_return_if_fail (tzid != NULL);
6341 async_context = g_slice_new0 (AsyncContext);
6342 async_context->tzid = g_strdup (tzid);
6344 simple = g_simple_async_result_new (
6345 G_OBJECT (client), callback, user_data,
6346 e_cal_client_get_timezone);
6348 g_simple_async_result_set_check_cancellable (simple, cancellable);
6350 g_simple_async_result_set_op_res_gpointer (
6351 simple, async_context, (GDestroyNotify) async_context_free);
6353 g_simple_async_result_run_in_thread (
6354 simple, cal_client_get_timezone_thread,
6355 G_PRIORITY_DEFAULT, cancellable);
6357 g_object_unref (simple);
6361 * e_cal_client_get_timezone_finish:
6362 * @client: an #ECalClient
6363 * @result: a #GAsyncResult
6364 * @out_zone: (out): Return value for the timezone
6365 * @error: (out): a #GError to set an error, if any
6367 * Finishes previous call of e_cal_client_get_timezone() and
6368 * sets @out_zone to a retrieved timezone object from the calendar backend.
6369 * This object is owned by the @client, thus do not free it.
6371 * Returns: %TRUE if successful, %FALSE otherwise.
6376 e_cal_client_get_timezone_finish (ECalClient *client,
6377 GAsyncResult *result,
6378 icaltimezone **out_zone,
6381 GSimpleAsyncResult *simple;
6382 AsyncContext *async_context;
6384 g_return_val_if_fail (
6385 g_simple_async_result_is_valid (
6386 result, G_OBJECT (client),
6387 e_cal_client_get_timezone), FALSE);
6389 simple = G_SIMPLE_ASYNC_RESULT (result);
6390 async_context = g_simple_async_result_get_op_res_gpointer (simple);
6392 if (g_simple_async_result_propagate_error (simple, error))
6395 g_return_val_if_fail (async_context->zone != NULL, FALSE);
6397 if (out_zone != NULL) {
6398 *out_zone = async_context->zone;
6399 async_context->zone = NULL;
6406 * e_cal_client_get_timezone_sync:
6407 * @client: an #ECalClient
6408 * @tzid: ID of the timezone to retrieve
6409 * @out_zone: (out): Return value for the timezone
6410 * @cancellable: a #GCancellable; can be %NULL
6411 * @error: (out): a #GError to set an error, if any
6413 * Retrieves a timezone object from the calendar backend.
6414 * This object is owned by the @client, thus do not free it.
6416 * Returns: %TRUE if successful, %FALSE otherwise.
6421 e_cal_client_get_timezone_sync (ECalClient *client,
6423 icaltimezone **out_zone,
6424 GCancellable *cancellable,
6427 icalcomponent *icalcomp;
6430 gchar *string = NULL;
6433 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
6434 g_return_val_if_fail (tzid != NULL, FALSE);
6435 g_return_val_if_fail (out_zone != NULL, FALSE);
6437 if (client->priv->dbus_proxy == NULL) {
6438 set_proxy_gone_error (error);
6442 zone = e_timezone_cache_get_timezone (
6443 E_TIMEZONE_CACHE (client), tzid);
6449 utf8_tzid = e_util_utf8_make_valid (tzid);
6451 success = e_dbus_calendar_call_get_timezone_sync (
6452 client->priv->dbus_proxy, utf8_tzid,
6453 &string, cancellable, error);
6458 g_return_val_if_fail (
6459 (success && (string != NULL)) ||
6460 (!success && (string == NULL)), FALSE);
6465 icalcomp = icalparser_parse_string (string);
6469 if (icalcomp == NULL) {
6470 g_set_error_literal (
6471 error, E_CAL_CLIENT_ERROR,
6472 E_CAL_CLIENT_ERROR_INVALID_OBJECT,
6473 e_cal_client_error_to_string (
6474 E_CAL_CLIENT_ERROR_INVALID_OBJECT));
6478 zone = icaltimezone_new ();
6479 if (!icaltimezone_set_component (zone, icalcomp)) {
6480 g_set_error_literal (
6481 error, E_CAL_CLIENT_ERROR,
6482 E_CAL_CLIENT_ERROR_INVALID_OBJECT,
6483 e_cal_client_error_to_string (
6484 E_CAL_CLIENT_ERROR_INVALID_OBJECT));
6485 icalcomponent_free (icalcomp);
6486 icaltimezone_free (zone, 1);
6490 /* Add the timezone to the cache directly,
6491 * otherwise we'd have to free this struct
6492 * and fetch the cached copy. */
6493 g_mutex_lock (&client->priv->zone_cache_lock);
6494 g_hash_table_insert (
6495 client->priv->zone_cache, g_strdup (tzid), zone);
6496 g_mutex_unlock (&client->priv->zone_cache_lock);
6503 /* Helper for e_cal_client_add_timezone() */
6505 cal_client_add_timezone_thread (GSimpleAsyncResult *simple,
6506 GObject *source_object,
6507 GCancellable *cancellable)
6509 AsyncContext *async_context;
6510 GError *error = NULL;
6512 async_context = g_simple_async_result_get_op_res_gpointer (simple);
6514 e_cal_client_add_timezone_sync (
6515 E_CAL_CLIENT (source_object),
6516 async_context->zone,
6517 cancellable, &error);
6520 g_simple_async_result_take_error (simple, error);
6524 * e_cal_client_add_timezone:
6525 * @client: an #ECalClient
6526 * @zone: The timezone to add
6527 * @cancellable: a #GCancellable; can be %NULL
6528 * @callback: callback to call when a result is ready
6529 * @user_data: user data for the @callback
6531 * Add a VTIMEZONE object to the given calendar client.
6532 * The call is finished by e_cal_client_add_timezone_finish() from
6538 e_cal_client_add_timezone (ECalClient *client,
6540 GCancellable *cancellable,
6541 GAsyncReadyCallback callback,
6544 GSimpleAsyncResult *simple;
6545 AsyncContext *async_context;
6546 icalcomponent *icalcomp;
6548 g_return_if_fail (E_IS_CAL_CLIENT (client));
6549 g_return_if_fail (zone != NULL);
6551 icalcomp = icaltimezone_get_component (zone);
6552 g_return_if_fail (icalcomp != NULL);
6554 async_context = g_slice_new0 (AsyncContext);
6555 async_context->zone = icaltimezone_new ();
6557 icalcomp = icalcomponent_new_clone (icalcomp);
6558 icaltimezone_set_component (async_context->zone, icalcomp);
6560 simple = g_simple_async_result_new (
6561 G_OBJECT (client), callback, user_data,
6562 e_cal_client_add_timezone);
6564 g_simple_async_result_set_check_cancellable (simple, cancellable);
6566 g_simple_async_result_set_op_res_gpointer (
6567 simple, async_context, (GDestroyNotify) async_context_free);
6569 if (zone == icaltimezone_get_utc_timezone ())
6570 g_simple_async_result_complete_in_idle (simple);
6572 g_simple_async_result_run_in_thread (
6573 simple, cal_client_add_timezone_thread,
6574 G_PRIORITY_DEFAULT, cancellable);
6576 g_object_unref (simple);
6580 * e_cal_client_add_timezone_finish:
6581 * @client: an #ECalClient
6582 * @result: a #GAsyncResult
6583 * @error: (out): a #GError to set an error, if any
6585 * Finishes previous call of e_cal_client_add_timezone().
6587 * Returns: %TRUE if successful, %FALSE otherwise.
6592 e_cal_client_add_timezone_finish (ECalClient *client,
6593 GAsyncResult *result,
6596 GSimpleAsyncResult *simple;
6598 g_return_val_if_fail (
6599 g_simple_async_result_is_valid (
6600 result, G_OBJECT (client),
6601 e_cal_client_add_timezone), FALSE);
6603 simple = G_SIMPLE_ASYNC_RESULT (result);
6605 /* Assume success unless a GError is set. */
6606 return !g_simple_async_result_propagate_error (simple, error);
6610 * e_cal_client_add_timezone_sync:
6611 * @client: an #ECalClient
6612 * @zone: The timezone to add
6613 * @cancellable: a #GCancellable; can be %NULL
6614 * @error: (out): a #GError to set an error, if any
6616 * Add a VTIMEZONE object to the given calendar client.
6618 * Returns: %TRUE if successful, %FALSE otherwise.
6623 e_cal_client_add_timezone_sync (ECalClient *client,
6625 GCancellable *cancellable,
6628 icalcomponent *icalcomp;
6630 gchar *utf8_zone_str;
6633 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
6634 g_return_val_if_fail (zone != NULL, FALSE);
6636 if (zone == icaltimezone_get_utc_timezone ())
6639 icalcomp = icaltimezone_get_component (zone);
6640 if (icalcomp == NULL) {
6642 error, e_client_error_create (
6643 E_CLIENT_ERROR_INVALID_ARG, NULL));
6647 if (client->priv->dbus_proxy == NULL) {
6648 set_proxy_gone_error (error);
6652 zone_str = icalcomponent_as_ical_string_r (icalcomp);
6653 utf8_zone_str = e_util_utf8_make_valid (zone_str);
6655 success = e_dbus_calendar_call_add_timezone_sync (
6656 client->priv->dbus_proxy, utf8_zone_str, cancellable, error);
6659 g_free (utf8_zone_str);