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 cal_backend_authenticate_sync (EBackend *backend,
278 ESourceAuthenticator *auth,
279 GCancellable *cancellable,
282 ECalBackend *cal_backend;
283 ESourceRegistry *registry;
286 cal_backend = E_CAL_BACKEND (backend);
287 registry = e_cal_backend_get_registry (cal_backend);
288 source = e_backend_get_source (backend);
290 return e_source_registry_authenticate_sync (
291 registry, source, auth, cancellable, error);
295 e_cal_backend_class_init (ECalBackendClass *class)
297 GObjectClass *object_class;
298 EBackendClass *backend_class;
300 g_type_class_add_private (class, sizeof (ECalBackendPrivate));
302 object_class = G_OBJECT_CLASS (class);
303 object_class->set_property = cal_backend_set_property;
304 object_class->get_property = cal_backend_get_property;
305 object_class->dispose = cal_backend_dispose;
306 object_class->finalize = cal_backend_finalize;
307 object_class->constructed = cal_backend_constructed;
309 backend_class = E_BACKEND_CLASS (class);
310 backend_class->authenticate_sync = cal_backend_authenticate_sync;
312 class->get_backend_property = cal_backend_get_backend_property;
313 class->set_backend_property = cal_backend_set_backend_property;
315 g_object_class_install_property (
318 g_param_spec_string (
321 "The backend's cache directory",
324 G_PARAM_STATIC_STRINGS));
326 g_object_class_install_property (
332 "The kind of iCalendar components "
333 "this backend manages",
335 ICAL_XLICMIMEPART_COMPONENT,
338 G_PARAM_CONSTRUCT_ONLY |
339 G_PARAM_STATIC_STRINGS));
341 g_object_class_install_property (
344 g_param_spec_object (
347 "Data source registry",
348 E_TYPE_SOURCE_REGISTRY,
350 G_PARAM_CONSTRUCT_ONLY |
351 G_PARAM_STATIC_STRINGS));
355 e_cal_backend_init (ECalBackend *backend)
357 backend->priv = E_CAL_BACKEND_GET_PRIVATE (backend);
359 backend->priv->clients = NULL;
360 backend->priv->clients_mutex = g_mutex_new ();
362 backend->priv->views = NULL;
363 backend->priv->views_mutex = g_mutex_new ();
365 backend->priv->readonly = TRUE;
369 * e_cal_backend_get_kind:
370 * @backend: an #ECalBackend
372 * Gets the kind of components the given backend stores.
374 * Returns: The kind of components for this backend.
377 e_cal_backend_get_kind (ECalBackend *backend)
379 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), ICAL_NO_COMPONENT);
381 return backend->priv->kind;
385 * e_cal_backend_get_registry:
386 * @backend: an #ECalBackend
388 * Returns the data source registry to which #EBackend:source belongs.
390 * Returns: an #ESourceRegistry
395 e_cal_backend_get_registry (ECalBackend *backend)
397 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), NULL);
399 return backend->priv->registry;
403 * e_cal_backend_is_opened:
404 * @backend: an #ECalBackend
406 * Checks if @backend's storage has been opened (and
407 * authenticated, if necessary) and the backend itself
408 * is ready for accessing. This property is changed automatically
409 * within call of e_cal_backend_notify_opened().
411 * Returns: %TRUE if fully opened, %FALSE otherwise.
416 e_cal_backend_is_opened (ECalBackend *backend)
418 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), FALSE);
420 return backend->priv->opened;
424 * e_cal_backend_is_opening:
425 * @backend: an #ECalBackend
427 * Checks if @backend is processing its opening phase, which
428 * includes everything since the e_cal_backend_open() call,
429 * through authentication, up to e_cal_backend_notify_opened().
430 * This property is managed automatically and the backend deny
431 * every operation except of cancel and authenticate_user while
432 * it is being opening.
434 * Returns: %TRUE if opening phase is in the effect, %FALSE otherwise.
439 e_cal_backend_is_opening (ECalBackend *backend)
441 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), FALSE);
443 return backend->priv->opening;
447 * e_cal_backend_is_readonly:
448 * @backend: an #ECalBackend
450 * Returns: Whether is backend read-only. This value is the last used
451 * in a call of e_cal_backend_notify_readonly().
456 e_cal_backend_is_readonly (ECalBackend *backend)
458 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), FALSE);
460 return backend->priv->readonly;
464 * e_cal_backend_is_removed:
465 * @backend: an #ECalBackend
467 * Checks if @backend has been removed from its physical storage.
469 * Returns: %TRUE if @backend has been removed, %FALSE otherwise.
474 e_cal_backend_is_removed (ECalBackend *backend)
476 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), FALSE);
478 return backend->priv->removed;
482 * e_cal_backend_set_is_removed:
483 * @backend: an #ECalBackend
484 * @is_removed: A flag indicating whether the backend's storage was removed
486 * Sets the flag indicating whether @backend was removed to @is_removed.
487 * Meant to be used by backend implementations.
492 e_cal_backend_set_is_removed (ECalBackend *backend,
495 g_return_if_fail (E_IS_CAL_BACKEND (backend));
497 backend->priv->removed = is_removed;
501 * e_cal_backend_get_cache_dir:
502 * @backend: an #ECalBackend
504 * Returns the cache directory for the given backend.
506 * Returns: the cache directory for the backend
511 e_cal_backend_get_cache_dir (ECalBackend *backend)
513 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), NULL);
515 return backend->priv->cache_dir;
519 * e_cal_backend_set_cache_dir:
520 * @backend: an #ECalBackend
521 * @cache_dir: a local cache directory
523 * Sets the cache directory for the given backend.
525 * Note that #ECalBackend is initialized with a usable default based on
526 * #ECalBackend:source and #ECalBackend:kind properties. Backends should
527 * not override the default without good reason.
532 e_cal_backend_set_cache_dir (ECalBackend *backend,
533 const gchar *cache_dir)
535 g_return_if_fail (E_IS_CAL_BACKEND (backend));
536 g_return_if_fail (cache_dir != NULL);
538 if (g_strcmp0 (backend->priv->cache_dir, cache_dir) == 0)
541 g_free (backend->priv->cache_dir);
542 backend->priv->cache_dir = g_strdup (cache_dir);
544 g_object_notify (G_OBJECT (backend), "cache-dir");
548 * e_cal_backend_create_cache_filename:
549 * @backend: an #ECalBackend
550 * @uid: a component UID
551 * @filename: a filename to use; can be NULL
552 * @fileindex: index of a file; used only when @filename is NULL
554 * Returns: a filename for an attachment in a local cache dir. Free returned
555 * pointer with a g_free().
560 e_cal_backend_create_cache_filename (ECalBackend *backend,
562 const gchar *filename,
565 g_return_val_if_fail (backend != NULL, NULL);
566 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), NULL);
568 return e_filename_mkdir_encoded (e_cal_backend_get_cache_dir (backend), uid, filename, fileindex);
572 * e_cal_backend_get_backend_property:
573 * @backend: an #ECalBackend
575 * @opid: the ID to use for this operation
576 * @cancellable: a #GCancellable for the operation
577 * @prop_name: property name to get value of; cannot be NULL
579 * Calls the get_backend_property method on the given backend.
580 * This might be finished with e_data_cal_respond_get_backend_property().
581 * Default implementation takes care of common properties and returns
582 * an 'unsupported' error for any unknown properties. The subclass may
583 * always call this default implementation for properties which fetching
584 * it doesn't overwrite.
589 e_cal_backend_get_backend_property (ECalBackend *backend,
592 GCancellable *cancellable,
593 const gchar *prop_name)
595 g_return_if_fail (backend != NULL);
596 g_return_if_fail (E_IS_CAL_BACKEND (backend));
597 g_return_if_fail (prop_name != NULL);
598 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_backend_property != NULL);
600 (* E_CAL_BACKEND_GET_CLASS (backend)->get_backend_property) (backend, cal, opid, cancellable, prop_name);
604 * e_cal_backend_set_backend_property:
605 * @backend: an #ECalBackend
607 * @opid: the ID to use for this operation
608 * @cancellable: a #GCancellable for the operation
609 * @prop_name: property name to change; cannot be NULL
610 * @prop_value: value to set to @prop_name; cannot be NULL
612 * Calls the set_backend_property method on the given backend.
613 * This might be finished with e_data_cal_respond_set_backend_property().
614 * Default implementation simply returns an 'unsupported' error.
615 * The subclass may always call this default implementation for properties
616 * which fetching it doesn't overwrite.
621 e_cal_backend_set_backend_property (ECalBackend *backend,
624 GCancellable *cancellable,
625 const gchar *prop_name,
626 const gchar *prop_value)
628 g_return_if_fail (backend != NULL);
629 g_return_if_fail (E_IS_CAL_BACKEND (backend));
630 g_return_if_fail (prop_name != NULL);
631 g_return_if_fail (prop_value != NULL);
632 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->set_backend_property != NULL);
634 (* E_CAL_BACKEND_GET_CLASS (backend)->set_backend_property) (backend, cal, opid, cancellable, prop_name, prop_value);
638 cal_destroy_cb (gpointer data,
639 GObject *where_cal_was)
641 e_cal_backend_remove_client_private (E_CAL_BACKEND (data),
642 (EDataCal *) where_cal_was, FALSE);
646 * e_cal_backend_add_client:
647 * @backend: an #ECalBackend
650 * Adds a new client to the given backend. For any event, the backend will
651 * notify all clients added via this function.
654 e_cal_backend_add_client (ECalBackend *backend,
657 ECalBackendPrivate *priv;
659 g_return_if_fail (backend != NULL);
660 g_return_if_fail (E_IS_CAL_BACKEND (backend));
661 g_return_if_fail (cal != NULL);
662 g_return_if_fail (E_IS_DATA_CAL (cal));
664 priv = backend->priv;
666 g_object_weak_ref (G_OBJECT (cal), cal_destroy_cb, backend);
668 g_mutex_lock (priv->clients_mutex);
669 priv->clients = g_slist_append (priv->clients, cal);
670 g_mutex_unlock (priv->clients_mutex);
674 e_cal_backend_remove_client_private (ECalBackend *backend,
678 g_return_if_fail (E_IS_CAL_BACKEND (backend));
679 g_return_if_fail (E_IS_DATA_CAL (cal));
682 g_object_weak_unref (G_OBJECT (cal), cal_destroy_cb, backend);
684 /* Make sure the backend stays alive while holding the mutex. */
685 g_object_ref (backend);
688 g_mutex_lock (backend->priv->clients_mutex);
689 backend->priv->clients = g_slist_remove (backend->priv->clients, cal);
691 if (backend->priv->clients == NULL)
692 backend->priv->opening = FALSE;
694 g_mutex_unlock (backend->priv->clients_mutex);
696 g_object_unref (backend);
700 * e_cal_backend_remove_client:
701 * @backend: an #ECalBackend
704 * Removes a client from the list of connected clients to the given backend.
707 e_cal_backend_remove_client (ECalBackend *backend,
710 e_cal_backend_remove_client_private (backend, cal, TRUE);
714 * e_cal_backend_add_view:
715 * @backend: an #ECalBackend
716 * @view: An #EDataCalView object.
718 * Adds a view to the list of live views being run by the given backend.
719 * Doing so means that any listener on the view will get notified of any
720 * change that affect the live view.
725 e_cal_backend_add_view (ECalBackend *backend,
728 g_return_if_fail (backend != NULL);
729 g_return_if_fail (E_IS_CAL_BACKEND (backend));
731 g_mutex_lock (backend->priv->views_mutex);
733 backend->priv->views = g_slist_append (backend->priv->views, view);
735 g_mutex_unlock (backend->priv->views_mutex);
739 * e_cal_backend_remove_view
740 * @backend: an #ECalBackend
741 * @view: An #EDataCalView object, previously added with @ref e_cal_backend_add_view.
743 * Removes view from the list of live views for the backend.
748 e_cal_backend_remove_view (ECalBackend *backend,
751 g_return_if_fail (backend != NULL);
752 g_return_if_fail (E_IS_CAL_BACKEND (backend));
754 g_mutex_lock (backend->priv->views_mutex);
756 backend->priv->views = g_slist_remove (backend->priv->views, view);
758 g_mutex_unlock (backend->priv->views_mutex);
762 * e_cal_backend_foreach_view:
763 * @backend: an #ECalBackend
764 * @callback: callback to call
765 * @user_data: user_data passed into the @callback
767 * Calls @callback for each known calendar view of this @backend.
768 * @callback returns %FALSE to stop further processing.
773 e_cal_backend_foreach_view (ECalBackend *backend,
774 gboolean (*callback) (EDataCalView *view,
780 gboolean stop = FALSE;
782 g_return_if_fail (backend != NULL);
783 g_return_if_fail (callback != NULL);
785 g_mutex_lock (backend->priv->views_mutex);
787 for (views = backend->priv->views; views && !stop; views = views->next) {
788 view = E_DATA_CAL_VIEW (views->data);
791 stop = !callback (view, user_data);
792 g_object_unref (view);
795 g_mutex_unlock (backend->priv->views_mutex);
799 * e_cal_backend_set_notification_proxy:
800 * @backend: an #ECalBackend
801 * @proxy: The calendar backend to act as notification proxy.
803 * Sets the backend that will act as notification proxy for the given backend.
808 e_cal_backend_set_notification_proxy (ECalBackend *backend,
811 g_return_if_fail (E_IS_CAL_BACKEND (backend));
813 backend->priv->notification_proxy = proxy;
817 * e_cal_backend_open:
818 * @backend: an #ECalBackend
820 * @opid: the ID to use for this operation
821 * @cancellable: a #GCancellable for the operation
822 * @only_if_exists: Whether the calendar should be opened only if it already
823 * exists. If FALSE, a new calendar will be created when the specified @uri
826 * Opens a calendar backend with data from a calendar stored at the specified URI.
827 * This might be finished with e_data_cal_respond_open() or e_cal_backend_respond_opened(),
828 * though the overall opening phase finishes only after call
829 * of e_cal_backend_notify_opened() after which call the backend
830 * is either fully opened (including authentication against (remote)
831 * server/storage) or an error was encountered during this opening phase.
832 * 'opened' and 'opening' properties are updated automatically.
833 * The backend refuses all other operations until the opening phase is finished.
835 * The e_cal_backend_notify_opened() is called either from this function
836 * or from e_cal_backend_authenticate_user(), or after necessary steps
837 * initiated by these two functions.
839 * The opening phase usually works like this:
840 * 1) client requests open for the backend
841 * 2) server receives this request and calls e_cal_backend_open() - the opening phase begun
842 * 3) either the backend is opened during this call, and notifies client
843 * with e_cal_backend_notify_opened() about that. This is usually
844 * for local backends; their opening phase is finished
845 * 4) or the backend requires authentication, thus it notifies client
846 * about that with e_cal_backend_notify_auth_required() and is
847 * waiting for credentials, which will be received from client
848 * by e_cal_backend_authenticate_user() call. Backend's opening
849 * phase is still running in this case, thus it doesn't call
850 * e_cal_backend_notify_opened() within e_cal_backend_open() call.
851 * 5) when backend receives credentials in e_cal_backend_authenticate_user()
852 * then it tries to authenticate against a server/storage with them
853 * and only after it knows result of the authentication, whether user
854 * was or wasn't authenticated, it notifies client with the result
855 * by e_cal_backend_notify_opened() and it's opening phase is
856 * finished now. If there was no error returned then the backend is
857 * considered opened, otherwise it's considered closed. Use AuthenticationFailed
858 * error when the given credentials were rejected by the server/store, which
859 * will result in a re-prompt on the client side, otherwise use AuthenticationRequired
860 * if there was anything wrong with the given credentials. Set error's
861 * message to a reason for a re-prompt, it'll be shown to a user.
862 * 6) client checks error returned from e_cal_backend_notify_opened() and
863 * reprompts for a password if it was AuthenticationFailed. Otherwise
864 * considers backend opened based on the error presence (no error means success).
866 * In any case, the call of e_cal_backend_open() should be always finished
867 * with e_data_cal_respond_open(), which has no influence on the opening phase,
868 * or alternatively with e_cal_backend_respond_opened(). Never use authentication
869 * errors in e_data_cal_respond_open() to notify the client the authentication is
870 * required, there is e_cal_backend_notify_auth_required() for this.
873 e_cal_backend_open (ECalBackend *backend,
876 GCancellable *cancellable,
877 gboolean only_if_exists)
879 g_return_if_fail (backend != NULL);
880 g_return_if_fail (E_IS_CAL_BACKEND (backend));
881 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->open != NULL);
883 g_mutex_lock (backend->priv->clients_mutex);
885 if (e_cal_backend_is_opened (backend)) {
888 g_mutex_unlock (backend->priv->clients_mutex);
890 e_data_cal_report_readonly (cal, backend->priv->readonly);
892 online = e_backend_get_online (E_BACKEND (backend));
893 e_data_cal_report_online (cal, online);
895 e_cal_backend_respond_opened (backend, cal, opid, NULL);
896 } else if (e_cal_backend_is_opening (backend)) {
897 g_mutex_unlock (backend->priv->clients_mutex);
899 e_data_cal_respond_open (cal, opid, EDC_OPENING_ERROR);
901 backend->priv->opening = TRUE;
902 g_mutex_unlock (backend->priv->clients_mutex);
904 (* E_CAL_BACKEND_GET_CLASS (backend)->open) (backend, cal, opid, cancellable, only_if_exists);
909 * e_cal_backend_remove:
910 * @backend: an #ECalBackend
912 * @opid: the ID to use for this operation
913 * @cancellable: a #GCancellable for the operation
915 * Removes the calendar being accessed by the given backend.
916 * This might be finished with e_data_cal_respond_remove().
919 e_cal_backend_remove (ECalBackend *backend,
922 GCancellable *cancellable)
924 g_return_if_fail (backend != NULL);
925 g_return_if_fail (E_IS_CAL_BACKEND (backend));
926 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->remove != NULL);
928 if (e_cal_backend_is_opening (backend))
929 e_data_cal_respond_remove (cal, opid, EDC_OPENING_ERROR);
931 (* E_CAL_BACKEND_GET_CLASS (backend)->remove) (backend, cal, opid, cancellable);
935 * e_cal_backend_refresh:
936 * @backend: an #ECalBackend
938 * @opid: the ID to use for this operation
939 * @cancellable: a #GCancellable for the operation
941 * Refreshes the calendar being accessed by the given backend.
942 * This might be finished with e_data_cal_respond_refresh(),
943 * and it might be called as soon as possible; it doesn't mean
944 * that the refreshing is done after calling that, the backend
945 * is only notifying client whether it started the refresh process
951 e_cal_backend_refresh (ECalBackend *backend,
954 GCancellable *cancellable)
956 g_return_if_fail (backend != NULL);
957 g_return_if_fail (E_IS_CAL_BACKEND (backend));
959 if (e_cal_backend_is_opening (backend))
960 e_data_cal_respond_refresh (cal, opid, EDC_OPENING_ERROR);
961 else if (!E_CAL_BACKEND_GET_CLASS (backend)->refresh)
962 e_data_cal_respond_refresh (cal, opid, EDC_ERROR (UnsupportedMethod));
963 else if (!e_cal_backend_is_opened (backend))
964 e_data_cal_respond_refresh (cal, opid, EDC_NOT_OPENED_ERROR);
966 (* E_CAL_BACKEND_GET_CLASS (backend)->refresh) (backend, cal, opid, cancellable);
970 * e_cal_backend_get_object:
971 * @backend: an #ECalBackend
973 * @opid: the ID to use for this operation
974 * @cancellable: a #GCancellable for the operation
975 * @uid: Unique identifier for a calendar object.
976 * @rid: ID for the object's recurrence to get.
978 * Queries a calendar backend for a calendar object based on its unique
979 * identifier and its recurrence ID (if a recurrent appointment).
980 * This might be finished with e_data_cal_respond_get_object().
983 e_cal_backend_get_object (ECalBackend *backend,
986 GCancellable *cancellable,
990 g_return_if_fail (backend != NULL);
991 g_return_if_fail (E_IS_CAL_BACKEND (backend));
992 g_return_if_fail (uid != NULL);
993 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_object != NULL);
995 if (e_cal_backend_is_opening (backend))
996 e_data_cal_respond_get_object (cal, opid, EDC_OPENING_ERROR, NULL);
997 else if (!e_cal_backend_is_opened (backend))
998 e_data_cal_respond_get_object (cal, opid, EDC_NOT_OPENED_ERROR, NULL);
1000 (* E_CAL_BACKEND_GET_CLASS (backend)->get_object) (backend, cal, opid, cancellable, uid, rid);
1004 * e_cal_backend_get_object_list:
1005 * @backend: an #ECalBackend
1006 * @cal: an #EDataCal
1007 * @opid: the ID to use for this operation
1008 * @cancellable: a #GCancellable for the operation
1009 * @sexp: Expression to search for.
1011 * Calls the get_object_list method on the given backend.
1012 * This might be finished with e_data_cal_respond_get_object_list().
1015 e_cal_backend_get_object_list (ECalBackend *backend,
1018 GCancellable *cancellable,
1021 g_return_if_fail (backend != NULL);
1022 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1023 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_object_list != NULL);
1025 if (e_cal_backend_is_opening (backend))
1026 e_data_cal_respond_get_object_list (cal, opid, EDC_OPENING_ERROR, NULL);
1027 else if (!e_cal_backend_is_opened (backend))
1028 e_data_cal_respond_get_object_list (cal, opid, EDC_NOT_OPENED_ERROR, NULL);
1030 (* E_CAL_BACKEND_GET_CLASS (backend)->get_object_list) (backend, cal, opid, cancellable, sexp);
1034 * e_cal_backend_get_free_busy:
1035 * @backend: an #ECalBackend
1036 * @cal: an #EDataCal
1037 * @opid: the ID to use for this operation
1038 * @cancellable: a #GCancellable for the operation
1039 * @users: List of users to get free/busy information for.
1040 * @start: Start time for query.
1041 * @end: End time for query.
1043 * Gets a free/busy object for the given time interval. Client side is
1044 * notified about free/busy objects throug e_data_cal_report_free_busy_data().
1045 * This might be finished with e_data_cal_respond_get_free_busy().
1048 e_cal_backend_get_free_busy (ECalBackend *backend,
1051 GCancellable *cancellable,
1052 const GSList *users,
1056 g_return_if_fail (backend != NULL);
1057 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1058 g_return_if_fail (start != -1 && end != -1);
1059 g_return_if_fail (start <= end);
1060 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_free_busy != NULL);
1062 if (e_cal_backend_is_opening (backend))
1063 e_data_cal_respond_get_free_busy (cal, opid, EDC_OPENING_ERROR);
1064 else if (!e_cal_backend_is_opened (backend))
1065 e_data_cal_respond_get_free_busy (cal, opid, EDC_NOT_OPENED_ERROR);
1067 (* E_CAL_BACKEND_GET_CLASS (backend)->get_free_busy) (backend, cal, opid, cancellable, users, start, end);
1071 * e_cal_backend_create_objects:
1072 * @backend: an #ECalBackend
1073 * @cal: an #EDataCal
1074 * @opid: the ID to use for this operation
1075 * @cancellable: a #GCancellable for the operation
1076 * @calobjs: The objects to create (list of gchar *).
1078 * Calls the create_object method on the given backend.
1079 * This might be finished with e_data_cal_respond_create_objects().
1084 e_cal_backend_create_objects (ECalBackend *backend,
1087 GCancellable *cancellable,
1088 const GSList *calobjs)
1090 g_return_if_fail (backend != NULL);
1091 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1092 g_return_if_fail (calobjs != NULL);
1094 if (e_cal_backend_is_opening (backend))
1095 e_data_cal_respond_create_objects (cal, opid, EDC_OPENING_ERROR, NULL, NULL);
1096 else if (!E_CAL_BACKEND_GET_CLASS (backend)->create_objects)
1097 e_data_cal_respond_create_objects (cal, opid, EDC_ERROR (UnsupportedMethod), NULL, NULL);
1098 else if (!e_cal_backend_is_opened (backend))
1099 e_data_cal_respond_create_objects (cal, opid, EDC_NOT_OPENED_ERROR, NULL, NULL);
1101 (* E_CAL_BACKEND_GET_CLASS (backend)->create_objects) (backend, cal, opid, cancellable, calobjs);
1105 * e_cal_backend_modify_objects:
1106 * @backend: an #ECalBackend
1107 * @cal: an #EDataCal
1108 * @opid: the ID to use for this operation
1109 * @cancellable: a #GCancellable for the operation
1110 * @calobjs: Objects to be modified (list of gchar *).
1111 * @mod: Type of modification.
1113 * Calls the modify_objects method on the given backend.
1114 * This might be finished with e_data_cal_respond_modify_objects().
1119 e_cal_backend_modify_objects (ECalBackend *backend,
1122 GCancellable *cancellable,
1123 const GSList *calobjs,
1126 g_return_if_fail (backend != NULL);
1127 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1128 g_return_if_fail (calobjs != NULL);
1130 if (e_cal_backend_is_opening (backend))
1131 e_data_cal_respond_modify_objects (cal, opid, EDC_OPENING_ERROR, NULL, NULL);
1132 else if (!E_CAL_BACKEND_GET_CLASS (backend)->modify_objects)
1133 e_data_cal_respond_modify_objects (cal, opid, EDC_ERROR (UnsupportedMethod), NULL, NULL);
1134 else if (!e_cal_backend_is_opened (backend))
1135 e_data_cal_respond_modify_objects (cal, opid, EDC_NOT_OPENED_ERROR, NULL, NULL);
1137 (* E_CAL_BACKEND_GET_CLASS (backend)->modify_objects) (backend, cal, opid, cancellable, calobjs, mod);
1141 * e_cal_backend_remove_objects:
1142 * @backend: an #ECalBackend
1143 * @cal: an #EDataCal
1144 * @opid: the ID to use for this operation
1145 * @cancellable: a #GCancellable for the operation
1146 * @ids: List of #ECalComponentId objects identifying the objects to remove
1147 * @mod: Type of removal.
1149 * Removes objects in a calendar backend. The backend will notify all of its
1150 * clients about the change.
1151 * This might be finished with e_data_cal_respond_remove_objects().
1156 e_cal_backend_remove_objects (ECalBackend *backend,
1159 GCancellable *cancellable,
1163 g_return_if_fail (backend != NULL);
1164 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1165 g_return_if_fail (ids != NULL);
1166 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->remove_objects != NULL);
1168 if (e_cal_backend_is_opening (backend))
1169 e_data_cal_respond_remove_objects (cal, opid, EDC_OPENING_ERROR, NULL, NULL, NULL);
1170 else if (!e_cal_backend_is_opened (backend))
1171 e_data_cal_respond_remove_objects (cal, opid, EDC_NOT_OPENED_ERROR, NULL, NULL, NULL);
1173 (* E_CAL_BACKEND_GET_CLASS (backend)->remove_objects) (backend, cal, opid, cancellable, ids, mod);
1177 * e_cal_backend_receive_objects:
1178 * @backend: an #ECalBackend
1179 * @cal: an #EDataCal
1180 * @opid: the ID to use for this operation
1181 * @cancellable: a #GCancellable for the operation
1182 * @calobj: iCalendar object.
1184 * Calls the receive_objects method on the given backend.
1185 * This might be finished with e_data_cal_respond_receive_objects().
1188 e_cal_backend_receive_objects (ECalBackend *backend,
1191 GCancellable *cancellable,
1192 const gchar *calobj)
1194 g_return_if_fail (backend != NULL);
1195 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1196 g_return_if_fail (calobj != NULL);
1197 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->receive_objects != NULL);
1199 if (e_cal_backend_is_opening (backend))
1200 e_data_cal_respond_receive_objects (cal, opid, EDC_OPENING_ERROR);
1201 else if (!e_cal_backend_is_opened (backend))
1202 e_data_cal_respond_receive_objects (cal, opid, EDC_NOT_OPENED_ERROR);
1204 (* E_CAL_BACKEND_GET_CLASS (backend)->receive_objects) (backend, cal, opid, cancellable, calobj);
1208 * e_cal_backend_send_objects:
1209 * @backend: an #ECalBackend
1210 * @cal: an #EDataCal
1211 * @opid: the ID to use for this operation
1212 * @cancellable: a #GCancellable for the operation
1213 * @calobj: iCalendar object to be sent.
1215 * Calls the send_objects method on the given backend.
1216 * This might be finished with e_data_cal_respond_send_objects().
1219 e_cal_backend_send_objects (ECalBackend *backend,
1222 GCancellable *cancellable,
1223 const gchar *calobj)
1225 g_return_if_fail (backend != NULL);
1226 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1227 g_return_if_fail (calobj != NULL);
1228 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->send_objects != NULL);
1230 if (e_cal_backend_is_opening (backend))
1231 e_data_cal_respond_send_objects (cal, opid, EDC_OPENING_ERROR, NULL, NULL);
1232 else if (!e_cal_backend_is_opened (backend))
1233 e_data_cal_respond_send_objects (cal, opid, EDC_NOT_OPENED_ERROR, NULL, NULL);
1235 (* E_CAL_BACKEND_GET_CLASS (backend)->send_objects) (backend, cal, opid, cancellable, calobj);
1239 * e_cal_backend_get_attachment_uris:
1240 * @backend: an #ECalBackend
1241 * @cal: an #EDataCal
1242 * @opid: the ID to use for this operation
1243 * @cancellable: a #GCancellable for the operation
1244 * @uid: Unique identifier for a calendar object.
1245 * @rid: ID for the object's recurrence to get.
1247 * Queries a calendar backend for attachments present in a calendar object based
1248 * on its unique identifier and its recurrence ID (if a recurrent appointment).
1249 * This might be finished with e_data_cal_respond_get_attachment_uris().
1254 e_cal_backend_get_attachment_uris (ECalBackend *backend,
1257 GCancellable *cancellable,
1261 g_return_if_fail (backend != NULL);
1262 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1263 g_return_if_fail (uid != NULL);
1264 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_attachment_uris != NULL);
1266 if (e_cal_backend_is_opening (backend))
1267 e_data_cal_respond_get_attachment_uris (cal, opid, EDC_OPENING_ERROR, NULL);
1268 else if (!e_cal_backend_is_opened (backend))
1269 e_data_cal_respond_get_attachment_uris (cal, opid, EDC_NOT_OPENED_ERROR, NULL);
1271 (* E_CAL_BACKEND_GET_CLASS (backend)->get_attachment_uris) (backend, cal, opid, cancellable, uid, rid);
1275 * e_cal_backend_discard_alarm:
1276 * @backend: an #ECalBackend
1277 * @cal: an #EDataCal
1278 * @opid: the ID to use for this operation
1279 * @cancellable: a #GCancellable for the operation
1280 * @uid: Unique identifier for a calendar object.
1281 * @rid: ID for the object's recurrence to discard alarm in.
1282 * @auid: Unique identifier of the alarm itself.
1284 * Discards alarm @auid from the object identified by @uid and @rid.
1285 * This might be finished with e_data_cal_respond_discard_alarm().
1286 * Default implementation of this method returns Not Supported error.
1289 e_cal_backend_discard_alarm (ECalBackend *backend,
1292 GCancellable *cancellable,
1297 g_return_if_fail (backend != NULL);
1298 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1299 g_return_if_fail (uid != NULL);
1300 g_return_if_fail (auid != NULL);
1302 if (e_cal_backend_is_opening (backend))
1303 e_data_cal_respond_discard_alarm (cal, opid, EDC_OPENING_ERROR);
1304 else if (!E_CAL_BACKEND_GET_CLASS (backend)->discard_alarm)
1305 e_data_cal_respond_discard_alarm (cal, opid, e_data_cal_create_error (NotSupported, NULL));
1306 else if (!e_cal_backend_is_opened (backend))
1307 e_data_cal_respond_discard_alarm (cal, opid, EDC_NOT_OPENED_ERROR);
1309 (* E_CAL_BACKEND_GET_CLASS (backend)->discard_alarm) (backend, cal, opid, cancellable, uid, rid, auid);
1313 * e_cal_backend_get_timezone:
1314 * @backend: an #ECalBackend
1315 * @cal: an #EDataCal
1316 * @opid: the ID to use for this operation
1317 * @cancellable: a #GCancellable for the operation
1318 * @tzid: Unique identifier of a VTIMEZONE object. Note that this must not be
1321 * Returns the icaltimezone* corresponding to the TZID, or NULL if the TZID
1323 * This might be finished with e_data_cal_respond_get_timezone().
1326 e_cal_backend_get_timezone (ECalBackend *backend,
1329 GCancellable *cancellable,
1332 g_return_if_fail (backend != NULL);
1333 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1334 g_return_if_fail (tzid != NULL);
1335 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_timezone != NULL);
1337 if (e_cal_backend_is_opening (backend))
1338 e_data_cal_respond_get_timezone (cal, opid, EDC_OPENING_ERROR, NULL);
1339 else if (!e_cal_backend_is_opened (backend))
1340 e_data_cal_respond_get_timezone (cal, opid, EDC_NOT_OPENED_ERROR, NULL);
1342 (* E_CAL_BACKEND_GET_CLASS (backend)->get_timezone) (backend, cal, opid, cancellable, tzid);
1346 * e_cal_backend_add_timezone
1347 * @backend: an #ECalBackend
1348 * @cal: an #EDataCal
1349 * @opid: the ID to use for this operation
1350 * @cancellable: a #GCancellable for the operation
1351 * @tzobject: The timezone object, in a string.
1353 * Add a timezone object to the given backend.
1354 * This might be finished with e_data_cal_respond_add_timezone().
1357 e_cal_backend_add_timezone (ECalBackend *backend,
1360 GCancellable *cancellable,
1361 const gchar *tzobject)
1363 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1364 g_return_if_fail (tzobject != NULL);
1365 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->add_timezone != NULL);
1367 if (e_cal_backend_is_opening (backend))
1368 e_data_cal_respond_add_timezone (cal, opid, EDC_OPENING_ERROR);
1369 else if (!e_cal_backend_is_opened (backend))
1370 e_data_cal_respond_add_timezone (cal, opid, EDC_NOT_OPENED_ERROR);
1372 (* E_CAL_BACKEND_GET_CLASS (backend)->add_timezone) (backend, cal, opid, cancellable, tzobject);
1376 * e_cal_backend_internal_get_timezone:
1377 * @backend: an #ECalBackend
1378 * @tzid: ID of the timezone to get.
1380 * Calls the internal_get_timezone method on the given backend.
1383 e_cal_backend_internal_get_timezone (ECalBackend *backend,
1386 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), NULL);
1387 g_return_val_if_fail (tzid != NULL, NULL);
1388 g_return_val_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->internal_get_timezone != NULL, NULL);
1390 return (* E_CAL_BACKEND_GET_CLASS (backend)->internal_get_timezone) (backend, tzid);
1394 * e_cal_backend_start_view:
1395 * @backend: an #ECalBackend
1396 * @view: The view to be started.
1398 * Starts a new live view on the given backend.
1403 e_cal_backend_start_view (ECalBackend *backend,
1406 g_return_if_fail (backend != NULL);
1407 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1408 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->start_view != NULL);
1410 (* E_CAL_BACKEND_GET_CLASS (backend)->start_view) (backend, view);
1414 * e_cal_backend_stop_view:
1415 * @backend: an #ECalBackend
1416 * @view: The view to be stopped.
1418 * Stops a previously started live view on the given backend.
1423 e_cal_backend_stop_view (ECalBackend *backend,
1426 g_return_if_fail (backend != NULL);
1427 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1429 /* backward compatibility, do not force each backend define this function */
1430 if (!E_CAL_BACKEND_GET_CLASS (backend)->stop_view)
1433 (* E_CAL_BACKEND_GET_CLASS (backend)->stop_view) (backend, view);
1437 component_created_cb (EDataCalView *view,
1440 ECalComponent *comp = data;
1442 if (e_data_cal_view_component_matches (view, comp))
1443 e_data_cal_view_notify_components_added_1 (view, comp);
1449 * e_cal_backend_notify_component_created:
1450 * @backend: an #ECalBackend
1451 * @component: the newly created #ECalComponent
1453 * Notifies each of the backend's listeners about a new object.
1455 * Like e_cal_backend_notify_object_created() except takes an #ECalComponent
1456 * instead of an ical string representation and uses the #EDataCalView's
1457 * fields-of-interest to filter out unwanted information from ical strings
1458 * sent over the bus.
1463 e_cal_backend_notify_component_created (ECalBackend *backend,
1464 /* const */ ECalComponent *component)
1466 ECalBackendPrivate *priv;
1468 priv = backend->priv;
1470 if (priv->notification_proxy) {
1471 e_cal_backend_notify_component_created (priv->notification_proxy, component);
1475 e_cal_backend_foreach_view (backend, component_created_cb, component);
1479 match_view_and_notify_component (EDataCalView *view,
1480 ECalComponent *old_component,
1481 ECalComponent *new_component)
1483 gboolean old_match = FALSE, new_match = FALSE;
1486 old_match = e_data_cal_view_component_matches (view, old_component);
1488 new_match = e_data_cal_view_component_matches (view, new_component);
1490 if (old_match && new_match)
1491 e_data_cal_view_notify_components_modified_1 (view, new_component);
1493 e_data_cal_view_notify_components_added_1 (view, new_component);
1494 else if (old_match) {
1496 ECalComponentId *id = e_cal_component_get_id (old_component);
1498 e_data_cal_view_notify_objects_removed_1 (view, id);
1500 e_cal_component_free_id (id);
1504 struct component_call_data {
1505 ECalComponent *old_component;
1506 ECalComponent *new_component;
1507 const ECalComponentId *id;
1511 call_match_and_notify_component (EDataCalView *view,
1514 struct component_call_data *cd = user_data;
1516 g_return_val_if_fail (user_data != NULL, FALSE);
1518 match_view_and_notify_component (view, cd->old_component, cd->new_component);
1524 * e_cal_backend_notify_component_modified:
1525 * @backend: an #ECalBackend
1526 * @old_component: the #ECalComponent before the modification
1527 * @new_component: the #ECalComponent after the modification
1529 * Notifies each of the backend's listeners about a modified object.
1531 * Like e_cal_backend_notify_object_modified() except takes an #ECalComponent
1532 * instead of an ical string representation and uses the #EDataCalView's
1533 * fields-of-interest to filter out unwanted information from ical strings
1534 * sent over the bus.
1539 e_cal_backend_notify_component_modified (ECalBackend *backend,
1540 /* const */ ECalComponent *old_component,
1541 /* const */ ECalComponent *new_component)
1543 ECalBackendPrivate *priv;
1544 struct component_call_data cd;
1546 priv = backend->priv;
1548 if (priv->notification_proxy) {
1549 e_cal_backend_notify_component_modified (priv->notification_proxy, old_component, new_component);
1553 cd.old_component = old_component;
1554 cd.new_component = new_component;
1557 e_cal_backend_foreach_view (backend, call_match_and_notify_component, &cd);
1561 component_removed_cb (EDataCalView *view,
1564 struct component_call_data *cd = user_data;
1566 g_return_val_if_fail (user_data != NULL, FALSE);
1568 if (cd->new_component == NULL) {
1569 /* if object == NULL, it means the object has been completely
1570 * removed from the backend */
1571 if (!cd->old_component || e_data_cal_view_component_matches (view, cd->old_component))
1572 e_data_cal_view_notify_objects_removed_1 (view, cd->id);
1574 match_view_and_notify_component (view, cd->old_component, cd->new_component);
1580 * e_cal_backend_notify_component_removed:
1581 * @backend: an #ECalBackend
1582 * @id: the Id of the removed object
1583 * @old_component: the removed component
1584 * @new_component: the component after the removal. This only applies to recurrent
1585 * appointments that had an instance removed. In that case, this function
1586 * notifies a modification instead of a removal.
1588 * Notifies each of the backend's listeners about a removed object.
1590 * Like e_cal_backend_notify_object_removed() except takes an #ECalComponent
1591 * instead of an ical string representation and uses the #EDataCalView's
1592 * fields-of-interest to filter out unwanted information from ical strings
1593 * sent over the bus.
1598 e_cal_backend_notify_component_removed (ECalBackend *backend,
1599 const ECalComponentId *id,
1600 /* const */ ECalComponent *old_component,
1601 /* const */ ECalComponent *new_component)
1603 ECalBackendPrivate *priv;
1604 struct component_call_data cd;
1606 priv = backend->priv;
1608 if (priv->notification_proxy) {
1609 e_cal_backend_notify_component_removed (priv->notification_proxy, id, old_component, new_component);
1613 cd.old_component = old_component;
1614 cd.new_component = new_component;
1617 e_cal_backend_foreach_view (backend, component_removed_cb, &cd);
1621 * e_cal_backend_notify_error:
1622 * @backend: an #ECalBackend
1623 * @message: Error message
1625 * Notifies each of the backend's listeners about an error
1628 e_cal_backend_notify_error (ECalBackend *backend,
1629 const gchar *message)
1631 ECalBackendPrivate *priv = backend->priv;
1634 if (priv->notification_proxy) {
1635 e_cal_backend_notify_error (priv->notification_proxy, message);
1639 g_mutex_lock (priv->clients_mutex);
1641 for (l = priv->clients; l; l = l->next)
1642 e_data_cal_report_error (l->data, message);
1644 g_mutex_unlock (priv->clients_mutex);
1648 * e_cal_backend_notify_readonly:
1649 * @backend: an #ECalBackend
1650 * @is_readonly: flag indicating readonly status
1652 * Notifies all backend's clients about the current readonly state.
1653 * Meant to be used by backend implementations.
1656 e_cal_backend_notify_readonly (ECalBackend *backend,
1657 gboolean is_readonly)
1659 ECalBackendPrivate *priv;
1662 priv = backend->priv;
1663 priv->readonly = is_readonly;
1665 if (priv->notification_proxy) {
1666 e_cal_backend_notify_readonly (priv->notification_proxy, is_readonly);
1670 g_mutex_lock (priv->clients_mutex);
1672 for (l = priv->clients; l; l = l->next)
1673 e_data_cal_report_readonly (l->data, is_readonly);
1675 g_mutex_unlock (priv->clients_mutex);
1679 * e_cal_backend_notify_online:
1680 * @backend: an #ECalBackend
1681 * @is_online: flag indicating whether @backend is connected and online
1683 * Notifies clients of @backend's connection status indicated by @is_online.
1684 * Meant to be used by backend implementations.
1689 e_cal_backend_notify_online (ECalBackend *backend,
1692 ECalBackendPrivate *priv;
1695 priv = backend->priv;
1697 if (priv->notification_proxy) {
1698 e_cal_backend_notify_online (priv->notification_proxy, is_online);
1702 g_mutex_lock (priv->clients_mutex);
1704 for (clients = priv->clients; clients != NULL; clients = g_slist_next (clients))
1705 e_data_cal_report_online (E_DATA_CAL (clients->data), is_online);
1707 g_mutex_unlock (priv->clients_mutex);
1711 * e_cal_backend_notify_opened:
1712 * @backend: an #ECalBackend
1713 * @error: a #GError corresponding to the error encountered during
1714 * the opening phase. Use %NULL for success. The @error is freed
1715 * automatically if not %NULL.
1717 * Notifies clients that @backend finished its opening phase.
1718 * See e_cal_backend_open() for more information how the opening
1719 * phase works. Calling this function changes 'opening' property,
1720 * same as 'opened'. 'opening' is set to %FALSE and the backend
1721 * is considered 'opened' only if the @error is %NULL.
1723 * See also: e_cal_backend_respond_opened()
1725 * Note: The @error is freed automatically if not %NULL.
1727 * Meant to be used by backend implementations.
1732 e_cal_backend_notify_opened (ECalBackend *backend,
1735 ECalBackendPrivate *priv;
1738 priv = backend->priv;
1739 g_mutex_lock (priv->clients_mutex);
1741 priv->opening = FALSE;
1742 priv->opened = error == NULL;
1744 for (clients = priv->clients; clients != NULL; clients = g_slist_next (clients))
1745 e_data_cal_report_opened (E_DATA_CAL (clients->data), error);
1747 g_mutex_unlock (priv->clients_mutex);
1750 g_error_free (error);
1754 * e_cal_backend_notify_property_changed:
1755 * @backend: an #ECalBackend
1756 * @prop_name: property name, which changed
1757 * @prop_value: new property value
1759 * Notifies client about property value change.
1764 e_cal_backend_notify_property_changed (ECalBackend *backend,
1765 const gchar *prop_name,
1766 const gchar *prop_value)
1768 ECalBackendPrivate *priv;
1771 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1772 g_return_if_fail (prop_name != NULL);
1773 g_return_if_fail (*prop_name != '\0');
1774 g_return_if_fail (prop_value != NULL);
1776 priv = backend->priv;
1777 g_mutex_lock (priv->clients_mutex);
1779 for (clients = priv->clients; clients != NULL; clients = g_slist_next (clients))
1780 e_data_cal_report_backend_property_changed (E_DATA_CAL (clients->data), prop_name, prop_value);
1782 g_mutex_unlock (priv->clients_mutex);
1786 * e_cal_backend_respond_opened:
1787 * @backend: an #ECalBackend
1788 * @cal: an #EDataCal
1789 * @opid: an operation ID
1790 * @error: result error; can be %NULL, if it isn't then it's automatically freed
1792 * This is a replacement for e_data_cal_respond_open() for cases where
1793 * the finish of 'open' method call also finishes backend opening phase.
1794 * This function covers calling of both e_cal_backend_notify_opened() and
1795 * e_data_cal_respond_open() with the same @error.
1797 * See e_cal_backend_open() for more details how the opening phase works.
1802 e_cal_backend_respond_opened (ECalBackend *backend,
1807 GError *copy = NULL;
1809 g_return_if_fail (backend != NULL);
1810 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1811 g_return_if_fail (cal != NULL);
1812 g_return_if_fail (opid != 0);
1815 copy = g_error_copy (error);
1817 e_cal_backend_notify_opened (backend, copy);
1818 e_data_cal_respond_open (cal, opid, error);
1822 * e_cal_backend_empty_cache:
1823 * @backend: an #ECalBackend
1824 * @cache: Backend's cache to empty.
1826 * Empties backend's cache with all notifications and so on, thus all listening
1827 * will know there is nothing in this backend.
1832 e_cal_backend_empty_cache (ECalBackend *backend,
1833 ECalBackendCache *cache)
1835 GList *comps_in_cache;
1837 g_return_if_fail (backend != NULL);
1838 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1843 g_return_if_fail (E_IS_CAL_BACKEND_CACHE (cache));
1845 e_file_cache_freeze_changes (E_FILE_CACHE (cache));
1847 for (comps_in_cache = e_cal_backend_cache_get_components (cache);
1849 comps_in_cache = comps_in_cache->next) {
1850 ECalComponentId *id;
1851 ECalComponent *comp = comps_in_cache->data;
1853 id = e_cal_component_get_id (comp);
1855 e_cal_backend_cache_remove_component (cache, id->uid, id->rid);
1857 e_cal_backend_notify_component_removed (backend, id, comp, NULL);
1859 e_cal_component_free_id (id);
1860 g_object_unref (comp);
1863 g_list_free (comps_in_cache);
1865 e_file_cache_thaw_changes (E_FILE_CACHE (cache));