1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* Evolution calendar - generic backend class
4 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
6 * Authors: Federico Mena-Quintero <federico@ximian.com>
7 * JP Rosevear <jpr@ximian.com>
8 * Rodrigo Moya <rodrigo@ximian.com>
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of version 2 of the GNU Lesser General Public
12 * License as published by the Free Software Foundation.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26 #include <glib/gi18n-lib.h>
28 #include "e-cal-backend.h"
29 #include "e-cal-backend-cache.h"
31 #define E_CAL_BACKEND_GET_PRIVATE(obj) \
32 (G_TYPE_INSTANCE_GET_PRIVATE \
33 ((obj), E_TYPE_CAL_BACKEND, ECalBackendPrivate))
35 #define EDC_ERROR(_code) e_data_cal_create_error (_code, NULL)
36 #define EDC_OPENING_ERROR e_data_cal_create_error (Busy, _("Cannot process, calendar backend is opening"))
37 #define EDC_NOT_OPENED_ERROR e_data_cal_create_error (NotOpened, NULL)
39 /* Private part of the CalBackend structure */
40 struct _ECalBackendPrivate {
41 ESourceRegistry *registry;
43 /* The kind of components for this backend */
44 icalcomponent_kind kind;
46 gboolean opening, opened, readonly, removed;
50 /* List of Cal objects */
51 GMutex *clients_mutex;
57 /* ECalBackend to pass notifications on to */
58 ECalBackend *notification_proxy;
70 static void e_cal_backend_remove_client_private (ECalBackend *backend, EDataCal *cal, gboolean weak_unref);
72 G_DEFINE_TYPE (ECalBackend, e_cal_backend, E_TYPE_BACKEND);
75 cal_backend_set_default_cache_dir (ECalBackend *backend)
78 icalcomponent_kind kind;
79 const gchar *component_type;
80 const gchar *user_cache_dir;
84 user_cache_dir = e_get_user_cache_dir ();
86 kind = e_cal_backend_get_kind (backend);
87 source = e_backend_get_source (E_BACKEND (backend));
89 uid = e_source_get_uid (source);
90 g_return_if_fail (uid != NULL);
93 case ICAL_VEVENT_COMPONENT:
94 component_type = "calendar";
96 case ICAL_VTODO_COMPONENT:
97 component_type = "tasks";
99 case ICAL_VJOURNAL_COMPONENT:
100 component_type = "memos";
103 g_return_if_reached ();
106 filename = g_build_filename (
107 user_cache_dir, component_type, uid, NULL);
108 e_cal_backend_set_cache_dir (backend, filename);
113 cal_backend_get_backend_property (ECalBackend *backend,
116 GCancellable *cancellable,
117 const gchar *prop_name)
119 g_return_if_fail (backend != NULL);
120 g_return_if_fail (E_IS_CAL_BACKEND (backend));
121 g_return_if_fail (cal != NULL);
122 g_return_if_fail (prop_name != NULL);
124 if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_OPENED)) {
125 e_data_cal_respond_get_backend_property (cal, opid, NULL, e_cal_backend_is_opened (backend) ? "TRUE" : "FALSE");
126 } else if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_OPENING)) {
127 e_data_cal_respond_get_backend_property (cal, opid, NULL, e_cal_backend_is_opening (backend) ? "TRUE" : "FALSE");
128 } else if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_ONLINE)) {
129 e_data_cal_respond_get_backend_property (cal, opid, NULL, e_backend_get_online (E_BACKEND (backend)) ? "TRUE" : "FALSE");
130 } else if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_READONLY)) {
131 e_data_cal_respond_get_backend_property (cal, opid, NULL, e_cal_backend_is_readonly (backend) ? "TRUE" : "FALSE");
132 } else if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CACHE_DIR)) {
133 e_data_cal_respond_get_backend_property (cal, opid, NULL, e_cal_backend_get_cache_dir (backend));
135 e_data_cal_respond_get_backend_property (cal, opid, e_data_cal_create_error_fmt (NotSupported, _("Unknown calendar property '%s'"), prop_name), NULL);
140 cal_backend_set_backend_property (ECalBackend *backend,
143 GCancellable *cancellable,
144 const gchar *prop_name,
145 const gchar *prop_value)
147 g_return_if_fail (backend != NULL);
148 g_return_if_fail (E_IS_CAL_BACKEND (backend));
149 g_return_if_fail (cal != NULL);
150 g_return_if_fail (prop_name != NULL);
152 e_data_cal_respond_set_backend_property (cal, opid, e_data_cal_create_error_fmt (NotSupported, _("Cannot change value of calendar property '%s'"), prop_name));
156 cal_backend_set_kind (ECalBackend *backend,
157 icalcomponent_kind kind)
159 backend->priv->kind = kind;
163 cal_backend_set_registry (ECalBackend *backend,
164 ESourceRegistry *registry)
166 g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
167 g_return_if_fail (backend->priv->registry == NULL);
169 backend->priv->registry = g_object_ref (registry);
173 cal_backend_set_property (GObject *object,
178 switch (property_id) {
180 e_cal_backend_set_cache_dir (
181 E_CAL_BACKEND (object),
182 g_value_get_string (value));
186 cal_backend_set_kind (
187 E_CAL_BACKEND (object),
188 g_value_get_ulong (value));
192 cal_backend_set_registry (
193 E_CAL_BACKEND (object),
194 g_value_get_object (value));
198 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
202 cal_backend_get_property (GObject *object,
207 switch (property_id) {
210 value, e_cal_backend_get_cache_dir (
211 E_CAL_BACKEND (object)));
216 value, e_cal_backend_get_kind (
217 E_CAL_BACKEND (object)));
222 value, e_cal_backend_get_registry (
223 E_CAL_BACKEND (object)));
227 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
231 cal_backend_dispose (GObject *object)
233 ECalBackendPrivate *priv;
235 priv = E_CAL_BACKEND_GET_PRIVATE (object);
237 if (priv->registry != NULL) {
238 g_object_unref (priv->registry);
239 priv->registry = NULL;
242 /* Chain up to parent's dispose() method. */
243 G_OBJECT_CLASS (e_cal_backend_parent_class)->dispose (object);
247 cal_backend_finalize (GObject *object)
249 ECalBackendPrivate *priv;
251 priv = E_CAL_BACKEND_GET_PRIVATE (object);
253 g_assert (priv->clients == NULL);
255 g_slist_free (priv->views);
256 /* should be NULL, anyway */
257 g_slist_free (priv->clients);
259 g_mutex_free (priv->clients_mutex);
260 g_mutex_free (priv->views_mutex);
262 g_free (priv->cache_dir);
264 /* Chain up to parent's finalize() method. */
265 G_OBJECT_CLASS (e_cal_backend_parent_class)->finalize (object);
269 cal_backend_constructed (GObject *object)
271 cal_backend_set_default_cache_dir (E_CAL_BACKEND (object));
273 G_OBJECT_CLASS (e_cal_backend_parent_class)->constructed (object);
277 e_cal_backend_class_init (ECalBackendClass *class)
279 GObjectClass *object_class;
281 g_type_class_add_private (class, sizeof (ECalBackendPrivate));
283 object_class = G_OBJECT_CLASS (class);
284 object_class->set_property = cal_backend_set_property;
285 object_class->get_property = cal_backend_get_property;
286 object_class->dispose = cal_backend_dispose;
287 object_class->finalize = cal_backend_finalize;
288 object_class->constructed = cal_backend_constructed;
290 class->get_backend_property = cal_backend_get_backend_property;
291 class->set_backend_property = cal_backend_set_backend_property;
293 g_object_class_install_property (
296 g_param_spec_string (
299 "The backend's cache directory",
302 G_PARAM_STATIC_STRINGS));
304 g_object_class_install_property (
310 "The kind of iCalendar components "
311 "this backend manages",
313 ICAL_XLICMIMEPART_COMPONENT,
316 G_PARAM_CONSTRUCT_ONLY |
317 G_PARAM_STATIC_STRINGS));
319 g_object_class_install_property (
322 g_param_spec_object (
325 "Data source registry",
326 E_TYPE_SOURCE_REGISTRY,
328 G_PARAM_CONSTRUCT_ONLY |
329 G_PARAM_STATIC_STRINGS));
333 e_cal_backend_init (ECalBackend *backend)
335 backend->priv = E_CAL_BACKEND_GET_PRIVATE (backend);
337 backend->priv->clients = NULL;
338 backend->priv->clients_mutex = g_mutex_new ();
340 backend->priv->views = NULL;
341 backend->priv->views_mutex = g_mutex_new ();
343 backend->priv->readonly = TRUE;
347 * e_cal_backend_get_kind:
348 * @backend: an #ECalBackend
350 * Gets the kind of components the given backend stores.
352 * Returns: The kind of components for this backend.
355 e_cal_backend_get_kind (ECalBackend *backend)
357 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), ICAL_NO_COMPONENT);
359 return backend->priv->kind;
363 * e_cal_backend_get_registry:
364 * @backend: an #ECalBackend
366 * Returns the data source registry to which #EBackend:source belongs.
368 * Returns: an #ESourceRegistry
373 e_cal_backend_get_registry (ECalBackend *backend)
375 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), NULL);
377 return backend->priv->registry;
381 * e_cal_backend_is_opened:
382 * @backend: an #ECalBackend
384 * Checks if @backend's storage has been opened (and
385 * authenticated, if necessary) and the backend itself
386 * is ready for accessing. This property is changed automatically
387 * within call of e_cal_backend_notify_opened().
389 * Returns: %TRUE if fully opened, %FALSE otherwise.
394 e_cal_backend_is_opened (ECalBackend *backend)
396 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), FALSE);
398 return backend->priv->opened;
402 * e_cal_backend_is_opening:
403 * @backend: an #ECalBackend
405 * Checks if @backend is processing its opening phase, which
406 * includes everything since the e_cal_backend_open() call,
407 * through authentication, up to e_cal_backend_notify_opened().
408 * This property is managed automatically and the backend deny
409 * every operation except of cancel and authenticate_user while
410 * it is being opening.
412 * Returns: %TRUE if opening phase is in the effect, %FALSE otherwise.
417 e_cal_backend_is_opening (ECalBackend *backend)
419 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), FALSE);
421 return backend->priv->opening;
425 * e_cal_backend_is_readonly:
426 * @backend: an #ECalBackend
428 * Returns: Whether is backend read-only. This value is the last used
429 * in a call of e_cal_backend_notify_readonly().
434 e_cal_backend_is_readonly (ECalBackend *backend)
436 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), FALSE);
438 return backend->priv->readonly;
442 * e_cal_backend_is_removed:
443 * @backend: an #ECalBackend
445 * Checks if @backend has been removed from its physical storage.
447 * Returns: %TRUE if @backend has been removed, %FALSE otherwise.
452 e_cal_backend_is_removed (ECalBackend *backend)
454 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), FALSE);
456 return backend->priv->removed;
460 * e_cal_backend_set_is_removed:
461 * @backend: an #ECalBackend
462 * @is_removed: A flag indicating whether the backend's storage was removed
464 * Sets the flag indicating whether @backend was removed to @is_removed.
465 * Meant to be used by backend implementations.
470 e_cal_backend_set_is_removed (ECalBackend *backend,
473 g_return_if_fail (E_IS_CAL_BACKEND (backend));
475 backend->priv->removed = is_removed;
479 * e_cal_backend_get_cache_dir:
480 * @backend: an #ECalBackend
482 * Returns the cache directory for the given backend.
484 * Returns: the cache directory for the backend
489 e_cal_backend_get_cache_dir (ECalBackend *backend)
491 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), NULL);
493 return backend->priv->cache_dir;
497 * e_cal_backend_set_cache_dir:
498 * @backend: an #ECalBackend
499 * @cache_dir: a local cache directory
501 * Sets the cache directory for the given backend.
503 * Note that #ECalBackend is initialized with a usable default based on
504 * #ECalBackend:source and #ECalBackend:kind properties. Backends should
505 * not override the default without good reason.
510 e_cal_backend_set_cache_dir (ECalBackend *backend,
511 const gchar *cache_dir)
513 g_return_if_fail (E_IS_CAL_BACKEND (backend));
514 g_return_if_fail (cache_dir != NULL);
516 if (g_strcmp0 (backend->priv->cache_dir, cache_dir) == 0)
519 g_free (backend->priv->cache_dir);
520 backend->priv->cache_dir = g_strdup (cache_dir);
522 g_object_notify (G_OBJECT (backend), "cache-dir");
526 * e_cal_backend_create_cache_filename:
527 * @backend: an #ECalBackend
528 * @uid: a component UID
529 * @filename: a filename to use; can be NULL
530 * @fileindex: index of a file; used only when @filename is NULL
532 * Returns: a filename for an attachment in a local cache dir. Free returned
533 * pointer with a g_free().
538 e_cal_backend_create_cache_filename (ECalBackend *backend,
540 const gchar *filename,
543 g_return_val_if_fail (backend != NULL, NULL);
544 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), NULL);
546 return e_filename_mkdir_encoded (e_cal_backend_get_cache_dir (backend), uid, filename, fileindex);
550 * e_cal_backend_get_backend_property:
551 * @backend: an #ECalBackend
553 * @opid: the ID to use for this operation
554 * @cancellable: a #GCancellable for the operation
555 * @prop_name: property name to get value of; cannot be NULL
557 * Calls the get_backend_property method on the given backend.
558 * This might be finished with e_data_cal_respond_get_backend_property().
559 * Default implementation takes care of common properties and returns
560 * an 'unsupported' error for any unknown properties. The subclass may
561 * always call this default implementation for properties which fetching
562 * it doesn't overwrite.
567 e_cal_backend_get_backend_property (ECalBackend *backend,
570 GCancellable *cancellable,
571 const gchar *prop_name)
573 g_return_if_fail (backend != NULL);
574 g_return_if_fail (E_IS_CAL_BACKEND (backend));
575 g_return_if_fail (prop_name != NULL);
576 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_backend_property != NULL);
578 (* E_CAL_BACKEND_GET_CLASS (backend)->get_backend_property) (backend, cal, opid, cancellable, prop_name);
582 * e_cal_backend_set_backend_property:
583 * @backend: an #ECalBackend
585 * @opid: the ID to use for this operation
586 * @cancellable: a #GCancellable for the operation
587 * @prop_name: property name to change; cannot be NULL
588 * @prop_value: value to set to @prop_name; cannot be NULL
590 * Calls the set_backend_property method on the given backend.
591 * This might be finished with e_data_cal_respond_set_backend_property().
592 * Default implementation simply returns an 'unsupported' error.
593 * The subclass may always call this default implementation for properties
594 * which fetching it doesn't overwrite.
599 e_cal_backend_set_backend_property (ECalBackend *backend,
602 GCancellable *cancellable,
603 const gchar *prop_name,
604 const gchar *prop_value)
606 g_return_if_fail (backend != NULL);
607 g_return_if_fail (E_IS_CAL_BACKEND (backend));
608 g_return_if_fail (prop_name != NULL);
609 g_return_if_fail (prop_value != NULL);
610 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->set_backend_property != NULL);
612 (* E_CAL_BACKEND_GET_CLASS (backend)->set_backend_property) (backend, cal, opid, cancellable, prop_name, prop_value);
616 cal_destroy_cb (gpointer data,
617 GObject *where_cal_was)
619 e_cal_backend_remove_client_private (E_CAL_BACKEND (data),
620 (EDataCal *) where_cal_was, FALSE);
624 * e_cal_backend_add_client:
625 * @backend: an #ECalBackend
628 * Adds a new client to the given backend. For any event, the backend will
629 * notify all clients added via this function.
632 e_cal_backend_add_client (ECalBackend *backend,
635 ECalBackendPrivate *priv;
637 g_return_if_fail (backend != NULL);
638 g_return_if_fail (E_IS_CAL_BACKEND (backend));
639 g_return_if_fail (cal != NULL);
640 g_return_if_fail (E_IS_DATA_CAL (cal));
642 priv = backend->priv;
644 g_object_weak_ref (G_OBJECT (cal), cal_destroy_cb, backend);
646 g_mutex_lock (priv->clients_mutex);
647 priv->clients = g_slist_append (priv->clients, cal);
648 g_mutex_unlock (priv->clients_mutex);
652 e_cal_backend_remove_client_private (ECalBackend *backend,
656 g_return_if_fail (E_IS_CAL_BACKEND (backend));
657 g_return_if_fail (E_IS_DATA_CAL (cal));
660 g_object_weak_unref (G_OBJECT (cal), cal_destroy_cb, backend);
662 /* Make sure the backend stays alive while holding the mutex. */
663 g_object_ref (backend);
666 g_mutex_lock (backend->priv->clients_mutex);
667 backend->priv->clients = g_slist_remove (backend->priv->clients, cal);
669 if (backend->priv->clients == NULL)
670 backend->priv->opening = FALSE;
672 g_mutex_unlock (backend->priv->clients_mutex);
674 g_object_unref (backend);
678 * e_cal_backend_remove_client:
679 * @backend: an #ECalBackend
682 * Removes a client from the list of connected clients to the given backend.
685 e_cal_backend_remove_client (ECalBackend *backend,
688 e_cal_backend_remove_client_private (backend, cal, TRUE);
692 * e_cal_backend_add_view:
693 * @backend: an #ECalBackend
694 * @view: An #EDataCalView object.
696 * Adds a view to the list of live views being run by the given backend.
697 * Doing so means that any listener on the view will get notified of any
698 * change that affect the live view.
703 e_cal_backend_add_view (ECalBackend *backend,
706 g_return_if_fail (backend != NULL);
707 g_return_if_fail (E_IS_CAL_BACKEND (backend));
709 g_mutex_lock (backend->priv->views_mutex);
711 backend->priv->views = g_slist_append (backend->priv->views, view);
713 g_mutex_unlock (backend->priv->views_mutex);
717 * e_cal_backend_remove_view
718 * @backend: an #ECalBackend
719 * @view: An #EDataCalView object, previously added with @ref e_cal_backend_add_view.
721 * Removes view from the list of live views for the backend.
726 e_cal_backend_remove_view (ECalBackend *backend,
729 g_return_if_fail (backend != NULL);
730 g_return_if_fail (E_IS_CAL_BACKEND (backend));
732 g_mutex_lock (backend->priv->views_mutex);
734 backend->priv->views = g_slist_remove (backend->priv->views, view);
736 g_mutex_unlock (backend->priv->views_mutex);
740 * e_cal_backend_foreach_view:
741 * @backend: an #ECalBackend
742 * @callback: callback to call
743 * @user_data: user_data passed into the @callback
745 * Calls @callback for each known calendar view of this @backend.
746 * @callback returns %FALSE to stop further processing.
751 e_cal_backend_foreach_view (ECalBackend *backend,
752 gboolean (*callback) (EDataCalView *view,
758 gboolean stop = FALSE;
760 g_return_if_fail (backend != NULL);
761 g_return_if_fail (callback != NULL);
763 g_mutex_lock (backend->priv->views_mutex);
765 for (views = backend->priv->views; views && !stop; views = views->next) {
766 view = E_DATA_CAL_VIEW (views->data);
769 stop = !callback (view, user_data);
770 g_object_unref (view);
773 g_mutex_unlock (backend->priv->views_mutex);
777 * e_cal_backend_set_notification_proxy:
778 * @backend: an #ECalBackend
779 * @proxy: The calendar backend to act as notification proxy.
781 * Sets the backend that will act as notification proxy for the given backend.
786 e_cal_backend_set_notification_proxy (ECalBackend *backend,
789 g_return_if_fail (E_IS_CAL_BACKEND (backend));
791 backend->priv->notification_proxy = proxy;
795 * e_cal_backend_open:
796 * @backend: an #ECalBackend
798 * @opid: the ID to use for this operation
799 * @cancellable: a #GCancellable for the operation
800 * @only_if_exists: Whether the calendar should be opened only if it already
801 * exists. If FALSE, a new calendar will be created when the specified @uri
804 * Opens a calendar backend with data from a calendar stored at the specified URI.
805 * This might be finished with e_data_cal_respond_open() or e_cal_backend_respond_opened(),
806 * though the overall opening phase finishes only after call
807 * of e_cal_backend_notify_opened() after which call the backend
808 * is either fully opened (including authentication against (remote)
809 * server/storage) or an error was encountered during this opening phase.
810 * 'opened' and 'opening' properties are updated automatically.
811 * The backend refuses all other operations until the opening phase is finished.
813 * The e_cal_backend_notify_opened() is called either from this function
814 * or from e_cal_backend_authenticate_user(), or after necessary steps
815 * initiated by these two functions.
817 * The opening phase usually works like this:
818 * 1) client requests open for the backend
819 * 2) server receives this request and calls e_cal_backend_open() - the opening phase begun
820 * 3) either the backend is opened during this call, and notifies client
821 * with e_cal_backend_notify_opened() about that. This is usually
822 * for local backends; their opening phase is finished
823 * 4) or the backend requires authentication, thus it notifies client
824 * about that with e_cal_backend_notify_auth_required() and is
825 * waiting for credentials, which will be received from client
826 * by e_cal_backend_authenticate_user() call. Backend's opening
827 * phase is still running in this case, thus it doesn't call
828 * e_cal_backend_notify_opened() within e_cal_backend_open() call.
829 * 5) when backend receives credentials in e_cal_backend_authenticate_user()
830 * then it tries to authenticate against a server/storage with them
831 * and only after it knows result of the authentication, whether user
832 * was or wasn't authenticated, it notifies client with the result
833 * by e_cal_backend_notify_opened() and it's opening phase is
834 * finished now. If there was no error returned then the backend is
835 * considered opened, otherwise it's considered closed. Use AuthenticationFailed
836 * error when the given credentials were rejected by the server/store, which
837 * will result in a re-prompt on the client side, otherwise use AuthenticationRequired
838 * if there was anything wrong with the given credentials. Set error's
839 * message to a reason for a re-prompt, it'll be shown to a user.
840 * 6) client checks error returned from e_cal_backend_notify_opened() and
841 * reprompts for a password if it was AuthenticationFailed. Otherwise
842 * considers backend opened based on the error presence (no error means success).
844 * In any case, the call of e_cal_backend_open() should be always finished
845 * with e_data_cal_respond_open(), which has no influence on the opening phase,
846 * or alternatively with e_cal_backend_respond_opened(). Never use authentication
847 * errors in e_data_cal_respond_open() to notify the client the authentication is
848 * required, there is e_cal_backend_notify_auth_required() for this.
851 e_cal_backend_open (ECalBackend *backend,
854 GCancellable *cancellable,
855 gboolean only_if_exists)
857 g_return_if_fail (backend != NULL);
858 g_return_if_fail (E_IS_CAL_BACKEND (backend));
859 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->open != NULL);
861 g_mutex_lock (backend->priv->clients_mutex);
863 if (e_cal_backend_is_opened (backend)) {
866 g_mutex_unlock (backend->priv->clients_mutex);
868 e_data_cal_report_readonly (cal, backend->priv->readonly);
870 online = e_backend_get_online (E_BACKEND (backend));
871 e_data_cal_report_online (cal, online);
873 e_cal_backend_respond_opened (backend, cal, opid, NULL);
874 } else if (e_cal_backend_is_opening (backend)) {
875 g_mutex_unlock (backend->priv->clients_mutex);
877 e_data_cal_respond_open (cal, opid, EDC_OPENING_ERROR);
879 backend->priv->opening = TRUE;
880 g_mutex_unlock (backend->priv->clients_mutex);
882 (* E_CAL_BACKEND_GET_CLASS (backend)->open) (backend, cal, opid, cancellable, only_if_exists);
887 * e_cal_backend_remove:
888 * @backend: an #ECalBackend
890 * @opid: the ID to use for this operation
891 * @cancellable: a #GCancellable for the operation
893 * Removes the calendar being accessed by the given backend.
894 * This might be finished with e_data_cal_respond_remove().
897 e_cal_backend_remove (ECalBackend *backend,
900 GCancellable *cancellable)
902 g_return_if_fail (backend != NULL);
903 g_return_if_fail (E_IS_CAL_BACKEND (backend));
904 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->remove != NULL);
906 if (e_cal_backend_is_opening (backend))
907 e_data_cal_respond_remove (cal, opid, EDC_OPENING_ERROR);
909 (* E_CAL_BACKEND_GET_CLASS (backend)->remove) (backend, cal, opid, cancellable);
913 * e_cal_backend_refresh:
914 * @backend: an #ECalBackend
916 * @opid: the ID to use for this operation
917 * @cancellable: a #GCancellable for the operation
919 * Refreshes the calendar being accessed by the given backend.
920 * This might be finished with e_data_cal_respond_refresh(),
921 * and it might be called as soon as possible; it doesn't mean
922 * that the refreshing is done after calling that, the backend
923 * is only notifying client whether it started the refresh process
929 e_cal_backend_refresh (ECalBackend *backend,
932 GCancellable *cancellable)
934 g_return_if_fail (backend != NULL);
935 g_return_if_fail (E_IS_CAL_BACKEND (backend));
937 if (e_cal_backend_is_opening (backend))
938 e_data_cal_respond_refresh (cal, opid, EDC_OPENING_ERROR);
939 else if (!E_CAL_BACKEND_GET_CLASS (backend)->refresh)
940 e_data_cal_respond_refresh (cal, opid, EDC_ERROR (UnsupportedMethod));
941 else if (!e_cal_backend_is_opened (backend))
942 e_data_cal_respond_refresh (cal, opid, EDC_NOT_OPENED_ERROR);
944 (* E_CAL_BACKEND_GET_CLASS (backend)->refresh) (backend, cal, opid, cancellable);
948 * e_cal_backend_get_object:
949 * @backend: an #ECalBackend
951 * @opid: the ID to use for this operation
952 * @cancellable: a #GCancellable for the operation
953 * @uid: Unique identifier for a calendar object.
954 * @rid: ID for the object's recurrence to get.
956 * Queries a calendar backend for a calendar object based on its unique
957 * identifier and its recurrence ID (if a recurrent appointment).
958 * This might be finished with e_data_cal_respond_get_object().
961 e_cal_backend_get_object (ECalBackend *backend,
964 GCancellable *cancellable,
968 g_return_if_fail (backend != NULL);
969 g_return_if_fail (E_IS_CAL_BACKEND (backend));
970 g_return_if_fail (uid != NULL);
971 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_object != NULL);
973 if (e_cal_backend_is_opening (backend))
974 e_data_cal_respond_get_object (cal, opid, EDC_OPENING_ERROR, NULL);
975 else if (!e_cal_backend_is_opened (backend))
976 e_data_cal_respond_get_object (cal, opid, EDC_NOT_OPENED_ERROR, NULL);
978 (* E_CAL_BACKEND_GET_CLASS (backend)->get_object) (backend, cal, opid, cancellable, uid, rid);
982 * e_cal_backend_get_object_list:
983 * @backend: an #ECalBackend
985 * @opid: the ID to use for this operation
986 * @cancellable: a #GCancellable for the operation
987 * @sexp: Expression to search for.
989 * Calls the get_object_list method on the given backend.
990 * This might be finished with e_data_cal_respond_get_object_list().
993 e_cal_backend_get_object_list (ECalBackend *backend,
996 GCancellable *cancellable,
999 g_return_if_fail (backend != NULL);
1000 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1001 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_object_list != NULL);
1003 if (e_cal_backend_is_opening (backend))
1004 e_data_cal_respond_get_object_list (cal, opid, EDC_OPENING_ERROR, NULL);
1005 else if (!e_cal_backend_is_opened (backend))
1006 e_data_cal_respond_get_object_list (cal, opid, EDC_NOT_OPENED_ERROR, NULL);
1008 (* E_CAL_BACKEND_GET_CLASS (backend)->get_object_list) (backend, cal, opid, cancellable, sexp);
1012 * e_cal_backend_get_free_busy:
1013 * @backend: an #ECalBackend
1014 * @cal: an #EDataCal
1015 * @opid: the ID to use for this operation
1016 * @cancellable: a #GCancellable for the operation
1017 * @users: List of users to get free/busy information for.
1018 * @start: Start time for query.
1019 * @end: End time for query.
1021 * Gets a free/busy object for the given time interval. Client side is
1022 * notified about free/busy objects throug e_data_cal_report_free_busy_data().
1023 * This might be finished with e_data_cal_respond_get_free_busy().
1026 e_cal_backend_get_free_busy (ECalBackend *backend,
1029 GCancellable *cancellable,
1030 const GSList *users,
1034 g_return_if_fail (backend != NULL);
1035 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1036 g_return_if_fail (start != -1 && end != -1);
1037 g_return_if_fail (start <= end);
1038 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_free_busy != NULL);
1040 if (e_cal_backend_is_opening (backend))
1041 e_data_cal_respond_get_free_busy (cal, opid, EDC_OPENING_ERROR);
1042 else if (!e_cal_backend_is_opened (backend))
1043 e_data_cal_respond_get_free_busy (cal, opid, EDC_NOT_OPENED_ERROR);
1045 (* E_CAL_BACKEND_GET_CLASS (backend)->get_free_busy) (backend, cal, opid, cancellable, users, start, end);
1049 * e_cal_backend_create_objects:
1050 * @backend: an #ECalBackend
1051 * @cal: an #EDataCal
1052 * @opid: the ID to use for this operation
1053 * @cancellable: a #GCancellable for the operation
1054 * @calobjs: The objects to create (list of gchar *).
1056 * Calls the create_object method on the given backend.
1057 * This might be finished with e_data_cal_respond_create_objects().
1060 e_cal_backend_create_objects (ECalBackend *backend,
1063 GCancellable *cancellable,
1064 const GSList *calobjs)
1066 g_return_if_fail (backend != NULL);
1067 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1068 g_return_if_fail (calobjs != NULL);
1070 if (e_cal_backend_is_opening (backend))
1071 e_data_cal_respond_create_objects (cal, opid, EDC_OPENING_ERROR, NULL, NULL);
1072 else if (!E_CAL_BACKEND_GET_CLASS (backend)->create_objects)
1073 e_data_cal_respond_create_objects (cal, opid, EDC_ERROR (UnsupportedMethod), NULL, NULL);
1074 else if (!e_cal_backend_is_opened (backend))
1075 e_data_cal_respond_create_objects (cal, opid, EDC_NOT_OPENED_ERROR, NULL, NULL);
1077 (* E_CAL_BACKEND_GET_CLASS (backend)->create_objects) (backend, cal, opid, cancellable, calobjs);
1081 * e_cal_backend_modify_objects:
1082 * @backend: an #ECalBackend
1083 * @cal: an #EDataCal
1084 * @opid: the ID to use for this operation
1085 * @cancellable: a #GCancellable for the operation
1086 * @calobjs: Objects to be modified (list of gchar *).
1087 * @mod: Type of modification.
1089 * Calls the modify_objects method on the given backend.
1090 * This might be finished with e_data_cal_respond_modify_objects().
1093 e_cal_backend_modify_objects (ECalBackend *backend,
1096 GCancellable *cancellable,
1097 const GSList *calobjs,
1100 g_return_if_fail (backend != NULL);
1101 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1102 g_return_if_fail (calobjs != NULL);
1104 if (e_cal_backend_is_opening (backend))
1105 e_data_cal_respond_modify_objects (cal, opid, EDC_OPENING_ERROR, NULL, NULL);
1106 else if (!E_CAL_BACKEND_GET_CLASS (backend)->modify_objects)
1107 e_data_cal_respond_modify_objects (cal, opid, EDC_ERROR (UnsupportedMethod), NULL, NULL);
1108 else if (!e_cal_backend_is_opened (backend))
1109 e_data_cal_respond_modify_objects (cal, opid, EDC_NOT_OPENED_ERROR, NULL, NULL);
1111 (* E_CAL_BACKEND_GET_CLASS (backend)->modify_objects) (backend, cal, opid, cancellable, calobjs, mod);
1115 * e_cal_backend_remove_objects:
1116 * @backend: an #ECalBackend
1117 * @cal: an #EDataCal
1118 * @opid: the ID to use for this operation
1119 * @cancellable: a #GCancellable for the operation
1120 * @ids: List of #ECalComponentId objects identifying the objects to remove
1121 * @mod: Type of removal.
1123 * Removes objects in a calendar backend. The backend will notify all of its
1124 * clients about the change.
1125 * This might be finished with e_data_cal_respond_remove_objects().
1128 e_cal_backend_remove_objects (ECalBackend *backend,
1131 GCancellable *cancellable,
1135 g_return_if_fail (backend != NULL);
1136 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1137 g_return_if_fail (ids != NULL);
1138 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->remove_objects != NULL);
1140 if (e_cal_backend_is_opening (backend))
1141 e_data_cal_respond_remove_objects (cal, opid, EDC_OPENING_ERROR, NULL, NULL, NULL);
1142 else if (!e_cal_backend_is_opened (backend))
1143 e_data_cal_respond_remove_objects (cal, opid, EDC_NOT_OPENED_ERROR, NULL, NULL, NULL);
1145 (* E_CAL_BACKEND_GET_CLASS (backend)->remove_objects) (backend, cal, opid, cancellable, ids, mod);
1149 * e_cal_backend_receive_objects:
1150 * @backend: an #ECalBackend
1151 * @cal: an #EDataCal
1152 * @opid: the ID to use for this operation
1153 * @cancellable: a #GCancellable for the operation
1154 * @calobj: iCalendar object.
1156 * Calls the receive_objects method on the given backend.
1157 * This might be finished with e_data_cal_respond_receive_objects().
1160 e_cal_backend_receive_objects (ECalBackend *backend,
1163 GCancellable *cancellable,
1164 const gchar *calobj)
1166 g_return_if_fail (backend != NULL);
1167 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1168 g_return_if_fail (calobj != NULL);
1169 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->receive_objects != NULL);
1171 if (e_cal_backend_is_opening (backend))
1172 e_data_cal_respond_receive_objects (cal, opid, EDC_OPENING_ERROR);
1173 else if (!e_cal_backend_is_opened (backend))
1174 e_data_cal_respond_receive_objects (cal, opid, EDC_NOT_OPENED_ERROR);
1176 (* E_CAL_BACKEND_GET_CLASS (backend)->receive_objects) (backend, cal, opid, cancellable, calobj);
1180 * e_cal_backend_send_objects:
1181 * @backend: an #ECalBackend
1182 * @cal: an #EDataCal
1183 * @opid: the ID to use for this operation
1184 * @cancellable: a #GCancellable for the operation
1185 * @calobj: iCalendar object to be sent.
1187 * Calls the send_objects method on the given backend.
1188 * This might be finished with e_data_cal_respond_send_objects().
1191 e_cal_backend_send_objects (ECalBackend *backend,
1194 GCancellable *cancellable,
1195 const gchar *calobj)
1197 g_return_if_fail (backend != NULL);
1198 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1199 g_return_if_fail (calobj != NULL);
1200 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->send_objects != NULL);
1202 if (e_cal_backend_is_opening (backend))
1203 e_data_cal_respond_send_objects (cal, opid, EDC_OPENING_ERROR, NULL, NULL);
1204 else if (!e_cal_backend_is_opened (backend))
1205 e_data_cal_respond_send_objects (cal, opid, EDC_NOT_OPENED_ERROR, NULL, NULL);
1207 (* E_CAL_BACKEND_GET_CLASS (backend)->send_objects) (backend, cal, opid, cancellable, calobj);
1211 * e_cal_backend_get_attachment_uris:
1212 * @backend: an #ECalBackend
1213 * @cal: an #EDataCal
1214 * @opid: the ID to use for this operation
1215 * @cancellable: a #GCancellable for the operation
1216 * @uid: Unique identifier for a calendar object.
1217 * @rid: ID for the object's recurrence to get.
1219 * Queries a calendar backend for attachments present in a calendar object based
1220 * on its unique identifier and its recurrence ID (if a recurrent appointment).
1221 * This might be finished with e_data_cal_respond_get_attachment_uris().
1226 e_cal_backend_get_attachment_uris (ECalBackend *backend,
1229 GCancellable *cancellable,
1233 g_return_if_fail (backend != NULL);
1234 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1235 g_return_if_fail (uid != NULL);
1236 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_attachment_uris != NULL);
1238 if (e_cal_backend_is_opening (backend))
1239 e_data_cal_respond_get_attachment_uris (cal, opid, EDC_OPENING_ERROR, NULL);
1240 else if (!e_cal_backend_is_opened (backend))
1241 e_data_cal_respond_get_attachment_uris (cal, opid, EDC_NOT_OPENED_ERROR, NULL);
1243 (* E_CAL_BACKEND_GET_CLASS (backend)->get_attachment_uris) (backend, cal, opid, cancellable, uid, rid);
1247 * e_cal_backend_discard_alarm:
1248 * @backend: an #ECalBackend
1249 * @cal: an #EDataCal
1250 * @opid: the ID to use for this operation
1251 * @cancellable: a #GCancellable for the operation
1252 * @uid: Unique identifier for a calendar object.
1253 * @rid: ID for the object's recurrence to discard alarm in.
1254 * @auid: Unique identifier of the alarm itself.
1256 * Discards alarm @auid from the object identified by @uid and @rid.
1257 * This might be finished with e_data_cal_respond_discard_alarm().
1258 * Default implementation of this method returns Not Supported error.
1261 e_cal_backend_discard_alarm (ECalBackend *backend,
1264 GCancellable *cancellable,
1269 g_return_if_fail (backend != NULL);
1270 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1271 g_return_if_fail (uid != NULL);
1272 g_return_if_fail (auid != NULL);
1274 if (e_cal_backend_is_opening (backend))
1275 e_data_cal_respond_discard_alarm (cal, opid, EDC_OPENING_ERROR);
1276 else if (!E_CAL_BACKEND_GET_CLASS (backend)->discard_alarm)
1277 e_data_cal_respond_discard_alarm (cal, opid, e_data_cal_create_error (NotSupported, NULL));
1278 else if (!e_cal_backend_is_opened (backend))
1279 e_data_cal_respond_discard_alarm (cal, opid, EDC_NOT_OPENED_ERROR);
1281 (* E_CAL_BACKEND_GET_CLASS (backend)->discard_alarm) (backend, cal, opid, cancellable, uid, rid, auid);
1285 * e_cal_backend_get_timezone:
1286 * @backend: an #ECalBackend
1287 * @cal: an #EDataCal
1288 * @opid: the ID to use for this operation
1289 * @cancellable: a #GCancellable for the operation
1290 * @tzid: Unique identifier of a VTIMEZONE object. Note that this must not be
1293 * Returns the icaltimezone* corresponding to the TZID, or NULL if the TZID
1295 * This might be finished with e_data_cal_respond_get_timezone().
1298 e_cal_backend_get_timezone (ECalBackend *backend,
1301 GCancellable *cancellable,
1304 g_return_if_fail (backend != NULL);
1305 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1306 g_return_if_fail (tzid != NULL);
1307 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_timezone != NULL);
1309 if (e_cal_backend_is_opening (backend))
1310 e_data_cal_respond_get_timezone (cal, opid, EDC_OPENING_ERROR, NULL);
1311 else if (!e_cal_backend_is_opened (backend))
1312 e_data_cal_respond_get_timezone (cal, opid, EDC_NOT_OPENED_ERROR, NULL);
1314 (* E_CAL_BACKEND_GET_CLASS (backend)->get_timezone) (backend, cal, opid, cancellable, tzid);
1318 * e_cal_backend_add_timezone
1319 * @backend: an #ECalBackend
1320 * @cal: an #EDataCal
1321 * @opid: the ID to use for this operation
1322 * @cancellable: a #GCancellable for the operation
1323 * @tzobject: The timezone object, in a string.
1325 * Add a timezone object to the given backend.
1326 * This might be finished with e_data_cal_respond_add_timezone().
1329 e_cal_backend_add_timezone (ECalBackend *backend,
1332 GCancellable *cancellable,
1333 const gchar *tzobject)
1335 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1336 g_return_if_fail (tzobject != NULL);
1337 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->add_timezone != NULL);
1339 if (e_cal_backend_is_opening (backend))
1340 e_data_cal_respond_add_timezone (cal, opid, EDC_OPENING_ERROR);
1341 else if (!e_cal_backend_is_opened (backend))
1342 e_data_cal_respond_add_timezone (cal, opid, EDC_NOT_OPENED_ERROR);
1344 (* E_CAL_BACKEND_GET_CLASS (backend)->add_timezone) (backend, cal, opid, cancellable, tzobject);
1348 * e_cal_backend_internal_get_timezone:
1349 * @backend: an #ECalBackend
1350 * @tzid: ID of the timezone to get.
1352 * Calls the internal_get_timezone method on the given backend.
1355 e_cal_backend_internal_get_timezone (ECalBackend *backend,
1358 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), NULL);
1359 g_return_val_if_fail (tzid != NULL, NULL);
1360 g_return_val_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->internal_get_timezone != NULL, NULL);
1362 return (* E_CAL_BACKEND_GET_CLASS (backend)->internal_get_timezone) (backend, tzid);
1366 * e_cal_backend_start_view:
1367 * @backend: an #ECalBackend
1368 * @view: The view to be started.
1370 * Starts a new live view on the given backend.
1375 e_cal_backend_start_view (ECalBackend *backend,
1378 g_return_if_fail (backend != NULL);
1379 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1380 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->start_view != NULL);
1382 (* E_CAL_BACKEND_GET_CLASS (backend)->start_view) (backend, view);
1386 * e_cal_backend_stop_view:
1387 * @backend: an #ECalBackend
1388 * @view: The view to be stopped.
1390 * Stops a previously started live view on the given backend.
1395 e_cal_backend_stop_view (ECalBackend *backend,
1398 g_return_if_fail (backend != NULL);
1399 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1401 /* backward compatibility, do not force each backend define this function */
1402 if (!E_CAL_BACKEND_GET_CLASS (backend)->stop_view)
1405 (* E_CAL_BACKEND_GET_CLASS (backend)->stop_view) (backend, view);
1409 component_created_cb (EDataCalView *view,
1412 ECalComponent *comp = data;
1414 if (e_data_cal_view_component_matches (view, comp))
1415 e_data_cal_view_notify_components_added_1 (view, comp);
1421 * e_cal_backend_notify_component_created:
1422 * @backend: an #ECalBackend
1423 * @component: the newly created #ECalComponent
1425 * Notifies each of the backend's listeners about a new object.
1427 * Like e_cal_backend_notify_object_created() except takes an #ECalComponent
1428 * instead of an ical string representation and uses the #EDataCalView's
1429 * fields-of-interest to filter out unwanted information from ical strings
1430 * sent over the bus.
1435 e_cal_backend_notify_component_created (ECalBackend *backend,
1436 /* const */ ECalComponent *component)
1438 ECalBackendPrivate *priv;
1440 priv = backend->priv;
1442 if (priv->notification_proxy) {
1443 e_cal_backend_notify_component_created (priv->notification_proxy, component);
1447 e_cal_backend_foreach_view (backend, component_created_cb, component);
1451 match_view_and_notify_component (EDataCalView *view,
1452 ECalComponent *old_component,
1453 ECalComponent *new_component)
1455 gboolean old_match = FALSE, new_match = FALSE;
1458 old_match = e_data_cal_view_component_matches (view, old_component);
1460 new_match = e_data_cal_view_component_matches (view, new_component);
1462 if (old_match && new_match)
1463 e_data_cal_view_notify_components_modified_1 (view, new_component);
1465 e_data_cal_view_notify_components_added_1 (view, new_component);
1466 else if (old_match) {
1468 ECalComponentId *id = e_cal_component_get_id (old_component);
1470 e_data_cal_view_notify_objects_removed_1 (view, id);
1472 e_cal_component_free_id (id);
1476 struct component_call_data {
1477 ECalComponent *old_component;
1478 ECalComponent *new_component;
1479 const ECalComponentId *id;
1483 call_match_and_notify_component (EDataCalView *view,
1486 struct component_call_data *cd = user_data;
1488 g_return_val_if_fail (user_data != NULL, FALSE);
1490 match_view_and_notify_component (view, cd->old_component, cd->new_component);
1496 * e_cal_backend_notify_component_modified:
1497 * @backend: an #ECalBackend
1498 * @old_component: the #ECalComponent before the modification
1499 * @new_component: the #ECalComponent after the modification
1501 * Notifies each of the backend's listeners about a modified object.
1503 * Like e_cal_backend_notify_object_modified() except takes an #ECalComponent
1504 * instead of an ical string representation and uses the #EDataCalView's
1505 * fields-of-interest to filter out unwanted information from ical strings
1506 * sent over the bus.
1511 e_cal_backend_notify_component_modified (ECalBackend *backend,
1512 /* const */ ECalComponent *old_component,
1513 /* const */ ECalComponent *new_component)
1515 ECalBackendPrivate *priv;
1516 struct component_call_data cd;
1518 priv = backend->priv;
1520 if (priv->notification_proxy) {
1521 e_cal_backend_notify_component_modified (priv->notification_proxy, old_component, new_component);
1525 cd.old_component = old_component;
1526 cd.new_component = new_component;
1529 e_cal_backend_foreach_view (backend, call_match_and_notify_component, &cd);
1533 component_removed_cb (EDataCalView *view,
1536 struct component_call_data *cd = user_data;
1538 g_return_val_if_fail (user_data != NULL, FALSE);
1540 if (cd->new_component == NULL) {
1541 /* if object == NULL, it means the object has been completely
1542 * removed from the backend */
1543 if (!cd->old_component || e_data_cal_view_component_matches (view, cd->old_component))
1544 e_data_cal_view_notify_objects_removed_1 (view, cd->id);
1546 match_view_and_notify_component (view, cd->old_component, cd->new_component);
1552 * e_cal_backend_notify_component_removed:
1553 * @backend: an #ECalBackend
1554 * @id: the Id of the removed object
1555 * @old_component: the removed component
1556 * @new_component: the component after the removal. This only applies to recurrent
1557 * appointments that had an instance removed. In that case, this function
1558 * notifies a modification instead of a removal.
1560 * Notifies each of the backend's listeners about a removed object.
1562 * Like e_cal_backend_notify_object_removed() except takes an #ECalComponent
1563 * instead of an ical string representation and uses the #EDataCalView's
1564 * fields-of-interest to filter out unwanted information from ical strings
1565 * sent over the bus.
1570 e_cal_backend_notify_component_removed (ECalBackend *backend,
1571 const ECalComponentId *id,
1572 /* const */ ECalComponent *old_component,
1573 /* const */ ECalComponent *new_component)
1575 ECalBackendPrivate *priv;
1576 struct component_call_data cd;
1578 priv = backend->priv;
1580 if (priv->notification_proxy) {
1581 e_cal_backend_notify_component_removed (priv->notification_proxy, id, old_component, new_component);
1585 cd.old_component = old_component;
1586 cd.new_component = new_component;
1589 e_cal_backend_foreach_view (backend, component_removed_cb, &cd);
1593 object_created_cb (EDataCalView *view,
1596 const gchar *calobj = data;
1598 if (e_data_cal_view_object_matches (view, calobj))
1599 e_data_cal_view_notify_objects_added_1 (view, calobj);
1605 * e_cal_backend_notify_object_created:
1606 * @backend: an #ECalBackend
1607 * @calobj: the newly created object
1609 * Notifies each of the backend's listeners about a new object.
1611 * #e_data_cal_notify_object_created() calls this for you. You only need to
1612 * call e_cal_backend_notify_object_created() yourself to report objects
1613 * created by non-EDS clients.
1615 * Deprecated: 3.4: Use e_cal_backend_notify_component_created() instead.
1618 e_cal_backend_notify_object_created (ECalBackend *backend,
1619 const gchar *calobj)
1621 ECalBackendPrivate *priv;
1623 priv = backend->priv;
1625 if (priv->notification_proxy) {
1626 e_cal_backend_notify_object_created (priv->notification_proxy, calobj);
1630 e_cal_backend_foreach_view (backend, object_created_cb, (gpointer) calobj);
1634 * e_cal_backend_notify_objects_added:
1638 * Deprecated: 3.4: Use e_data_cal_view_notify_objects_added() instead.
1641 e_cal_backend_notify_objects_added (ECalBackend *backend,
1643 const GSList *objects)
1645 e_data_cal_view_notify_objects_added (view, objects);
1649 match_view_and_notify_object (EDataCalView *view,
1650 const gchar *old_object,
1651 const gchar *object)
1653 gboolean old_match = FALSE, new_match = FALSE;
1656 old_match = e_data_cal_view_object_matches (view, old_object);
1658 new_match = e_data_cal_view_object_matches (view, object);
1659 if (old_match && new_match)
1660 e_data_cal_view_notify_objects_modified_1 (view, object);
1662 e_data_cal_view_notify_objects_added_1 (view, object);
1663 else if (old_match) {
1664 ECalComponent *comp = NULL;
1666 comp = e_cal_component_new_from_string (old_object);
1668 ECalComponentId *id = e_cal_component_get_id (comp);
1670 e_data_cal_view_notify_objects_removed_1 (view, id);
1672 e_cal_component_free_id (id);
1673 g_object_unref (comp);
1678 struct object_call_data {
1679 const gchar *old_object;
1680 const gchar *object;
1681 const ECalComponentId *id;
1685 call_match_and_notify_object (EDataCalView *view,
1688 struct object_call_data *cd = user_data;
1690 g_return_val_if_fail (user_data != NULL, FALSE);
1692 match_view_and_notify_object (view, cd->old_object, cd->object);
1698 * e_cal_backend_notify_object_modified:
1699 * @backend: an #ECalBackend
1700 * @old_object: iCalendar representation of the original form of the object
1701 * @object: iCalendar representation of the new form of the object
1703 * Notifies each of the backend's listeners about a modified object.
1705 * #e_data_cal_notify_object_modified() calls this for you. You only need to
1706 * call e_cal_backend_notify_object_modified() yourself to report objects
1707 * modified by non-EDS clients.
1709 * Deprecated: 3.4: Use e_cal_backend_notify_component_modified() instead.
1712 e_cal_backend_notify_object_modified (ECalBackend *backend,
1713 const gchar *old_object,
1714 const gchar *object)
1716 ECalBackendPrivate *priv;
1717 struct object_call_data cd;
1719 priv = backend->priv;
1721 if (priv->notification_proxy) {
1722 e_cal_backend_notify_object_modified (priv->notification_proxy, old_object, object);
1726 cd.old_object = old_object;
1730 e_cal_backend_foreach_view (backend, call_match_and_notify_object, &cd);
1734 * e_cal_backend_notify_objects_modified:
1738 * Deprecated: 3.4: Use e_data_cal_view_notify_objects_modified() instead.
1741 e_cal_backend_notify_objects_modified (ECalBackend *backend,
1743 const GSList *objects)
1745 e_data_cal_view_notify_objects_modified (view, objects);
1749 object_removed_cb (EDataCalView *view,
1752 struct object_call_data *cd = user_data;
1754 g_return_val_if_fail (user_data != NULL, FALSE);
1756 if (cd->object == NULL) {
1757 /* if object == NULL, it means the object has been completely
1758 * removed from the backend */
1759 if (!cd->old_object || e_data_cal_view_object_matches (view, cd->old_object))
1760 e_data_cal_view_notify_objects_removed_1 (view, cd->id);
1762 match_view_and_notify_object (view, cd->old_object, cd->object);
1768 * e_cal_backend_notify_object_removed:
1769 * @backend: an #ECalBackend
1770 * @id: the Id of the removed object
1771 * @old_object: iCalendar representation of the removed object
1772 * @new_object: iCalendar representation of the object after the removal. This
1773 * only applies to recurrent appointments that had an instance removed. In that
1774 * case, this function notifies a modification instead of a removal.
1776 * Notifies each of the backend's listeners about a removed object.
1778 * e_data_cal_notify_object_removed() calls this for you. You only need to
1779 * call e_cal_backend_notify_object_removed() yourself to report objects
1780 * removed by non-EDS clients.
1782 * Deprecated: 3.4: Use e_cal_backend_notify_component_removed() instead.
1785 e_cal_backend_notify_object_removed (ECalBackend *backend,
1786 const ECalComponentId *id,
1787 const gchar *old_object,
1788 const gchar *new_object)
1790 ECalBackendPrivate *priv;
1791 struct object_call_data cd;
1793 priv = backend->priv;
1795 if (priv->notification_proxy) {
1796 e_cal_backend_notify_object_removed (priv->notification_proxy, id, old_object, new_object);
1800 cd.old_object = old_object;
1801 cd.object = new_object;
1804 e_cal_backend_foreach_view (backend, object_removed_cb, &cd);
1808 * e_cal_backend_notify_objects_removed:
1812 * Deprecated: 3.4: Use e_data_cal_view_notify_objects_removed() instead.
1815 e_cal_backend_notify_objects_removed (ECalBackend *backend,
1819 e_data_cal_view_notify_objects_removed (view, ids);
1823 * e_cal_backend_notify_error:
1824 * @backend: an #ECalBackend
1825 * @message: Error message
1827 * Notifies each of the backend's listeners about an error
1830 e_cal_backend_notify_error (ECalBackend *backend,
1831 const gchar *message)
1833 ECalBackendPrivate *priv = backend->priv;
1836 if (priv->notification_proxy) {
1837 e_cal_backend_notify_error (priv->notification_proxy, message);
1841 g_mutex_lock (priv->clients_mutex);
1843 for (l = priv->clients; l; l = l->next)
1844 e_data_cal_report_error (l->data, message);
1846 g_mutex_unlock (priv->clients_mutex);
1850 * e_cal_backend_notify_readonly:
1851 * @backend: an #ECalBackend
1852 * @is_readonly: flag indicating readonly status
1854 * Notifies all backend's clients about the current readonly state.
1855 * Meant to be used by backend implementations.
1858 e_cal_backend_notify_readonly (ECalBackend *backend,
1859 gboolean is_readonly)
1861 ECalBackendPrivate *priv;
1864 priv = backend->priv;
1865 priv->readonly = is_readonly;
1867 if (priv->notification_proxy) {
1868 e_cal_backend_notify_readonly (priv->notification_proxy, is_readonly);
1872 g_mutex_lock (priv->clients_mutex);
1874 for (l = priv->clients; l; l = l->next)
1875 e_data_cal_report_readonly (l->data, is_readonly);
1877 g_mutex_unlock (priv->clients_mutex);
1881 * e_cal_backend_notify_online:
1882 * @backend: an #ECalBackend
1883 * @is_online: flag indicating whether @backend is connected and online
1885 * Notifies clients of @backend's connection status indicated by @is_online.
1886 * Meant to be used by backend implementations.
1891 e_cal_backend_notify_online (ECalBackend *backend,
1894 ECalBackendPrivate *priv;
1897 priv = backend->priv;
1899 if (priv->notification_proxy) {
1900 e_cal_backend_notify_online (priv->notification_proxy, is_online);
1904 g_mutex_lock (priv->clients_mutex);
1906 for (clients = priv->clients; clients != NULL; clients = g_slist_next (clients))
1907 e_data_cal_report_online (E_DATA_CAL (clients->data), is_online);
1909 g_mutex_unlock (priv->clients_mutex);
1913 * e_cal_backend_notify_opened:
1914 * @backend: an #ECalBackend
1915 * @error: a #GError corresponding to the error encountered during
1916 * the opening phase. Use %NULL for success. The @error is freed
1917 * automatically if not %NULL.
1919 * Notifies clients that @backend finished its opening phase.
1920 * See e_cal_backend_open() for more information how the opening
1921 * phase works. Calling this function changes 'opening' property,
1922 * same as 'opened'. 'opening' is set to %FALSE and the backend
1923 * is considered 'opened' only if the @error is %NULL.
1925 * See also: e_cal_backend_respond_opened()
1927 * Note: The @error is freed automatically if not %NULL.
1929 * Meant to be used by backend implementations.
1934 e_cal_backend_notify_opened (ECalBackend *backend,
1937 ECalBackendPrivate *priv;
1940 priv = backend->priv;
1941 g_mutex_lock (priv->clients_mutex);
1943 priv->opening = FALSE;
1944 priv->opened = error == NULL;
1946 for (clients = priv->clients; clients != NULL; clients = g_slist_next (clients))
1947 e_data_cal_report_opened (E_DATA_CAL (clients->data), error);
1949 g_mutex_unlock (priv->clients_mutex);
1952 g_error_free (error);
1956 * e_cal_backend_notify_property_changed:
1957 * @backend: an #ECalBackend
1958 * @prop_name: property name, which changed
1959 * @prop_value: new property value
1961 * Notifies client about property value change.
1966 e_cal_backend_notify_property_changed (ECalBackend *backend,
1967 const gchar *prop_name,
1968 const gchar *prop_value)
1970 ECalBackendPrivate *priv;
1973 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1974 g_return_if_fail (prop_name != NULL);
1975 g_return_if_fail (*prop_name != '\0');
1976 g_return_if_fail (prop_value != NULL);
1978 priv = backend->priv;
1979 g_mutex_lock (priv->clients_mutex);
1981 for (clients = priv->clients; clients != NULL; clients = g_slist_next (clients))
1982 e_data_cal_report_backend_property_changed (E_DATA_CAL (clients->data), prop_name, prop_value);
1984 g_mutex_unlock (priv->clients_mutex);
1988 * e_cal_backend_respond_opened:
1989 * @backend: an #ECalBackend
1990 * @cal: an #EDataCal
1991 * @opid: an operation ID
1992 * @error: result error; can be %NULL, if it isn't then it's automatically freed
1994 * This is a replacement for e_data_cal_respond_open() for cases where
1995 * the finish of 'open' method call also finishes backend opening phase.
1996 * This function covers calling of both e_cal_backend_notify_opened() and
1997 * e_data_cal_respond_open() with the same @error.
1999 * See e_cal_backend_open() for more details how the opening phase works.
2004 e_cal_backend_respond_opened (ECalBackend *backend,
2009 GError *copy = NULL;
2011 g_return_if_fail (backend != NULL);
2012 g_return_if_fail (E_IS_CAL_BACKEND (backend));
2013 g_return_if_fail (cal != NULL);
2014 g_return_if_fail (opid != 0);
2017 copy = g_error_copy (error);
2019 e_cal_backend_notify_opened (backend, copy);
2020 e_data_cal_respond_open (cal, opid, error);
2024 * e_cal_backend_empty_cache:
2025 * @backend: an #ECalBackend
2026 * @cache: Backend's cache to empty.
2028 * Empties backend's cache with all notifications and so on, thus all listening
2029 * will know there is nothing in this backend.
2034 e_cal_backend_empty_cache (ECalBackend *backend,
2035 ECalBackendCache *cache)
2037 GList *comps_in_cache;
2039 g_return_if_fail (backend != NULL);
2040 g_return_if_fail (E_IS_CAL_BACKEND (backend));
2045 g_return_if_fail (E_IS_CAL_BACKEND_CACHE (cache));
2047 e_file_cache_freeze_changes (E_FILE_CACHE (cache));
2049 for (comps_in_cache = e_cal_backend_cache_get_components (cache);
2051 comps_in_cache = comps_in_cache->next) {
2052 ECalComponentId *id;
2053 ECalComponent *comp = comps_in_cache->data;
2055 id = e_cal_component_get_id (comp);
2057 e_cal_backend_cache_remove_component (cache, id->uid, id->rid);
2059 e_cal_backend_notify_component_removed (backend, id, comp, NULL);
2061 e_cal_component_free_id (id);
2062 g_object_unref (comp);
2065 g_list_free (comps_in_cache);
2067 e_file_cache_thaw_changes (E_FILE_CACHE (cache));