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 <libedataserver/e-data-server-util.h>
30 #include "e-cal-backend.h"
31 #include "e-cal-backend-cache.h"
33 #define E_CAL_BACKEND_GET_PRIVATE(obj) \
34 (G_TYPE_INSTANCE_GET_PRIVATE \
35 ((obj), E_TYPE_CAL_BACKEND, ECalBackendPrivate))
37 #define EDC_ERROR(_code) e_data_cal_create_error (_code, NULL)
38 #define EDC_OPENING_ERROR e_data_cal_create_error (Busy, _("Cannot process, calendar backend is opening"))
39 #define EDC_NOT_OPENED_ERROR e_data_cal_create_error (NotOpened, NULL)
41 /* Private part of the CalBackend structure */
42 struct _ECalBackendPrivate {
43 ESourceRegistry *registry;
45 /* The kind of components for this backend */
46 icalcomponent_kind kind;
48 gboolean opening, opened, readonly, removed;
52 /* List of Cal objects */
53 GMutex *clients_mutex;
59 /* ECalBackend to pass notifications on to */
60 ECalBackend *notification_proxy;
72 static void e_cal_backend_remove_client_private (ECalBackend *backend, EDataCal *cal, gboolean weak_unref);
74 G_DEFINE_TYPE (ECalBackend, e_cal_backend, E_TYPE_BACKEND);
77 cal_backend_set_default_cache_dir (ECalBackend *backend)
80 icalcomponent_kind kind;
81 const gchar *component_type;
82 const gchar *user_cache_dir;
86 user_cache_dir = e_get_user_cache_dir ();
88 kind = e_cal_backend_get_kind (backend);
89 source = e_backend_get_source (E_BACKEND (backend));
91 uid = e_source_get_uid (source);
92 g_return_if_fail (uid != NULL);
95 case ICAL_VEVENT_COMPONENT:
96 component_type = "calendar";
98 case ICAL_VTODO_COMPONENT:
99 component_type = "tasks";
101 case ICAL_VJOURNAL_COMPONENT:
102 component_type = "memos";
105 g_return_if_reached ();
108 filename = g_build_filename (
109 user_cache_dir, component_type, uid, NULL);
110 e_cal_backend_set_cache_dir (backend, filename);
115 cal_backend_get_backend_property (ECalBackend *backend,
118 GCancellable *cancellable,
119 const gchar *prop_name)
121 g_return_if_fail (backend != NULL);
122 g_return_if_fail (E_IS_CAL_BACKEND (backend));
123 g_return_if_fail (cal != NULL);
124 g_return_if_fail (prop_name != NULL);
126 if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_OPENED)) {
127 e_data_cal_respond_get_backend_property (cal, opid, NULL, e_cal_backend_is_opened (backend) ? "TRUE" : "FALSE");
128 } else if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_OPENING)) {
129 e_data_cal_respond_get_backend_property (cal, opid, NULL, e_cal_backend_is_opening (backend) ? "TRUE" : "FALSE");
130 } else if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_ONLINE)) {
131 e_data_cal_respond_get_backend_property (cal, opid, NULL, e_backend_get_online (E_BACKEND (backend)) ? "TRUE" : "FALSE");
132 } else if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_READONLY)) {
133 e_data_cal_respond_get_backend_property (cal, opid, NULL, e_cal_backend_is_readonly (backend) ? "TRUE" : "FALSE");
134 } else if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CACHE_DIR)) {
135 e_data_cal_respond_get_backend_property (cal, opid, NULL, e_cal_backend_get_cache_dir (backend));
137 e_data_cal_respond_get_backend_property (cal, opid, e_data_cal_create_error_fmt (NotSupported, _("Unknown calendar property '%s'"), prop_name), NULL);
142 cal_backend_set_backend_property (ECalBackend *backend,
145 GCancellable *cancellable,
146 const gchar *prop_name,
147 const gchar *prop_value)
149 g_return_if_fail (backend != NULL);
150 g_return_if_fail (E_IS_CAL_BACKEND (backend));
151 g_return_if_fail (cal != NULL);
152 g_return_if_fail (prop_name != NULL);
154 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));
158 cal_backend_set_kind (ECalBackend *backend,
159 icalcomponent_kind kind)
161 backend->priv->kind = kind;
165 cal_backend_set_registry (ECalBackend *backend,
166 ESourceRegistry *registry)
168 g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
169 g_return_if_fail (backend->priv->registry == NULL);
171 backend->priv->registry = g_object_ref (registry);
175 cal_backend_set_property (GObject *object,
180 switch (property_id) {
182 e_cal_backend_set_cache_dir (
183 E_CAL_BACKEND (object),
184 g_value_get_string (value));
188 cal_backend_set_kind (
189 E_CAL_BACKEND (object),
190 g_value_get_ulong (value));
194 cal_backend_set_registry (
195 E_CAL_BACKEND (object),
196 g_value_get_object (value));
200 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
204 cal_backend_get_property (GObject *object,
209 switch (property_id) {
212 value, e_cal_backend_get_cache_dir (
213 E_CAL_BACKEND (object)));
218 value, e_cal_backend_get_kind (
219 E_CAL_BACKEND (object)));
224 value, e_cal_backend_get_registry (
225 E_CAL_BACKEND (object)));
229 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
233 cal_backend_dispose (GObject *object)
235 ECalBackendPrivate *priv;
237 priv = E_CAL_BACKEND_GET_PRIVATE (object);
239 if (priv->registry != NULL) {
240 g_object_unref (priv->registry);
241 priv->registry = NULL;
244 /* Chain up to parent's dispose() method. */
245 G_OBJECT_CLASS (e_cal_backend_parent_class)->dispose (object);
249 cal_backend_finalize (GObject *object)
251 ECalBackendPrivate *priv;
253 priv = E_CAL_BACKEND_GET_PRIVATE (object);
255 g_assert (priv->clients == NULL);
257 g_slist_free (priv->views);
258 /* should be NULL, anyway */
259 g_slist_free (priv->clients);
261 g_mutex_free (priv->clients_mutex);
262 g_mutex_free (priv->views_mutex);
264 g_free (priv->cache_dir);
266 /* Chain up to parent's finalize() method. */
267 G_OBJECT_CLASS (e_cal_backend_parent_class)->finalize (object);
271 cal_backend_constructed (GObject *object)
273 cal_backend_set_default_cache_dir (E_CAL_BACKEND (object));
275 G_OBJECT_CLASS (e_cal_backend_parent_class)->constructed (object);
279 e_cal_backend_class_init (ECalBackendClass *class)
281 GObjectClass *object_class;
283 g_type_class_add_private (class, sizeof (ECalBackendPrivate));
285 object_class = G_OBJECT_CLASS (class);
286 object_class->set_property = cal_backend_set_property;
287 object_class->get_property = cal_backend_get_property;
288 object_class->dispose = cal_backend_dispose;
289 object_class->finalize = cal_backend_finalize;
290 object_class->constructed = cal_backend_constructed;
292 class->get_backend_property = cal_backend_get_backend_property;
293 class->set_backend_property = cal_backend_set_backend_property;
295 g_object_class_install_property (
298 g_param_spec_string (
301 "The backend's cache directory",
304 G_PARAM_STATIC_STRINGS));
306 g_object_class_install_property (
312 "The kind of iCalendar components "
313 "this backend manages",
315 ICAL_XLICMIMEPART_COMPONENT,
318 G_PARAM_CONSTRUCT_ONLY |
319 G_PARAM_STATIC_STRINGS));
321 g_object_class_install_property (
324 g_param_spec_object (
327 "Data source registry",
328 E_TYPE_SOURCE_REGISTRY,
330 G_PARAM_CONSTRUCT_ONLY |
331 G_PARAM_STATIC_STRINGS));
335 e_cal_backend_init (ECalBackend *backend)
337 backend->priv = E_CAL_BACKEND_GET_PRIVATE (backend);
339 backend->priv->clients = NULL;
340 backend->priv->clients_mutex = g_mutex_new ();
342 backend->priv->views = NULL;
343 backend->priv->views_mutex = g_mutex_new ();
345 backend->priv->readonly = TRUE;
349 * e_cal_backend_get_kind:
350 * @backend: an #ECalBackend
352 * Gets the kind of components the given backend stores.
354 * Returns: The kind of components for this backend.
357 e_cal_backend_get_kind (ECalBackend *backend)
359 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), ICAL_NO_COMPONENT);
361 return backend->priv->kind;
365 * e_cal_backend_get_registry:
366 * @backend: an #ECalBackend
368 * Returns the data source registry to which #EBackend:source belongs.
370 * Returns: an #ESourceRegistry
375 e_cal_backend_get_registry (ECalBackend *backend)
377 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), NULL);
379 return backend->priv->registry;
383 * e_cal_backend_is_opened:
384 * @backend: an #ECalBackend
386 * Checks if @backend's storage has been opened (and
387 * authenticated, if necessary) and the backend itself
388 * is ready for accessing. This property is changed automatically
389 * within call of e_cal_backend_notify_opened().
391 * Returns: %TRUE if fully opened, %FALSE otherwise.
396 e_cal_backend_is_opened (ECalBackend *backend)
398 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), FALSE);
400 return backend->priv->opened;
404 * e_cal_backend_is_opening:
405 * @backend: an #ECalBackend
407 * Checks if @backend is processing its opening phase, which
408 * includes everything since the e_cal_backend_open() call,
409 * through authentication, up to e_cal_backend_notify_opened().
410 * This property is managed automatically and the backend deny
411 * every operation except of cancel and authenticate_user while
412 * it is being opening.
414 * Returns: %TRUE if opening phase is in the effect, %FALSE otherwise.
419 e_cal_backend_is_opening (ECalBackend *backend)
421 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), FALSE);
423 return backend->priv->opening;
427 * e_cal_backend_is_readonly:
428 * @backend: an #ECalBackend
430 * Returns: Whether is backend read-only. This value is the last used
431 * in a call of e_cal_backend_notify_readonly().
436 e_cal_backend_is_readonly (ECalBackend *backend)
438 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), FALSE);
440 return backend->priv->readonly;
444 * e_cal_backend_is_removed:
445 * @backend: an #ECalBackend
447 * Checks if @backend has been removed from its physical storage.
449 * Returns: %TRUE if @backend has been removed, %FALSE otherwise.
454 e_cal_backend_is_removed (ECalBackend *backend)
456 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), FALSE);
458 return backend->priv->removed;
462 * e_cal_backend_set_is_removed:
463 * @backend: an #ECalBackend
464 * @is_removed: A flag indicating whether the backend's storage was removed
466 * Sets the flag indicating whether @backend was removed to @is_removed.
467 * Meant to be used by backend implementations.
472 e_cal_backend_set_is_removed (ECalBackend *backend,
475 g_return_if_fail (E_IS_CAL_BACKEND (backend));
477 backend->priv->removed = is_removed;
481 * e_cal_backend_get_cache_dir:
482 * @backend: an #ECalBackend
484 * Returns the cache directory for the given backend.
486 * Returns: the cache directory for the backend
491 e_cal_backend_get_cache_dir (ECalBackend *backend)
493 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), NULL);
495 return backend->priv->cache_dir;
499 * e_cal_backend_set_cache_dir:
500 * @backend: an #ECalBackend
501 * @cache_dir: a local cache directory
503 * Sets the cache directory for the given backend.
505 * Note that #ECalBackend is initialized with a usable default based on
506 * #ECalBackend:source and #ECalBackend:kind properties. Backends should
507 * not override the default without good reason.
512 e_cal_backend_set_cache_dir (ECalBackend *backend,
513 const gchar *cache_dir)
515 g_return_if_fail (E_IS_CAL_BACKEND (backend));
516 g_return_if_fail (cache_dir != NULL);
518 g_free (backend->priv->cache_dir);
519 backend->priv->cache_dir = g_strdup (cache_dir);
521 g_object_notify (G_OBJECT (backend), "cache-dir");
525 * e_cal_backend_create_cache_filename:
526 * @backend: an #ECalBackend
527 * @uid: a component UID
528 * @filename: a filename to use; can be NULL
529 * @fileindex: index of a file; used only when @filename is NULL
531 * Returns: a filename for an attachment in a local cache dir. Free returned
532 * pointer with a g_free().
537 e_cal_backend_create_cache_filename (ECalBackend *backend,
539 const gchar *filename,
542 g_return_val_if_fail (backend != NULL, NULL);
543 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), NULL);
545 return e_filename_mkdir_encoded (e_cal_backend_get_cache_dir (backend), uid, filename, fileindex);
549 * e_cal_backend_get_backend_property:
550 * @backend: an #ECalBackend
552 * @opid: the ID to use for this operation
553 * @cancellable: a #GCancellable for the operation
554 * @prop_name: property name to get value of; cannot be NULL
556 * Calls the get_backend_property method on the given backend.
557 * This might be finished with e_data_cal_respond_get_backend_property().
558 * Default implementation takes care of common properties and returns
559 * an 'unsupported' error for any unknown properties. The subclass may
560 * always call this default implementation for properties which fetching
561 * it doesn't overwrite.
566 e_cal_backend_get_backend_property (ECalBackend *backend,
569 GCancellable *cancellable,
570 const gchar *prop_name)
572 g_return_if_fail (backend != NULL);
573 g_return_if_fail (E_IS_CAL_BACKEND (backend));
574 g_return_if_fail (prop_name != NULL);
575 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_backend_property != NULL);
577 (* E_CAL_BACKEND_GET_CLASS (backend)->get_backend_property) (backend, cal, opid, cancellable, prop_name);
581 * e_cal_backend_set_backend_property:
582 * @backend: an #ECalBackend
584 * @opid: the ID to use for this operation
585 * @cancellable: a #GCancellable for the operation
586 * @prop_name: property name to change; cannot be NULL
587 * @prop_value: value to set to @prop_name; cannot be NULL
589 * Calls the set_backend_property method on the given backend.
590 * This might be finished with e_data_cal_respond_set_backend_property().
591 * Default implementation simply returns an 'unsupported' error.
592 * The subclass may always call this default implementation for properties
593 * which fetching it doesn't overwrite.
598 e_cal_backend_set_backend_property (ECalBackend *backend,
601 GCancellable *cancellable,
602 const gchar *prop_name,
603 const gchar *prop_value)
605 g_return_if_fail (backend != NULL);
606 g_return_if_fail (E_IS_CAL_BACKEND (backend));
607 g_return_if_fail (prop_name != NULL);
608 g_return_if_fail (prop_value != NULL);
609 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->set_backend_property != NULL);
611 (* E_CAL_BACKEND_GET_CLASS (backend)->set_backend_property) (backend, cal, opid, cancellable, prop_name, prop_value);
615 cal_destroy_cb (gpointer data,
616 GObject *where_cal_was)
618 e_cal_backend_remove_client_private (E_CAL_BACKEND (data),
619 (EDataCal *) where_cal_was, FALSE);
623 * e_cal_backend_add_client:
624 * @backend: an #ECalBackend
627 * Adds a new client to the given backend. For any event, the backend will
628 * notify all clients added via this function.
631 e_cal_backend_add_client (ECalBackend *backend,
634 ECalBackendPrivate *priv;
636 g_return_if_fail (backend != NULL);
637 g_return_if_fail (E_IS_CAL_BACKEND (backend));
638 g_return_if_fail (cal != NULL);
639 g_return_if_fail (E_IS_DATA_CAL (cal));
641 priv = backend->priv;
643 g_object_weak_ref (G_OBJECT (cal), cal_destroy_cb, backend);
645 g_mutex_lock (priv->clients_mutex);
646 priv->clients = g_slist_append (priv->clients, cal);
647 g_mutex_unlock (priv->clients_mutex);
651 e_cal_backend_remove_client_private (ECalBackend *backend,
655 g_return_if_fail (E_IS_CAL_BACKEND (backend));
656 g_return_if_fail (E_IS_DATA_CAL (cal));
659 g_object_weak_unref (G_OBJECT (cal), cal_destroy_cb, backend);
661 /* Make sure the backend stays alive while holding the mutex. */
662 g_object_ref (backend);
665 g_mutex_lock (backend->priv->clients_mutex);
666 backend->priv->clients = g_slist_remove (backend->priv->clients, cal);
668 if (backend->priv->clients == NULL)
669 backend->priv->opening = FALSE;
671 g_mutex_unlock (backend->priv->clients_mutex);
673 g_object_unref (backend);
677 * e_cal_backend_remove_client:
678 * @backend: an #ECalBackend
681 * Removes a client from the list of connected clients to the given backend.
684 e_cal_backend_remove_client (ECalBackend *backend,
687 e_cal_backend_remove_client_private (backend, cal, TRUE);
691 * e_cal_backend_add_view:
692 * @backend: an #ECalBackend
693 * @view: An #EDataCalView object.
695 * Adds a view to the list of live views being run by the given backend.
696 * Doing so means that any listener on the view will get notified of any
697 * change that affect the live view.
702 e_cal_backend_add_view (ECalBackend *backend,
705 g_return_if_fail (backend != NULL);
706 g_return_if_fail (E_IS_CAL_BACKEND (backend));
708 g_mutex_lock (backend->priv->views_mutex);
710 backend->priv->views = g_slist_append (backend->priv->views, view);
712 g_mutex_unlock (backend->priv->views_mutex);
716 * e_cal_backend_remove_view
717 * @backend: an #ECalBackend
718 * @view: An #EDataCalView object, previously added with @ref e_cal_backend_add_view.
720 * Removes view from the list of live views for the backend.
725 e_cal_backend_remove_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_remove (backend->priv->views, view);
735 g_mutex_unlock (backend->priv->views_mutex);
739 * e_cal_backend_foreach_view:
740 * @backend: an #ECalBackend
741 * @callback: callback to call
742 * @user_data: user_data passed into the @callback
744 * Calls @callback for each known calendar view of this @backend.
745 * @callback returns %FALSE to stop further processing.
750 e_cal_backend_foreach_view (ECalBackend *backend,
751 gboolean (*callback) (EDataCalView *view,
757 gboolean stop = FALSE;
759 g_return_if_fail (backend != NULL);
760 g_return_if_fail (callback != NULL);
762 g_mutex_lock (backend->priv->views_mutex);
764 for (views = backend->priv->views; views && !stop; views = views->next) {
765 view = E_DATA_CAL_VIEW (views->data);
768 stop = !callback (view, user_data);
769 g_object_unref (view);
772 g_mutex_unlock (backend->priv->views_mutex);
776 * e_cal_backend_set_notification_proxy:
777 * @backend: an #ECalBackend
778 * @proxy: The calendar backend to act as notification proxy.
780 * Sets the backend that will act as notification proxy for the given backend.
785 e_cal_backend_set_notification_proxy (ECalBackend *backend,
788 g_return_if_fail (E_IS_CAL_BACKEND (backend));
790 backend->priv->notification_proxy = proxy;
794 * e_cal_backend_open:
795 * @backend: an #ECalBackend
797 * @opid: the ID to use for this operation
798 * @cancellable: a #GCancellable for the operation
799 * @only_if_exists: Whether the calendar should be opened only if it already
800 * exists. If FALSE, a new calendar will be created when the specified @uri
803 * Opens a calendar backend with data from a calendar stored at the specified URI.
804 * This might be finished with e_data_cal_respond_open() or e_cal_backend_respond_opened(),
805 * though the overall opening phase finishes only after call
806 * of e_cal_backend_notify_opened() after which call the backend
807 * is either fully opened (including authentication against (remote)
808 * server/storage) or an error was encountered during this opening phase.
809 * 'opened' and 'opening' properties are updated automatically.
810 * The backend refuses all other operations until the opening phase is finished.
812 * The e_cal_backend_notify_opened() is called either from this function
813 * or from e_cal_backend_authenticate_user(), or after necessary steps
814 * initiated by these two functions.
816 * The opening phase usually works like this:
817 * 1) client requests open for the backend
818 * 2) server receives this request and calls e_cal_backend_open() - the opening phase begun
819 * 3) either the backend is opened during this call, and notifies client
820 * with e_cal_backend_notify_opened() about that. This is usually
821 * for local backends; their opening phase is finished
822 * 4) or the backend requires authentication, thus it notifies client
823 * about that with e_cal_backend_notify_auth_required() and is
824 * waiting for credentials, which will be received from client
825 * by e_cal_backend_authenticate_user() call. Backend's opening
826 * phase is still running in this case, thus it doesn't call
827 * e_cal_backend_notify_opened() within e_cal_backend_open() call.
828 * 5) when backend receives credentials in e_cal_backend_authenticate_user()
829 * then it tries to authenticate against a server/storage with them
830 * and only after it knows result of the authentication, whether user
831 * was or wasn't authenticated, it notifies client with the result
832 * by e_cal_backend_notify_opened() and it's opening phase is
833 * finished now. If there was no error returned then the backend is
834 * considered opened, otherwise it's considered closed. Use AuthenticationFailed
835 * error when the given credentials were rejected by the server/store, which
836 * will result in a re-prompt on the client side, otherwise use AuthenticationRequired
837 * if there was anything wrong with the given credentials. Set error's
838 * message to a reason for a re-prompt, it'll be shown to a user.
839 * 6) client checks error returned from e_cal_backend_notify_opened() and
840 * reprompts for a password if it was AuthenticationFailed. Otherwise
841 * considers backend opened based on the error presence (no error means success).
843 * In any case, the call of e_cal_backend_open() should be always finished
844 * with e_data_cal_respond_open(), which has no influence on the opening phase,
845 * or alternatively with e_cal_backend_respond_opened(). Never use authentication
846 * errors in e_data_cal_respond_open() to notify the client the authentication is
847 * required, there is e_cal_backend_notify_auth_required() for this.
850 e_cal_backend_open (ECalBackend *backend,
853 GCancellable *cancellable,
854 gboolean only_if_exists)
856 g_return_if_fail (backend != NULL);
857 g_return_if_fail (E_IS_CAL_BACKEND (backend));
858 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->open != NULL);
860 g_mutex_lock (backend->priv->clients_mutex);
862 if (e_cal_backend_is_opened (backend)) {
865 g_mutex_unlock (backend->priv->clients_mutex);
867 e_data_cal_report_readonly (cal, backend->priv->readonly);
869 online = e_backend_get_online (E_BACKEND (backend));
870 e_data_cal_report_online (cal, online);
872 e_cal_backend_respond_opened (backend, cal, opid, NULL);
873 } else if (e_cal_backend_is_opening (backend)) {
874 g_mutex_unlock (backend->priv->clients_mutex);
876 e_data_cal_respond_open (cal, opid, EDC_OPENING_ERROR);
878 backend->priv->opening = TRUE;
879 g_mutex_unlock (backend->priv->clients_mutex);
881 (* E_CAL_BACKEND_GET_CLASS (backend)->open) (backend, cal, opid, cancellable, only_if_exists);
886 * e_cal_backend_remove:
887 * @backend: an #ECalBackend
889 * @opid: the ID to use for this operation
890 * @cancellable: a #GCancellable for the operation
892 * Removes the calendar being accessed by the given backend.
893 * This might be finished with e_data_cal_respond_remove().
896 e_cal_backend_remove (ECalBackend *backend,
899 GCancellable *cancellable)
901 g_return_if_fail (backend != NULL);
902 g_return_if_fail (E_IS_CAL_BACKEND (backend));
903 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->remove != NULL);
905 if (e_cal_backend_is_opening (backend))
906 e_data_cal_respond_remove (cal, opid, EDC_OPENING_ERROR);
908 (* E_CAL_BACKEND_GET_CLASS (backend)->remove) (backend, cal, opid, cancellable);
912 * e_cal_backend_refresh:
913 * @backend: an #ECalBackend
915 * @opid: the ID to use for this operation
916 * @cancellable: a #GCancellable for the operation
918 * Refreshes the calendar being accessed by the given backend.
919 * This might be finished with e_data_cal_respond_refresh(),
920 * and it might be called as soon as possible; it doesn't mean
921 * that the refreshing is done after calling that, the backend
922 * is only notifying client whether it started the refresh process
928 e_cal_backend_refresh (ECalBackend *backend,
931 GCancellable *cancellable)
933 g_return_if_fail (backend != NULL);
934 g_return_if_fail (E_IS_CAL_BACKEND (backend));
936 if (e_cal_backend_is_opening (backend))
937 e_data_cal_respond_refresh (cal, opid, EDC_OPENING_ERROR);
938 else if (!E_CAL_BACKEND_GET_CLASS (backend)->refresh)
939 e_data_cal_respond_refresh (cal, opid, EDC_ERROR (UnsupportedMethod));
940 else if (!e_cal_backend_is_opened (backend))
941 e_data_cal_respond_refresh (cal, opid, EDC_NOT_OPENED_ERROR);
943 (* E_CAL_BACKEND_GET_CLASS (backend)->refresh) (backend, cal, opid, cancellable);
947 * e_cal_backend_get_object:
948 * @backend: an #ECalBackend
950 * @opid: the ID to use for this operation
951 * @cancellable: a #GCancellable for the operation
952 * @uid: Unique identifier for a calendar object.
953 * @rid: ID for the object's recurrence to get.
955 * Queries a calendar backend for a calendar object based on its unique
956 * identifier and its recurrence ID (if a recurrent appointment).
957 * This might be finished with e_data_cal_respond_get_object().
960 e_cal_backend_get_object (ECalBackend *backend,
963 GCancellable *cancellable,
967 g_return_if_fail (backend != NULL);
968 g_return_if_fail (E_IS_CAL_BACKEND (backend));
969 g_return_if_fail (uid != NULL);
970 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_object != NULL);
972 if (e_cal_backend_is_opening (backend))
973 e_data_cal_respond_get_object (cal, opid, EDC_OPENING_ERROR, NULL);
974 else if (!e_cal_backend_is_opened (backend))
975 e_data_cal_respond_get_object (cal, opid, EDC_NOT_OPENED_ERROR, NULL);
977 (* E_CAL_BACKEND_GET_CLASS (backend)->get_object) (backend, cal, opid, cancellable, uid, rid);
981 * e_cal_backend_get_object_list:
982 * @backend: an #ECalBackend
984 * @opid: the ID to use for this operation
985 * @cancellable: a #GCancellable for the operation
986 * @sexp: Expression to search for.
988 * Calls the get_object_list method on the given backend.
989 * This might be finished with e_data_cal_respond_get_object_list().
992 e_cal_backend_get_object_list (ECalBackend *backend,
995 GCancellable *cancellable,
998 g_return_if_fail (backend != NULL);
999 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1000 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_object_list != NULL);
1002 if (e_cal_backend_is_opening (backend))
1003 e_data_cal_respond_get_object_list (cal, opid, EDC_OPENING_ERROR, NULL);
1004 else if (!e_cal_backend_is_opened (backend))
1005 e_data_cal_respond_get_object_list (cal, opid, EDC_NOT_OPENED_ERROR, NULL);
1007 (* E_CAL_BACKEND_GET_CLASS (backend)->get_object_list) (backend, cal, opid, cancellable, sexp);
1011 * e_cal_backend_get_free_busy:
1012 * @backend: an #ECalBackend
1013 * @cal: an #EDataCal
1014 * @opid: the ID to use for this operation
1015 * @cancellable: a #GCancellable for the operation
1016 * @users: List of users to get free/busy information for.
1017 * @start: Start time for query.
1018 * @end: End time for query.
1020 * Gets a free/busy object for the given time interval. Client side is
1021 * notified about free/busy objects throug e_data_cal_report_free_busy_data().
1022 * This might be finished with e_data_cal_respond_get_free_busy().
1025 e_cal_backend_get_free_busy (ECalBackend *backend,
1028 GCancellable *cancellable,
1029 const GSList *users,
1033 g_return_if_fail (backend != NULL);
1034 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1035 g_return_if_fail (start != -1 && end != -1);
1036 g_return_if_fail (start <= end);
1037 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_free_busy != NULL);
1039 if (e_cal_backend_is_opening (backend))
1040 e_data_cal_respond_get_free_busy (cal, opid, EDC_OPENING_ERROR);
1041 else if (!e_cal_backend_is_opened (backend))
1042 e_data_cal_respond_get_free_busy (cal, opid, EDC_NOT_OPENED_ERROR);
1044 (* E_CAL_BACKEND_GET_CLASS (backend)->get_free_busy) (backend, cal, opid, cancellable, users, start, end);
1048 * e_cal_backend_create_objects:
1049 * @backend: an #ECalBackend
1050 * @cal: an #EDataCal
1051 * @opid: the ID to use for this operation
1052 * @cancellable: a #GCancellable for the operation
1053 * @calobjs: The objects to create (list of gchar *).
1055 * Calls the create_object method on the given backend.
1056 * This might be finished with e_data_cal_respond_create_objects().
1059 e_cal_backend_create_objects (ECalBackend *backend,
1062 GCancellable *cancellable,
1063 const GSList *calobjs)
1065 g_return_if_fail (backend != NULL);
1066 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1067 g_return_if_fail (calobjs != NULL);
1069 if (e_cal_backend_is_opening (backend))
1070 e_data_cal_respond_create_objects (cal, opid, EDC_OPENING_ERROR, NULL, NULL);
1071 else if (!E_CAL_BACKEND_GET_CLASS (backend)->create_objects)
1072 e_data_cal_respond_create_objects (cal, opid, EDC_ERROR (UnsupportedMethod), NULL, NULL);
1073 else if (!e_cal_backend_is_opened (backend))
1074 e_data_cal_respond_create_objects (cal, opid, EDC_NOT_OPENED_ERROR, NULL, NULL);
1076 (* E_CAL_BACKEND_GET_CLASS (backend)->create_objects) (backend, cal, opid, cancellable, calobjs);
1080 * e_cal_backend_modify_objects:
1081 * @backend: an #ECalBackend
1082 * @cal: an #EDataCal
1083 * @opid: the ID to use for this operation
1084 * @cancellable: a #GCancellable for the operation
1085 * @calobjs: Objects to be modified (list of gchar *).
1086 * @mod: Type of modification.
1088 * Calls the modify_objects method on the given backend.
1089 * This might be finished with e_data_cal_respond_modify_objects().
1092 e_cal_backend_modify_objects (ECalBackend *backend,
1095 GCancellable *cancellable,
1096 const GSList *calobjs,
1099 g_return_if_fail (backend != NULL);
1100 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1101 g_return_if_fail (calobjs != NULL);
1103 if (e_cal_backend_is_opening (backend))
1104 e_data_cal_respond_modify_objects (cal, opid, EDC_OPENING_ERROR, NULL, NULL);
1105 else if (!E_CAL_BACKEND_GET_CLASS (backend)->modify_objects)
1106 e_data_cal_respond_modify_objects (cal, opid, EDC_ERROR (UnsupportedMethod), NULL, NULL);
1107 else if (!e_cal_backend_is_opened (backend))
1108 e_data_cal_respond_modify_objects (cal, opid, EDC_NOT_OPENED_ERROR, NULL, NULL);
1110 (* E_CAL_BACKEND_GET_CLASS (backend)->modify_objects) (backend, cal, opid, cancellable, calobjs, mod);
1114 * e_cal_backend_remove_objects:
1115 * @backend: an #ECalBackend
1116 * @cal: an #EDataCal
1117 * @opid: the ID to use for this operation
1118 * @cancellable: a #GCancellable for the operation
1119 * @ids: List of #ECalComponentId objects identifying the objects to remove
1120 * @mod: Type of removal.
1122 * Removes objects in a calendar backend. The backend will notify all of its
1123 * clients about the change.
1124 * This might be finished with e_data_cal_respond_remove_objects().
1127 e_cal_backend_remove_objects (ECalBackend *backend,
1130 GCancellable *cancellable,
1134 g_return_if_fail (backend != NULL);
1135 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1136 g_return_if_fail (ids != NULL);
1137 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->remove_objects != NULL);
1139 if (e_cal_backend_is_opening (backend))
1140 e_data_cal_respond_remove_objects (cal, opid, EDC_OPENING_ERROR, NULL, NULL, NULL);
1141 else if (!e_cal_backend_is_opened (backend))
1142 e_data_cal_respond_remove_objects (cal, opid, EDC_NOT_OPENED_ERROR, NULL, NULL, NULL);
1144 (* E_CAL_BACKEND_GET_CLASS (backend)->remove_objects) (backend, cal, opid, cancellable, ids, mod);
1148 * e_cal_backend_receive_objects:
1149 * @backend: an #ECalBackend
1150 * @cal: an #EDataCal
1151 * @opid: the ID to use for this operation
1152 * @cancellable: a #GCancellable for the operation
1153 * @calobj: iCalendar object.
1155 * Calls the receive_objects method on the given backend.
1156 * This might be finished with e_data_cal_respond_receive_objects().
1159 e_cal_backend_receive_objects (ECalBackend *backend,
1162 GCancellable *cancellable,
1163 const gchar *calobj)
1165 g_return_if_fail (backend != NULL);
1166 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1167 g_return_if_fail (calobj != NULL);
1168 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->receive_objects != NULL);
1170 if (e_cal_backend_is_opening (backend))
1171 e_data_cal_respond_receive_objects (cal, opid, EDC_OPENING_ERROR);
1172 else if (!e_cal_backend_is_opened (backend))
1173 e_data_cal_respond_receive_objects (cal, opid, EDC_NOT_OPENED_ERROR);
1175 (* E_CAL_BACKEND_GET_CLASS (backend)->receive_objects) (backend, cal, opid, cancellable, calobj);
1179 * e_cal_backend_send_objects:
1180 * @backend: an #ECalBackend
1181 * @cal: an #EDataCal
1182 * @opid: the ID to use for this operation
1183 * @cancellable: a #GCancellable for the operation
1184 * @calobj: iCalendar object to be sent.
1186 * Calls the send_objects method on the given backend.
1187 * This might be finished with e_data_cal_respond_send_objects().
1190 e_cal_backend_send_objects (ECalBackend *backend,
1193 GCancellable *cancellable,
1194 const gchar *calobj)
1196 g_return_if_fail (backend != NULL);
1197 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1198 g_return_if_fail (calobj != NULL);
1199 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->send_objects != NULL);
1201 if (e_cal_backend_is_opening (backend))
1202 e_data_cal_respond_send_objects (cal, opid, EDC_OPENING_ERROR, NULL, NULL);
1203 else if (!e_cal_backend_is_opened (backend))
1204 e_data_cal_respond_send_objects (cal, opid, EDC_NOT_OPENED_ERROR, NULL, NULL);
1206 (* E_CAL_BACKEND_GET_CLASS (backend)->send_objects) (backend, cal, opid, cancellable, calobj);
1210 * e_cal_backend_get_attachment_uris:
1211 * @backend: an #ECalBackend
1212 * @cal: an #EDataCal
1213 * @opid: the ID to use for this operation
1214 * @cancellable: a #GCancellable for the operation
1215 * @uid: Unique identifier for a calendar object.
1216 * @rid: ID for the object's recurrence to get.
1218 * Queries a calendar backend for attachments present in a calendar object based
1219 * on its unique identifier and its recurrence ID (if a recurrent appointment).
1220 * This might be finished with e_data_cal_respond_get_attachment_uris().
1225 e_cal_backend_get_attachment_uris (ECalBackend *backend,
1228 GCancellable *cancellable,
1232 g_return_if_fail (backend != NULL);
1233 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1234 g_return_if_fail (uid != NULL);
1235 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_attachment_uris != NULL);
1237 if (e_cal_backend_is_opening (backend))
1238 e_data_cal_respond_get_attachment_uris (cal, opid, EDC_OPENING_ERROR, NULL);
1239 else if (!e_cal_backend_is_opened (backend))
1240 e_data_cal_respond_get_attachment_uris (cal, opid, EDC_NOT_OPENED_ERROR, NULL);
1242 (* E_CAL_BACKEND_GET_CLASS (backend)->get_attachment_uris) (backend, cal, opid, cancellable, uid, rid);
1246 * e_cal_backend_discard_alarm:
1247 * @backend: an #ECalBackend
1248 * @cal: an #EDataCal
1249 * @opid: the ID to use for this operation
1250 * @cancellable: a #GCancellable for the operation
1251 * @uid: Unique identifier for a calendar object.
1252 * @rid: ID for the object's recurrence to discard alarm in.
1253 * @auid: Unique identifier of the alarm itself.
1255 * Discards alarm @auid from the object identified by @uid and @rid.
1256 * This might be finished with e_data_cal_respond_discard_alarm().
1257 * Default implementation of this method returns Not Supported error.
1260 e_cal_backend_discard_alarm (ECalBackend *backend,
1263 GCancellable *cancellable,
1268 g_return_if_fail (backend != NULL);
1269 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1270 g_return_if_fail (uid != NULL);
1271 g_return_if_fail (auid != NULL);
1273 if (e_cal_backend_is_opening (backend))
1274 e_data_cal_respond_discard_alarm (cal, opid, EDC_OPENING_ERROR);
1275 else if (!E_CAL_BACKEND_GET_CLASS (backend)->discard_alarm)
1276 e_data_cal_respond_discard_alarm (cal, opid, e_data_cal_create_error (NotSupported, NULL));
1277 else if (!e_cal_backend_is_opened (backend))
1278 e_data_cal_respond_discard_alarm (cal, opid, EDC_NOT_OPENED_ERROR);
1280 (* E_CAL_BACKEND_GET_CLASS (backend)->discard_alarm) (backend, cal, opid, cancellable, uid, rid, auid);
1284 * e_cal_backend_get_timezone:
1285 * @backend: an #ECalBackend
1286 * @cal: an #EDataCal
1287 * @opid: the ID to use for this operation
1288 * @cancellable: a #GCancellable for the operation
1289 * @tzid: Unique identifier of a VTIMEZONE object. Note that this must not be
1292 * Returns the icaltimezone* corresponding to the TZID, or NULL if the TZID
1294 * This might be finished with e_data_cal_respond_get_timezone().
1297 e_cal_backend_get_timezone (ECalBackend *backend,
1300 GCancellable *cancellable,
1303 g_return_if_fail (backend != NULL);
1304 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1305 g_return_if_fail (tzid != NULL);
1306 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_timezone != NULL);
1308 if (e_cal_backend_is_opening (backend))
1309 e_data_cal_respond_get_timezone (cal, opid, EDC_OPENING_ERROR, NULL);
1310 else if (!e_cal_backend_is_opened (backend))
1311 e_data_cal_respond_get_timezone (cal, opid, EDC_NOT_OPENED_ERROR, NULL);
1313 (* E_CAL_BACKEND_GET_CLASS (backend)->get_timezone) (backend, cal, opid, cancellable, tzid);
1317 * e_cal_backend_add_timezone
1318 * @backend: an #ECalBackend
1319 * @cal: an #EDataCal
1320 * @opid: the ID to use for this operation
1321 * @cancellable: a #GCancellable for the operation
1322 * @tzobject: The timezone object, in a string.
1324 * Add a timezone object to the given backend.
1325 * This might be finished with e_data_cal_respond_add_timezone().
1328 e_cal_backend_add_timezone (ECalBackend *backend,
1331 GCancellable *cancellable,
1332 const gchar *tzobject)
1334 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1335 g_return_if_fail (tzobject != NULL);
1336 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->add_timezone != NULL);
1338 if (e_cal_backend_is_opening (backend))
1339 e_data_cal_respond_add_timezone (cal, opid, EDC_OPENING_ERROR);
1340 else if (!e_cal_backend_is_opened (backend))
1341 e_data_cal_respond_add_timezone (cal, opid, EDC_NOT_OPENED_ERROR);
1343 (* E_CAL_BACKEND_GET_CLASS (backend)->add_timezone) (backend, cal, opid, cancellable, tzobject);
1347 * e_cal_backend_internal_get_timezone:
1348 * @backend: an #ECalBackend
1349 * @tzid: ID of the timezone to get.
1351 * Calls the internal_get_timezone method on the given backend.
1354 e_cal_backend_internal_get_timezone (ECalBackend *backend,
1357 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), NULL);
1358 g_return_val_if_fail (tzid != NULL, NULL);
1359 g_return_val_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->internal_get_timezone != NULL, NULL);
1361 return (* E_CAL_BACKEND_GET_CLASS (backend)->internal_get_timezone) (backend, tzid);
1365 * e_cal_backend_start_view:
1366 * @backend: an #ECalBackend
1367 * @view: The view to be started.
1369 * Starts a new live view on the given backend.
1374 e_cal_backend_start_view (ECalBackend *backend,
1377 g_return_if_fail (backend != NULL);
1378 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1379 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->start_view != NULL);
1381 (* E_CAL_BACKEND_GET_CLASS (backend)->start_view) (backend, view);
1385 * e_cal_backend_stop_view:
1386 * @backend: an #ECalBackend
1387 * @view: The view to be stopped.
1389 * Stops a previously started live view on the given backend.
1394 e_cal_backend_stop_view (ECalBackend *backend,
1397 g_return_if_fail (backend != NULL);
1398 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1400 /* backward compatibility, do not force each backend define this function */
1401 if (!E_CAL_BACKEND_GET_CLASS (backend)->stop_view)
1404 (* E_CAL_BACKEND_GET_CLASS (backend)->stop_view) (backend, view);
1408 component_created_cb (EDataCalView *view,
1411 ECalComponent *comp = data;
1413 if (e_data_cal_view_component_matches (view, comp))
1414 e_data_cal_view_notify_components_added_1 (view, comp);
1420 * e_cal_backend_notify_component_created:
1421 * @backend: an #ECalBackend
1422 * @component: the newly created #ECalComponent
1424 * Notifies each of the backend's listeners about a new object.
1426 * Like e_cal_backend_notify_object_created() except takes an #ECalComponent
1427 * instead of an ical string representation and uses the #EDataCalView's
1428 * fields-of-interest to filter out unwanted information from ical strings
1429 * sent over the bus.
1434 e_cal_backend_notify_component_created (ECalBackend *backend,
1435 /* const */ ECalComponent *component)
1437 ECalBackendPrivate *priv;
1439 priv = backend->priv;
1441 if (priv->notification_proxy) {
1442 e_cal_backend_notify_component_created (priv->notification_proxy, component);
1446 e_cal_backend_foreach_view (backend, component_created_cb, component);
1450 match_view_and_notify_component (EDataCalView *view,
1451 ECalComponent *old_component,
1452 ECalComponent *new_component)
1454 gboolean old_match = FALSE, new_match = FALSE;
1457 old_match = e_data_cal_view_component_matches (view, old_component);
1459 new_match = e_data_cal_view_component_matches (view, new_component);
1461 if (old_match && new_match)
1462 e_data_cal_view_notify_components_modified_1 (view, new_component);
1464 e_data_cal_view_notify_components_added_1 (view, new_component);
1465 else if (old_match) {
1467 ECalComponentId *id = e_cal_component_get_id (old_component);
1469 e_data_cal_view_notify_objects_removed_1 (view, id);
1471 e_cal_component_free_id (id);
1475 struct component_call_data {
1476 ECalComponent *old_component;
1477 ECalComponent *new_component;
1478 const ECalComponentId *id;
1482 call_match_and_notify_component (EDataCalView *view,
1485 struct component_call_data *cd = user_data;
1487 g_return_val_if_fail (user_data != NULL, FALSE);
1489 match_view_and_notify_component (view, cd->old_component, cd->new_component);
1495 * e_cal_backend_notify_component_modified:
1496 * @backend: an #ECalBackend
1497 * @old_component: the #ECalComponent before the modification
1498 * @new_component: the #ECalComponent after the modification
1500 * Notifies each of the backend's listeners about a modified object.
1502 * Like e_cal_backend_notify_object_modified() except takes an #ECalComponent
1503 * instead of an ical string representation and uses the #EDataCalView's
1504 * fields-of-interest to filter out unwanted information from ical strings
1505 * sent over the bus.
1510 e_cal_backend_notify_component_modified (ECalBackend *backend,
1511 /* const */ ECalComponent *old_component,
1512 /* const */ ECalComponent *new_component)
1514 ECalBackendPrivate *priv;
1515 struct component_call_data cd;
1517 priv = backend->priv;
1519 if (priv->notification_proxy) {
1520 e_cal_backend_notify_component_modified (priv->notification_proxy, old_component, new_component);
1524 cd.old_component = old_component;
1525 cd.new_component = new_component;
1528 e_cal_backend_foreach_view (backend, call_match_and_notify_component, &cd);
1532 component_removed_cb (EDataCalView *view,
1535 struct component_call_data *cd = user_data;
1537 g_return_val_if_fail (user_data != NULL, FALSE);
1539 if (cd->new_component == NULL) {
1540 /* if object == NULL, it means the object has been completely
1541 * removed from the backend */
1542 if (!cd->old_component || e_data_cal_view_component_matches (view, cd->old_component))
1543 e_data_cal_view_notify_objects_removed_1 (view, cd->id);
1545 match_view_and_notify_component (view, cd->old_component, cd->new_component);
1551 * e_cal_backend_notify_component_removed:
1552 * @backend: an #ECalBackend
1553 * @id: the Id of the removed object
1554 * @old_component: the removed component
1555 * @new_component: the component after the removal. This only applies to recurrent
1556 * appointments that had an instance removed. In that case, this function
1557 * notifies a modification instead of a removal.
1559 * Notifies each of the backend's listeners about a removed object.
1561 * Like e_cal_backend_notify_object_removed() except takes an #ECalComponent
1562 * instead of an ical string representation and uses the #EDataCalView's
1563 * fields-of-interest to filter out unwanted information from ical strings
1564 * sent over the bus.
1569 e_cal_backend_notify_component_removed (ECalBackend *backend,
1570 const ECalComponentId *id,
1571 /* const */ ECalComponent *old_component,
1572 /* const */ ECalComponent *new_component)
1574 ECalBackendPrivate *priv;
1575 struct component_call_data cd;
1577 priv = backend->priv;
1579 if (priv->notification_proxy) {
1580 e_cal_backend_notify_component_removed (priv->notification_proxy, id, old_component, new_component);
1584 cd.old_component = old_component;
1585 cd.new_component = new_component;
1588 e_cal_backend_foreach_view (backend, component_removed_cb, &cd);
1592 object_created_cb (EDataCalView *view,
1595 const gchar *calobj = data;
1597 if (e_data_cal_view_object_matches (view, calobj))
1598 e_data_cal_view_notify_objects_added_1 (view, calobj);
1604 * e_cal_backend_notify_object_created:
1605 * @backend: an #ECalBackend
1606 * @calobj: the newly created object
1608 * Notifies each of the backend's listeners about a new object.
1610 * #e_data_cal_notify_object_created() calls this for you. You only need to
1611 * call e_cal_backend_notify_object_created() yourself to report objects
1612 * created by non-EDS clients.
1614 * Deprecated: 3.4: Use e_cal_backend_notify_component_created() instead.
1617 e_cal_backend_notify_object_created (ECalBackend *backend,
1618 const gchar *calobj)
1620 ECalBackendPrivate *priv;
1622 priv = backend->priv;
1624 if (priv->notification_proxy) {
1625 e_cal_backend_notify_object_created (priv->notification_proxy, calobj);
1629 e_cal_backend_foreach_view (backend, object_created_cb, (gpointer) calobj);
1633 * e_cal_backend_notify_objects_added:
1637 * Deprecated: 3.4: Use e_data_cal_view_notify_objects_added() instead.
1640 e_cal_backend_notify_objects_added (ECalBackend *backend,
1642 const GSList *objects)
1644 e_data_cal_view_notify_objects_added (view, objects);
1648 match_view_and_notify_object (EDataCalView *view,
1649 const gchar *old_object,
1650 const gchar *object)
1652 gboolean old_match = FALSE, new_match = FALSE;
1655 old_match = e_data_cal_view_object_matches (view, old_object);
1657 new_match = e_data_cal_view_object_matches (view, object);
1658 if (old_match && new_match)
1659 e_data_cal_view_notify_objects_modified_1 (view, object);
1661 e_data_cal_view_notify_objects_added_1 (view, object);
1662 else if (old_match) {
1663 ECalComponent *comp = NULL;
1665 comp = e_cal_component_new_from_string (old_object);
1667 ECalComponentId *id = e_cal_component_get_id (comp);
1669 e_data_cal_view_notify_objects_removed_1 (view, id);
1671 e_cal_component_free_id (id);
1672 g_object_unref (comp);
1677 struct object_call_data {
1678 const gchar *old_object;
1679 const gchar *object;
1680 const ECalComponentId *id;
1684 call_match_and_notify_object (EDataCalView *view,
1687 struct object_call_data *cd = user_data;
1689 g_return_val_if_fail (user_data != NULL, FALSE);
1691 match_view_and_notify_object (view, cd->old_object, cd->object);
1697 * e_cal_backend_notify_object_modified:
1698 * @backend: an #ECalBackend
1699 * @old_object: iCalendar representation of the original form of the object
1700 * @object: iCalendar representation of the new form of the object
1702 * Notifies each of the backend's listeners about a modified object.
1704 * #e_data_cal_notify_object_modified() calls this for you. You only need to
1705 * call e_cal_backend_notify_object_modified() yourself to report objects
1706 * modified by non-EDS clients.
1708 * Deprecated: 3.4: Use e_cal_backend_notify_component_modified() instead.
1711 e_cal_backend_notify_object_modified (ECalBackend *backend,
1712 const gchar *old_object,
1713 const gchar *object)
1715 ECalBackendPrivate *priv;
1716 struct object_call_data cd;
1718 priv = backend->priv;
1720 if (priv->notification_proxy) {
1721 e_cal_backend_notify_object_modified (priv->notification_proxy, old_object, object);
1725 cd.old_object = old_object;
1729 e_cal_backend_foreach_view (backend, call_match_and_notify_object, &cd);
1733 * e_cal_backend_notify_objects_modified:
1737 * Deprecated: 3.4: Use e_data_cal_view_notify_objects_modified() instead.
1740 e_cal_backend_notify_objects_modified (ECalBackend *backend,
1742 const GSList *objects)
1744 e_data_cal_view_notify_objects_modified (view, objects);
1748 object_removed_cb (EDataCalView *view,
1751 struct object_call_data *cd = user_data;
1753 g_return_val_if_fail (user_data != NULL, FALSE);
1755 if (cd->object == NULL) {
1756 /* if object == NULL, it means the object has been completely
1757 * removed from the backend */
1758 if (!cd->old_object || e_data_cal_view_object_matches (view, cd->old_object))
1759 e_data_cal_view_notify_objects_removed_1 (view, cd->id);
1761 match_view_and_notify_object (view, cd->old_object, cd->object);
1767 * e_cal_backend_notify_object_removed:
1768 * @backend: an #ECalBackend
1769 * @id: the Id of the removed object
1770 * @old_object: iCalendar representation of the removed object
1771 * @new_object: iCalendar representation of the object after the removal. This
1772 * only applies to recurrent appointments that had an instance removed. In that
1773 * case, this function notifies a modification instead of a removal.
1775 * Notifies each of the backend's listeners about a removed object.
1777 * e_data_cal_notify_object_removed() calls this for you. You only need to
1778 * call e_cal_backend_notify_object_removed() yourself to report objects
1779 * removed by non-EDS clients.
1781 * Deprecated: 3.4: Use e_cal_backend_notify_component_removed() instead.
1784 e_cal_backend_notify_object_removed (ECalBackend *backend,
1785 const ECalComponentId *id,
1786 const gchar *old_object,
1787 const gchar *new_object)
1789 ECalBackendPrivate *priv;
1790 struct object_call_data cd;
1792 priv = backend->priv;
1794 if (priv->notification_proxy) {
1795 e_cal_backend_notify_object_removed (priv->notification_proxy, id, old_object, new_object);
1799 cd.old_object = old_object;
1800 cd.object = new_object;
1803 e_cal_backend_foreach_view (backend, object_removed_cb, &cd);
1807 * e_cal_backend_notify_objects_removed:
1811 * Deprecated: 3.4: Use e_data_cal_view_notify_objects_removed() instead.
1814 e_cal_backend_notify_objects_removed (ECalBackend *backend,
1818 e_data_cal_view_notify_objects_removed (view, ids);
1822 * e_cal_backend_notify_error:
1823 * @backend: an #ECalBackend
1824 * @message: Error message
1826 * Notifies each of the backend's listeners about an error
1829 e_cal_backend_notify_error (ECalBackend *backend,
1830 const gchar *message)
1832 ECalBackendPrivate *priv = backend->priv;
1835 if (priv->notification_proxy) {
1836 e_cal_backend_notify_error (priv->notification_proxy, message);
1840 g_mutex_lock (priv->clients_mutex);
1842 for (l = priv->clients; l; l = l->next)
1843 e_data_cal_report_error (l->data, message);
1845 g_mutex_unlock (priv->clients_mutex);
1849 * e_cal_backend_notify_readonly:
1850 * @backend: an #ECalBackend
1851 * @is_readonly: flag indicating readonly status
1853 * Notifies all backend's clients about the current readonly state.
1854 * Meant to be used by backend implementations.
1857 e_cal_backend_notify_readonly (ECalBackend *backend,
1858 gboolean is_readonly)
1860 ECalBackendPrivate *priv;
1863 priv = backend->priv;
1864 priv->readonly = is_readonly;
1866 if (priv->notification_proxy) {
1867 e_cal_backend_notify_readonly (priv->notification_proxy, is_readonly);
1871 g_mutex_lock (priv->clients_mutex);
1873 for (l = priv->clients; l; l = l->next)
1874 e_data_cal_report_readonly (l->data, is_readonly);
1876 g_mutex_unlock (priv->clients_mutex);
1880 * e_cal_backend_notify_online:
1881 * @backend: an #ECalBackend
1882 * @is_online: flag indicating whether @backend is connected and online
1884 * Notifies clients of @backend's connection status indicated by @is_online.
1885 * Meant to be used by backend implementations.
1890 e_cal_backend_notify_online (ECalBackend *backend,
1893 ECalBackendPrivate *priv;
1896 priv = backend->priv;
1898 if (priv->notification_proxy) {
1899 e_cal_backend_notify_online (priv->notification_proxy, is_online);
1903 g_mutex_lock (priv->clients_mutex);
1905 for (clients = priv->clients; clients != NULL; clients = g_slist_next (clients))
1906 e_data_cal_report_online (E_DATA_CAL (clients->data), is_online);
1908 g_mutex_unlock (priv->clients_mutex);
1912 * e_cal_backend_notify_opened:
1913 * @backend: an #ECalBackend
1914 * @error: a #GError corresponding to the error encountered during
1915 * the opening phase. Use %NULL for success. The @error is freed
1916 * automatically if not %NULL.
1918 * Notifies clients that @backend finished its opening phase.
1919 * See e_cal_backend_open() for more information how the opening
1920 * phase works. Calling this function changes 'opening' property,
1921 * same as 'opened'. 'opening' is set to %FALSE and the backend
1922 * is considered 'opened' only if the @error is %NULL.
1924 * See also: e_cal_backend_respond_opened()
1926 * Note: The @error is freed automatically if not %NULL.
1928 * Meant to be used by backend implementations.
1933 e_cal_backend_notify_opened (ECalBackend *backend,
1936 ECalBackendPrivate *priv;
1939 priv = backend->priv;
1940 g_mutex_lock (priv->clients_mutex);
1942 priv->opening = FALSE;
1943 priv->opened = error == NULL;
1945 for (clients = priv->clients; clients != NULL; clients = g_slist_next (clients))
1946 e_data_cal_report_opened (E_DATA_CAL (clients->data), error);
1948 g_mutex_unlock (priv->clients_mutex);
1951 g_error_free (error);
1955 * e_cal_backend_notify_property_changed:
1956 * @backend: an #ECalBackend
1957 * @prop_name: property name, which changed
1958 * @prop_value: new property value
1960 * Notifies client about property value change.
1965 e_cal_backend_notify_property_changed (ECalBackend *backend,
1966 const gchar *prop_name,
1967 const gchar *prop_value)
1969 ECalBackendPrivate *priv;
1972 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1973 g_return_if_fail (prop_name != NULL);
1974 g_return_if_fail (*prop_name != '\0');
1975 g_return_if_fail (prop_value != NULL);
1977 priv = backend->priv;
1978 g_mutex_lock (priv->clients_mutex);
1980 for (clients = priv->clients; clients != NULL; clients = g_slist_next (clients))
1981 e_data_cal_report_backend_property_changed (E_DATA_CAL (clients->data), prop_name, prop_value);
1983 g_mutex_unlock (priv->clients_mutex);
1987 * e_cal_backend_respond_opened:
1988 * @backend: an #ECalBackend
1989 * @cal: an #EDataCal
1990 * @opid: an operation ID
1991 * @error: result error; can be %NULL, if it isn't then it's automatically freed
1993 * This is a replacement for e_data_cal_respond_open() for cases where
1994 * the finish of 'open' method call also finishes backend opening phase.
1995 * This function covers calling of both e_cal_backend_notify_opened() and
1996 * e_data_cal_respond_open() with the same @error.
1998 * See e_cal_backend_open() for more details how the opening phase works.
2003 e_cal_backend_respond_opened (ECalBackend *backend,
2008 GError *copy = NULL;
2010 g_return_if_fail (backend != NULL);
2011 g_return_if_fail (E_IS_CAL_BACKEND (backend));
2012 g_return_if_fail (cal != NULL);
2013 g_return_if_fail (opid != 0);
2016 copy = g_error_copy (error);
2018 e_cal_backend_notify_opened (backend, copy);
2019 e_data_cal_respond_open (cal, opid, error);
2023 * e_cal_backend_empty_cache:
2024 * @backend: an #ECalBackend
2025 * @cache: Backend's cache to empty.
2027 * Empties backend's cache with all notifications and so on, thus all listening
2028 * will know there is nothing in this backend.
2033 e_cal_backend_empty_cache (ECalBackend *backend,
2034 ECalBackendCache *cache)
2036 GList *comps_in_cache;
2038 g_return_if_fail (backend != NULL);
2039 g_return_if_fail (E_IS_CAL_BACKEND (backend));
2044 g_return_if_fail (E_IS_CAL_BACKEND_CACHE (cache));
2046 e_file_cache_freeze_changes (E_FILE_CACHE (cache));
2048 for (comps_in_cache = e_cal_backend_cache_get_components (cache);
2050 comps_in_cache = comps_in_cache->next) {
2051 ECalComponentId *id;
2052 ECalComponent *comp = comps_in_cache->data;
2054 id = e_cal_component_get_id (comp);
2056 e_cal_backend_cache_remove_component (cache, id->uid, id->rid);
2058 e_cal_backend_notify_component_removed (backend, id, comp, NULL);
2060 e_cal_component_free_id (id);
2061 g_object_unref (comp);
2064 g_list_free (comps_in_cache);
2066 e_file_cache_thaw_changes (E_FILE_CACHE (cache));