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 guint name_watcher_id;
60 ECalClientSourceType source_type;
61 icaltimezone *default_zone;
63 GMutex zone_cache_lock;
64 GHashTable *zone_cache;
66 gulong dbus_proxy_error_handler_id;
67 gulong dbus_proxy_notify_handler_id;
68 gulong dbus_proxy_free_busy_data_handler_id;
71 struct _AsyncContext {
72 ECalClientView *client_view;
73 icalcomponent *in_comp;
74 icalcomponent *out_comp;
89 struct _SignalClosure {
93 gchar **free_busy_data;
94 icaltimezone *cached_zone;
97 struct _ConnectClosure {
99 GCancellable *cancellable;
102 struct _RunInThreadClosure {
103 GSimpleAsyncThreadFunc func;
104 GSimpleAsyncResult *simple;
105 GCancellable *cancellable;
110 PROP_DEFAULT_TIMEZONE,
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_weak_ref_set (&signal_closure->client, NULL);
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 if (custom_msg == NULL)
292 custom_msg = e_cal_client_error_to_string (code);
294 return g_error_new_literal (E_CAL_CLIENT_ERROR, code, custom_msg);
298 cal_client_dbus_thread (gpointer user_data)
300 GMainContext *main_context = user_data;
301 GMainLoop *main_loop;
303 g_main_context_push_thread_default (main_context);
305 main_loop = g_main_loop_new (main_context, FALSE);
306 g_main_loop_run (main_loop);
307 g_main_loop_unref (main_loop);
309 g_main_context_pop_thread_default (main_context);
311 g_main_context_unref (main_context);
317 cal_client_dbus_thread_init (gpointer unused)
319 GMainContext *main_context;
321 main_context = g_main_context_new ();
323 /* This thread terminates when the process itself terminates, so
324 * no need to worry about unreferencing the returned GThread. */
326 "cal-client-dbus-thread",
327 cal_client_dbus_thread,
328 g_main_context_ref (main_context));
333 static GMainContext *
334 cal_client_ref_dbus_main_context (void)
336 static GOnce cal_client_dbus_thread_once = G_ONCE_INIT;
339 &cal_client_dbus_thread_once,
340 cal_client_dbus_thread_init, NULL);
342 return g_main_context_ref (cal_client_dbus_thread_once.retval);
346 cal_client_run_in_dbus_thread_idle_cb (gpointer user_data)
348 RunInThreadClosure *closure = user_data;
349 GObject *source_object;
350 GAsyncResult *result;
352 result = G_ASYNC_RESULT (closure->simple);
353 source_object = g_async_result_get_source_object (result);
358 closure->cancellable);
360 if (source_object != NULL)
361 g_object_unref (source_object);
363 g_simple_async_result_complete_in_idle (closure->simple);
369 cal_client_run_in_dbus_thread (GSimpleAsyncResult *simple,
370 GSimpleAsyncThreadFunc func,
372 GCancellable *cancellable)
374 RunInThreadClosure *closure;
375 GMainContext *main_context;
376 GSource *idle_source;
378 main_context = cal_client_ref_dbus_main_context ();
380 closure = g_slice_new0 (RunInThreadClosure);
381 closure->func = func;
382 closure->simple = g_object_ref (simple);
384 if (G_IS_CANCELLABLE (cancellable))
385 closure->cancellable = g_object_ref (cancellable);
387 idle_source = g_idle_source_new ();
388 g_source_set_priority (idle_source, io_priority);
389 g_source_set_callback (
390 idle_source, cal_client_run_in_dbus_thread_idle_cb,
391 closure, (GDestroyNotify) run_in_thread_closure_free);
392 g_source_attach (idle_source, main_context);
393 g_source_unref (idle_source);
395 g_main_context_unref (main_context);
399 cal_client_emit_backend_died_idle_cb (gpointer user_data)
401 SignalClosure *signal_closure = user_data;
404 client = g_weak_ref_get (&signal_closure->client);
406 if (client != NULL) {
407 g_signal_emit_by_name (client, "backend-died");
408 g_object_unref (client);
415 cal_client_emit_backend_error_idle_cb (gpointer user_data)
417 SignalClosure *signal_closure = user_data;
420 client = g_weak_ref_get (&signal_closure->client);
422 if (client != NULL) {
423 g_signal_emit_by_name (
424 client, "backend-error",
425 signal_closure->error_message);
426 g_object_unref (client);
433 cal_client_emit_backend_property_changed_idle_cb (gpointer user_data)
435 SignalClosure *signal_closure = user_data;
438 client = g_weak_ref_get (&signal_closure->client);
440 if (client != NULL) {
441 gchar *prop_value = NULL;
443 /* XXX Despite appearances, this function does not block. */
444 e_client_get_backend_property_sync (
446 signal_closure->property_name,
447 &prop_value, NULL, NULL);
449 if (prop_value != NULL) {
450 g_signal_emit_by_name (
452 "backend-property-changed",
453 signal_closure->property_name,
458 g_object_unref (client);
465 cal_client_emit_free_busy_data_idle_cb (gpointer user_data)
467 SignalClosure *signal_closure = user_data;
470 client = g_weak_ref_get (&signal_closure->client);
472 if (client != NULL) {
477 strv = signal_closure->free_busy_data;
479 for (ii = 0; strv[ii] != NULL; ii++) {
481 icalcomponent *icalcomp;
482 icalcomponent_kind kind;
484 icalcomp = icalcomponent_new_from_string (strv[ii]);
485 if (icalcomp == NULL)
488 kind = icalcomponent_isa (icalcomp);
489 if (kind != ICAL_VFREEBUSY_COMPONENT) {
490 icalcomponent_free (icalcomp);
494 comp = e_cal_component_new ();
495 if (!e_cal_component_set_icalcomponent (comp, icalcomp)) {
496 icalcomponent_free (icalcomp);
497 g_object_unref (comp);
501 list = g_slist_prepend (list, comp);
504 list = g_slist_reverse (list);
506 g_signal_emit (client, signals[FREE_BUSY_DATA], 0, list);
508 g_slist_free_full (list, (GDestroyNotify) g_object_unref);
510 g_object_unref (client);
517 cal_client_emit_timezone_added_idle_cb (gpointer user_data)
519 SignalClosure *signal_closure = user_data;
522 client = g_weak_ref_get (&signal_closure->client);
524 if (client != NULL) {
525 g_signal_emit_by_name (
526 client, "timezone-added",
527 signal_closure->cached_zone);
528 g_object_unref (client);
535 cal_client_dbus_proxy_error_cb (EDBusCalendar *dbus_proxy,
536 const gchar *error_message,
539 GSource *idle_source;
540 GMainContext *main_context;
541 SignalClosure *signal_closure;
543 signal_closure = g_slice_new0 (SignalClosure);
544 g_weak_ref_set (&signal_closure->client, client);
545 signal_closure->error_message = g_strdup (error_message);
547 main_context = e_client_ref_main_context (client);
549 idle_source = g_idle_source_new ();
550 g_source_set_callback (
552 cal_client_emit_backend_error_idle_cb,
554 (GDestroyNotify) signal_closure_free);
555 g_source_attach (idle_source, main_context);
556 g_source_unref (idle_source);
558 g_main_context_unref (main_context);
562 cal_client_dbus_proxy_notify_cb (EDBusCalendar *dbus_proxy,
566 const gchar *backend_prop_name = NULL;
568 if (g_str_equal (pspec->name, "alarm-email-address")) {
569 backend_prop_name = CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS;
572 if (g_str_equal (pspec->name, "cache-dir")) {
573 backend_prop_name = CLIENT_BACKEND_PROPERTY_CACHE_DIR;
576 if (g_str_equal (pspec->name, "cal-email-address")) {
577 backend_prop_name = CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS;
580 if (g_str_equal (pspec->name, "capabilities")) {
584 backend_prop_name = CLIENT_BACKEND_PROPERTY_CAPABILITIES;
586 strv = e_dbus_calendar_dup_capabilities (dbus_proxy);
588 csv = g_strjoinv (",", strv);
591 e_client_set_capabilities (client, csv);
595 if (g_str_equal (pspec->name, "default-object")) {
596 backend_prop_name = CAL_BACKEND_PROPERTY_DEFAULT_OBJECT;
599 if (g_str_equal (pspec->name, "online")) {
602 backend_prop_name = CLIENT_BACKEND_PROPERTY_ONLINE;
604 online = e_dbus_calendar_get_online (dbus_proxy);
605 e_client_set_online (client, online);
608 if (g_str_equal (pspec->name, "revision")) {
609 backend_prop_name = CLIENT_BACKEND_PROPERTY_REVISION;
612 if (g_str_equal (pspec->name, "writable")) {
615 backend_prop_name = CLIENT_BACKEND_PROPERTY_READONLY;
617 writable = e_dbus_calendar_get_writable (dbus_proxy);
618 e_client_set_readonly (client, !writable);
621 if (backend_prop_name != NULL) {
622 GSource *idle_source;
623 GMainContext *main_context;
624 SignalClosure *signal_closure;
626 signal_closure = g_slice_new0 (SignalClosure);
627 g_weak_ref_set (&signal_closure->client, client);
628 signal_closure->property_name = g_strdup (backend_prop_name);
630 main_context = e_client_ref_main_context (client);
632 idle_source = g_idle_source_new ();
633 g_source_set_callback (
635 cal_client_emit_backend_property_changed_idle_cb,
637 (GDestroyNotify) signal_closure_free);
638 g_source_attach (idle_source, main_context);
639 g_source_unref (idle_source);
641 g_main_context_unref (main_context);
646 cal_client_dbus_proxy_free_busy_data_cb (EDBusCalendar *dbus_proxy,
647 gchar **free_busy_data,
650 GSource *idle_source;
651 GMainContext *main_context;
652 SignalClosure *signal_closure;
654 signal_closure = g_slice_new0 (SignalClosure);
655 g_weak_ref_set (&signal_closure->client, client);
656 signal_closure->free_busy_data = g_strdupv (free_busy_data);
658 main_context = e_client_ref_main_context (client);
660 idle_source = g_idle_source_new ();
661 g_source_set_callback (
663 cal_client_emit_free_busy_data_idle_cb,
665 (GDestroyNotify) signal_closure_free);
666 g_source_attach (idle_source, main_context);
667 g_source_unref (idle_source);
669 g_main_context_unref (main_context);
673 cal_client_name_vanished_cb (GDBusConnection *connection,
677 GSource *idle_source;
678 GMainContext *main_context;
679 SignalClosure *signal_closure;
681 signal_closure = g_slice_new0 (SignalClosure);
682 g_weak_ref_set (&signal_closure->client, client);
684 main_context = e_client_ref_main_context (client);
686 idle_source = g_idle_source_new ();
687 g_source_set_callback (
689 cal_client_emit_backend_died_idle_cb,
691 (GDestroyNotify) signal_closure_free);
692 g_source_attach (idle_source, main_context);
693 g_source_unref (idle_source);
695 g_main_context_unref (main_context);
699 cal_client_close_cb (GObject *source_object,
700 GAsyncResult *result,
703 GError *error = NULL;
705 e_dbus_calendar_call_close_finish (
706 E_DBUS_CALENDAR (source_object), result, &error);
709 g_warning ("%s: %s", G_STRFUNC, error->message);
710 g_error_free (error);
715 cal_client_set_source_type (ECalClient *cal_client,
716 ECalClientSourceType source_type)
718 cal_client->priv->source_type = source_type;
722 cal_client_set_property (GObject *object,
727 switch (property_id) {
728 case PROP_DEFAULT_TIMEZONE:
729 e_cal_client_set_default_timezone (
730 E_CAL_CLIENT (object),
731 g_value_get_pointer (value));
734 case PROP_SOURCE_TYPE:
735 cal_client_set_source_type (
736 E_CAL_CLIENT (object),
737 g_value_get_enum (value));
741 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
745 cal_client_get_property (GObject *object,
750 switch (property_id) {
751 case PROP_DEFAULT_TIMEZONE:
752 g_value_set_pointer (
754 e_cal_client_get_default_timezone (
755 E_CAL_CLIENT (object)));
758 case PROP_SOURCE_TYPE:
761 e_cal_client_get_source_type (
762 E_CAL_CLIENT (object)));
766 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
770 cal_client_dispose (GObject *object)
772 ECalClientPrivate *priv;
774 priv = E_CAL_CLIENT_GET_PRIVATE (object);
776 if (priv->dbus_proxy_error_handler_id > 0) {
777 g_signal_handler_disconnect (
779 priv->dbus_proxy_error_handler_id);
780 priv->dbus_proxy_error_handler_id = 0;
783 if (priv->dbus_proxy_notify_handler_id > 0) {
784 g_signal_handler_disconnect (
786 priv->dbus_proxy_notify_handler_id);
787 priv->dbus_proxy_notify_handler_id = 0;
790 if (priv->dbus_proxy_free_busy_data_handler_id > 0) {
791 g_signal_handler_disconnect (
793 priv->dbus_proxy_free_busy_data_handler_id);
794 priv->dbus_proxy_free_busy_data_handler_id = 0;
797 if (priv->dbus_proxy != NULL) {
798 /* Call close() asynchronously
799 * so we don't block dispose(). */
800 e_dbus_calendar_call_close (
801 priv->dbus_proxy, NULL,
802 cal_client_close_cb, NULL);
803 g_object_unref (priv->dbus_proxy);
804 priv->dbus_proxy = NULL;
807 /* Chain up to parent's dispose() method. */
808 G_OBJECT_CLASS (e_cal_client_parent_class)->dispose (object);
812 cal_client_finalize (GObject *object)
814 ECalClientPrivate *priv;
816 priv = E_CAL_CLIENT_GET_PRIVATE (object);
818 if (priv->name_watcher_id > 0)
819 g_bus_unwatch_name (priv->name_watcher_id);
821 if (priv->default_zone && priv->default_zone != icaltimezone_get_utc_timezone ())
822 icaltimezone_free (priv->default_zone, 1);
824 g_mutex_lock (&priv->zone_cache_lock);
825 g_hash_table_destroy (priv->zone_cache);
826 g_mutex_unlock (&priv->zone_cache_lock);
828 g_mutex_clear (&priv->zone_cache_lock);
830 /* Chain up to parent's finalize() method. */
831 G_OBJECT_CLASS (e_cal_client_parent_class)->finalize (object);
835 cal_client_get_dbus_proxy (EClient *client)
837 ECalClientPrivate *priv;
839 priv = E_CAL_CLIENT_GET_PRIVATE (client);
841 return G_DBUS_PROXY (priv->dbus_proxy);
845 cal_client_get_backend_property_sync (EClient *client,
846 const gchar *prop_name,
848 GCancellable *cancellable,
851 ECalClient *cal_client;
852 EDBusCalendar *dbus_proxy;
855 cal_client = E_CAL_CLIENT (client);
856 dbus_proxy = cal_client->priv->dbus_proxy;
858 if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_OPENED)) {
859 *prop_value = g_strdup ("TRUE");
863 if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_OPENING)) {
864 *prop_value = g_strdup ("FALSE");
868 if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_ONLINE)) {
869 if (e_dbus_calendar_get_online (dbus_proxy))
870 *prop_value = g_strdup ("TRUE");
872 *prop_value = g_strdup ("FALSE");
876 if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_READONLY)) {
877 if (e_dbus_calendar_get_writable (dbus_proxy))
878 *prop_value = g_strdup ("FALSE");
880 *prop_value = g_strdup ("TRUE");
884 if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CACHE_DIR)) {
885 *prop_value = e_dbus_calendar_dup_cache_dir (dbus_proxy);
889 if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_REVISION)) {
890 *prop_value = e_dbus_calendar_dup_revision (dbus_proxy);
894 if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CAPABILITIES)) {
895 strv = e_dbus_calendar_dup_capabilities (dbus_proxy);
897 *prop_value = g_strjoinv (",", strv);
899 *prop_value = g_strdup ("");
904 if (g_str_equal (prop_name, CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS)) {
905 *prop_value = e_dbus_calendar_dup_alarm_email_address (dbus_proxy);
909 if (g_str_equal (prop_name, CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS)) {
910 *prop_value = e_dbus_calendar_dup_cal_email_address (dbus_proxy);
914 if (g_str_equal (prop_name, CAL_BACKEND_PROPERTY_DEFAULT_OBJECT)) {
915 *prop_value = e_dbus_calendar_dup_default_object (dbus_proxy);
920 error, E_CLIENT_ERROR, E_CLIENT_ERROR_NOT_SUPPORTED,
921 _("Unknown calendar property '%s'"), prop_name);
927 cal_client_set_backend_property_sync (EClient *client,
928 const gchar *prop_name,
929 const gchar *prop_value,
930 GCancellable *cancellable,
934 error, E_CLIENT_ERROR,
935 E_CLIENT_ERROR_NOT_SUPPORTED,
936 _("Cannot change value of calendar property '%s'"),
943 cal_client_open_sync (EClient *client,
944 gboolean only_if_exists,
945 GCancellable *cancellable,
948 ECalClient *cal_client;
950 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
952 cal_client = E_CAL_CLIENT (client);
954 return e_dbus_calendar_call_open_sync (
955 cal_client->priv->dbus_proxy, cancellable, error);
959 cal_client_refresh_sync (EClient *client,
960 GCancellable *cancellable,
963 ECalClient *cal_client;
965 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
967 cal_client = E_CAL_CLIENT (client);
969 return e_dbus_calendar_call_refresh_sync (
970 cal_client->priv->dbus_proxy, cancellable, error);
974 cal_client_init_in_dbus_thread (GSimpleAsyncResult *simple,
975 GObject *source_object,
976 GCancellable *cancellable)
978 ECalClientPrivate *priv;
979 EDBusCalendarFactory *factory_proxy;
980 GDBusConnection *connection;
985 gchar *object_path = NULL;
987 GError *error = NULL;
989 priv = E_CAL_CLIENT_GET_PRIVATE (source_object);
991 client = E_CLIENT (source_object);
992 source = e_client_get_source (client);
993 uid = e_source_get_uid (source);
995 connection = g_bus_get_sync (G_BUS_TYPE_SESSION, cancellable, &error);
999 ((connection != NULL) && (error == NULL)) ||
1000 ((connection == NULL) && (error != NULL)));
1002 if (error != NULL) {
1003 g_simple_async_result_take_error (simple, error);
1007 factory_proxy = e_dbus_calendar_factory_proxy_new_sync (
1009 G_DBUS_PROXY_FLAGS_NONE,
1010 CALENDAR_DBUS_SERVICE_NAME,
1011 "/org/gnome/evolution/dataserver/CalendarFactory",
1012 cancellable, &error);
1016 ((factory_proxy != NULL) && (error == NULL)) ||
1017 ((factory_proxy == NULL) && (error != NULL)));
1019 if (error != NULL) {
1020 g_simple_async_result_take_error (simple, error);
1021 g_object_unref (connection);
1025 switch (e_cal_client_get_source_type (E_CAL_CLIENT (client))) {
1026 case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
1027 e_dbus_calendar_factory_call_open_calendar_sync (
1028 factory_proxy, uid, &object_path,
1029 cancellable, &error);
1031 case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
1032 e_dbus_calendar_factory_call_open_task_list_sync (
1033 factory_proxy, uid, &object_path,
1034 cancellable, &error);
1036 case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
1037 e_dbus_calendar_factory_call_open_memo_list_sync (
1038 factory_proxy, uid, &object_path,
1039 cancellable, &error);
1042 g_return_if_reached ();
1045 g_object_unref (factory_proxy);
1049 ((object_path != NULL) && (error == NULL)) ||
1050 ((object_path == NULL) && (error != NULL)));
1052 if (object_path == NULL) {
1053 g_simple_async_result_take_error (simple, error);
1054 g_object_unref (connection);
1058 priv->dbus_proxy = e_dbus_calendar_proxy_new_sync (
1060 G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
1061 CALENDAR_DBUS_SERVICE_NAME,
1062 object_path, cancellable, &error);
1064 g_free (object_path);
1068 ((priv->dbus_proxy != NULL) && (error == NULL)) ||
1069 ((priv->dbus_proxy == NULL) && (error != NULL)));
1071 if (error != NULL) {
1072 g_simple_async_result_take_error (simple, error);
1073 g_object_unref (connection);
1077 /* Configure our new GDBusProxy. */
1079 proxy = G_DBUS_PROXY (priv->dbus_proxy);
1081 g_dbus_proxy_set_default_timeout (proxy, DBUS_PROXY_TIMEOUT_MS);
1083 priv->name_watcher_id = g_bus_watch_name_on_connection (
1085 g_dbus_proxy_get_name (proxy),
1086 G_BUS_NAME_WATCHER_FLAGS_NONE,
1087 (GBusNameAppearedCallback) NULL,
1088 (GBusNameVanishedCallback) cal_client_name_vanished_cb,
1089 client, (GDestroyNotify) NULL);
1091 handler_id = g_signal_connect_object (
1093 G_CALLBACK (cal_client_dbus_proxy_error_cb),
1095 priv->dbus_proxy_error_handler_id = handler_id;
1097 handler_id = g_signal_connect_object (
1099 G_CALLBACK (cal_client_dbus_proxy_notify_cb),
1101 priv->dbus_proxy_notify_handler_id = handler_id;
1103 handler_id = g_signal_connect_object (
1104 proxy, "free-busy-data",
1105 G_CALLBACK (cal_client_dbus_proxy_free_busy_data_cb),
1107 priv->dbus_proxy_free_busy_data_handler_id = handler_id;
1109 /* Initialize our public-facing GObject properties. */
1110 g_object_notify (G_OBJECT (proxy), "online");
1111 g_object_notify (G_OBJECT (proxy), "writable");
1112 g_object_notify (G_OBJECT (proxy), "capabilities");
1114 g_object_unref (connection);
1118 cal_client_initable_init (GInitable *initable,
1119 GCancellable *cancellable,
1122 EAsyncClosure *closure;
1123 GAsyncResult *result;
1126 closure = e_async_closure_new ();
1128 g_async_initable_init_async (
1129 G_ASYNC_INITABLE (initable),
1130 G_PRIORITY_DEFAULT, cancellable,
1131 e_async_closure_callback, closure);
1133 result = e_async_closure_wait (closure);
1135 success = g_async_initable_init_finish (
1136 G_ASYNC_INITABLE (initable), result, error);
1138 e_async_closure_free (closure);
1144 cal_client_initable_init_async (GAsyncInitable *initable,
1146 GCancellable *cancellable,
1147 GAsyncReadyCallback callback,
1150 GSimpleAsyncResult *simple;
1152 simple = g_simple_async_result_new (
1153 G_OBJECT (initable), callback, user_data,
1154 cal_client_initable_init_async);
1156 g_simple_async_result_set_check_cancellable (simple, cancellable);
1158 cal_client_run_in_dbus_thread (
1159 simple, cal_client_init_in_dbus_thread,
1160 io_priority, cancellable);
1162 g_object_unref (simple);
1166 cal_client_initable_init_finish (GAsyncInitable *initable,
1167 GAsyncResult *result,
1170 GSimpleAsyncResult *simple;
1172 g_return_val_if_fail (
1173 g_simple_async_result_is_valid (
1174 result, G_OBJECT (initable),
1175 cal_client_initable_init_async), FALSE);
1177 simple = G_SIMPLE_ASYNC_RESULT (result);
1179 /* Assume success unless a GError is set. */
1180 return !g_simple_async_result_propagate_error (simple, error);
1184 cal_client_add_cached_timezone (ETimezoneCache *cache,
1187 ECalClientPrivate *priv;
1190 priv = E_CAL_CLIENT_GET_PRIVATE (cache);
1192 g_mutex_lock (&priv->zone_cache_lock);
1194 tzid = icaltimezone_get_tzid (zone);
1196 /* Avoid replacing an existing cache entry. We don't want to
1197 * invalidate any icaltimezone pointers that may have already
1198 * been returned through e_timezone_cache_get_timezone(). */
1199 if (!g_hash_table_contains (priv->zone_cache, tzid)) {
1200 GSource *idle_source;
1201 GMainContext *main_context;
1202 SignalClosure *signal_closure;
1204 icalcomponent *icalcomp;
1205 icaltimezone *cached_zone;
1207 cached_zone = icaltimezone_new ();
1208 icalcomp = icaltimezone_get_component (zone);
1209 icalcomp = icalcomponent_new_clone (icalcomp);
1210 icaltimezone_set_component (cached_zone, icalcomp);
1212 g_hash_table_insert (
1214 g_strdup (tzid), cached_zone);
1216 /* The closure's client reference will keep the
1217 * internally cached icaltimezone alive for the
1218 * duration of the idle callback. */
1219 signal_closure = g_slice_new0 (SignalClosure);
1220 g_weak_ref_set (&signal_closure->client, cache);
1221 signal_closure->cached_zone = cached_zone;
1223 main_context = e_client_ref_main_context (E_CLIENT (cache));
1225 idle_source = g_idle_source_new ();
1226 g_source_set_callback (
1228 cal_client_emit_timezone_added_idle_cb,
1230 (GDestroyNotify) signal_closure_free);
1231 g_source_attach (idle_source, main_context);
1232 g_source_unref (idle_source);
1234 g_main_context_unref (main_context);
1237 g_mutex_unlock (&priv->zone_cache_lock);
1240 static icaltimezone *
1241 cal_client_get_cached_timezone (ETimezoneCache *cache,
1244 ECalClientPrivate *priv;
1245 icaltimezone *zone = NULL;
1246 icaltimezone *builtin_zone = NULL;
1247 icalcomponent *icalcomp;
1249 const gchar *builtin_tzid;
1251 priv = E_CAL_CLIENT_GET_PRIVATE (cache);
1253 if (g_str_equal (tzid, "UTC"))
1254 return icaltimezone_get_utc_timezone ();
1256 g_mutex_lock (&priv->zone_cache_lock);
1258 /* See if we already have it in the cache. */
1259 zone = g_hash_table_lookup (priv->zone_cache, tzid);
1264 /* Try to replace the original time zone with a more complete
1265 * and/or potentially updated built-in time zone. Note this also
1266 * applies to TZIDs which match built-in time zones exactly: they
1267 * are extracted via icaltimezone_get_builtin_timezone_from_tzid()
1268 * below without a roundtrip to the backend. */
1270 builtin_tzid = e_cal_match_tzid (tzid);
1272 if (builtin_tzid != NULL)
1273 builtin_zone = icaltimezone_get_builtin_timezone_from_tzid (
1276 if (builtin_zone == NULL)
1279 /* Use the built-in time zone *and* rename it. Likely the caller
1280 * is asking for a specific TZID because it has an event with such
1281 * a TZID. Returning an icaltimezone with a different TZID would
1282 * lead to broken VCALENDARs in the caller. */
1284 icalcomp = icaltimezone_get_component (builtin_zone);
1285 icalcomp = icalcomponent_new_clone (icalcomp);
1287 prop = icalcomponent_get_first_property (
1288 icalcomp, ICAL_ANY_PROPERTY);
1290 while (prop != NULL) {
1291 if (icalproperty_isa (prop) == ICAL_TZID_PROPERTY) {
1292 icalproperty_set_value_from_string (prop, tzid, "NO");
1296 prop = icalcomponent_get_next_property (
1297 icalcomp, ICAL_ANY_PROPERTY);
1300 if (icalcomp != NULL) {
1301 zone = icaltimezone_new ();
1302 if (icaltimezone_set_component (zone, icalcomp)) {
1303 tzid = icaltimezone_get_tzid (zone);
1304 g_hash_table_insert (
1306 g_strdup (tzid), zone);
1308 icalcomponent_free (icalcomp);
1309 icaltimezone_free (zone, 1);
1315 g_mutex_unlock (&priv->zone_cache_lock);
1321 cal_client_list_cached_timezones (ETimezoneCache *cache)
1323 ECalClientPrivate *priv;
1326 priv = E_CAL_CLIENT_GET_PRIVATE (cache);
1328 g_mutex_lock (&priv->zone_cache_lock);
1330 list = g_hash_table_get_values (priv->zone_cache);
1332 g_mutex_unlock (&priv->zone_cache_lock);
1338 e_cal_client_class_init (ECalClientClass *class)
1340 GObjectClass *object_class;
1341 EClientClass *client_class;
1343 g_type_class_add_private (class, sizeof (ECalClientPrivate));
1345 object_class = G_OBJECT_CLASS (class);
1346 object_class->set_property = cal_client_set_property;
1347 object_class->get_property = cal_client_get_property;
1348 object_class->dispose = cal_client_dispose;
1349 object_class->finalize = cal_client_finalize;
1351 client_class = E_CLIENT_CLASS (class);
1352 client_class->get_dbus_proxy = cal_client_get_dbus_proxy;
1353 client_class->get_backend_property_sync = cal_client_get_backend_property_sync;
1354 client_class->set_backend_property_sync = cal_client_set_backend_property_sync;
1355 client_class->open_sync = cal_client_open_sync;
1356 client_class->refresh_sync = cal_client_refresh_sync;
1358 g_object_class_install_property (
1360 PROP_DEFAULT_TIMEZONE,
1361 g_param_spec_pointer (
1364 "Timezone used to resolve DATE "
1365 "and floating DATE-TIME values",
1367 G_PARAM_STATIC_STRINGS));
1369 g_object_class_install_property (
1375 "The iCalendar data type",
1376 E_TYPE_CAL_CLIENT_SOURCE_TYPE,
1377 E_CAL_CLIENT_SOURCE_TYPE_EVENTS,
1379 G_PARAM_CONSTRUCT_ONLY |
1380 G_PARAM_STATIC_STRINGS));
1382 signals[FREE_BUSY_DATA] = g_signal_new (
1384 G_OBJECT_CLASS_TYPE (class),
1386 G_STRUCT_OFFSET (ECalClientClass, free_busy_data),
1388 g_cclosure_marshal_VOID__POINTER,
1394 e_cal_client_initable_init (GInitableIface *interface)
1396 interface->init = cal_client_initable_init;
1400 e_cal_client_async_initable_init (GAsyncInitableIface *interface)
1402 interface->init_async = cal_client_initable_init_async;
1403 interface->init_finish = cal_client_initable_init_finish;
1407 e_cal_client_timezone_cache_init (ETimezoneCacheInterface *interface)
1409 interface->add_timezone = cal_client_add_cached_timezone;
1410 interface->get_timezone = cal_client_get_cached_timezone;
1411 interface->list_timezones = cal_client_list_cached_timezones;
1415 e_cal_client_init (ECalClient *client)
1417 GHashTable *zone_cache;
1419 zone_cache = g_hash_table_new_full (
1420 (GHashFunc) g_str_hash,
1421 (GEqualFunc) g_str_equal,
1422 (GDestroyNotify) g_free,
1423 (GDestroyNotify) free_zone_cb);
1425 client->priv = E_CAL_CLIENT_GET_PRIVATE (client);
1426 client->priv->source_type = E_CAL_CLIENT_SOURCE_TYPE_LAST;
1427 client->priv->default_zone = icaltimezone_get_utc_timezone ();
1428 g_mutex_init (&client->priv->zone_cache_lock);
1429 client->priv->zone_cache = zone_cache;
1433 * e_cal_client_connect_sync:
1434 * @source: an #ESource
1435 * @source_type: source type of the calendar
1436 * @cancellable: (allow-none): optional #GCancellable object, or %NULL
1437 * @error: return location for a #GError, or %NULL
1439 * Creates a new #ECalClient for @source and @source_type. If an error
1440 * occurs, the function will set @error and return %FALSE.
1442 * Unlike with e_cal_client_new(), there is no need to call
1443 * e_client_open_sync() after obtaining the #ECalClient.
1445 * For error handling convenience, any error message returned by this
1446 * function will have a descriptive prefix that includes the display
1449 * Returns: a new #ECalClient, or %NULL
1454 e_cal_client_connect_sync (ESource *source,
1455 ECalClientSourceType source_type,
1456 GCancellable *cancellable,
1462 g_return_val_if_fail (E_IS_SOURCE (source), NULL);
1463 g_return_val_if_fail (
1464 source_type == E_CAL_CLIENT_SOURCE_TYPE_EVENTS ||
1465 source_type == E_CAL_CLIENT_SOURCE_TYPE_TASKS ||
1466 source_type == E_CAL_CLIENT_SOURCE_TYPE_MEMOS, NULL);
1468 client = g_object_new (
1471 "source-type", source_type, NULL);
1473 success = g_initable_init (
1474 G_INITABLE (client), cancellable, error);
1477 success = e_dbus_calendar_call_open_sync (
1478 client->priv->dbus_proxy, cancellable, error);
1482 error,_("Unable to connect to '%s': "),
1483 e_source_get_display_name (source));
1484 g_object_unref (client);
1488 return E_CLIENT (client);
1491 /* Helper for e_cal_client_connect() */
1493 cal_client_connect_open_cb (GObject *source_object,
1494 GAsyncResult *result,
1497 GSimpleAsyncResult *simple;
1498 GError *error = NULL;
1500 simple = G_SIMPLE_ASYNC_RESULT (user_data);
1502 e_dbus_calendar_call_open_finish (
1503 E_DBUS_CALENDAR (source_object), result, &error);
1506 g_simple_async_result_take_error (simple, error);
1508 g_simple_async_result_complete (simple);
1510 g_object_unref (simple);
1513 /* Helper for e_cal_client_connect() */
1515 cal_client_connect_init_cb (GObject *source_object,
1516 GAsyncResult *result,
1519 GSimpleAsyncResult *simple;
1520 ECalClientPrivate *priv;
1521 ConnectClosure *closure;
1522 GError *error = NULL;
1524 simple = G_SIMPLE_ASYNC_RESULT (user_data);
1526 g_async_initable_init_finish (
1527 G_ASYNC_INITABLE (source_object), result, &error);
1529 if (error != NULL) {
1530 g_simple_async_result_take_error (simple, error);
1531 g_simple_async_result_complete (simple);
1535 /* Note, we're repurposing some function parameters. */
1537 result = G_ASYNC_RESULT (simple);
1538 source_object = g_async_result_get_source_object (result);
1539 closure = g_simple_async_result_get_op_res_gpointer (simple);
1541 priv = E_CAL_CLIENT_GET_PRIVATE (source_object);
1543 e_dbus_calendar_call_open (
1545 closure->cancellable,
1546 cal_client_connect_open_cb,
1547 g_object_ref (simple));
1549 g_object_unref (source_object);
1552 g_object_unref (simple);
1556 * e_cal_client_connect:
1557 * @source: an #ESource
1558 * @source_type: source tpe of the calendar
1559 * @cancellable: (allow-none): optional #GCancellable object, or %NULL
1560 * @callback: (scope async): a #GAsyncReadyCallback to call when the request
1562 * @user_data: (closure): data to pass to the callback function
1564 * Asynchronously creates a new #ECalClient for @source and @source_type.
1566 * Unlike with e_cal_client_new(), there is no need to call e_client_open()
1567 * after obtaining the #ECalClient.
1569 * When the operation is finished, @callback will be called. You can then
1570 * call e_cal_client_connect_finish() to get the result of the operation.
1575 e_cal_client_connect (ESource *source,
1576 ECalClientSourceType source_type,
1577 GCancellable *cancellable,
1578 GAsyncReadyCallback callback,
1581 GSimpleAsyncResult *simple;
1582 ConnectClosure *closure;
1585 g_return_if_fail (E_IS_SOURCE (source));
1587 source_type == E_CAL_CLIENT_SOURCE_TYPE_EVENTS ||
1588 source_type == E_CAL_CLIENT_SOURCE_TYPE_TASKS ||
1589 source_type == E_CAL_CLIENT_SOURCE_TYPE_MEMOS);
1591 /* Two things with this: 1) instantiate the client object
1592 * immediately to make sure the thread-default GMainContext
1593 * gets plucked, and 2) do not call the D-Bus open() method
1594 * from our designated D-Bus thread -- it may take a long
1595 * time and block other clients from receiving signals. */
1597 closure = g_slice_new0 (ConnectClosure);
1598 closure->source = g_object_ref (source);
1600 if (G_IS_CANCELLABLE (cancellable))
1601 closure->cancellable = g_object_ref (cancellable);
1603 client = g_object_new (
1606 "source-type", source_type, NULL);
1608 simple = g_simple_async_result_new (
1609 G_OBJECT (client), callback,
1610 user_data, e_cal_client_connect);
1612 g_simple_async_result_set_check_cancellable (simple, cancellable);
1614 g_simple_async_result_set_op_res_gpointer (
1615 simple, closure, (GDestroyNotify) connect_closure_free);
1617 g_async_initable_init_async (
1618 G_ASYNC_INITABLE (client),
1619 G_PRIORITY_DEFAULT, cancellable,
1620 cal_client_connect_init_cb,
1621 g_object_ref (simple));
1623 g_object_unref (simple);
1624 g_object_unref (client);
1628 * e_cal_client_connect_finish:
1629 * @result: a #GAsyncResult
1630 * @error: return location for a #GError, or %NULL
1632 * Finishes the operation started with e_cal_client_connect(). If an
1633 * error occurs in connecting to the D-Bus service, the function sets
1634 * @error and returns %NULL.
1636 * For error handling convenience, any error message returned by this
1637 * function will have a descriptive prefix that includes the display
1638 * name of the #ESource passed to e_cal_client_connect().
1640 * Returns: a new #ECalClient, or %NULL
1645 e_cal_client_connect_finish (GAsyncResult *result,
1648 GSimpleAsyncResult *simple;
1649 ConnectClosure *closure;
1650 gpointer source_tag;
1652 g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), NULL);
1654 simple = G_SIMPLE_ASYNC_RESULT (result);
1655 closure = g_simple_async_result_get_op_res_gpointer (simple);
1657 source_tag = g_simple_async_result_get_source_tag (simple);
1658 g_return_val_if_fail (source_tag == e_cal_client_connect, NULL);
1660 if (g_simple_async_result_propagate_error (simple, error)) {
1662 error, _("Unable to connect to '%s': "),
1663 e_source_get_display_name (closure->source));
1667 return E_CLIENT (g_async_result_get_source_object (result));
1672 * @source: An #ESource pointer
1673 * @source_type: source type of the calendar
1674 * @error: A #GError pointer
1676 * Creates a new #ECalClient corresponding to the given source. There are
1677 * only two operations that are valid on this calendar at this point:
1678 * e_client_open(), and e_client_remove().
1680 * Returns: a new but unopened #ECalClient.
1684 * Deprecated: 3.8: It covertly makes synchronous D-Bus calls, with no
1685 * way to cancel. Use e_cal_client_connect() instead,
1686 * which combines e_cal_client_new() and e_client_open()
1690 e_cal_client_new (ESource *source,
1691 ECalClientSourceType source_type,
1694 g_return_val_if_fail (E_IS_SOURCE (source), NULL);
1695 g_return_val_if_fail (
1696 source_type == E_CAL_CLIENT_SOURCE_TYPE_EVENTS ||
1697 source_type == E_CAL_CLIENT_SOURCE_TYPE_TASKS ||
1698 source_type == E_CAL_CLIENT_SOURCE_TYPE_MEMOS, NULL);
1700 return g_initable_new (
1701 E_TYPE_CAL_CLIENT, NULL, error,
1703 "source-type", source_type, NULL);
1707 * e_cal_client_get_source_type:
1708 * @client: A calendar client.
1710 * Gets the source type of the calendar client.
1712 * Returns: an #ECalClientSourceType value corresponding
1713 * to the source type of the calendar client.
1717 ECalClientSourceType
1718 e_cal_client_get_source_type (ECalClient *client)
1720 g_return_val_if_fail (
1721 E_IS_CAL_CLIENT (client),
1722 E_CAL_CLIENT_SOURCE_TYPE_LAST);
1724 return client->priv->source_type;
1728 * e_cal_client_get_local_attachment_store:
1729 * @client: A calendar client.
1731 * Queries the URL where the calendar attachments are
1732 * serialized in the local filesystem. This enable clients
1733 * to operate with the reference to attachments rather than the data itself
1734 * unless it specifically uses the attachments for open/sending
1737 * Returns: The URL where the attachments are serialized in the
1743 e_cal_client_get_local_attachment_store (ECalClient *client)
1745 g_return_val_if_fail (E_IS_CAL_CLIENT (client), NULL);
1747 return e_dbus_calendar_get_cache_dir (client->priv->dbus_proxy);
1750 /* icaltimezone_copy does a shallow copy while icaltimezone_free tries to
1751 * free the entire the contents inside the structure with libical 0.43.
1752 * Use this, till eds allows older libical.
1754 static icaltimezone *
1755 copy_timezone (icaltimezone *ozone)
1757 icaltimezone *zone = NULL;
1760 tzid = icaltimezone_get_tzid (ozone);
1762 if (g_strcmp0 (tzid, "UTC") != 0) {
1763 icalcomponent *comp;
1765 comp = icaltimezone_get_component (ozone);
1767 zone = icaltimezone_new ();
1768 icaltimezone_set_component (
1769 zone, icalcomponent_new_clone (comp));
1774 zone = icaltimezone_get_utc_timezone ();
1780 * e_cal_client_set_default_timezone:
1781 * @client: A calendar client.
1782 * @zone: A timezone object.
1784 * Sets the default timezone to use to resolve DATE and floating DATE-TIME
1785 * values. This will typically be from the user's timezone setting. Call this
1786 * before using any other object fetching functions.
1791 e_cal_client_set_default_timezone (ECalClient *client,
1794 g_return_if_fail (E_IS_CAL_CLIENT (client));
1795 g_return_if_fail (zone != NULL);
1797 if (zone == client->priv->default_zone)
1800 if (client->priv->default_zone != icaltimezone_get_utc_timezone ())
1801 icaltimezone_free (client->priv->default_zone, 1);
1803 if (zone == icaltimezone_get_utc_timezone ())
1804 client->priv->default_zone = zone;
1806 client->priv->default_zone = copy_timezone (zone);
1808 g_object_notify (G_OBJECT (client), "default-timezone");
1812 * e_cal_client_get_default_timezone:
1813 * @client: A calendar client.
1815 * Returns the default timezone previously set with
1816 * e_cal_client_set_default_timezone(). The returned pointer is owned by
1817 * the @client and should not be freed.
1819 * Returns: an #icaltimezone
1824 e_cal_client_get_default_timezone (ECalClient *client)
1826 g_return_val_if_fail (E_IS_CAL_CLIENT (client), NULL);
1828 return client->priv->default_zone;
1832 * e_cal_client_check_one_alarm_only:
1833 * @client: A calendar client.
1835 * Checks if a calendar supports only one alarm per component.
1837 * Returns: TRUE if the calendar allows only one alarm, FALSE otherwise.
1842 e_cal_client_check_one_alarm_only (ECalClient *client)
1844 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
1846 return e_client_check_capability (
1848 CAL_STATIC_CAPABILITY_ONE_ALARM_ONLY);
1852 * e_cal_client_check_save_schedules:
1853 * @client: A calendar client.
1855 * Checks whether the calendar saves schedules.
1857 * Returns: TRUE if it saves schedules, FALSE otherwise.
1862 e_cal_client_check_save_schedules (ECalClient *client)
1864 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
1866 return e_client_check_capability (
1868 CAL_STATIC_CAPABILITY_SAVE_SCHEDULES);
1872 * e_cal_client_check_organizer_must_attend:
1873 * @client: A calendar client.
1875 * Checks if a calendar forces organizers of meetings to be also attendees.
1877 * Returns: TRUE if the calendar forces organizers to attend meetings,
1883 e_cal_client_check_organizer_must_attend (ECalClient *client)
1885 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
1887 return e_client_check_capability (
1889 CAL_STATIC_CAPABILITY_ORGANIZER_MUST_ATTEND);
1893 * e_cal_client_check_organizer_must_accept:
1894 * @client: A calendar client.
1896 * Checks whether a calendar requires organizer to accept their attendance to
1899 * Returns: TRUE if the calendar requires organizers to accept, FALSE
1905 e_cal_client_check_organizer_must_accept (ECalClient *client)
1907 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
1909 return e_client_check_capability (
1911 CAL_STATIC_CAPABILITY_ORGANIZER_MUST_ACCEPT);
1915 * e_cal_client_check_recurrences_no_master:
1916 * @client: A calendar client.
1918 * Checks if the calendar has a master object for recurrences.
1920 * Returns: TRUE if the calendar has a master object for recurrences,
1926 e_cal_client_check_recurrences_no_master (ECalClient *client)
1928 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
1930 return e_client_check_capability (
1932 CAL_STATIC_CAPABILITY_RECURRENCES_NO_MASTER);
1936 * e_cal_client_free_icalcomp_slist:
1937 * @icalcomps: (element-type icalcomponent): list of icalcomponent objects
1939 * Frees each element of the @icalcomps list and the list itself.
1940 * Each element is an object of type #icalcomponent.
1945 e_cal_client_free_icalcomp_slist (GSList *icalcomps)
1947 g_slist_foreach (icalcomps, (GFunc) icalcomponent_free, NULL);
1948 g_slist_free (icalcomps);
1952 * e_cal_client_free_ecalcomp_slist:
1953 * @ecalcomps: (element-type ECalComponent): list of #ECalComponent objects
1955 * Frees each element of the @ecalcomps list and the list itself.
1956 * Each element is an object of type #ECalComponent.
1961 e_cal_client_free_ecalcomp_slist (GSList *ecalcomps)
1963 g_slist_foreach (ecalcomps, (GFunc) g_object_unref, NULL);
1964 g_slist_free (ecalcomps);
1968 * e_cal_client_resolve_tzid_cb:
1969 * @tzid: ID of the timezone to resolve.
1970 * @data: Closure data for the callback, in this case #ECalClient.
1972 * Resolves TZIDs for the recurrence generator.
1974 * Returns: The timezone identified by the @tzid argument, or %NULL if
1975 * it could not be found.
1980 e_cal_client_resolve_tzid_cb (const gchar *tzid,
1983 ECalClient *client = data;
1984 icaltimezone *zone = NULL;
1985 GError *error = NULL;
1987 g_return_val_if_fail (E_IS_CAL_CLIENT (client), NULL);
1989 e_cal_client_get_timezone_sync (client, tzid, &zone, NULL, &error);
1991 if (error != NULL) {
1993 "%s: Failed to find '%s' timezone: %s",
1994 G_STRFUNC, tzid, error->message);
1995 g_error_free (error);
2001 struct comp_instance {
2002 ECalComponent *comp;
2007 struct instances_info {
2009 icaltimezone *start_zone;
2010 icaltimezone *end_zone;
2013 /* Called from cal_recur_generate_instances(); adds an instance to the list */
2015 add_instance (ECalComponent *comp,
2021 struct comp_instance *ci;
2022 icalcomponent *icalcomp;
2023 struct instances_info *instances_hold;
2025 instances_hold = data;
2026 list = instances_hold->instances;
2028 ci = g_new (struct comp_instance, 1);
2030 icalcomp = icalcomponent_new_clone (
2031 e_cal_component_get_icalcomponent (comp));
2033 /* add the instance to the list */
2034 ci->comp = e_cal_component_new ();
2035 e_cal_component_set_icalcomponent (ci->comp, icalcomp);
2037 /* make sure we return an instance */
2038 if (e_cal_util_component_has_recurrences (icalcomp) &&
2039 !(icalcomponent_get_first_property (icalcomp, ICAL_RECURRENCEID_PROPERTY))) {
2040 ECalComponentRange *range;
2041 struct icaltimetype itt;
2042 ECalComponentDateTime dtstart, dtend;
2044 /* update DTSTART */
2045 dtstart.value = NULL;
2046 dtstart.tzid = NULL;
2048 e_cal_component_get_dtstart (comp, &dtstart);
2050 if (instances_hold->start_zone) {
2051 itt = icaltime_from_timet_with_zone (
2052 start, dtstart.value && dtstart.value->is_date,
2053 instances_hold->start_zone);
2054 g_free ((gchar *) dtstart.tzid);
2055 dtstart.tzid = g_strdup (icaltimezone_get_tzid (
2056 instances_hold->start_zone));
2058 itt = icaltime_from_timet (
2059 start, dtstart.value && dtstart.value->is_date);
2061 g_free ((gchar *) dtstart.tzid);
2062 dtstart.tzid = NULL;
2066 g_free (dtstart.value);
2067 dtstart.value = &itt;
2068 e_cal_component_set_dtstart (ci->comp, &dtstart);
2070 /* set the RECUR-ID for the instance */
2071 range = g_new0 (ECalComponentRange, 1);
2072 range->type = E_CAL_COMPONENT_RANGE_SINGLE;
2073 range->datetime = dtstart;
2075 e_cal_component_set_recurid (ci->comp, range);
2078 g_free ((gchar *) dtstart.tzid);
2084 e_cal_component_get_dtend (comp, &dtend);
2086 if (instances_hold->end_zone) {
2087 itt = icaltime_from_timet_with_zone (
2088 end, dtend.value && dtend.value->is_date,
2089 instances_hold->end_zone);
2090 g_free ((gchar *) dtend.tzid);
2091 dtend.tzid = g_strdup (icaltimezone_get_tzid (
2092 instances_hold->end_zone));
2094 itt = icaltime_from_timet (
2095 end, dtend.value && dtend.value->is_date);
2097 g_free ((gchar *) dtend.tzid);
2102 g_free (dtend.value);
2104 e_cal_component_set_dtend (ci->comp, &dtend);
2106 g_free ((gchar *) dtend.tzid);
2112 *list = g_slist_prepend (*list, ci);
2117 /* Used from g_slist_sort(); compares two struct comp_instance structures */
2119 compare_comp_instance (gconstpointer a,
2122 const struct comp_instance *cia, *cib;
2128 diff = cia->start - cib->start;
2129 return (diff < 0) ? -1 : (diff > 0) ? 1 : 0;
2133 process_detached_instances (GSList *instances,
2134 GSList *detached_instances)
2136 struct comp_instance *ci, *cid;
2137 GSList *dl, *unprocessed_instances = NULL;
2139 for (dl = detached_instances; dl != NULL; dl = dl->next) {
2143 ECalComponentRange recur_id, instance_recur_id;
2146 recur_id.type = E_CAL_COMPONENT_RANGE_SINGLE;
2147 instance_recur_id.type = E_CAL_COMPONENT_RANGE_SINGLE;
2150 e_cal_component_get_uid (cid->comp, &uid);
2151 e_cal_component_get_recurid (cid->comp, &recur_id);
2153 /* search for coincident instances already expanded */
2154 for (il = instances; il != NULL; il = il->next) {
2155 const gchar *instance_uid;
2159 e_cal_component_get_uid (ci->comp, &instance_uid);
2160 e_cal_component_get_recurid (ci->comp, &instance_recur_id);
2161 if (strcmp (uid, instance_uid) == 0) {
2162 gchar *i_rid = NULL, *d_rid = NULL;
2164 i_rid = e_cal_component_get_recurid_as_string (ci->comp);
2165 d_rid = e_cal_component_get_recurid_as_string (cid->comp);
2167 if (i_rid && d_rid && strcmp (i_rid, d_rid) == 0) {
2168 g_object_unref (ci->comp);
2169 ci->comp = g_object_ref (cid->comp);
2170 ci->start = cid->start;
2175 if (!instance_recur_id.datetime.value ||
2176 !recur_id.datetime.value) {
2178 * Prevent obvious segfault by ignoring missing
2179 * recurrency ids. Real problem might be elsewhere,
2180 * but anything is better than crashing...
2184 G_LOG_LEVEL_CRITICAL,
2185 "UID %s: instance RECURRENCE-ID %s + detached instance RECURRENCE-ID %s: cannot compare",
2190 e_cal_component_free_datetime (&instance_recur_id.datetime);
2195 cmp = icaltime_compare (
2196 *instance_recur_id.datetime.value,
2197 *recur_id.datetime.value);
2198 if ((recur_id.type == E_CAL_COMPONENT_RANGE_THISPRIOR && cmp <= 0) ||
2199 (recur_id.type == E_CAL_COMPONENT_RANGE_THISFUTURE && cmp >= 0)) {
2200 ECalComponent *comp;
2202 comp = e_cal_component_new ();
2203 e_cal_component_set_icalcomponent (
2205 icalcomponent_new_clone (e_cal_component_get_icalcomponent (cid->comp)));
2206 e_cal_component_set_recurid (comp, &instance_recur_id);
2208 /* replace the generated instances */
2209 g_object_unref (ci->comp);
2216 e_cal_component_free_datetime (&instance_recur_id.datetime);
2219 e_cal_component_free_datetime (&recur_id.datetime);
2222 unprocessed_instances = g_slist_prepend (unprocessed_instances, cid);
2225 /* add the unprocessed instances
2226 * (ie, detached instances with no master object) */
2227 while (unprocessed_instances != NULL) {
2228 cid = unprocessed_instances->data;
2229 ci = g_new0 (struct comp_instance, 1);
2230 ci->comp = g_object_ref (cid->comp);
2231 ci->start = cid->start;
2233 instances = g_slist_append (instances, ci);
2235 unprocessed_instances = g_slist_remove (unprocessed_instances, cid);
2242 generate_instances (ECalClient *client,
2246 GCancellable *cancellable,
2247 ECalRecurInstanceFn cb,
2250 GSList *instances, *detached_instances = NULL;
2252 ECalClientPrivate *priv;
2254 priv = client->priv;
2258 for (l = objects; l && !g_cancellable_is_cancelled (cancellable); l = l->next) {
2259 ECalComponent *comp;
2260 icaltimezone *default_zone;
2262 if (priv->default_zone)
2263 default_zone = priv->default_zone;
2265 default_zone = icaltimezone_get_utc_timezone ();
2268 if (e_cal_component_is_instance (comp)) {
2269 struct comp_instance *ci;
2270 ECalComponentDateTime dtstart, dtend;
2271 icaltimezone *start_zone = NULL, *end_zone = NULL;
2273 /* keep the detached instances apart */
2274 ci = g_new0 (struct comp_instance, 1);
2275 ci->comp = g_object_ref (comp);
2277 e_cal_component_get_dtstart (comp, &dtstart);
2278 e_cal_component_get_dtend (comp, &dtend);
2280 /* For DATE-TIME values with a TZID, we use
2281 * e_cal_resolve_tzid_cb to resolve the TZID.
2282 * For DATE values and DATE-TIME values without a
2283 * TZID (i.e. floating times) we use the default
2285 if (dtstart.tzid && dtstart.value && !dtstart.value->is_date) {
2286 start_zone = e_cal_client_resolve_tzid_cb (
2287 dtstart.tzid, client);
2289 start_zone = default_zone;
2291 start_zone = default_zone;
2294 if (dtend.tzid && dtend.value && !dtend.value->is_date) {
2295 end_zone = e_cal_client_resolve_tzid_cb (
2296 dtend.tzid, client);
2298 end_zone = default_zone;
2300 end_zone = default_zone;
2303 ci->start = icaltime_as_timet_with_zone (
2304 *dtstart.value, start_zone);
2307 ci->end = icaltime_as_timet_with_zone (
2308 *dtend.value, end_zone);
2309 else if (icaltime_is_date (*dtstart.value))
2310 ci->end = time_day_end (ci->start);
2312 ci->end = ci->start;
2314 e_cal_component_free_datetime (&dtstart);
2315 e_cal_component_free_datetime (&dtend);
2317 if (ci->start <= end && ci->end >= start) {
2318 detached_instances = g_slist_prepend (
2319 detached_instances, ci);
2321 /* it doesn't fit to our time range, thus skip it */
2322 g_object_unref (G_OBJECT (ci->comp));
2326 ECalComponentDateTime datetime;
2327 icaltimezone *start_zone = NULL, *end_zone = NULL;
2328 struct instances_info *instances_hold;
2330 /* Get the start timezone */
2331 e_cal_component_get_dtstart (comp, &datetime);
2333 e_cal_client_get_timezone_sync (
2334 client, datetime.tzid,
2335 &start_zone, cancellable, NULL);
2338 e_cal_component_free_datetime (&datetime);
2340 /* Get the end timezone */
2341 e_cal_component_get_dtend (comp, &datetime);
2343 e_cal_client_get_timezone_sync (
2344 client, datetime.tzid,
2345 &end_zone, cancellable, NULL);
2348 e_cal_component_free_datetime (&datetime);
2350 instances_hold = g_new0 (struct instances_info, 1);
2351 instances_hold->instances = &instances;
2352 instances_hold->start_zone = start_zone;
2353 instances_hold->end_zone = end_zone;
2355 e_cal_recur_generate_instances (
2356 comp, start, end, add_instance, instances_hold,
2357 e_cal_client_resolve_tzid_cb, client,
2360 g_free (instances_hold);
2364 g_slist_foreach (objects, (GFunc) g_object_unref, NULL);
2365 g_slist_free (objects);
2367 /* Generate instances and spew them out */
2369 if (!g_cancellable_is_cancelled (cancellable)) {
2370 instances = g_slist_sort (instances, compare_comp_instance);
2371 instances = process_detached_instances (instances, detached_instances);
2374 for (l = instances; l && !g_cancellable_is_cancelled (cancellable); l = l->next) {
2375 struct comp_instance *ci;
2380 result = (* cb) (ci->comp, ci->start, ci->end, cb_data);
2388 for (l = instances; l; l = l->next) {
2389 struct comp_instance *ci;
2392 g_object_unref (G_OBJECT (ci->comp));
2396 g_slist_free (instances);
2398 for (l = detached_instances; l; l = l->next) {
2399 struct comp_instance *ci;
2402 g_object_unref (G_OBJECT (ci->comp));
2406 g_slist_free (detached_instances);
2410 get_objects_sync (ECalClient *client,
2415 GSList *objects = NULL;
2417 /* Generate objects */
2419 GError *error = NULL;
2421 e_cal_client_get_objects_for_uid_sync (
2422 client, uid, &objects, NULL, &error);
2424 if (error != NULL) {
2426 "Failed to get recurrence objects "
2427 "for uid: %s\n", error->message);
2428 g_clear_error (&error);
2432 gchar *iso_start, *iso_end;
2435 iso_start = isodate_from_time_t (start);
2439 iso_end = isodate_from_time_t (end);
2445 query = g_strdup_printf (
2446 "(occur-in-time-range? "
2447 "(make-time \"%s\") (make-time \"%s\"))",
2448 iso_start, iso_end);
2451 if (!e_cal_client_get_object_list_as_comps_sync (
2452 client, query, &objects, NULL, NULL)) {
2462 struct get_objects_async_data {
2463 GCancellable *cancellable;
2467 ECalRecurInstanceFn cb;
2469 GDestroyNotify destroy_cb_data;
2473 void (* ready_cb) (struct get_objects_async_data *goad, GSList *objects);
2474 icaltimezone *start_zone;
2475 icaltimezone *end_zone;
2476 ECalComponent *comp;
2480 free_get_objects_async_data (struct get_objects_async_data *goad)
2485 if (goad->cancellable)
2486 g_object_unref (goad->cancellable);
2487 if (goad->destroy_cb_data)
2488 goad->destroy_cb_data (goad->cb_data);
2490 g_object_unref (goad->client);
2492 g_object_unref (goad->comp);
2493 g_free (goad->query);
2499 got_objects_for_uid_cb (GObject *source_object,
2500 GAsyncResult *result,
2503 struct get_objects_async_data *goad = user_data;
2504 GSList *objects = NULL;
2505 GError *error = NULL;
2507 g_return_if_fail (source_object != NULL);
2508 g_return_if_fail (result != NULL);
2509 g_return_if_fail (goad != NULL);
2510 g_return_if_fail (goad->client == E_CAL_CLIENT (source_object));
2512 e_cal_client_get_objects_for_uid_finish (
2513 goad->client, result, &objects, &error);
2515 if (error != NULL) {
2516 if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED) ||
2517 g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
2518 free_get_objects_async_data (goad);
2519 g_clear_error (&error);
2523 g_clear_error (&error);
2527 g_return_if_fail (goad->ready_cb != NULL);
2529 /* takes care of the objects and goad */
2530 goad->ready_cb (goad, objects);
2534 got_object_list_as_comps_cb (GObject *source_object,
2535 GAsyncResult *result,
2538 struct get_objects_async_data *goad = user_data;
2539 GSList *objects = NULL;
2540 GError *error = NULL;
2542 g_return_if_fail (source_object != NULL);
2543 g_return_if_fail (result != NULL);
2544 g_return_if_fail (goad != NULL);
2545 g_return_if_fail (goad->client == E_CAL_CLIENT (source_object));
2547 e_cal_client_get_object_list_as_comps_finish (
2548 goad->client, result, &objects, &error);
2550 if (error != NULL) {
2551 if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED) ||
2552 g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
2553 free_get_objects_async_data (goad);
2554 g_clear_error (&error);
2558 g_clear_error (&error);
2562 g_return_if_fail (goad->ready_cb != NULL);
2564 /* takes care of the objects and goad */
2565 goad->ready_cb (goad, objects);
2568 /* ready_cb may take care of both arguments, goad and objects;
2569 * objects can be also NULL */
2571 get_objects_async (void (*ready_cb) (struct get_objects_async_data *goad,
2573 struct get_objects_async_data *goad)
2575 g_return_if_fail (ready_cb != NULL);
2576 g_return_if_fail (goad != NULL);
2578 goad->ready_cb = ready_cb;
2580 if (goad->uid && *goad->uid) {
2581 e_cal_client_get_objects_for_uid (
2582 goad->client, goad->uid, goad->cancellable,
2583 got_objects_for_uid_cb, goad);
2585 gchar *iso_start, *iso_end;
2587 iso_start = isodate_from_time_t (goad->start);
2589 free_get_objects_async_data (goad);
2593 iso_end = isodate_from_time_t (goad->end);
2596 free_get_objects_async_data (goad);
2600 goad->query = g_strdup_printf (
2601 "(occur-in-time-range? "
2602 "(make-time \"%s\") (make-time \"%s\"))",
2603 iso_start, iso_end);
2608 e_cal_client_get_object_list_as_comps (
2609 goad->client, goad->query, goad->cancellable,
2610 got_object_list_as_comps_cb, goad);
2615 generate_instances_got_objects_cb (struct get_objects_async_data *goad,
2618 g_return_if_fail (goad != NULL);
2620 /* generate_instaces () frees 'objects' slist */
2622 generate_instances (
2623 goad->client, goad->start, goad->end, objects,
2624 goad->cancellable, goad->cb, goad->cb_data);
2626 free_get_objects_async_data (goad);
2630 * e_cal_client_generate_instances:
2631 * @client: A calendar client.
2632 * @start: Start time for query.
2633 * @end: End time for query.
2634 * @cancellable: a #GCancellable; can be %NULL
2635 * @cb: Callback for each generated instance.
2636 * @cb_data: Closure data for the callback.
2637 * @destroy_cb_data: Function to call when the processing is done, to free
2638 * @cb_data; can be %NULL.
2640 * Does a combination of e_cal_client_get_object_list() and
2641 * e_cal_client_recur_generate_instances(). Unlike
2642 * e_cal_client_generate_instances_sync(), this returns immediately and the
2643 * @cb callback is called asynchronously.
2645 * The callback function should do a g_object_ref() of the calendar component
2646 * it gets passed if it intends to keep it around, since it will be unref'ed
2647 * as soon as the callback returns.
2652 e_cal_client_generate_instances (ECalClient *client,
2655 GCancellable *cancellable,
2656 ECalRecurInstanceFn cb,
2658 GDestroyNotify destroy_cb_data)
2660 struct get_objects_async_data *goad;
2661 GCancellable *use_cancellable;
2663 g_return_if_fail (E_IS_CAL_CLIENT (client));
2665 g_return_if_fail (start >= 0);
2666 g_return_if_fail (end >= 0);
2667 g_return_if_fail (cb != NULL);
2669 use_cancellable = cancellable;
2670 if (!use_cancellable)
2671 use_cancellable = g_cancellable_new ();
2673 goad = g_new0 (struct get_objects_async_data, 1);
2674 goad->cancellable = g_object_ref (use_cancellable);
2675 goad->client = g_object_ref (client);
2676 goad->start = start;
2679 goad->cb_data = cb_data;
2680 goad->destroy_cb_data = destroy_cb_data;
2682 get_objects_async (generate_instances_got_objects_cb, goad);
2684 if (use_cancellable != cancellable)
2685 g_object_unref (use_cancellable);
2689 * e_cal_client_generate_instances_sync:
2690 * @client: A calendar client
2691 * @start: Start time for query
2692 * @end: End time for query
2693 * @cb: (closure cb_data) (scope call): Callback for each generated instance
2694 * @cb_data: (closure): Closure data for the callback
2696 * Does a combination of e_cal_client_get_object_list() and
2697 * e_cal_client_recur_generate_instances().
2699 * The callback function should do a g_object_ref() of the calendar component
2700 * it gets passed if it intends to keep it around, since it will be unreffed
2701 * as soon as the callback returns.
2706 e_cal_client_generate_instances_sync (ECalClient *client,
2709 ECalRecurInstanceFn cb,
2712 GSList *objects = NULL;
2714 g_return_if_fail (E_IS_CAL_CLIENT (client));
2716 g_return_if_fail (start >= 0);
2717 g_return_if_fail (end >= 0);
2718 g_return_if_fail (cb != NULL);
2720 objects = get_objects_sync (client, start, end, NULL);
2724 /* generate_instaces frees 'objects' slist */
2725 generate_instances (client, start, end, objects, NULL, cb, cb_data);
2728 /* also frees 'instances' GSList */
2730 process_instances (ECalComponent *comp,
2732 ECalRecurInstanceFn cb,
2738 g_return_if_fail (comp != NULL);
2739 g_return_if_fail (cb != NULL);
2741 rid = e_cal_component_get_recurid_as_string (comp);
2743 /* Reverse the instances list because the add_instance() function
2745 instances = g_slist_reverse (instances);
2747 /* now only return back the instances for the given object */
2749 while (instances != NULL) {
2750 struct comp_instance *ci;
2751 gchar *instance_rid = NULL;
2753 ci = instances->data;
2756 instance_rid = e_cal_component_get_recurid_as_string (ci->comp);
2759 if (instance_rid && *instance_rid && strcmp (rid, instance_rid) == 0)
2760 result = (* cb) (ci->comp, ci->start, ci->end, cb_data);
2762 result = (* cb) (ci->comp, ci->start, ci->end, cb_data);
2765 /* remove instance from list */
2766 instances = g_slist_remove (instances, ci);
2767 g_object_unref (ci->comp);
2769 g_free (instance_rid);
2777 generate_instances_for_object_got_objects_cb (struct get_objects_async_data *goad,
2780 struct instances_info *instances_hold;
2781 GSList *instances = NULL;
2783 g_return_if_fail (goad != NULL);
2785 instances_hold = g_new0 (struct instances_info, 1);
2786 instances_hold->instances = &instances;
2787 instances_hold->start_zone = goad->start_zone;
2788 instances_hold->end_zone = goad->end_zone;
2790 /* generate all instances in the given time range */
2791 generate_instances (
2792 goad->client, goad->start, goad->end, objects,
2793 goad->cancellable, add_instance, instances_hold);
2795 /* it also frees 'instances' GSList */
2797 goad->comp, *(instances_hold->instances),
2798 goad->cb, goad->cb_data);
2801 free_get_objects_async_data (goad);
2802 g_free (instances_hold);
2806 * e_cal_client_generate_instances_for_object:
2807 * @client: A calendar client.
2808 * @icalcomp: Object to generate instances from.
2809 * @start: Start time for query.
2810 * @end: End time for query.
2811 * @cancellable: a #GCancellable; can be %NULL
2812 * @cb: Callback for each generated instance.
2813 * @cb_data: Closure data for the callback.
2814 * @destroy_cb_data: Function to call when the processing is done, to
2815 * free @cb_data; can be %NULL.
2817 * Does a combination of e_cal_client_get_object_list() and
2818 * e_cal_client_recur_generate_instances(), like
2819 * e_cal_client_generate_instances(), but for a single object. Unlike
2820 * e_cal_client_generate_instances_for_object_sync(), this returns immediately
2821 * and the @cb callback is called asynchronously.
2823 * The callback function should do a g_object_ref() of the calendar component
2824 * it gets passed if it intends to keep it around, since it will be unref'ed
2825 * as soon as the callback returns.
2830 e_cal_client_generate_instances_for_object (ECalClient *client,
2831 icalcomponent *icalcomp,
2834 GCancellable *cancellable,
2835 ECalRecurInstanceFn cb,
2837 GDestroyNotify destroy_cb_data)
2839 ECalComponent *comp;
2841 ECalComponentDateTime datetime;
2842 icaltimezone *start_zone = NULL, *end_zone = NULL;
2843 gboolean is_single_instance = FALSE;
2844 struct get_objects_async_data *goad;
2845 GCancellable *use_cancellable;
2847 g_return_if_fail (E_IS_CAL_CLIENT (client));
2849 g_return_if_fail (start >= 0);
2850 g_return_if_fail (end >= 0);
2851 g_return_if_fail (cb != NULL);
2853 comp = e_cal_component_new ();
2854 e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (icalcomp));
2856 if (!e_cal_component_has_recurrences (comp))
2857 is_single_instance = TRUE;
2859 /* If the backend stores it as individual instances and does not
2860 * have a master object - do not expand */
2861 if (is_single_instance || e_client_check_capability (E_CLIENT (client), CAL_STATIC_CAPABILITY_RECURRENCES_NO_MASTER)) {
2862 /* return the same instance */
2864 icaltime_as_timet_with_zone (
2865 icalcomponent_get_dtstart (icalcomp),
2866 client->priv->default_zone),
2867 icaltime_as_timet_with_zone (
2868 icalcomponent_get_dtend (icalcomp),
2869 client->priv->default_zone),
2871 g_object_unref (comp);
2873 if (destroy_cb_data)
2874 destroy_cb_data (cb_data);
2878 e_cal_component_get_uid (comp, &uid);
2880 /* Get the start timezone */
2881 e_cal_component_get_dtstart (comp, &datetime);
2883 e_cal_client_get_timezone_sync (
2884 client, datetime.tzid, &start_zone, NULL, NULL);
2887 e_cal_component_free_datetime (&datetime);
2889 /* Get the end timezone */
2890 e_cal_component_get_dtend (comp, &datetime);
2892 e_cal_client_get_timezone_sync (
2893 client, datetime.tzid, &end_zone, NULL, NULL);
2896 e_cal_component_free_datetime (&datetime);
2898 use_cancellable = cancellable;
2899 if (!use_cancellable)
2900 use_cancellable = g_cancellable_new ();
2902 goad = g_new0 (struct get_objects_async_data, 1);
2903 goad->cancellable = g_object_ref (use_cancellable);
2904 goad->client = g_object_ref (client);
2905 goad->start = start;
2908 goad->cb_data = cb_data;
2909 goad->destroy_cb_data = destroy_cb_data;
2910 goad->start_zone = start_zone;
2911 goad->end_zone = end_zone;
2913 goad->uid = g_strdup (uid);
2915 get_objects_async (generate_instances_for_object_got_objects_cb, goad);
2917 if (use_cancellable != cancellable)
2918 g_object_unref (use_cancellable);
2922 * e_cal_client_generate_instances_for_object_sync:
2923 * @client: A calendar client
2924 * @icalcomp: Object to generate instances from
2925 * @start: Start time for query
2926 * @end: End time for query
2927 * @cb: (closure cb_data) (scope call): Callback for each generated instance
2928 * @cb_data: (closure): Closure data for the callback
2930 * Does a combination of e_cal_client_get_object_list() and
2931 * e_cal_client_recur_generate_instances(), like
2932 * e_cal_client_generate_instances_sync(), but for a single object.
2934 * The callback function should do a g_object_ref() of the calendar component
2935 * it gets passed if it intends to keep it around, since it will be unref'ed
2936 * as soon as the callback returns.
2941 e_cal_client_generate_instances_for_object_sync (ECalClient *client,
2942 icalcomponent *icalcomp,
2945 ECalRecurInstanceFn cb,
2948 ECalComponent *comp;
2950 GSList *instances = NULL;
2951 ECalComponentDateTime datetime;
2952 icaltimezone *start_zone = NULL, *end_zone = NULL;
2953 struct instances_info *instances_hold;
2954 gboolean is_single_instance = FALSE;
2956 g_return_if_fail (E_IS_CAL_CLIENT (client));
2958 g_return_if_fail (start >= 0);
2959 g_return_if_fail (end >= 0);
2960 g_return_if_fail (cb != NULL);
2962 comp = e_cal_component_new ();
2963 e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (icalcomp));
2965 if (!e_cal_component_has_recurrences (comp))
2966 is_single_instance = TRUE;
2968 /* If the backend stores it as individual instances and does not
2969 * have a master object - do not expand */
2970 if (is_single_instance || e_client_check_capability (E_CLIENT (client), CAL_STATIC_CAPABILITY_RECURRENCES_NO_MASTER)) {
2971 /* return the same instance */
2973 icaltime_as_timet_with_zone (
2974 icalcomponent_get_dtstart (icalcomp),
2975 client->priv->default_zone),
2976 icaltime_as_timet_with_zone (
2977 icalcomponent_get_dtend (icalcomp),
2978 client->priv->default_zone),
2980 g_object_unref (comp);
2984 e_cal_component_get_uid (comp, &uid);
2986 /* Get the start timezone */
2987 e_cal_component_get_dtstart (comp, &datetime);
2989 e_cal_client_get_timezone_sync (
2990 client, datetime.tzid, &start_zone, NULL, NULL);
2993 e_cal_component_free_datetime (&datetime);
2995 /* Get the end timezone */
2996 e_cal_component_get_dtend (comp, &datetime);
2998 e_cal_client_get_timezone_sync (
2999 client, datetime.tzid, &end_zone, NULL, NULL);
3002 e_cal_component_free_datetime (&datetime);
3004 instances_hold = g_new0 (struct instances_info, 1);
3005 instances_hold->instances = &instances;
3006 instances_hold->start_zone = start_zone;
3007 instances_hold->end_zone = end_zone;
3009 /* generate all instances in the given time range */
3010 generate_instances (
3012 get_objects_sync (client, start, end, uid),
3013 NULL, add_instance, instances_hold);
3015 /* it also frees 'instances' GSList */
3016 process_instances (comp, *(instances_hold->instances), cb, cb_data);
3019 g_object_unref (comp);
3020 g_free (instances_hold);
3023 typedef struct _ForeachTZIDCallbackData ForeachTZIDCallbackData;
3024 struct _ForeachTZIDCallbackData {
3026 GHashTable *timezone_hash;
3030 /* This adds the VTIMEZONE given by the TZID parameter to the GHashTable in
3033 foreach_tzid_callback (icalparameter *param,
3036 ForeachTZIDCallbackData *data = cbdata;
3038 icaltimezone *zone = NULL;
3039 icalcomponent *vtimezone_comp;
3040 gchar *vtimezone_as_string;
3042 /* Get the TZID string from the parameter. */
3043 tzid = icalparameter_get_tzid (param);
3047 /* Check if we've already added it to the GHashTable. */
3048 if (g_hash_table_lookup (data->timezone_hash, tzid))
3051 if (!e_cal_client_get_timezone_sync (data->client, tzid, &zone, NULL, NULL) || !zone) {
3052 data->success = FALSE;
3056 /* Convert it to a string and add it to the hash. */
3057 vtimezone_comp = icaltimezone_get_component (zone);
3058 if (!vtimezone_comp)
3061 vtimezone_as_string = icalcomponent_as_ical_string_r (vtimezone_comp);
3063 g_hash_table_insert (data->timezone_hash, (gchar *) tzid, vtimezone_as_string);
3066 /* This appends the value string to the GString given in data. */
3068 append_timezone_string (gpointer key,
3072 GString *vcal_string = data;
3074 g_string_append (vcal_string, value);
3078 /* This simply frees the hash values. */
3080 free_timezone_string (gpointer key,
3088 * e_cal_client_get_component_as_string:
3089 * @client: A calendar client.
3090 * @icalcomp: A calendar component object.
3092 * Gets a calendar component as an iCalendar string, with a toplevel
3093 * VCALENDAR component and all VTIMEZONEs needed for the component.
3095 * Returns: the component as a complete iCalendar string, or NULL on
3096 * failure. The string should be freed with g_free().
3101 e_cal_client_get_component_as_string (ECalClient *client,
3102 icalcomponent *icalcomp)
3104 GHashTable *timezone_hash;
3105 GString *vcal_string;
3106 ForeachTZIDCallbackData cbdata;
3109 g_return_val_if_fail (E_IS_CAL_CLIENT (client), NULL);
3110 g_return_val_if_fail (icalcomp != NULL, NULL);
3112 timezone_hash = g_hash_table_new (g_str_hash, g_str_equal);
3114 /* Add any timezones needed to the hash. We use a hash since we only
3115 * want to add each timezone once at most. */
3116 cbdata.client = client;
3117 cbdata.timezone_hash = timezone_hash;
3118 cbdata.success = TRUE;
3119 icalcomponent_foreach_tzid (icalcomp, foreach_tzid_callback, &cbdata);
3120 if (!cbdata.success) {
3121 g_hash_table_foreach (timezone_hash, free_timezone_string, NULL);
3125 /* Create the start of a VCALENDAR, to add the VTIMEZONES to,
3126 * and remember its length so we know if any VTIMEZONEs get added. */
3127 vcal_string = g_string_new (NULL);
3131 "PRODID:-//Ximian//NONSGML Evolution Calendar//EN\n"
3133 "METHOD:PUBLISH\n");
3135 /* Now concatenate all the timezone strings. This also frees the
3136 * timezone strings as it goes. */
3137 g_hash_table_foreach (timezone_hash, append_timezone_string, vcal_string);
3139 /* Get the string for the VEVENT/VTODO. */
3140 obj_string = icalcomponent_as_ical_string_r (icalcomp);
3142 /* If there were any timezones to send, create a complete VCALENDAR,
3143 * else just send the VEVENT/VTODO string. */
3144 g_string_append (vcal_string, obj_string);
3145 g_string_append (vcal_string, "END:VCALENDAR\n");
3146 g_free (obj_string);
3148 obj_string = g_string_free (vcal_string, FALSE);
3150 g_hash_table_destroy (timezone_hash);
3155 /* Helper for e_cal_client_get_default_object() */
3157 cal_client_get_default_object_thread (GSimpleAsyncResult *simple,
3158 GObject *source_object,
3159 GCancellable *cancellable)
3161 AsyncContext *async_context;
3162 GError *error = NULL;
3164 async_context = g_simple_async_result_get_op_res_gpointer (simple);
3166 e_cal_client_get_default_object_sync (
3167 E_CAL_CLIENT (source_object),
3168 &async_context->out_comp,
3169 cancellable, &error);
3172 g_simple_async_result_take_error (simple, error);
3176 * e_cal_client_get_default_object:
3177 * @client: an #ECalClient
3178 * @cancellable: a #GCancellable; can be %NULL
3179 * @callback: callback to call when a result is ready
3180 * @user_data: user data for the @callback
3182 * Retrives an #icalcomponent from the backend that contains the default
3183 * values for properties needed. The call is finished
3184 * by e_cal_client_get_default_object_finish() from the @callback.
3189 e_cal_client_get_default_object (ECalClient *client,
3190 GCancellable *cancellable,
3191 GAsyncReadyCallback callback,
3194 GSimpleAsyncResult *simple;
3195 AsyncContext *async_context;
3197 g_return_if_fail (E_IS_CAL_CLIENT (client));
3199 async_context = g_slice_new0 (AsyncContext);
3201 simple = g_simple_async_result_new (
3202 G_OBJECT (client), callback, user_data,
3203 e_cal_client_get_default_object);
3205 g_simple_async_result_set_check_cancellable (simple, cancellable);
3207 g_simple_async_result_set_op_res_gpointer (
3208 simple, async_context, (GDestroyNotify) async_context_free);
3210 g_simple_async_result_run_in_thread (
3211 simple, cal_client_get_default_object_thread,
3212 G_PRIORITY_DEFAULT, cancellable);
3214 g_object_unref (simple);
3218 * e_cal_client_get_default_object_finish:
3219 * @client: an #ECalClient
3220 * @result: a #GAsyncResult
3221 * @out_icalcomp: (out): Return value for the default calendar object.
3222 * @error: (out): a #GError to set an error, if any
3224 * Finishes previous call of e_cal_client_get_default_object() and
3225 * sets @out_icalcomp to an #icalcomponent from the backend that contains
3226 * the default values for properties needed. This @out_icalcomp should be
3227 * freed with icalcomponent_free().
3229 * Returns: %TRUE if successful, %FALSE otherwise.
3234 e_cal_client_get_default_object_finish (ECalClient *client,
3235 GAsyncResult *result,
3236 icalcomponent **out_icalcomp,
3239 GSimpleAsyncResult *simple;
3240 AsyncContext *async_context;
3242 g_return_val_if_fail (
3243 g_simple_async_result_is_valid (
3244 result, G_OBJECT (client),
3245 e_cal_client_get_default_object), FALSE);
3247 simple = G_SIMPLE_ASYNC_RESULT (result);
3248 async_context = g_simple_async_result_get_op_res_gpointer (simple);
3250 if (g_simple_async_result_propagate_error (simple, error))
3253 g_return_val_if_fail (async_context->out_comp != NULL, FALSE);
3255 if (out_icalcomp != NULL) {
3256 *out_icalcomp = async_context->out_comp;
3257 async_context->out_comp = NULL;
3264 * e_cal_client_get_default_object_sync:
3265 * @client: an #ECalClient
3266 * @out_icalcomp: (out): Return value for the default calendar object.
3267 * @cancellable: a #GCancellable; can be %NULL
3268 * @error: (out): a #GError to set an error, if any
3270 * Retrives an #icalcomponent from the backend that contains the default
3271 * values for properties needed. This @out_icalcomp should be freed with
3272 * icalcomponent_free().
3274 * Returns: %TRUE if successful, %FALSE otherwise.
3279 e_cal_client_get_default_object_sync (ECalClient *client,
3280 icalcomponent **out_icalcomp,
3281 GCancellable *cancellable,
3284 icalcomponent *icalcomp = NULL;
3287 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
3288 g_return_val_if_fail (out_icalcomp != NULL, FALSE);
3290 string = e_dbus_calendar_dup_default_object (client->priv->dbus_proxy);
3291 if (string != NULL) {
3292 icalcomp = icalparser_parse_string (string);
3296 if (icalcomp == NULL) {
3297 g_set_error_literal (
3298 error, E_CAL_CLIENT_ERROR,
3299 E_CAL_CLIENT_ERROR_INVALID_OBJECT,
3300 e_cal_client_error_to_string (
3301 E_CAL_CLIENT_ERROR_INVALID_OBJECT));
3305 if (icalcomponent_get_uid (icalcomp) != NULL) {
3308 /* Make sure the UID is always unique. */
3309 new_uid = e_cal_component_gen_uid ();
3310 icalcomponent_set_uid (icalcomp, new_uid);
3314 *out_icalcomp = icalcomp;
3319 /* Helper for e_cal_client_get_object() */
3321 cal_client_get_object_thread (GSimpleAsyncResult *simple,
3322 GObject *source_object,
3323 GCancellable *cancellable)
3325 AsyncContext *async_context;
3326 GError *error = NULL;
3328 async_context = g_simple_async_result_get_op_res_gpointer (simple);
3330 e_cal_client_get_object_sync (
3331 E_CAL_CLIENT (source_object),
3334 &async_context->out_comp,
3335 cancellable, &error);
3338 g_simple_async_result_take_error (simple, error);
3342 * e_cal_client_get_object:
3343 * @client: an #ECalClient
3344 * @uid: Unique identifier for a calendar component.
3345 * @rid: Recurrence identifier.
3346 * @cancellable: a #GCancellable; can be %NULL
3347 * @callback: callback to call when a result is ready
3348 * @user_data: user data for the @callback
3350 * Queries a calendar for a calendar component object based on its unique
3351 * identifier. The call is finished by e_cal_client_get_object_finish()
3352 * from the @callback.
3354 * Use e_cal_client_get_objects_for_uid() to get list of all
3355 * objects for the given uid, which includes master object and
3356 * all detached instances.
3361 e_cal_client_get_object (ECalClient *client,
3364 GCancellable *cancellable,
3365 GAsyncReadyCallback callback,
3368 GSimpleAsyncResult *simple;
3369 AsyncContext *async_context;
3371 g_return_if_fail (E_IS_CAL_CLIENT (client));
3372 g_return_if_fail (uid != NULL);
3373 /* rid is optional */
3375 async_context = g_slice_new0 (AsyncContext);
3376 async_context->uid = g_strdup (uid);
3377 async_context->rid = g_strdup (rid);
3379 simple = g_simple_async_result_new (
3380 G_OBJECT (client), callback, user_data,
3381 e_cal_client_get_object);
3383 g_simple_async_result_set_check_cancellable (simple, cancellable);
3385 g_simple_async_result_set_op_res_gpointer (
3386 simple, async_context, (GDestroyNotify) async_context_free);
3388 g_simple_async_result_run_in_thread (
3389 simple, cal_client_get_object_thread,
3390 G_PRIORITY_DEFAULT, cancellable);
3392 g_object_unref (simple);
3396 * e_cal_client_get_object_finish:
3397 * @client: an #ECalClient
3398 * @result: a #GAsyncResult
3399 * @out_icalcomp: (out): Return value for the calendar component object.
3400 * @error: (out): a #GError to set an error, if any
3402 * Finishes previous call of e_cal_client_get_object() and
3403 * sets @out_icalcomp to queried component. This function always returns
3404 * master object for a case of @rid being NULL or an empty string.
3405 * This component should be freed with icalcomponent_free().
3407 * Use e_cal_client_get_objects_for_uid() to get list of all
3408 * objects for the given uid, which includes master object and
3409 * all detached instances.
3411 * Returns: %TRUE if successful, %FALSE otherwise.
3416 e_cal_client_get_object_finish (ECalClient *client,
3417 GAsyncResult *result,
3418 icalcomponent **out_icalcomp,
3421 GSimpleAsyncResult *simple;
3422 AsyncContext *async_context;
3424 g_return_val_if_fail (
3425 g_simple_async_result_is_valid (
3426 result, G_OBJECT (client),
3427 e_cal_client_get_object), FALSE);
3429 simple = G_SIMPLE_ASYNC_RESULT (result);
3430 async_context = g_simple_async_result_get_op_res_gpointer (simple);
3432 if (g_simple_async_result_propagate_error (simple, error))
3435 g_return_val_if_fail (async_context->out_comp != NULL, FALSE);
3437 if (out_icalcomp != NULL) {
3438 *out_icalcomp = async_context->out_comp;
3439 async_context->out_comp = NULL;
3446 * e_cal_client_get_object_sync:
3447 * @client: an #ECalClient
3448 * @uid: Unique identifier for a calendar component.
3449 * @rid: Recurrence identifier.
3450 * @out_icalcomp: (out): Return value for the calendar component object.
3451 * @cancellable: a #GCancellable; can be %NULL
3452 * @error: (out): a #GError to set an error, if any
3454 * Queries a calendar for a calendar component object based
3455 * on its unique identifier. This function always returns
3456 * master object for a case of @rid being NULL or an empty string.
3457 * This component should be freed with icalcomponent_free().
3459 * Use e_cal_client_get_objects_for_uid_sync() to get list of all
3460 * objects for the given uid, which includes master object and
3461 * all detached instances.
3463 * Returns: %TRUE if successful, %FALSE otherwise.
3468 e_cal_client_get_object_sync (ECalClient *client,
3471 icalcomponent **out_icalcomp,
3472 GCancellable *cancellable,
3475 icalcomponent *icalcomp = NULL;
3476 icalcomponent_kind kind;
3479 gchar *string = NULL;
3482 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
3483 g_return_val_if_fail (uid != NULL, FALSE);
3484 g_return_val_if_fail (out_icalcomp != NULL, FALSE);
3489 utf8_uid = e_util_utf8_make_valid (uid);
3490 utf8_rid = e_util_utf8_make_valid (rid);
3492 success = e_dbus_calendar_call_get_object_sync (
3493 client->priv->dbus_proxy, utf8_uid, utf8_rid,
3494 &string, cancellable, error);
3500 g_return_val_if_fail (
3501 (success && (string != NULL)) ||
3502 (!success && (string == NULL)), FALSE);
3507 icalcomp = icalparser_parse_string (string);
3511 if (icalcomp == NULL) {
3512 g_set_error_literal (
3513 error, E_CAL_CLIENT_ERROR,
3514 E_CAL_CLIENT_ERROR_INVALID_OBJECT,
3515 e_cal_client_error_to_string (
3516 E_CAL_CLIENT_ERROR_INVALID_OBJECT));
3520 switch (e_cal_client_get_source_type (client)) {
3521 case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
3522 kind = ICAL_VEVENT_COMPONENT;
3524 case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
3525 kind = ICAL_VTODO_COMPONENT;
3527 case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
3528 kind = ICAL_VJOURNAL_COMPONENT;
3531 g_warn_if_reached ();
3532 kind = ICAL_VEVENT_COMPONENT;
3536 if (icalcomponent_isa (icalcomp) == kind) {
3537 *out_icalcomp = icalcomp;
3539 } else if (icalcomponent_isa (icalcomp) == ICAL_VCALENDAR_COMPONENT) {
3540 icalcomponent *subcomponent;
3542 for (subcomponent = icalcomponent_get_first_component (icalcomp, kind);
3543 subcomponent != NULL;
3544 subcomponent = icalcomponent_get_next_component (icalcomp, kind)) {
3545 struct icaltimetype recurrenceid;
3547 if (icalcomponent_get_uid (subcomponent) == NULL)
3551 icalcomponent_get_recurrenceid (subcomponent);
3553 if (icaltime_is_null_time (recurrenceid))
3556 if (!icaltime_is_valid_time (recurrenceid))
3560 if (subcomponent == NULL)
3561 subcomponent = icalcomponent_get_first_component (icalcomp, kind);
3562 if (subcomponent != NULL)
3563 subcomponent = icalcomponent_new_clone (subcomponent);
3565 /* XXX Shouldn't we set an error is this is still NULL? */
3566 *out_icalcomp = subcomponent;
3568 icalcomponent_free (icalcomp);
3574 /* Helper for e_cal_client_get_objects_for_uid() */
3576 cal_client_get_objects_for_uid_thread (GSimpleAsyncResult *simple,
3577 GObject *source_object,
3578 GCancellable *cancellable)
3580 AsyncContext *async_context;
3581 GError *error = NULL;
3583 async_context = g_simple_async_result_get_op_res_gpointer (simple);
3585 e_cal_client_get_objects_for_uid_sync (
3586 E_CAL_CLIENT (source_object),
3588 &async_context->object_list,
3589 cancellable, &error);
3592 g_simple_async_result_take_error (simple, error);
3596 * e_cal_client_get_objects_for_uid:
3597 * @client: an #ECalClient
3598 * @uid: Unique identifier for a calendar component
3599 * @cancellable: a #GCancellable; can be %NULL
3600 * @callback: callback to call when a result is ready
3601 * @user_data: user data for the @callback
3603 * Queries a calendar for all calendar components with the given unique
3604 * ID. This will return any recurring event and all its detached recurrences.
3605 * For non-recurring events, it will just return the object with that ID.
3606 * The call is finished by e_cal_client_get_objects_for_uid_finish() from
3612 e_cal_client_get_objects_for_uid (ECalClient *client,
3614 GCancellable *cancellable,
3615 GAsyncReadyCallback callback,
3618 GSimpleAsyncResult *simple;
3619 AsyncContext *async_context;
3621 g_return_if_fail (E_IS_CAL_CLIENT (client));
3622 g_return_if_fail (uid != NULL);
3624 async_context = g_slice_new0 (AsyncContext);
3625 async_context->uid = g_strdup (uid);
3627 simple = g_simple_async_result_new (
3628 G_OBJECT (client), callback, user_data,
3629 e_cal_client_get_objects_for_uid);
3631 g_simple_async_result_set_check_cancellable (simple, cancellable);
3633 g_simple_async_result_set_op_res_gpointer (
3634 simple, async_context, (GDestroyNotify) async_context_free);
3636 g_simple_async_result_run_in_thread (
3637 simple, cal_client_get_objects_for_uid_thread,
3638 G_PRIORITY_DEFAULT, cancellable);
3640 g_object_unref (simple);
3644 * e_cal_client_get_objects_for_uid_finish:
3645 * @client: an #ECalClient
3646 * @result: a #GAsyncResult
3647 * @out_ecalcomps: (out) (transfer full) (element-type ECalComponent):
3648 * Return location for the list of objects obtained from the
3650 * @error: (out): a #GError to set an error, if any
3652 * Finishes previous call of e_cal_client_get_objects_for_uid() and
3653 * sets @out_ecalcomps to a list of #ECalComponent<!-- -->s corresponding to
3654 * found components for a given uid of the same type as this client.
3655 * This list should be freed with e_cal_client_free_ecalcomp_slist().
3657 * Returns: %TRUE if successful, %FALSE otherwise.
3662 e_cal_client_get_objects_for_uid_finish (ECalClient *client,
3663 GAsyncResult *result,
3664 GSList **out_ecalcomps,
3667 GSimpleAsyncResult *simple;
3668 AsyncContext *async_context;
3670 g_return_val_if_fail (
3671 g_simple_async_result_is_valid (
3672 result, G_OBJECT (client),
3673 e_cal_client_get_objects_for_uid), FALSE);
3675 simple = G_SIMPLE_ASYNC_RESULT (result);
3676 async_context = g_simple_async_result_get_op_res_gpointer (simple);
3678 if (g_simple_async_result_propagate_error (simple, error))
3681 if (out_ecalcomps != NULL) {
3682 *out_ecalcomps = async_context->object_list;
3683 async_context->object_list = NULL;
3690 * e_cal_client_get_objects_for_uid_sync:
3691 * @client: an #ECalClient
3692 * @uid: Unique identifier for a calendar component
3693 * @out_ecalcomps: (out) (transfer full) (element-type ECalComponent):
3694 * Return location for the list of objects obtained from the
3696 * @cancellable: (allow-none): a #GCancellable; can be %NULL
3697 * @error: (out): a #GError to set an error, if any
3699 * Queries a calendar for all calendar components with the given unique
3700 * ID. This will return any recurring event and all its detached recurrences.
3701 * For non-recurring events, it will just return the object with that ID.
3702 * This list should be freed with e_cal_client_free_ecalcomp_slist().
3704 * Returns: %TRUE if successful, %FALSE otherwise.
3709 e_cal_client_get_objects_for_uid_sync (ECalClient *client,
3711 GSList **out_ecalcomps,
3712 GCancellable *cancellable,
3715 icalcomponent *icalcomp;
3716 icalcomponent_kind kind;
3718 gchar *string = NULL;
3721 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
3722 g_return_val_if_fail (uid != NULL, FALSE);
3723 g_return_val_if_fail (out_ecalcomps != NULL, FALSE);
3725 utf8_uid = e_util_utf8_make_valid (uid);
3727 success = e_dbus_calendar_call_get_object_sync (
3728 client->priv->dbus_proxy, utf8_uid, "",
3729 &string, cancellable, error);
3734 g_return_val_if_fail (
3735 (success && (string != NULL)) ||
3736 (!success && (string == NULL)), FALSE);
3741 icalcomp = icalparser_parse_string (string);
3745 if (icalcomp == NULL) {
3746 g_set_error_literal (
3747 error, E_CAL_CLIENT_ERROR,
3748 E_CAL_CLIENT_ERROR_INVALID_OBJECT,
3749 e_cal_client_error_to_string (
3750 E_CAL_CLIENT_ERROR_INVALID_OBJECT));
3754 switch (e_cal_client_get_source_type (client)) {
3755 case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
3756 kind = ICAL_VEVENT_COMPONENT;
3758 case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
3759 kind = ICAL_VTODO_COMPONENT;
3761 case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
3762 kind = ICAL_VJOURNAL_COMPONENT;
3765 g_warn_if_reached ();
3766 kind = ICAL_VEVENT_COMPONENT;
3770 if (icalcomponent_isa (icalcomp) == kind) {
3771 ECalComponent *comp;
3773 comp = e_cal_component_new ();
3774 e_cal_component_set_icalcomponent (comp, icalcomp);
3775 *out_ecalcomps = g_slist_append (NULL, comp);
3777 } else if (icalcomponent_isa (icalcomp) == ICAL_VCALENDAR_COMPONENT) {
3779 icalcomponent *subcomponent;
3781 subcomponent = icalcomponent_get_first_component (
3784 while (subcomponent != NULL) {
3785 ECalComponent *comp;
3786 icalcomponent *clone;
3788 comp = e_cal_component_new ();
3789 clone = icalcomponent_new_clone (subcomponent);
3790 e_cal_component_set_icalcomponent (comp, clone);
3791 tmp = g_slist_prepend (tmp, comp);
3793 subcomponent = icalcomponent_get_next_component (
3797 *out_ecalcomps = g_slist_reverse (tmp);
3799 icalcomponent_free (icalcomp);
3805 /* Helper for e_cal_client_get_object_list() */
3807 cal_client_get_object_list_thread (GSimpleAsyncResult *simple,
3808 GObject *source_object,
3809 GCancellable *cancellable)
3811 AsyncContext *async_context;
3812 GError *error = NULL;
3814 async_context = g_simple_async_result_get_op_res_gpointer (simple);
3816 e_cal_client_get_object_list_sync (
3817 E_CAL_CLIENT (source_object),
3818 async_context->sexp,
3819 &async_context->comp_list,
3820 cancellable, &error);
3823 g_simple_async_result_take_error (simple, error);
3827 * e_cal_client_get_object_list:
3828 * @client: an #ECalClient
3829 * @sexp: an S-expression representing the query
3830 * @cancellable: a #GCancellable; can be %NULL
3831 * @callback: callback to call when a result is ready
3832 * @user_data: user data for the @callback
3834 * Gets a list of objects from the calendar that match the query specified
3835 * by the @sexp argument, returning matching objects as a list of #icalcomponent-s.
3836 * The call is finished by e_cal_client_get_object_list_finish() from
3842 e_cal_client_get_object_list (ECalClient *client,
3844 GCancellable *cancellable,
3845 GAsyncReadyCallback callback,
3848 GSimpleAsyncResult *simple;
3849 AsyncContext *async_context;
3851 g_return_if_fail (E_IS_CAL_CLIENT (client));
3852 g_return_if_fail (sexp != NULL);
3854 async_context = g_slice_new0 (AsyncContext);
3855 async_context->sexp = g_strdup (sexp);
3857 simple = g_simple_async_result_new (
3858 G_OBJECT (client), callback, user_data,
3859 e_cal_client_get_object_list);
3861 g_simple_async_result_set_check_cancellable (simple, cancellable);
3863 g_simple_async_result_set_op_res_gpointer (
3864 simple, async_context, (GDestroyNotify) async_context_free);
3866 g_simple_async_result_run_in_thread (
3867 simple, cal_client_get_object_list_thread,
3868 G_PRIORITY_DEFAULT, cancellable);
3870 g_object_unref (simple);
3874 * e_cal_client_get_object_list_finish:
3875 * @client: an #ECalClient
3876 * @result: a #GAsyncResult
3877 * @out_icalcomps: (out) (element-type icalcomponent): list of matching
3878 * #icalcomponent<!-- -->s
3879 * @error: (out): a #GError to set an error, if any
3881 * Finishes previous call of e_cal_client_get_object_list() and
3882 * sets @out_icalcomps to a matching list of #icalcomponent-s.
3883 * This list should be freed with e_cal_client_free_icalcomp_slist().
3885 * Returns: %TRUE if successful, %FALSE otherwise.
3890 e_cal_client_get_object_list_finish (ECalClient *client,
3891 GAsyncResult *result,
3892 GSList **out_icalcomps,
3895 GSimpleAsyncResult *simple;
3896 AsyncContext *async_context;
3898 g_return_val_if_fail (
3899 g_simple_async_result_is_valid (
3900 result, G_OBJECT (client),
3901 e_cal_client_get_object_list), FALSE);
3903 simple = G_SIMPLE_ASYNC_RESULT (result);
3904 async_context = g_simple_async_result_get_op_res_gpointer (simple);
3906 if (g_simple_async_result_propagate_error (simple, error))
3909 if (out_icalcomps != NULL) {
3910 *out_icalcomps = async_context->comp_list;
3911 async_context->comp_list = NULL;
3918 * e_cal_client_get_object_list_sync:
3919 * @client: an #ECalClient
3920 * @sexp: an S-expression representing the query
3921 * @out_icalcomps: (out) (element-type icalcomponent): list of matching
3922 * #icalcomponent<!-- -->s
3923 * @cancellable: (allow-none): a #GCancellable; can be %NULL
3924 * @error: (out): a #GError to set an error, if any
3926 * Gets a list of objects from the calendar that match the query specified
3927 * by the @sexp argument. The objects will be returned in the @out_icalcomps
3928 * argument, which is a list of #icalcomponent.
3929 * This list should be freed with e_cal_client_free_icalcomp_slist().
3931 * Returns: %TRUE if successful, %FALSE otherwise.
3936 e_cal_client_get_object_list_sync (ECalClient *client,
3938 GSList **out_icalcomps,
3939 GCancellable *cancellable,
3944 gchar **strv = NULL;
3948 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
3949 g_return_val_if_fail (sexp != NULL, FALSE);
3950 g_return_val_if_fail (out_icalcomps != NULL, FALSE);
3952 utf8_sexp = e_util_utf8_make_valid (sexp);
3954 success = e_dbus_calendar_call_get_object_list_sync (
3955 client->priv->dbus_proxy, utf8_sexp,
3956 &strv, cancellable, error);
3961 g_return_val_if_fail (
3962 (success && (strv != NULL)) ||
3963 (!success && (strv == NULL)), FALSE);
3968 for (ii = 0; strv[ii] != NULL; ii++) {
3969 icalcomponent *icalcomp;
3971 icalcomp = icalcomponent_new_from_string (strv[ii]);
3972 if (icalcomp == NULL)
3975 tmp = g_slist_prepend (tmp, icalcomp);
3978 *out_icalcomps = g_slist_reverse (tmp);
3983 /* Helper for e_cal_client_get_object_list_as_comps() */
3985 cal_client_get_object_list_as_comps_thread (GSimpleAsyncResult *simple,
3986 GObject *source_object,
3987 GCancellable *cancellable)
3989 AsyncContext *async_context;
3990 GError *error = NULL;
3992 async_context = g_simple_async_result_get_op_res_gpointer (simple);
3994 e_cal_client_get_object_list_as_comps_sync (
3995 E_CAL_CLIENT (source_object),
3996 async_context->sexp,
3997 &async_context->object_list,
3998 cancellable, &error);
4001 g_simple_async_result_take_error (simple, error);
4005 * e_cal_client_get_object_list_as_comps:
4006 * @client: an #ECalClient
4007 * @sexp: an S-expression representing the query
4008 * @cancellable: a #GCancellable; can be %NULL
4009 * @callback: callback to call when a result is ready
4010 * @user_data: user data for the @callback
4012 * Gets a list of objects from the calendar that match the query specified
4013 * by the @sexp argument, returning matching objects as a list of #ECalComponent-s.
4014 * The call is finished by e_cal_client_get_object_list_as_comps_finish() from
4020 e_cal_client_get_object_list_as_comps (ECalClient *client,
4022 GCancellable *cancellable,
4023 GAsyncReadyCallback callback,
4026 GSimpleAsyncResult *simple;
4027 AsyncContext *async_context;
4029 g_return_if_fail (E_IS_CAL_CLIENT (client));
4030 g_return_if_fail (sexp != NULL);
4032 async_context = g_slice_new0 (AsyncContext);
4033 async_context->sexp = g_strdup (sexp);
4035 simple = g_simple_async_result_new (
4036 G_OBJECT (client), callback, user_data,
4037 e_cal_client_get_object_list_as_comps);
4039 g_simple_async_result_set_check_cancellable (simple, cancellable);
4041 g_simple_async_result_set_op_res_gpointer (
4042 simple, async_context, (GDestroyNotify) async_context_free);
4044 g_simple_async_result_run_in_thread (
4045 simple, cal_client_get_object_list_as_comps_thread,
4046 G_PRIORITY_DEFAULT, cancellable);
4048 g_object_unref (simple);
4052 * e_cal_client_get_object_list_as_comps_finish:
4053 * @client: an #ECalClient
4054 * @result: a #GAsyncResult
4055 * @out_ecalcomps: (out) (element-type ECalComponent): list of matching
4056 * #ECalComponent<!-- -->s
4057 * @error: (out): a #GError to set an error, if any
4059 * Finishes previous call of e_cal_client_get_object_list_as_comps() and
4060 * sets @out_ecalcomps to a matching list of #ECalComponent-s.
4061 * This list should be freed with e_cal_client_free_ecalcomp_slist().
4063 * Returns: %TRUE if successful, %FALSE otherwise.
4068 e_cal_client_get_object_list_as_comps_finish (ECalClient *client,
4069 GAsyncResult *result,
4070 GSList **out_ecalcomps,
4073 GSimpleAsyncResult *simple;
4074 AsyncContext *async_context;
4076 g_return_val_if_fail (
4077 g_simple_async_result_is_valid (
4078 result, G_OBJECT (client),
4079 e_cal_client_get_object_list_as_comps), FALSE);
4081 simple = G_SIMPLE_ASYNC_RESULT (result);
4082 async_context = g_simple_async_result_get_op_res_gpointer (simple);
4084 if (g_simple_async_result_propagate_error (simple, error))
4087 if (out_ecalcomps != NULL) {
4088 *out_ecalcomps = async_context->object_list;
4089 async_context->object_list = NULL;
4096 * e_cal_client_get_object_list_as_comps_sync:
4097 * @client: an #ECalClient
4098 * @sexp: an S-expression representing the query
4099 * @out_ecalcomps: (out) (element-type ECalComponent): list of matching
4100 * #ECalComponent<!-- -->s
4101 * @cancellable: (allow-none): a #GCancellable; can be %NULL
4102 * @error: (out): a #GError to set an error, if any
4104 * Gets a list of objects from the calendar that match the query specified
4105 * by the @sexp argument. The objects will be returned in the @out_ecalcomps
4106 * argument, which is a list of #ECalComponent.
4107 * This list should be freed with e_cal_client_free_ecalcomp_slist().
4109 * Returns: %TRUE if successful, %FALSE otherwise.
4114 e_cal_client_get_object_list_as_comps_sync (ECalClient *client,
4116 GSList **out_ecalcomps,
4117 GCancellable *cancellable,
4120 GSList *list = NULL;
4122 GQueue trash = G_QUEUE_INIT;
4125 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
4126 g_return_val_if_fail (sexp != NULL, FALSE);
4127 g_return_val_if_fail (out_ecalcomps != NULL, FALSE);
4129 success = e_cal_client_get_object_list_sync (
4130 client, sexp, &list, cancellable, error);
4133 g_warn_if_fail (list == NULL);
4137 /* Convert the icalcomponent list to an ECalComponent list. */
4138 for (link = list; link != NULL; link = g_slist_next (link)) {
4139 ECalComponent *comp;
4140 icalcomponent *icalcomp = link->data;
4142 comp = e_cal_component_new ();
4144 /* This takes ownership of the icalcomponent, if it works. */
4145 if (e_cal_component_set_icalcomponent (comp, icalcomp)) {
4146 link->data = g_object_ref (comp);
4148 /* On failure, free resources and add
4149 * the GSList link to the trash queue. */
4150 icalcomponent_free (icalcomp);
4151 g_queue_push_tail (&trash, link);
4155 g_object_unref (comp);
4158 /* Delete GSList links we failed to convert. */
4159 while ((link = g_queue_pop_head (&trash)) != NULL)
4160 list = g_slist_delete_link (list, link);
4162 *out_ecalcomps = list;
4167 /* Helper for e_cal_client_get_free_busy() */
4169 cal_client_get_free_busy_thread (GSimpleAsyncResult *simple,
4170 GObject *source_object,
4171 GCancellable *cancellable)
4173 AsyncContext *async_context;
4174 GError *error = NULL;
4176 async_context = g_simple_async_result_get_op_res_gpointer (simple);
4178 e_cal_client_get_free_busy_sync (
4179 E_CAL_CLIENT (source_object),
4180 async_context->start,
4182 async_context->string_list,
4183 cancellable, &error);
4186 g_simple_async_result_take_error (simple, error);
4190 * e_cal_client_get_free_busy:
4191 * @client: an #ECalClient
4192 * @start: Start time for query
4193 * @end: End time for query
4194 * @users: (element-type utf8): List of users to retrieve free/busy information for
4195 * @cancellable: (allow-none): a #GCancellable; can be %NULL
4196 * @callback: callback to call when a result is ready
4197 * @user_data: user data for the @callback
4199 * Begins retrieval of free/busy information from the calendar server
4200 * as a list of #ECalComponent-s. Connect to "free-busy-data" signal
4201 * to receive chunks of free/busy components.
4202 * The call is finished by e_cal_client_get_free_busy_finish() from
4208 e_cal_client_get_free_busy (ECalClient *client,
4211 const GSList *users,
4212 GCancellable *cancellable,
4213 GAsyncReadyCallback callback,
4216 GSimpleAsyncResult *simple;
4217 AsyncContext *async_context;
4219 g_return_if_fail (E_IS_CAL_CLIENT (client));
4220 g_return_if_fail (start > 0);
4221 g_return_if_fail (end > 0);
4223 async_context = g_slice_new0 (AsyncContext);
4224 async_context->start = start;
4225 async_context->end = end;
4226 async_context->string_list = g_slist_copy_deep (
4227 (GSList *) users, (GCopyFunc) g_strdup, NULL);
4229 simple = g_simple_async_result_new (
4230 G_OBJECT (client), callback, user_data,
4231 e_cal_client_get_free_busy);
4233 g_simple_async_result_set_check_cancellable (simple, cancellable);
4235 g_simple_async_result_set_op_res_gpointer (
4236 simple, async_context, (GDestroyNotify) async_context_free);
4238 g_simple_async_result_run_in_thread (
4239 simple, cal_client_get_free_busy_thread,
4240 G_PRIORITY_DEFAULT, cancellable);
4242 g_object_unref (simple);
4246 * e_cal_client_get_free_busy_finish:
4247 * @client: an #ECalClient
4248 * @result: a #GAsyncResult
4249 * @error: (out): a #GError to set an error, if any
4251 * Finishes previous call of e_cal_client_get_free_busy().
4252 * All VFREEBUSY #ECalComponent-s were received by "free-busy-data" signal.
4254 * Returns: %TRUE if successful, %FALSE otherwise.
4259 e_cal_client_get_free_busy_finish (ECalClient *client,
4260 GAsyncResult *result,
4263 GSimpleAsyncResult *simple;
4265 g_return_val_if_fail (
4266 g_simple_async_result_is_valid (
4267 result, G_OBJECT (client),
4268 e_cal_client_get_free_busy), FALSE);
4270 simple = G_SIMPLE_ASYNC_RESULT (result);
4272 /* Assume success unless a GError is set. */
4273 return !g_simple_async_result_propagate_error (simple, error);
4277 * e_cal_client_get_free_busy_sync:
4278 * @client: an #ECalClient
4279 * @start: Start time for query
4280 * @end: End time for query
4281 * @users: (element-type utf8): List of users to retrieve free/busy information for
4282 * @cancellable: (allow-none): a #GCancellable; can be %NULL
4283 * @error: (out): a #GError to set an error, if any
4285 * Gets free/busy information from the calendar server.
4286 * All VFREEBUSY #ECalComponent-s were received by "free-busy-data" signal.
4288 * Returns: %TRUE if successful, %FALSE otherwise.
4293 e_cal_client_get_free_busy_sync (ECalClient *client,
4296 const GSList *users,
4297 GCancellable *cancellable,
4304 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
4305 g_return_val_if_fail (start > 0, FALSE);
4306 g_return_val_if_fail (end > 0, FALSE);
4308 strv = g_new0 (gchar *, g_slist_length ((GSList *) users) + 1);
4309 while (users != NULL) {
4310 strv[ii++] = e_util_utf8_make_valid (users->data);
4311 users = g_slist_next (users);
4314 success = e_dbus_calendar_call_get_free_busy_sync (
4315 client->priv->dbus_proxy,
4316 (gint64) start, (gint64) end,
4317 (const gchar * const *) strv,
4318 cancellable, error);
4325 /* Helper for e_cal_client_create_object() */
4327 cal_client_create_object_thread (GSimpleAsyncResult *simple,
4328 GObject *source_object,
4329 GCancellable *cancellable)
4331 AsyncContext *async_context;
4332 GError *error = NULL;
4334 async_context = g_simple_async_result_get_op_res_gpointer (simple);
4336 e_cal_client_create_object_sync (
4337 E_CAL_CLIENT (source_object),
4338 async_context->in_comp,
4339 &async_context->uid,
4340 cancellable, &error);
4343 g_simple_async_result_take_error (simple, error);
4347 * e_cal_client_create_object:
4348 * @client: an #ECalClient
4349 * @icalcomp: The component to create
4350 * @cancellable: a #GCancellable; can be %NULL
4351 * @callback: callback to call when a result is ready
4352 * @user_data: user data for the @callback
4354 * Requests the calendar backend to create the object specified by the @icalcomp
4355 * argument. Some backends would assign a specific UID to the newly created object,
4356 * but this function does not modify the original @icalcomp if its UID changes.
4357 * The call is finished by e_cal_client_create_object_finish() from
4363 e_cal_client_create_object (ECalClient *client,
4364 icalcomponent *icalcomp,
4365 GCancellable *cancellable,
4366 GAsyncReadyCallback callback,
4369 GSimpleAsyncResult *simple;
4370 AsyncContext *async_context;
4372 g_return_if_fail (E_IS_CAL_CLIENT (client));
4373 g_return_if_fail (icalcomp != NULL);
4375 async_context = g_slice_new0 (AsyncContext);
4376 async_context->in_comp = icalcomponent_new_clone (icalcomp);
4378 simple = g_simple_async_result_new (
4379 G_OBJECT (client), callback, user_data,
4380 e_cal_client_create_object);
4382 g_simple_async_result_set_op_res_gpointer (
4383 simple, async_context, (GDestroyNotify) async_context_free);
4385 g_simple_async_result_run_in_thread (
4386 simple, cal_client_create_object_thread,
4387 G_PRIORITY_DEFAULT, cancellable);
4389 g_object_unref (simple);
4393 * e_cal_client_create_object_finish:
4394 * @client: an #ECalClient
4395 * @result: a #GAsyncResult
4396 * @out_uid: (out): Return value for the UID assigned to the new component
4397 * by the calendar backend
4398 * @error: (out): a #GError to set an error, if any
4400 * Finishes previous call of e_cal_client_create_object() and
4401 * sets @out_uid to newly assigned UID for the created object.
4402 * This @out_uid should be freed with g_free().
4404 * Returns: %TRUE if successful, %FALSE otherwise.
4409 e_cal_client_create_object_finish (ECalClient *client,
4410 GAsyncResult *result,
4414 GSimpleAsyncResult *simple;
4415 AsyncContext *async_context;
4417 g_return_val_if_fail (
4418 g_simple_async_result_is_valid (
4419 result, G_OBJECT (client),
4420 e_cal_client_create_object), FALSE);
4422 simple = G_SIMPLE_ASYNC_RESULT (result);
4423 async_context = g_simple_async_result_get_op_res_gpointer (simple);
4425 if (g_simple_async_result_propagate_error (simple, error))
4428 g_return_val_if_fail (async_context->uid != NULL, FALSE);
4430 if (out_uid != NULL) {
4431 *out_uid = async_context->uid;
4432 async_context->uid = NULL;
4439 * e_cal_client_create_object_sync:
4440 * @client: an #ECalClient
4441 * @icalcomp: The component to create
4442 * @out_uid: (out): Return value for the UID assigned to the new component
4443 * by the calendar backend
4444 * @cancellable: a #GCancellable; can be %NULL
4445 * @error: (out): a #GError to set an error, if any
4447 * Requests the calendar backend to create the object specified by the
4448 * @icalcomp argument. Some backends would assign a specific UID to the newly
4449 * created object, in those cases that UID would be returned in the @out_uid
4450 * argument. This function does not modify the original @icalcomp if its UID
4451 * changes. Returned @out_uid should be freed with g_free().
4453 * Returns: %TRUE if successful, %FALSE otherwise.
4458 e_cal_client_create_object_sync (ECalClient *client,
4459 icalcomponent *icalcomp,
4461 GCancellable *cancellable,
4464 GSList link = { icalcomp, NULL };
4465 GSList *string_list = NULL;
4468 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
4469 g_return_val_if_fail (icalcomp != NULL, FALSE);
4471 success = e_cal_client_create_objects_sync (
4472 client, &link, &string_list, cancellable, error);
4475 g_return_val_if_fail (
4476 (success && (string_list != NULL)) ||
4477 (!success && (string_list == NULL)), FALSE);
4479 if (out_uid != NULL && string_list != NULL)
4480 *out_uid = g_strdup (string_list->data);
4482 g_slist_free_full (string_list, (GDestroyNotify) g_free);
4487 /* Helper for e_cal_client_create_objects() */
4489 cal_client_create_objects_thread (GSimpleAsyncResult *simple,
4490 GObject *source_object,
4491 GCancellable *cancellable)
4493 AsyncContext *async_context;
4494 GError *error = NULL;
4496 async_context = g_simple_async_result_get_op_res_gpointer (simple);
4498 e_cal_client_create_objects_sync (
4499 E_CAL_CLIENT (source_object),
4500 async_context->comp_list,
4501 &async_context->string_list,
4502 cancellable, &error);
4505 g_simple_async_result_take_error (simple, error);
4509 * e_cal_client_create_objects:
4510 * @client: an #ECalClient
4511 * @icalcomps: (element-type icalcomponent): The components to create
4512 * @cancellable: (allow-none): a #GCancellable; can be %NULL
4513 * @callback: callback to call when a result is ready
4514 * @user_data: user data for the @callback
4516 * Requests the calendar backend to create the objects specified by the @icalcomps
4517 * argument. Some backends would assign a specific UID to the newly created object,
4518 * but this function does not modify the original @icalcomps if their UID changes.
4519 * The call is finished by e_cal_client_create_objects_finish() from
4525 e_cal_client_create_objects (ECalClient *client,
4527 GCancellable *cancellable,
4528 GAsyncReadyCallback callback,
4531 GSimpleAsyncResult *simple;
4532 AsyncContext *async_context;
4534 g_return_if_fail (E_IS_CAL_CLIENT (client));
4535 g_return_if_fail (icalcomps != NULL);
4537 async_context = g_slice_new0 (AsyncContext);
4538 async_context->comp_list = g_slist_copy_deep (
4539 icalcomps, (GCopyFunc) icalcomponent_new_clone, NULL);
4541 simple = g_simple_async_result_new (
4542 G_OBJECT (client), callback, user_data,
4543 e_cal_client_create_objects);
4545 g_simple_async_result_set_check_cancellable (simple, cancellable);
4547 g_simple_async_result_set_op_res_gpointer (
4548 simple, async_context, (GDestroyNotify) async_context_free);
4550 g_simple_async_result_run_in_thread (
4551 simple, cal_client_create_objects_thread,
4552 G_PRIORITY_DEFAULT, cancellable);
4554 g_object_unref (simple);
4558 * e_cal_client_create_objects_finish:
4559 * @client: an #ECalClient
4560 * @result: a #GAsyncResult
4561 * @out_uids: (out) (element-type utf8): Return value for the UIDs assigned
4562 * to the new components by the calendar backend
4563 * @error: (out): a #GError to set an error, if any
4565 * Finishes previous call of e_cal_client_create_objects() and
4566 * sets @out_uids to newly assigned UIDs for the created objects.
4567 * This @out_uids should be freed with e_client_util_free_string_slist().
4569 * Returns: %TRUE if successful, %FALSE otherwise.
4574 e_cal_client_create_objects_finish (ECalClient *client,
4575 GAsyncResult *result,
4579 GSimpleAsyncResult *simple;
4580 AsyncContext *async_context;
4582 g_return_val_if_fail (
4583 g_simple_async_result_is_valid (
4584 result, G_OBJECT (client),
4585 e_cal_client_create_objects), FALSE);
4587 simple = G_SIMPLE_ASYNC_RESULT (result);
4588 async_context = g_simple_async_result_get_op_res_gpointer (simple);
4590 if (g_simple_async_result_propagate_error (simple, error))
4593 if (out_uids != NULL) {
4594 *out_uids = async_context->string_list;
4595 async_context->string_list = NULL;
4602 * e_cal_client_create_objects_sync:
4603 * @client: an #ECalClient
4604 * @icalcomps: (element-type icalcomponent): The components to create
4605 * @out_uids: (out) (element-type utf8): Return value for the UIDs assigned
4606 * to the new components by the calendar backend
4607 * @cancellable: (allow-none): a #GCancellable; can be %NULL
4608 * @error: (out): a #GError to set an error, if any
4610 * Requests the calendar backend to create the objects specified by the
4611 * @icalcomps argument. Some backends would assign a specific UID to the
4612 * newly created objects, in those cases these UIDs would be returned in
4613 * the @out_uids argument. This function does not modify the original
4614 * @icalcomps if their UID changes. Returned @out_uids should be freed
4615 * with e_client_util_free_string_slist().
4617 * Returns: %TRUE if successful, %FALSE otherwise.
4622 e_cal_client_create_objects_sync (ECalClient *client,
4625 GCancellable *cancellable,
4629 gchar **uids = NULL;
4633 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
4634 g_return_val_if_fail (icalcomps != NULL, FALSE);
4635 g_return_val_if_fail (out_uids != NULL, FALSE);
4637 strv = g_new0 (gchar *, g_slist_length (icalcomps) + 1);
4638 while (icalcomps != NULL) {
4641 ical_string = icalcomponent_as_ical_string_r (icalcomps->data);
4642 strv[ii++] = e_util_utf8_make_valid (ical_string);
4643 g_free (ical_string);
4645 icalcomps = g_slist_next (icalcomps);
4648 success = e_dbus_calendar_call_create_objects_sync (
4649 client->priv->dbus_proxy,
4650 (const gchar * const *) strv,
4651 &uids, cancellable, error);
4656 g_return_val_if_fail (
4657 (success && (uids != NULL)) ||
4658 (!success && (uids == NULL)), FALSE);
4663 /* Steal the string array elements. */
4664 for (ii = 0; uids[ii] != NULL; ii++) {
4665 tmp = g_slist_prepend (tmp, uids[ii]);
4669 *out_uids = g_slist_reverse (tmp);
4677 /* Helper for e_cal_client_modify_object() */
4679 cal_client_modify_object_thread (GSimpleAsyncResult *simple,
4680 GObject *source_object,
4681 GCancellable *cancellable)
4683 AsyncContext *async_context;
4684 GError *error = NULL;
4686 async_context = g_simple_async_result_get_op_res_gpointer (simple);
4688 e_cal_client_modify_object_sync (
4689 E_CAL_CLIENT (source_object),
4690 async_context->in_comp,
4692 cancellable, &error);
4695 g_simple_async_result_take_error (simple, error);
4699 * e_cal_client_modify_object:
4700 * @client: an #ECalClient
4701 * @icalcomp: Component to modify
4702 * @mod: Type of modification
4703 * @cancellable: a #GCancellable; can be %NULL
4704 * @callback: callback to call when a result is ready
4705 * @user_data: user data for the @callback
4707 * Requests the calendar backend to modify an existing object. If the object
4708 * does not exist on the calendar, an error will be returned.
4710 * For recurrent appointments, the @mod argument specifies what to modify,
4711 * if all instances (E_CAL_OBJ_MOD_ALL), a single instance (E_CAL_OBJ_MOD_THIS),
4712 * or a specific set of instances (E_CAL_OBJ_MOD_THIS_AND_PRIOR and
4713 * E_CAL_OBJ_MOD_THIS_AND_FUTURE).
4715 * The call is finished by e_cal_client_modify_object_finish() from
4721 e_cal_client_modify_object (ECalClient *client,
4722 icalcomponent *icalcomp,
4724 GCancellable *cancellable,
4725 GAsyncReadyCallback callback,
4728 GSimpleAsyncResult *simple;
4729 AsyncContext *async_context;
4731 g_return_if_fail (E_IS_CAL_CLIENT (client));
4732 g_return_if_fail (icalcomp != NULL);
4734 async_context = g_slice_new0 (AsyncContext);
4735 async_context->in_comp = icalcomponent_new_clone (icalcomp);
4736 async_context->mod = mod;
4738 simple = g_simple_async_result_new (
4739 G_OBJECT (client), callback, user_data,
4740 e_cal_client_modify_object);
4742 g_simple_async_result_set_check_cancellable (simple, cancellable);
4744 g_simple_async_result_set_op_res_gpointer (
4745 simple, async_context, (GDestroyNotify) async_context_free);
4747 g_simple_async_result_run_in_thread (
4748 simple, cal_client_modify_object_thread,
4749 G_PRIORITY_DEFAULT, cancellable);
4751 g_object_unref (simple);
4755 * e_cal_client_modify_object_finish:
4756 * @client: an #ECalClient
4757 * @result: a #GAsyncResult
4758 * @error: (out): a #GError to set an error, if any
4760 * Finishes previous call of e_cal_client_modify_object().
4762 * Returns: %TRUE if successful, %FALSE otherwise.
4767 e_cal_client_modify_object_finish (ECalClient *client,
4768 GAsyncResult *result,
4771 GSimpleAsyncResult *simple;
4773 g_return_val_if_fail (
4774 g_simple_async_result_is_valid (
4775 result, G_OBJECT (client),
4776 e_cal_client_modify_object), FALSE);
4778 simple = G_SIMPLE_ASYNC_RESULT (result);
4780 /* Assume success unless a GError is set. */
4781 return !g_simple_async_result_propagate_error (simple, error);
4785 * e_cal_client_modify_object_sync:
4786 * @client: an #ECalClient
4787 * @icalcomp: Component to modify
4788 * @mod: Type of modification
4789 * @cancellable: a #GCancellable; can be %NULL
4790 * @error: (out): a #GError to set an error, if any
4792 * Requests the calendar backend to modify an existing object. If the object
4793 * does not exist on the calendar, an error will be returned.
4795 * For recurrent appointments, the @mod argument specifies what to modify,
4796 * if all instances (E_CAL_OBJ_MOD_ALL), a single instance (E_CAL_OBJ_MOD_THIS),
4797 * or a specific set of instances (E_CAL_OBJ_MOD_THISNADPRIOR and
4798 * E_CAL_OBJ_MOD_THIS_AND_FUTURE).
4800 * Returns: %TRUE if successful, %FALSE otherwise.
4805 e_cal_client_modify_object_sync (ECalClient *client,
4806 icalcomponent *icalcomp,
4808 GCancellable *cancellable,
4811 GSList link = { icalcomp, NULL };
4813 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
4814 g_return_val_if_fail (icalcomp != NULL, FALSE);
4816 return e_cal_client_modify_objects_sync (
4817 client, &link, mod, cancellable, error);
4820 /* Helper for e_cal_client_modify_objects() */
4822 cal_client_modify_objects_thread (GSimpleAsyncResult *simple,
4823 GObject *source_object,
4824 GCancellable *cancellable)
4826 AsyncContext *async_context;
4827 GError *error = NULL;
4829 async_context = g_simple_async_result_get_op_res_gpointer (simple);
4831 e_cal_client_modify_objects_sync (
4832 E_CAL_CLIENT (source_object),
4833 async_context->comp_list,
4835 cancellable, &error);
4838 g_simple_async_result_take_error (simple, error);
4842 * e_cal_client_modify_objects:
4843 * @client: an #ECalClient
4844 * @comps: (element-type icalcomponent): Components to modify
4845 * @mod: Type of modification
4846 * @cancellable: (allow-none): a #GCancellable; can be %NULL
4847 * @callback: callback to call when a result is ready
4848 * @user_data: user data for the @callback
4850 * Requests the calendar backend to modify existing objects. If an object
4851 * does not exist on the calendar, an error will be returned.
4853 * For recurrent appointments, the @mod argument specifies what to modify,
4854 * if all instances (E_CAL_OBJ_MOD_ALL), a single instance (E_CAL_OBJ_MOD_THIS),
4855 * or a specific set of instances (E_CAL_OBJ_MOD_THISNADPRIOR and
4856 * E_CAL_OBJ_MOD_THIS_AND_FUTURE).
4858 * The call is finished by e_cal_client_modify_objects_finish() from
4864 e_cal_client_modify_objects (ECalClient *client,
4867 GCancellable *cancellable,
4868 GAsyncReadyCallback callback,
4871 GSimpleAsyncResult *simple;
4872 AsyncContext *async_context;
4874 g_return_if_fail (E_IS_CAL_CLIENT (client));
4875 g_return_if_fail (comps != NULL);
4877 async_context = g_slice_new0 (AsyncContext);
4878 async_context->comp_list = g_slist_copy_deep (
4879 comps, (GCopyFunc) icalcomponent_new_clone, NULL);
4880 async_context->mod = mod;
4882 simple = g_simple_async_result_new (
4883 G_OBJECT (client), callback, user_data,
4884 e_cal_client_modify_objects);
4886 g_simple_async_result_set_check_cancellable (simple, cancellable);
4888 g_simple_async_result_set_op_res_gpointer (
4889 simple, async_context, (GDestroyNotify) async_context_free);
4891 g_simple_async_result_run_in_thread (
4892 simple, cal_client_modify_objects_thread,
4893 G_PRIORITY_DEFAULT, cancellable);
4895 g_object_unref (simple);
4899 * e_cal_client_modify_objects_finish:
4900 * @client: an #ECalClient
4901 * @result: a #GAsyncResult
4902 * @error: (out): a #GError to set an error, if any
4904 * Finishes previous call of e_cal_client_modify_objects().
4906 * Returns: %TRUE if successful, %FALSE otherwise.
4911 e_cal_client_modify_objects_finish (ECalClient *client,
4912 GAsyncResult *result,
4915 GSimpleAsyncResult *simple;
4917 g_return_val_if_fail (
4918 g_simple_async_result_is_valid (
4919 result, G_OBJECT (client),
4920 e_cal_client_modify_objects), FALSE);
4922 simple = G_SIMPLE_ASYNC_RESULT (result);
4924 /* Assume success unless a GError is set. */
4925 return !g_simple_async_result_propagate_error (simple, error);
4929 * e_cal_client_modify_objects_sync:
4930 * @client: an #ECalClient
4931 * @comps: (element-type icalcomponent): Components to modify
4932 * @mod: Type of modification
4933 * @cancellable: (allow-none): a #GCancellable; can be %NULL
4934 * @error: (out): a #GError to set an error, if any
4936 * Requests the calendar backend to modify existing objects. If an object
4937 * does not exist on the calendar, an error will be returned.
4939 * For recurrent appointments, the @mod argument specifies what to modify,
4940 * if all instances (E_CAL_OBJ_MOD_ALL), a single instance (E_CAL_OBJ_MOD_THIS),
4941 * or a specific set of instances (E_CAL_OBJ_MOD_THISNADPRIOR and
4942 * E_CAL_OBJ_MOD_THIS_AND_FUTURE).
4944 * Returns: %TRUE if successful, %FALSE otherwise.
4949 e_cal_client_modify_objects_sync (ECalClient *client,
4952 GCancellable *cancellable,
4955 GFlagsClass *flags_class;
4956 GFlagsValue *flags_value;
4962 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
4963 g_return_val_if_fail (comps != NULL, FALSE);
4965 flags = g_string_new (NULL);
4966 flags_class = g_type_class_ref (E_TYPE_CAL_OBJ_MOD_TYPE);
4967 flags_value = g_flags_get_first_value (flags_class, mod);
4968 while (flags_value != NULL) {
4970 g_string_append_c (flags, ':');
4971 g_string_append (flags, flags_value->value_nick);
4972 mod &= ~flags_value->value;
4973 flags_value = g_flags_get_first_value (flags_class, mod);
4976 strv = g_new0 (gchar *, g_slist_length (comps) + 1);
4977 while (comps != NULL) {
4980 ical_string = icalcomponent_as_ical_string_r (comps->data);
4981 strv[ii++] = e_util_utf8_make_valid (ical_string);
4982 g_free (ical_string);
4984 comps = g_slist_next (comps);
4987 success = e_dbus_calendar_call_modify_objects_sync (
4988 client->priv->dbus_proxy,
4989 (const gchar * const *) strv,
4990 flags->str, cancellable, error);
4994 g_type_class_unref (flags_class);
4995 g_string_free (flags, TRUE);
5000 /* Helper for e_cal_client_remove_object() */
5002 cal_client_remove_object_thread (GSimpleAsyncResult *simple,
5003 GObject *source_object,
5004 GCancellable *cancellable)
5006 AsyncContext *async_context;
5007 GError *error = NULL;
5009 async_context = g_simple_async_result_get_op_res_gpointer (simple);
5011 e_cal_client_remove_object_sync (
5012 E_CAL_CLIENT (source_object),
5016 cancellable, &error);
5019 g_simple_async_result_take_error (simple, error);
5023 * e_cal_client_remove_object:
5024 * @client: an #ECalClient
5025 * @uid: UID of the object to remove
5026 * @rid: Recurrence ID of the specific recurrence to remove
5027 * @mod: Type of the removal
5028 * @cancellable: a #GCancellable; can be %NULL
5029 * @callback: callback to call when a result is ready
5030 * @user_data: user data for the @callback
5032 * This function allows the removal of instances of a recurrent
5033 * appointment. By using a combination of the @uid, @rid and @mod
5034 * arguments, you can remove specific instances. If what you want
5035 * is to remove all instances, use %NULL @rid and E_CAL_OBJ_MOD_ALL
5038 * The call is finished by e_cal_client_remove_object_finish() from
5044 e_cal_client_remove_object (ECalClient *client,
5048 GCancellable *cancellable,
5049 GAsyncReadyCallback callback,
5052 GSimpleAsyncResult *simple;
5053 AsyncContext *async_context;
5055 g_return_if_fail (E_IS_CAL_CLIENT (client));
5056 g_return_if_fail (uid != NULL);
5057 /* rid is optional */
5059 async_context = g_slice_new0 (AsyncContext);
5060 async_context->uid = g_strdup (uid);
5061 async_context->rid = g_strdup (rid);
5062 async_context->mod = mod;
5064 simple = g_simple_async_result_new (
5065 G_OBJECT (client), callback, user_data,
5066 e_cal_client_remove_object);
5068 g_simple_async_result_set_check_cancellable (simple, cancellable);
5070 g_simple_async_result_set_op_res_gpointer (
5071 simple, async_context, (GDestroyNotify) async_context_free);
5073 g_simple_async_result_run_in_thread (
5074 simple, cal_client_remove_object_thread,
5075 G_PRIORITY_DEFAULT, cancellable);
5077 g_object_unref (simple);
5081 * e_cal_client_remove_object_finish:
5082 * @client: an #ECalClient
5083 * @result: a #GAsyncResult
5084 * @error: (out): a #GError to set an error, if any
5086 * Finishes previous call of e_cal_client_remove_object().
5088 * Returns: %TRUE if successful, %FALSE otherwise.
5093 e_cal_client_remove_object_finish (ECalClient *client,
5094 GAsyncResult *result,
5097 GSimpleAsyncResult *simple;
5099 g_return_val_if_fail (
5100 g_simple_async_result_is_valid (
5101 result, G_OBJECT (client),
5102 e_cal_client_remove_object), FALSE);
5104 simple = G_SIMPLE_ASYNC_RESULT (result);
5106 /* Assume success unless a GError is set. */
5107 return !g_simple_async_result_propagate_error (simple, error);
5111 * e_cal_client_remove_object_sync:
5112 * @client: an #ECalClient
5113 * @uid: UID of the object to remove
5114 * @rid: Recurrence ID of the specific recurrence to remove
5115 * @mod: Type of the removal
5116 * @cancellable: a #GCancellable; can be %NULL
5117 * @error: (out): a #GError to set an error, if any
5119 * This function allows the removal of instances of a recurrent
5120 * appointment. By using a combination of the @uid, @rid and @mod
5121 * arguments, you can remove specific instances. If what you want
5122 * is to remove all instances, use %NULL @rid and E_CAL_OBJ_MODE_THIS
5125 * Returns: %TRUE if successful, %FALSE otherwise.
5130 e_cal_client_remove_object_sync (ECalClient *client,
5134 GCancellable *cancellable,
5137 ECalComponentId id = { (gchar *) uid, (gchar *) rid };
5138 GSList link = { &id, NULL };
5140 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
5141 g_return_val_if_fail (uid != NULL, FALSE);
5143 return e_cal_client_remove_objects_sync (
5144 client, &link, mod, cancellable, error);
5147 /* Helper for e_cal_client_remove_objects() */
5149 cal_client_remove_objects_thread (GSimpleAsyncResult *simple,
5150 GObject *source_object,
5151 GCancellable *cancellable)
5153 AsyncContext *async_context;
5154 GError *error = NULL;
5156 async_context = g_simple_async_result_get_op_res_gpointer (simple);
5158 e_cal_client_remove_objects_sync (
5159 E_CAL_CLIENT (source_object),
5160 async_context->string_list,
5162 cancellable, &error);
5165 g_simple_async_result_take_error (simple, error);
5169 * e_cal_client_remove_objects:
5170 * @client: an #ECalClient
5171 * @ids: (element-type ECalComponentId): A list of #ECalComponentId objects
5172 * identifying the objects to remove
5173 * @mod: Type of the removal
5174 * @cancellable: a #GCancellable; can be %NULL
5175 * @callback: callback to call when a result is ready
5176 * @user_data: user data for the @callback
5178 * This function allows the removal of instances of recurrent appointments.
5179 * #ECalComponentId objects can identify specific instances (if rid is not
5180 * %NULL). If what you want is to remove all instances, use a %NULL rid in
5181 * the #ECalComponentId and E_CAL_OBJ_MOD_ALL for the @mod.
5183 * The call is finished by e_cal_client_remove_objects_finish() from
5189 e_cal_client_remove_objects (ECalClient *client,
5192 GCancellable *cancellable,
5193 GAsyncReadyCallback callback,
5196 GSimpleAsyncResult *simple;
5197 AsyncContext *async_context;
5199 g_return_if_fail (E_IS_CAL_CLIENT (client));
5200 g_return_if_fail (ids != NULL);
5202 async_context = g_slice_new0 (AsyncContext);
5203 async_context->string_list = g_slist_copy_deep (
5204 (GSList *) ids, (GCopyFunc) g_strdup, NULL);
5205 async_context->mod = mod;
5207 simple = g_simple_async_result_new (
5208 G_OBJECT (client), callback, user_data,
5209 e_cal_client_remove_objects);
5211 g_simple_async_result_set_check_cancellable (simple, cancellable);
5213 g_simple_async_result_set_op_res_gpointer (
5214 simple, async_context, (GDestroyNotify) async_context_free);
5216 g_simple_async_result_run_in_thread (
5217 simple, cal_client_remove_objects_thread,
5218 G_PRIORITY_DEFAULT, cancellable);
5220 g_object_unref (simple);
5224 * e_cal_client_remove_objects_finish:
5225 * @client: an #ECalClient
5226 * @result: a #GAsyncResult
5227 * @error: (out): a #GError to set an error, if any
5229 * Finishes previous call of e_cal_client_remove_objects().
5231 * Returns: %TRUE if successful, %FALSE otherwise.
5236 e_cal_client_remove_objects_finish (ECalClient *client,
5237 GAsyncResult *result,
5240 GSimpleAsyncResult *simple;
5242 g_return_val_if_fail (
5243 g_simple_async_result_is_valid (
5244 result, G_OBJECT (client),
5245 e_cal_client_remove_objects), FALSE);
5247 simple = G_SIMPLE_ASYNC_RESULT (result);
5249 /* Assume success unless a GError is set. */
5250 return !g_simple_async_result_propagate_error (simple, error);
5254 * e_cal_client_remove_objects_sync:
5255 * @client: an #ECalClient
5256 * @ids: (element-type ECalComponentId): a list of #ECalComponentId objects
5257 * identifying the objects to remove
5258 * @mod: Type of the removal
5259 * @cancellable: (allow-none): a #GCancellable; can be %NULL
5260 * @error: (out): a #GError to set an error, if any
5262 * This function allows the removal of instances of recurrent
5263 * appointments. #ECalComponentId objects can identify specific instances
5264 * (if rid is not %NULL). If what you want is to remove all instances, use
5265 * a %NULL rid in the #ECalComponentId and E_CAL_OBJ_MOD_ALL for the @mod.
5267 * Returns: %TRUE if successful, %FALSE otherwise.
5272 e_cal_client_remove_objects_sync (ECalClient *client,
5275 GCancellable *cancellable,
5278 GVariantBuilder builder;
5279 GFlagsClass *flags_class;
5280 GFlagsValue *flags_value;
5284 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
5285 g_return_val_if_fail (ids != NULL, FALSE);
5287 flags = g_string_new (NULL);
5288 flags_class = g_type_class_ref (E_TYPE_CAL_OBJ_MOD_TYPE);
5289 flags_value = g_flags_get_first_value (flags_class, mod);
5290 while (flags_value != NULL) {
5292 g_string_append_c (flags, ':');
5293 g_string_append (flags, flags_value->value_nick);
5294 mod &= ~flags_value->value;
5295 flags_value = g_flags_get_first_value (flags_class, mod);
5298 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
5299 while (ids != NULL) {
5300 ECalComponentId *id = ids->data;
5304 ids = g_slist_next (ids);
5306 if (id->uid == NULL || *id->uid == '\0')
5309 utf8_uid = e_util_utf8_make_valid (id->uid);
5310 if (id->rid != NULL)
5311 utf8_rid = e_util_utf8_make_valid (id->rid);
5313 utf8_rid = g_strdup ("");
5315 g_variant_builder_add (&builder, "(ss)", utf8_uid, utf8_rid);
5321 success = e_dbus_calendar_call_remove_objects_sync (
5322 client->priv->dbus_proxy,
5323 g_variant_builder_end (&builder),
5324 flags->str, cancellable, error);
5326 g_type_class_unref (flags_class);
5327 g_string_free (flags, TRUE);
5332 /* Helper for e_cal_client_receive_objects() */
5334 cal_client_receive_objects_thread (GSimpleAsyncResult *simple,
5335 GObject *source_object,
5336 GCancellable *cancellable)
5338 AsyncContext *async_context;
5339 GError *error = NULL;
5341 async_context = g_simple_async_result_get_op_res_gpointer (simple);
5343 e_cal_client_receive_objects_sync (
5344 E_CAL_CLIENT (source_object),
5345 async_context->in_comp,
5346 cancellable, &error);
5349 g_simple_async_result_take_error (simple, error);
5353 * e_cal_client_receive_objects:
5354 * @client: an #ECalClient
5355 * @icalcomp: An #icalcomponent
5356 * @cancellable: a #GCancellable; can be %NULL
5357 * @callback: callback to call when a result is ready
5358 * @user_data: user data for the @callback
5360 * Makes the backend receive the set of iCalendar objects specified in the
5361 * @icalcomp argument. This is used for iTIP confirmation/cancellation
5362 * messages for scheduled meetings.
5364 * The call is finished by e_cal_client_receive_objects_finish() from
5370 e_cal_client_receive_objects (ECalClient *client,
5371 icalcomponent *icalcomp,
5372 GCancellable *cancellable,
5373 GAsyncReadyCallback callback,
5376 GSimpleAsyncResult *simple;
5377 AsyncContext *async_context;
5379 g_return_if_fail (E_IS_CAL_CLIENT (client));
5380 g_return_if_fail (icalcomp != NULL);
5382 async_context = g_slice_new0 (AsyncContext);
5383 async_context->in_comp = icalcomponent_new_clone (icalcomp);
5385 simple = g_simple_async_result_new (
5386 G_OBJECT (client), callback, user_data,
5387 e_cal_client_receive_objects);
5389 g_simple_async_result_set_check_cancellable (simple, cancellable);
5391 g_simple_async_result_set_op_res_gpointer (
5392 simple, async_context, (GDestroyNotify) async_context_free);
5394 g_simple_async_result_run_in_thread (
5395 simple, cal_client_receive_objects_thread,
5396 G_PRIORITY_DEFAULT, cancellable);
5398 g_object_unref (simple);
5402 * e_cal_client_receive_objects_finish:
5403 * @client: an #ECalClient
5404 * @result: a #GAsyncResult
5405 * @error: (out): a #GError to set an error, if any
5407 * Finishes previous call of e_cal_client_receive_objects().
5409 * Returns: %TRUE if successful, %FALSE otherwise.
5414 e_cal_client_receive_objects_finish (ECalClient *client,
5415 GAsyncResult *result,
5418 GSimpleAsyncResult *simple;
5420 g_return_val_if_fail (
5421 g_simple_async_result_is_valid (
5422 result, G_OBJECT (client),
5423 e_cal_client_receive_objects), FALSE);
5425 simple = G_SIMPLE_ASYNC_RESULT (result);
5427 /* Assume success unless a GError is set. */
5428 return !g_simple_async_result_propagate_error (simple, error);
5432 * e_cal_client_receive_objects_sync:
5433 * @client: an #ECalClient
5434 * @icalcomp: An #icalcomponent
5435 * @cancellable: a #GCancellable; can be %NULL
5436 * @error: (out): a #GError to set an error, if any
5438 * Makes the backend receive the set of iCalendar objects specified in the
5439 * @icalcomp argument. This is used for iTIP confirmation/cancellation
5440 * messages for scheduled meetings.
5442 * Returns: %TRUE if successful, %FALSE otherwise.
5447 e_cal_client_receive_objects_sync (ECalClient *client,
5448 icalcomponent *icalcomp,
5449 GCancellable *cancellable,
5453 gchar *utf8_ical_string;
5456 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
5458 ical_string = icalcomponent_as_ical_string_r (icalcomp);
5459 utf8_ical_string = e_util_utf8_make_valid (ical_string);
5461 success = e_dbus_calendar_call_receive_objects_sync (
5462 client->priv->dbus_proxy,
5463 utf8_ical_string, cancellable, error);
5465 g_free (utf8_ical_string);
5466 g_free (ical_string);
5471 /* Helper for e_cal_client_send_objects() */
5473 cal_client_send_objects_thread (GSimpleAsyncResult *simple,
5474 GObject *source_object,
5475 GCancellable *cancellable)
5477 AsyncContext *async_context;
5478 GError *error = NULL;
5480 async_context = g_simple_async_result_get_op_res_gpointer (simple);
5482 e_cal_client_send_objects_sync (
5483 E_CAL_CLIENT (source_object),
5484 async_context->in_comp,
5485 &async_context->string_list,
5486 &async_context->out_comp,
5487 cancellable, &error);
5490 g_simple_async_result_take_error (simple, error);
5494 * e_cal_client_send_objects:
5495 * @client: an #ECalClient
5496 * @icalcomp: An icalcomponent to be sent
5497 * @cancellable: a #GCancellable; can be %NULL
5498 * @callback: callback to call when a result is ready
5499 * @user_data: user data for the @callback
5501 * Requests a calendar backend to send meeting information stored in @icalcomp.
5502 * The backend can modify this component and request a send to particular users.
5503 * The call is finished by e_cal_client_send_objects_finish() from
5509 e_cal_client_send_objects (ECalClient *client,
5510 icalcomponent *icalcomp,
5511 GCancellable *cancellable,
5512 GAsyncReadyCallback callback,
5515 GSimpleAsyncResult *simple;
5516 AsyncContext *async_context;
5518 g_return_if_fail (E_IS_CAL_CLIENT (client));
5519 g_return_if_fail (icalcomp != NULL);
5521 async_context = g_slice_new0 (AsyncContext);
5522 async_context->in_comp = icalcomponent_new_clone (icalcomp);
5524 simple = g_simple_async_result_new (
5525 G_OBJECT (client), callback, user_data,
5526 e_cal_client_send_objects);
5528 g_simple_async_result_set_check_cancellable (simple, cancellable);
5530 g_simple_async_result_set_op_res_gpointer (
5531 simple, async_context, (GDestroyNotify) async_context_free);
5533 g_simple_async_result_run_in_thread (
5534 simple, cal_client_send_objects_thread,
5535 G_PRIORITY_DEFAULT, cancellable);
5537 g_object_unref (simple);
5541 * e_cal_client_send_objects_finish:
5542 * @client: an #ECalClient
5543 * @result: a #GAsyncResult
5544 * @out_users: (out) (element-type utf8): List of users to send
5545 * the @out_modified_icalcomp to
5546 * @out_modified_icalcomp: (out): Return value for the icalcomponent to be sent
5547 * @error: (out): a #GError to set an error, if any
5549 * Finishes previous call of e_cal_client_send_objects() and
5550 * populates @out_users with a list of users to send @out_modified_icalcomp to.
5552 * The @out_users list should be freed with e_client_util_free_string_slist()
5553 * and the @out_modified_icalcomp should be freed with icalcomponent_free().
5555 * Returns: %TRUE if successful, %FALSE otherwise.
5560 e_cal_client_send_objects_finish (ECalClient *client,
5561 GAsyncResult *result,
5563 icalcomponent **out_modified_icalcomp,
5566 GSimpleAsyncResult *simple;
5567 AsyncContext *async_context;
5569 g_return_val_if_fail (
5570 g_simple_async_result_is_valid (
5571 result, G_OBJECT (client),
5572 e_cal_client_send_objects), FALSE);
5574 simple = G_SIMPLE_ASYNC_RESULT (result);
5575 async_context = g_simple_async_result_get_op_res_gpointer (simple);
5577 if (g_simple_async_result_propagate_error (simple, error))
5580 g_return_val_if_fail (async_context->out_comp != NULL, FALSE);
5582 if (out_users != NULL) {
5583 *out_users = async_context->string_list;
5584 async_context->string_list = NULL;
5587 if (out_modified_icalcomp != NULL) {
5588 *out_modified_icalcomp = async_context->out_comp;
5589 async_context->out_comp = NULL;
5596 * e_cal_client_send_objects_sync:
5597 * @client: an #ECalClient
5598 * @icalcomp: An icalcomponent to be sent
5599 * @out_users: (out) (element-type utf8): List of users to send the
5600 * @out_modified_icalcomp to
5601 * @out_modified_icalcomp: (out): Return value for the icalcomponent to be sent
5602 * @cancellable: (allow-none): a #GCancellable; can be %NULL
5603 * @error: (out): a #GError to set an error, if any
5605 * Requests a calendar backend to send meeting information stored in @icalcomp.
5606 * The backend can modify this component and request a send to users in the
5609 * The @out_users list should be freed with e_client_util_free_string_slist()
5610 * and the @out_modified_icalcomp should be freed with icalcomponent_free().
5612 * Returns: %TRUE if successful, %FALSE otherwise.
5617 e_cal_client_send_objects_sync (ECalClient *client,
5618 icalcomponent *icalcomp,
5620 icalcomponent **out_modified_icalcomp,
5621 GCancellable *cancellable,
5625 gchar *utf8_ical_string;
5626 gchar **users = NULL;
5627 gchar *out_ical_string = NULL;
5630 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
5631 g_return_val_if_fail (icalcomp != NULL, FALSE);
5632 g_return_val_if_fail (out_users != NULL, FALSE);
5633 g_return_val_if_fail (out_modified_icalcomp != NULL, FALSE);
5635 ical_string = icalcomponent_as_ical_string_r (icalcomp);
5636 utf8_ical_string = e_util_utf8_make_valid (ical_string);
5638 success = e_dbus_calendar_call_send_objects_sync (
5639 client->priv->dbus_proxy, utf8_ical_string,
5640 &users, &out_ical_string, cancellable, error);
5642 g_free (utf8_ical_string);
5643 g_free (ical_string);
5646 g_return_val_if_fail (
5647 (success && (out_ical_string != NULL)) ||
5648 (!success && (out_ical_string == NULL)), FALSE);
5651 g_warn_if_fail (users == NULL);
5655 icalcomp = icalparser_parse_string (out_ical_string);
5657 g_free (out_ical_string);
5659 if (icalcomp != NULL) {
5660 *out_modified_icalcomp = icalcomp;
5662 g_set_error_literal (
5663 error, E_CAL_CLIENT_ERROR,
5664 E_CAL_CLIENT_ERROR_INVALID_OBJECT,
5665 e_cal_client_error_to_string (
5666 E_CAL_CLIENT_ERROR_INVALID_OBJECT));
5671 if (users != NULL) {
5675 for (ii = 0; users[ii] != NULL; ii++) {
5676 tmp = g_slist_prepend (tmp, users[ii]);
5680 *out_users = g_slist_reverse (tmp);
5688 /* Helper for e_cal_client_get_attachment_uris() */
5690 cal_client_get_attachment_uris_thread (GSimpleAsyncResult *simple,
5691 GObject *source_object,
5692 GCancellable *cancellable)
5694 AsyncContext *async_context;
5695 GError *error = NULL;
5697 async_context = g_simple_async_result_get_op_res_gpointer (simple);
5699 e_cal_client_get_attachment_uris_sync (
5700 E_CAL_CLIENT (source_object),
5703 &async_context->string_list,
5704 cancellable, &error);
5707 g_simple_async_result_take_error (simple, error);
5711 * e_cal_client_get_attachment_uris:
5712 * @client: an #ECalClient
5713 * @uid: Unique identifier for a calendar component
5714 * @rid: Recurrence identifier
5715 * @cancellable: a #GCancellable; can be %NULL
5716 * @callback: callback to call when a result is ready
5717 * @user_data: user data for the @callback
5719 * Queries a calendar for a specified component's object attachment uris.
5720 * The call is finished by e_cal_client_get_attachment_uris_finish() from
5726 e_cal_client_get_attachment_uris (ECalClient *client,
5729 GCancellable *cancellable,
5730 GAsyncReadyCallback callback,
5733 GSimpleAsyncResult *simple;
5734 AsyncContext *async_context;
5736 g_return_if_fail (E_CAL_CLIENT (client));
5737 g_return_if_fail (uid != NULL);
5738 /* rid is optional */
5740 async_context = g_slice_new0 (AsyncContext);
5741 async_context->uid = g_strdup (uid);
5742 async_context->rid = g_strdup (rid);
5744 simple = g_simple_async_result_new (
5745 G_OBJECT (client), callback, user_data,
5746 e_cal_client_get_attachment_uris);
5748 g_simple_async_result_set_check_cancellable (simple, cancellable);
5750 g_simple_async_result_set_op_res_gpointer (
5751 simple, async_context, (GDestroyNotify) async_context_free);
5753 g_simple_async_result_run_in_thread (
5754 simple, cal_client_get_attachment_uris_thread,
5755 G_PRIORITY_DEFAULT, cancellable);
5757 g_object_unref (simple);
5761 * e_cal_client_get_attachment_uris_finish:
5762 * @client: an #ECalClient
5763 * @result: a #GAsyncResult
5764 * @out_attachment_uris: (out) (element-type utf8): Return location for the
5765 * list of attachment URIs
5766 * @error: (out): a #GError to set an error, if any
5768 * Finishes previous call of e_cal_client_get_attachment_uris() and
5769 * sets @out_attachment_uris to uris for component's attachments.
5770 * The list should be freed with e_client_util_free_string_slist().
5772 * Returns: %TRUE if successful, %FALSE otherwise.
5777 e_cal_client_get_attachment_uris_finish (ECalClient *client,
5778 GAsyncResult *result,
5779 GSList **out_attachment_uris,
5782 GSimpleAsyncResult *simple;
5783 AsyncContext *async_context;
5785 g_return_val_if_fail (
5786 g_simple_async_result_is_valid (
5787 result, G_OBJECT (client),
5788 e_cal_client_get_attachment_uris), FALSE);
5790 simple = G_SIMPLE_ASYNC_RESULT (result);
5791 async_context = g_simple_async_result_get_op_res_gpointer (simple);
5793 if (g_simple_async_result_propagate_error (simple, error))
5796 if (out_attachment_uris != NULL) {
5797 *out_attachment_uris = async_context->string_list;
5798 async_context->string_list = NULL;
5805 * e_cal_client_get_attachment_uris_sync:
5806 * @client: an #ECalClient
5807 * @uid: Unique identifier for a calendar component
5808 * @rid: Recurrence identifier
5809 * @out_attachment_uris: (out) (element-type utf8): Return location for the
5810 * list of attachment URIs
5811 * @cancellable: (allow-none): a #GCancellable; can be %NULL
5812 * @error: (out): a #GError to set an error, if any
5814 * Queries a calendar for a specified component's object attachment URIs.
5815 * The list should be freed with e_client_util_free_string_slist().
5817 * Returns: %TRUE if successful, %FALSE otherwise.
5822 e_cal_client_get_attachment_uris_sync (ECalClient *client,
5825 GSList **out_attachment_uris,
5826 GCancellable *cancellable,
5831 gchar **uris = NULL;
5834 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
5835 g_return_val_if_fail (uid != NULL, FALSE);
5836 g_return_val_if_fail (out_attachment_uris != NULL, FALSE);
5841 utf8_uid = e_util_utf8_make_valid (uid);
5842 utf8_rid = e_util_utf8_make_valid (rid);
5844 success = e_dbus_calendar_call_get_attachment_uris_sync (
5845 client->priv->dbus_proxy, utf8_uid,
5846 utf8_rid, &uris, cancellable, error);
5852 g_return_val_if_fail (
5853 (success && (uris != NULL)) ||
5854 (!success && (uris == NULL)), FALSE);
5860 for (ii = 0; uris[ii] != NULL; ii++) {
5861 tmp = g_slist_prepend (tmp, uris[ii]);
5865 *out_attachment_uris = g_slist_reverse (tmp);
5871 /* Helper for e_cal_client_discard_alarm() */
5873 cal_client_discard_alarm_thread (GSimpleAsyncResult *simple,
5874 GObject *source_object,
5875 GCancellable *cancellable)
5877 AsyncContext *async_context;
5878 GError *error = NULL;
5880 async_context = g_simple_async_result_get_op_res_gpointer (simple);
5882 e_cal_client_discard_alarm_sync (
5883 E_CAL_CLIENT (source_object),
5886 async_context->auid,
5887 cancellable, &error);
5890 g_simple_async_result_take_error (simple, error);
5894 * e_cal_client_discard_alarm:
5895 * @client: an #ECalClient
5896 * @uid: Unique identifier for a calendar component
5897 * @rid: Recurrence identifier
5898 * @auid: Alarm identifier to remove
5899 * @cancellable: a #GCancellable; can be %NULL
5900 * @callback: callback to call when a result is ready
5901 * @user_data: user data for the @callback
5903 * Removes alarm @auid from a given component identified by @uid and @rid.
5904 * The call is finished by e_cal_client_discard_alarm_finish() from
5910 e_cal_client_discard_alarm (ECalClient *client,
5914 GCancellable *cancellable,
5915 GAsyncReadyCallback callback,
5918 GSimpleAsyncResult *simple;
5919 AsyncContext *async_context;
5921 g_return_if_fail (E_IS_CAL_CLIENT (client));
5922 g_return_if_fail (uid != NULL);
5923 /* rid is optional */
5924 g_return_if_fail (auid != NULL);
5926 async_context = g_slice_new0 (AsyncContext);
5927 async_context->uid = g_strdup (uid);
5928 async_context->rid = NULL;
5929 async_context->auid = g_strdup (auid);
5931 simple = g_simple_async_result_new (
5932 G_OBJECT (client), callback, user_data,
5933 e_cal_client_discard_alarm);
5935 g_simple_async_result_set_check_cancellable (simple, cancellable);
5937 g_simple_async_result_set_op_res_gpointer (
5938 simple, async_context, (GDestroyNotify) async_context_free);
5940 g_simple_async_result_run_in_thread (
5941 simple, cal_client_discard_alarm_thread,
5942 G_PRIORITY_DEFAULT, cancellable);
5944 g_object_unref (simple);
5948 * e_cal_client_discard_alarm_finish:
5949 * @client: an #ECalClient
5950 * @result: a #GAsyncResult
5951 * @error: (out): a #GError to set an error, if any
5953 * Finishes previous call of e_cal_client_discard_alarm().
5955 * Returns: %TRUE if successful, %FALSE otherwise.
5960 e_cal_client_discard_alarm_finish (ECalClient *client,
5961 GAsyncResult *result,
5964 GSimpleAsyncResult *simple;
5966 g_return_val_if_fail (
5967 g_simple_async_result_is_valid (
5968 result, G_OBJECT (client),
5969 e_cal_client_discard_alarm), FALSE);
5971 simple = G_SIMPLE_ASYNC_RESULT (result);
5973 /* Assume success unless a GError is set. */
5974 return !g_simple_async_result_propagate_error (simple, error);
5978 * e_cal_client_discard_alarm_sync:
5979 * @client: an #ECalClient
5980 * @uid: Unique identifier for a calendar component
5981 * @rid: Recurrence identifier
5982 * @auid: Alarm identifier to remove
5983 * @cancellable: a #GCancellable; can be %NULL
5984 * @error: (out): a #GError to set an error, if any
5986 * Removes alarm @auid from a given component identified by @uid and @rid.
5988 * Returns: %TRUE if successful, %FALSE otherwise.
5993 e_cal_client_discard_alarm_sync (ECalClient *client,
5997 GCancellable *cancellable,
6005 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
6006 g_return_val_if_fail (uid != NULL, FALSE);
6007 g_return_val_if_fail (auid != NULL, FALSE);
6012 utf8_uid = e_util_utf8_make_valid (uid);
6013 utf8_rid = e_util_utf8_make_valid (rid);
6014 utf8_auid = e_util_utf8_make_valid (auid);
6016 success = e_dbus_calendar_call_discard_alarm_sync (
6017 client->priv->dbus_proxy, utf8_uid,
6018 utf8_rid, utf8_auid, cancellable, error);
6027 /* Helper for e_cal_client_get_view() */
6029 cal_client_get_view_in_dbus_thread (GSimpleAsyncResult *simple,
6030 GObject *source_object,
6031 GCancellable *cancellable)
6033 ECalClient *client = E_CAL_CLIENT (source_object);
6034 AsyncContext *async_context;
6036 gchar *object_path = NULL;
6037 GError *error = NULL;
6039 async_context = g_simple_async_result_get_op_res_gpointer (simple);
6041 utf8_sexp = e_util_utf8_make_valid (async_context->sexp);
6043 e_dbus_calendar_call_get_view_sync (
6044 client->priv->dbus_proxy, utf8_sexp,
6045 &object_path, cancellable, &error);
6051 ((object_path != NULL) && (error == NULL)) ||
6052 ((object_path == NULL) && (error != NULL)));
6054 if (object_path != NULL) {
6055 GDBusConnection *connection;
6056 ECalClientView *client_view;
6058 connection = g_dbus_proxy_get_connection (
6059 G_DBUS_PROXY (client->priv->dbus_proxy));
6061 client_view = g_initable_new (
6062 E_TYPE_CAL_CLIENT_VIEW,
6063 cancellable, &error,
6065 "connection", connection,
6066 "object-path", object_path,
6071 ((client_view != NULL) && (error == NULL)) ||
6072 ((client_view == NULL) && (error != NULL)));
6074 async_context->client_view = client_view;
6076 g_free (object_path);
6080 g_simple_async_result_take_error (simple, error);
6084 * e_cal_client_get_view:
6085 * @client: an #ECalClient
6086 * @sexp: an S-expression representing the query.
6087 * @cancellable: a #GCancellable; can be %NULL
6088 * @callback: callback to call when a result is ready
6089 * @user_data: user data for the @callback
6091 * Query @client with @sexp, creating an #ECalClientView.
6092 * The call is finished by e_cal_client_get_view_finish()
6093 * from the @callback.
6098 e_cal_client_get_view (ECalClient *client,
6100 GCancellable *cancellable,
6101 GAsyncReadyCallback callback,
6104 GSimpleAsyncResult *simple;
6105 AsyncContext *async_context;
6107 g_return_if_fail (E_IS_CAL_CLIENT (client));
6108 g_return_if_fail (sexp != NULL);
6110 async_context = g_slice_new0 (AsyncContext);
6111 async_context->sexp = g_strdup (sexp);
6113 simple = g_simple_async_result_new (
6114 G_OBJECT (client), callback, user_data,
6115 e_cal_client_get_view);
6117 g_simple_async_result_set_check_cancellable (simple, cancellable);
6119 g_simple_async_result_set_op_res_gpointer (
6120 simple, async_context, (GDestroyNotify) async_context_free);
6122 cal_client_run_in_dbus_thread (
6123 simple, cal_client_get_view_in_dbus_thread,
6124 G_PRIORITY_DEFAULT, cancellable);
6126 g_object_unref (simple);
6130 * e_cal_client_get_view_finish:
6131 * @client: an #ECalClient
6132 * @result: a #GAsyncResult
6133 * @out_view: (out) an #ECalClientView
6134 * @error: (out): a #GError to set an error, if any
6136 * Finishes previous call of e_cal_client_get_view().
6137 * If successful, then the @out_view is set to newly allocated #ECalClientView,
6138 * which should be freed with g_object_unref().
6140 * Returns: %TRUE if successful, %FALSE otherwise.
6145 e_cal_client_get_view_finish (ECalClient *client,
6146 GAsyncResult *result,
6147 ECalClientView **out_view,
6150 GSimpleAsyncResult *simple;
6151 AsyncContext *async_context;
6153 g_return_val_if_fail (
6154 g_simple_async_result_is_valid (
6155 result, G_OBJECT (client),
6156 e_cal_client_get_view), FALSE);
6158 simple = G_SIMPLE_ASYNC_RESULT (result);
6159 async_context = g_simple_async_result_get_op_res_gpointer (simple);
6161 if (g_simple_async_result_propagate_error (simple, error))
6164 g_return_val_if_fail (async_context->client_view != NULL, FALSE);
6166 if (out_view != NULL)
6167 *out_view = g_object_ref (async_context->client_view);
6173 * e_cal_client_get_view_sync:
6174 * @client: an #ECalClient
6175 * @sexp: an S-expression representing the query.
6176 * @out_view: (out) an #ECalClientView
6177 * @cancellable: a #GCancellable; can be %NULL
6178 * @error: (out): a #GError to set an error, if any
6180 * Query @client with @sexp, creating an #ECalClientView.
6181 * If successful, then the @out_view is set to newly allocated #ECalClientView,
6182 * which should be freed with g_object_unref().
6184 * Returns: %TRUE if successful, %FALSE otherwise.
6189 e_cal_client_get_view_sync (ECalClient *client,
6191 ECalClientView **out_view,
6192 GCancellable *cancellable,
6195 EAsyncClosure *closure;
6196 GAsyncResult *result;
6199 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
6200 g_return_val_if_fail (sexp != NULL, FALSE);
6201 g_return_val_if_fail (out_view != NULL, FALSE);
6203 closure = e_async_closure_new ();
6205 e_cal_client_get_view (
6206 client, sexp, cancellable,
6207 e_async_closure_callback, closure);
6209 result = e_async_closure_wait (closure);
6211 success = e_cal_client_get_view_finish (
6212 client, result, out_view, error);
6214 e_async_closure_free (closure);
6219 /* Helper for e_cal_client_get_timezone() */
6221 cal_client_get_timezone_thread (GSimpleAsyncResult *simple,
6222 GObject *source_object,
6223 GCancellable *cancellable)
6225 AsyncContext *async_context;
6226 GError *error = NULL;
6228 async_context = g_simple_async_result_get_op_res_gpointer (simple);
6230 e_cal_client_get_timezone_sync (
6231 E_CAL_CLIENT (source_object),
6232 async_context->tzid,
6233 &async_context->zone,
6234 cancellable, &error);
6237 g_simple_async_result_take_error (simple, error);
6241 * e_cal_client_get_timezone:
6242 * @client: an #ECalClient
6243 * @tzid: ID of the timezone to retrieve
6244 * @cancellable: a #GCancellable; can be %NULL
6245 * @callback: callback to call when a result is ready
6246 * @user_data: user data for the @callback
6248 * Retrieves a timezone object from the calendar backend.
6249 * The call is finished by e_cal_client_get_timezone_finish() from
6255 e_cal_client_get_timezone (ECalClient *client,
6257 GCancellable *cancellable,
6258 GAsyncReadyCallback callback,
6261 GSimpleAsyncResult *simple;
6262 AsyncContext *async_context;
6264 g_return_if_fail (E_IS_CAL_CLIENT (client));
6265 g_return_if_fail (tzid != NULL);
6267 async_context = g_slice_new0 (AsyncContext);
6268 async_context->tzid = g_strdup (tzid);
6270 simple = g_simple_async_result_new (
6271 G_OBJECT (client), callback, user_data,
6272 e_cal_client_get_timezone);
6274 g_simple_async_result_set_check_cancellable (simple, cancellable);
6276 g_simple_async_result_set_op_res_gpointer (
6277 simple, async_context, (GDestroyNotify) async_context_free);
6279 g_simple_async_result_run_in_thread (
6280 simple, cal_client_get_timezone_thread,
6281 G_PRIORITY_DEFAULT, cancellable);
6283 g_object_unref (simple);
6287 * e_cal_client_get_timezone_finish:
6288 * @client: an #ECalClient
6289 * @result: a #GAsyncResult
6290 * @out_zone: (out): Return value for the timezone
6291 * @error: (out): a #GError to set an error, if any
6293 * Finishes previous call of e_cal_client_get_timezone() and
6294 * sets @out_zone to a retrieved timezone object from the calendar backend.
6295 * This object is owned by the @client, thus do not free it.
6297 * Returns: %TRUE if successful, %FALSE otherwise.
6302 e_cal_client_get_timezone_finish (ECalClient *client,
6303 GAsyncResult *result,
6304 icaltimezone **out_zone,
6307 GSimpleAsyncResult *simple;
6308 AsyncContext *async_context;
6310 g_return_val_if_fail (
6311 g_simple_async_result_is_valid (
6312 result, G_OBJECT (client),
6313 e_cal_client_get_timezone), FALSE);
6315 simple = G_SIMPLE_ASYNC_RESULT (result);
6316 async_context = g_simple_async_result_get_op_res_gpointer (simple);
6318 if (g_simple_async_result_propagate_error (simple, error))
6321 g_return_val_if_fail (async_context->zone != NULL, FALSE);
6323 if (out_zone != NULL) {
6324 *out_zone = async_context->zone;
6325 async_context->zone = NULL;
6332 * e_cal_client_get_timezone_sync:
6333 * @client: an #ECalClient
6334 * @tzid: ID of the timezone to retrieve
6335 * @out_zone: (out): Return value for the timezone
6336 * @cancellable: a #GCancellable; can be %NULL
6337 * @error: (out): a #GError to set an error, if any
6339 * Retrieves a timezone object from the calendar backend.
6340 * This object is owned by the @client, thus do not free it.
6342 * Returns: %TRUE if successful, %FALSE otherwise.
6347 e_cal_client_get_timezone_sync (ECalClient *client,
6349 icaltimezone **out_zone,
6350 GCancellable *cancellable,
6353 icalcomponent *icalcomp;
6356 gchar *string = NULL;
6359 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
6360 g_return_val_if_fail (tzid != NULL, FALSE);
6361 g_return_val_if_fail (out_zone != NULL, FALSE);
6363 zone = e_timezone_cache_get_timezone (
6364 E_TIMEZONE_CACHE (client), tzid);
6370 utf8_tzid = e_util_utf8_make_valid (tzid);
6372 success = e_dbus_calendar_call_get_timezone_sync (
6373 client->priv->dbus_proxy, utf8_tzid,
6374 &string, cancellable, error);
6379 g_return_val_if_fail (
6380 (success && (string != NULL)) ||
6381 (!success && (string == NULL)), FALSE);
6386 icalcomp = icalparser_parse_string (string);
6390 if (icalcomp == NULL) {
6391 g_set_error_literal (
6392 error, E_CAL_CLIENT_ERROR,
6393 E_CAL_CLIENT_ERROR_INVALID_OBJECT,
6394 e_cal_client_error_to_string (
6395 E_CAL_CLIENT_ERROR_INVALID_OBJECT));
6399 zone = icaltimezone_new ();
6400 if (!icaltimezone_set_component (zone, icalcomp)) {
6401 g_set_error_literal (
6402 error, E_CAL_CLIENT_ERROR,
6403 E_CAL_CLIENT_ERROR_INVALID_OBJECT,
6404 e_cal_client_error_to_string (
6405 E_CAL_CLIENT_ERROR_INVALID_OBJECT));
6406 icalcomponent_free (icalcomp);
6407 icaltimezone_free (zone, 1);
6411 /* Add the timezone to the cache directly,
6412 * otherwise we'd have to free this struct
6413 * and fetch the cached copy. */
6414 g_mutex_lock (&client->priv->zone_cache_lock);
6415 g_hash_table_insert (
6416 client->priv->zone_cache, g_strdup (tzid), zone);
6417 g_mutex_unlock (&client->priv->zone_cache_lock);
6424 /* Helper for e_cal_client_add_timezone() */
6426 cal_client_add_timezone_thread (GSimpleAsyncResult *simple,
6427 GObject *source_object,
6428 GCancellable *cancellable)
6430 AsyncContext *async_context;
6431 GError *error = NULL;
6433 async_context = g_simple_async_result_get_op_res_gpointer (simple);
6435 e_cal_client_add_timezone_sync (
6436 E_CAL_CLIENT (source_object),
6437 async_context->zone,
6438 cancellable, &error);
6441 g_simple_async_result_take_error (simple, error);
6445 * e_cal_client_add_timezone:
6446 * @client: an #ECalClient
6447 * @zone: The timezone to add
6448 * @cancellable: a #GCancellable; can be %NULL
6449 * @callback: callback to call when a result is ready
6450 * @user_data: user data for the @callback
6452 * Add a VTIMEZONE object to the given calendar client.
6453 * The call is finished by e_cal_client_add_timezone_finish() from
6459 e_cal_client_add_timezone (ECalClient *client,
6461 GCancellable *cancellable,
6462 GAsyncReadyCallback callback,
6465 GSimpleAsyncResult *simple;
6466 AsyncContext *async_context;
6467 icalcomponent *icalcomp;
6469 g_return_if_fail (E_IS_CAL_CLIENT (client));
6470 g_return_if_fail (zone != NULL);
6472 icalcomp = icaltimezone_get_component (zone);
6473 g_return_if_fail (icalcomp != NULL);
6475 async_context = g_slice_new0 (AsyncContext);
6476 async_context->zone = icaltimezone_new ();
6478 icalcomp = icalcomponent_new_clone (icalcomp);
6479 icaltimezone_set_component (async_context->zone, icalcomp);
6481 simple = g_simple_async_result_new (
6482 G_OBJECT (client), callback, user_data,
6483 e_cal_client_add_timezone);
6485 g_simple_async_result_set_check_cancellable (simple, cancellable);
6487 g_simple_async_result_set_op_res_gpointer (
6488 simple, async_context, (GDestroyNotify) async_context_free);
6490 if (zone == icaltimezone_get_utc_timezone ())
6491 g_simple_async_result_complete_in_idle (simple);
6493 g_simple_async_result_run_in_thread (
6494 simple, cal_client_add_timezone_thread,
6495 G_PRIORITY_DEFAULT, cancellable);
6497 g_object_unref (simple);
6501 * e_cal_client_add_timezone_finish:
6502 * @client: an #ECalClient
6503 * @result: a #GAsyncResult
6504 * @error: (out): a #GError to set an error, if any
6506 * Finishes previous call of e_cal_client_add_timezone().
6508 * Returns: %TRUE if successful, %FALSE otherwise.
6513 e_cal_client_add_timezone_finish (ECalClient *client,
6514 GAsyncResult *result,
6517 GSimpleAsyncResult *simple;
6519 g_return_val_if_fail (
6520 g_simple_async_result_is_valid (
6521 result, G_OBJECT (client),
6522 e_cal_client_add_timezone), FALSE);
6524 simple = G_SIMPLE_ASYNC_RESULT (result);
6526 /* Assume success unless a GError is set. */
6527 return !g_simple_async_result_propagate_error (simple, error);
6531 * e_cal_client_add_timezone_sync:
6532 * @client: an #ECalClient
6533 * @zone: The timezone to add
6534 * @cancellable: a #GCancellable; can be %NULL
6535 * @error: (out): a #GError to set an error, if any
6537 * Add a VTIMEZONE object to the given calendar client.
6539 * Returns: %TRUE if successful, %FALSE otherwise.
6544 e_cal_client_add_timezone_sync (ECalClient *client,
6546 GCancellable *cancellable,
6549 icalcomponent *icalcomp;
6551 gchar *utf8_zone_str;
6554 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
6555 g_return_val_if_fail (zone != NULL, FALSE);
6557 if (zone == icaltimezone_get_utc_timezone ())
6560 icalcomp = icaltimezone_get_component (zone);
6561 if (icalcomp == NULL) {
6563 error, e_client_error_create (
6564 E_CLIENT_ERROR_INVALID_ARG, NULL));
6568 zone_str = icalcomponent_as_ical_string_r (icalcomp);
6569 utf8_zone_str = e_util_utf8_make_valid (zone_str);
6571 success = e_dbus_calendar_call_add_timezone_sync (
6572 client->priv->dbus_proxy, utf8_zone_str, cancellable, error);
6575 g_free (utf8_zone_str);