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 EDC_ERROR(_code) e_data_cal_create_error (_code, NULL)
34 #define EDC_OPENING_ERROR e_data_cal_create_error (Busy, _("Cannot process, calendar backend is opening"))
35 #define EDC_NOT_OPENED_ERROR e_data_cal_create_error (NotOpened, NULL)
37 /* Private part of the CalBackend structure */
38 struct _ECalBackendPrivate {
39 /* The source for this backend */
41 /* The kind of components for this backend */
42 icalcomponent_kind kind;
44 gboolean opening, opened, readonly, removed, online;
46 /* URI, from source. This is cached, since we return const. */
51 /* List of Cal objects */
52 GMutex *clients_mutex;
58 /* ECalBackend to pass notifications on to */
59 ECalBackend *notification_proxy;
78 static guint signals[LAST_SIGNAL];
80 static void e_cal_backend_remove_client_private (ECalBackend *backend, EDataCal *cal, gboolean weak_unref);
82 G_DEFINE_TYPE (ECalBackend, e_cal_backend, G_TYPE_OBJECT);
85 source_changed_cb (ESource *source, ECalBackend *backend)
87 ECalBackendPrivate *priv;
90 g_return_if_fail (source != NULL);
91 g_return_if_fail (backend != NULL);
92 g_return_if_fail (E_IS_CAL_BACKEND (backend));
95 g_return_if_fail (priv != NULL);
96 g_return_if_fail (priv->source == source);
98 suri = e_source_get_uri (priv->source);
99 if (!priv->uri || (suri && !g_str_equal (priv->uri, suri))) {
108 cal_backend_set_default_cache_dir (ECalBackend *backend)
111 icalcomponent_kind kind;
112 const gchar *component_type;
113 const gchar *user_cache_dir;
117 user_cache_dir = e_get_user_cache_dir ();
119 kind = e_cal_backend_get_kind (backend);
120 source = e_cal_backend_get_source (backend);
123 case ICAL_VEVENT_COMPONENT:
124 component_type = "calendar";
126 case ICAL_VTODO_COMPONENT:
127 component_type = "tasks";
129 case ICAL_VJOURNAL_COMPONENT:
130 component_type = "memos";
133 g_return_if_reached ();
136 /* Mangle the URI to not contain invalid characters. */
137 mangled_uri = g_strdelimit (e_source_get_uri (source), ":/", '_');
139 filename = g_build_filename (
140 user_cache_dir, component_type, mangled_uri, NULL);
141 e_cal_backend_set_cache_dir (backend, filename);
144 g_free (mangled_uri);
148 cal_backend_set_source (ECalBackend *backend,
151 if (backend->priv->source != NULL) {
152 g_signal_handlers_disconnect_matched (backend->priv->source, G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, 0, 0, NULL, source_changed_cb, backend);
153 g_object_unref (backend->priv->source);
158 g_object_ref (source), "changed",
159 G_CALLBACK (source_changed_cb), backend);
161 backend->priv->source = source;
164 if (source != NULL) {
165 g_free (backend->priv->uri);
166 backend->priv->uri = e_source_get_uri (source);
171 cal_backend_set_uri (ECalBackend *backend,
174 /* ESource's URI gets priority. */
175 if (backend->priv->source == NULL) {
176 g_free (backend->priv->uri);
177 backend->priv->uri = g_strdup (uri);
182 cal_backend_set_kind (ECalBackend *backend,
183 icalcomponent_kind kind)
185 backend->priv->kind = kind;
189 cal_backend_get_backend_property (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *prop_name)
191 g_return_if_fail (backend != NULL);
192 g_return_if_fail (E_IS_CAL_BACKEND (backend));
193 g_return_if_fail (cal != NULL);
194 g_return_if_fail (prop_name != NULL);
196 if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_OPENED)) {
197 e_data_cal_respond_get_backend_property (cal, opid, NULL, e_cal_backend_is_opened (backend) ? "TRUE" : "FALSE");
198 } else if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_OPENING)) {
199 e_data_cal_respond_get_backend_property (cal, opid, NULL, e_cal_backend_is_opening (backend) ? "TRUE" : "FALSE");
200 } else if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_ONLINE)) {
201 e_data_cal_respond_get_backend_property (cal, opid, NULL, e_cal_backend_is_online (backend) ? "TRUE" : "FALSE");
202 } else if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_READONLY)) {
203 e_data_cal_respond_get_backend_property (cal, opid, NULL, e_cal_backend_is_readonly (backend) ? "TRUE" : "FALSE");
204 } else if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CACHE_DIR)) {
205 e_data_cal_respond_get_backend_property (cal, opid, NULL, e_cal_backend_get_cache_dir (backend));
207 e_data_cal_respond_get_backend_property (cal, opid, e_data_cal_create_error_fmt (NotSupported, _("Unknown calendar property '%s'"), prop_name), NULL);
212 cal_backend_set_backend_property (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *prop_name, const gchar *prop_value)
214 g_return_if_fail (backend != NULL);
215 g_return_if_fail (E_IS_CAL_BACKEND (backend));
216 g_return_if_fail (cal != NULL);
217 g_return_if_fail (prop_name != NULL);
219 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));
223 cal_backend_set_property (GObject *object,
228 switch (property_id) {
230 e_cal_backend_set_cache_dir (
231 E_CAL_BACKEND (object),
232 g_value_get_string (value));
235 cal_backend_set_kind (
236 E_CAL_BACKEND (object),
237 g_value_get_ulong (value));
240 cal_backend_set_source (
241 E_CAL_BACKEND (object),
242 g_value_get_object (value));
245 cal_backend_set_uri (
246 E_CAL_BACKEND (object),
247 g_value_get_string (value));
251 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
255 cal_backend_get_property (GObject *object,
260 switch (property_id) {
263 value, e_cal_backend_get_cache_dir (
264 E_CAL_BACKEND (object)));
268 value, e_cal_backend_get_kind (
269 E_CAL_BACKEND (object)));
273 value, e_cal_backend_get_source (
274 E_CAL_BACKEND (object)));
278 value, e_cal_backend_get_uri (
279 E_CAL_BACKEND (object)));
283 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
287 cal_backend_finalize (GObject *object)
289 ECalBackendPrivate *priv;
291 priv = E_CAL_BACKEND (object)->priv;
293 g_assert (priv->clients == NULL);
295 g_slist_free (priv->views);
296 /* should be NULL, anyway */
297 g_slist_free (priv->clients);
299 g_mutex_free (priv->clients_mutex);
300 g_mutex_free (priv->views_mutex);
303 g_free (priv->cache_dir);
306 g_signal_handlers_disconnect_matched (priv->source, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, object);
307 g_object_unref (priv->source);
310 /* Chain up to parent's finalize() method. */
311 G_OBJECT_CLASS (e_cal_backend_parent_class)->finalize (object);
315 cal_backend_constructed (GObject *object)
317 cal_backend_set_default_cache_dir (E_CAL_BACKEND (object));
319 G_OBJECT_CLASS (e_cal_backend_parent_class)->constructed (object);
323 e_cal_backend_class_init (ECalBackendClass *klass)
325 GObjectClass *object_class;
327 g_type_class_add_private (klass, sizeof (ECalBackendPrivate));
329 object_class = G_OBJECT_CLASS (klass);
330 object_class->set_property = cal_backend_set_property;
331 object_class->get_property = cal_backend_get_property;
332 object_class->finalize = cal_backend_finalize;
333 object_class->constructed = cal_backend_constructed;
335 klass->get_backend_property = cal_backend_get_backend_property;
336 klass->set_backend_property = cal_backend_set_backend_property;
338 g_object_class_install_property (
341 g_param_spec_string (
348 g_object_class_install_property (
356 ICAL_XLICMIMEPART_COMPONENT,
359 G_PARAM_CONSTRUCT_ONLY));
361 g_object_class_install_property (
364 g_param_spec_object (
370 G_PARAM_CONSTRUCT_ONLY));
372 g_object_class_install_property (
375 g_param_spec_string (
381 G_PARAM_CONSTRUCT_ONLY));
383 signals[LAST_CLIENT_GONE] = g_signal_new (
385 G_TYPE_FROM_CLASS (klass),
387 G_STRUCT_OFFSET (ECalBackendClass, last_client_gone),
389 g_cclosure_marshal_VOID__VOID,
394 e_cal_backend_init (ECalBackend *backend)
396 backend->priv = G_TYPE_INSTANCE_GET_PRIVATE (
397 backend, E_TYPE_CAL_BACKEND, ECalBackendPrivate);
399 backend->priv->clients = NULL;
400 backend->priv->clients_mutex = g_mutex_new ();
402 backend->priv->views = NULL;
403 backend->priv->views_mutex = g_mutex_new ();
405 backend->priv->readonly = TRUE;
406 backend->priv->online = FALSE;
410 * e_cal_backend_get_source:
411 * @backend: an #ECalBackend
413 * Gets the #ESource associated with the given backend.
415 * Returns: The #ESource for the backend.
418 e_cal_backend_get_source (ECalBackend *backend)
420 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), NULL);
422 return backend->priv->source;
426 * e_cal_backend_get_uri:
427 * @backend: an #ECalBackend
429 * Queries the URI of a calendar backend, which must already have an open
432 * Returns: The URI where the calendar is stored.
435 e_cal_backend_get_uri (ECalBackend *backend)
437 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), NULL);
439 return backend->priv->uri;
443 * e_cal_backend_get_kind:
444 * @backend: an #ECalBackend
446 * Gets the kind of components the given backend stores.
448 * Returns: The kind of components for this backend.
451 e_cal_backend_get_kind (ECalBackend *backend)
453 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), ICAL_NO_COMPONENT);
455 return backend->priv->kind;
459 * e_cal_backend_is_online:
460 * @backend: an #ECalBackend
462 * Returns: Whether is backend online.
465 e_cal_backend_is_online (ECalBackend *backend)
467 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), FALSE);
469 return backend->priv->online;
473 * e_cal_backend_is_opened:
474 * @backend: an #ECalBackend
476 * Checks if @backend's storage has been opened (and
477 * authenticated, if necessary) and the backend itself
478 * is ready for accessing. This property is changed automatically
479 * within call of e_cal_backend_notify_opened().
481 * Returns: %TRUE if fully opened, %FALSE otherwise.
484 e_cal_backend_is_opened (ECalBackend *backend)
486 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), FALSE);
488 return backend->priv->opened;
492 * e_cal_backend_is_opening::
493 * @backend: an #ECalBackend
495 * Checks if @backend is processing its opening phase, which
496 * includes everything since the e_cal_backend_open() call,
497 * through authentication, up to e_cal_backend_notify_opened().
498 * This property is managed automatically and the backend deny
499 * every operation except of cancel and authenticate_user while
500 * it is being opening.
502 * Returns: %TRUE if opening phase is in the effect, %FALSE otherwise.
505 e_cal_backend_is_opening (ECalBackend *backend)
507 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), FALSE);
509 return backend->priv->opening;
513 * e_cal_backend_is_readonly:
514 * @backend: an #ECalBackend
516 * Returns: Whether is backend read-only. This value is the last used
517 * in a call of e_cal_backend_notify_readonly().
520 e_cal_backend_is_readonly (ECalBackend *backend)
522 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), FALSE);
524 return backend->priv->readonly;
528 * e_cal_backend_is_removed:
529 * @backend: an #ECalBackend
531 * Checks if @backend has been removed from its physical storage.
533 * Returns: %TRUE if @backend has been removed, %FALSE otherwise.
536 e_cal_backend_is_removed (ECalBackend *backend)
538 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), FALSE);
540 return backend->priv->removed;
544 * e_cal_backend_set_is_removed:
545 * @backend: an #ECalBackend
546 * @is_removed: A flag indicating whether the backend's storage was removed
548 * Sets the flag indicating whether @backend was removed to @is_removed.
549 * Meant to be used by backend implementations.
552 e_cal_backend_set_is_removed (ECalBackend *backend, gboolean is_removed)
554 g_return_if_fail (E_IS_CAL_BACKEND (backend));
556 backend->priv->removed = is_removed;
560 * e_cal_backend_get_cache_dir:
561 * @backend: an #ECalBackend
563 * Returns the cache directory for the given backend.
565 * Returns: the cache directory for the backend
570 e_cal_backend_get_cache_dir (ECalBackend *backend)
572 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), NULL);
574 return backend->priv->cache_dir;
578 * e_cal_backend_set_cache_dir:
579 * @backend: an #ECalBackend
580 * @cache_dir: a local cache directory
582 * Sets the cache directory for the given backend.
584 * Note that #ECalBackend is initialized with a usable default based on
585 * #ECalBackend:source and #ECalBackend:kind properties. Backends should
586 * not override the default without good reason.
591 e_cal_backend_set_cache_dir (ECalBackend *backend,
592 const gchar *cache_dir)
594 g_return_if_fail (E_IS_CAL_BACKEND (backend));
595 g_return_if_fail (cache_dir != NULL);
597 g_free (backend->priv->cache_dir);
598 backend->priv->cache_dir = g_strdup (cache_dir);
600 g_object_notify (G_OBJECT (backend), "cache-dir");
604 * e_cal_backend_get_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 get value of; cannot be NULL
611 * Calls the get_backend_property method on the given backend.
612 * This might be finished with e_data_cal_respond_get_backend_property().
613 * Default implementation takes care of common properties and returns
614 * an 'unsupported' error for any unknown properties. The subclass may
615 * always call this default implementation for properties which fetching
616 * it doesn't overwrite.
621 e_cal_backend_get_backend_property (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *prop_name)
623 g_return_if_fail (backend != NULL);
624 g_return_if_fail (E_IS_CAL_BACKEND (backend));
625 g_return_if_fail (prop_name != NULL);
626 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_backend_property != NULL);
628 (* E_CAL_BACKEND_GET_CLASS (backend)->get_backend_property) (backend, cal, opid, cancellable, prop_name);
632 * e_cal_backend_set_backend_property:
633 * @backend: an #ECalBackend
635 * @opid: the ID to use for this operation
636 * @cancellable: a #GCancellable for the operation
637 * @prop_name: property name to change; cannot be NULL
638 * @prop_value: value to set to @prop_name; cannot be NULL
640 * Calls the set_backend_property method on the given backend.
641 * This might be finished with e_data_cal_respond_set_backend_property().
642 * Default implementation simply returns an 'unsupported' error.
643 * The subclass may always call this default implementation for properties
644 * which fetching it doesn't overwrite.
649 e_cal_backend_set_backend_property (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *prop_name, const gchar *prop_value)
651 g_return_if_fail (backend != NULL);
652 g_return_if_fail (E_IS_CAL_BACKEND (backend));
653 g_return_if_fail (prop_name != NULL);
654 g_return_if_fail (prop_value != NULL);
655 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->set_backend_property != NULL);
657 (* E_CAL_BACKEND_GET_CLASS (backend)->set_backend_property) (backend, cal, opid, cancellable, prop_name, prop_value);
661 cal_destroy_cb (gpointer data, GObject *where_cal_was)
663 e_cal_backend_remove_client_private (E_CAL_BACKEND (data),
664 (EDataCal *) where_cal_was, FALSE);
668 * e_cal_backend_add_client:
669 * @backend: an #ECalBackend
672 * Adds a new client to the given backend. For any event, the backend will
673 * notify all clients added via this function.
676 e_cal_backend_add_client (ECalBackend *backend, EDataCal *cal)
678 ECalBackendPrivate *priv;
680 g_return_if_fail (backend != NULL);
681 g_return_if_fail (E_IS_CAL_BACKEND (backend));
682 g_return_if_fail (cal != NULL);
683 g_return_if_fail (E_IS_DATA_CAL (cal));
685 priv = backend->priv;
687 g_object_weak_ref (G_OBJECT (cal), cal_destroy_cb, backend);
689 g_mutex_lock (priv->clients_mutex);
690 priv->clients = g_slist_append (priv->clients, cal);
691 g_mutex_unlock (priv->clients_mutex);
695 e_cal_backend_remove_client_private (ECalBackend *backend, EDataCal *cal, gboolean weak_unref)
697 ECalBackendPrivate *priv;
699 /* XXX this needs a bit more thinking wrt the mutex - we
700 should be holding it when we check to see if clients is
702 g_return_if_fail (backend != NULL);
703 g_return_if_fail (E_IS_CAL_BACKEND (backend));
704 g_return_if_fail (cal != NULL);
705 g_return_if_fail (E_IS_DATA_CAL (cal));
707 priv = backend->priv;
710 g_object_weak_unref (G_OBJECT (cal), cal_destroy_cb, backend);
713 g_mutex_lock (priv->clients_mutex);
714 priv->clients = g_slist_remove (priv->clients, cal);
715 g_mutex_unlock (priv->clients_mutex);
717 /* When all clients go away, notify the parent factory about it so that
718 * it may decide whether to kill the backend or not.
721 g_signal_emit (backend, signals[LAST_CLIENT_GONE], 0);
725 * e_cal_backend_remove_client:
726 * @backend: an #ECalBackend
729 * Removes a client from the list of connected clients to the given backend.
732 e_cal_backend_remove_client (ECalBackend *backend, EDataCal *cal)
734 e_cal_backend_remove_client_private (backend, cal, TRUE);
738 * e_cal_backend_add_view:
739 * @backend: an #ECalBackend
740 * @view: An #EDataCalView object.
742 * Adds a view to the list of live views being run by the given backend.
743 * Doing so means that any listener on the view will get notified of any
744 * change that affect the live view.
747 e_cal_backend_add_view (ECalBackend *backend, EDataCalView *view)
749 g_return_if_fail (backend != NULL);
750 g_return_if_fail (E_IS_CAL_BACKEND (backend));
752 g_mutex_lock (backend->priv->views_mutex);
754 backend->priv->views = g_slist_append (backend->priv->views, view);
756 g_mutex_unlock (backend->priv->views_mutex);
760 * e_cal_backend_remove_view
761 * @backend: an #ECalBackend
762 * @view: An #EDataCalView object, previously added with @ref e_cal_backend_add_view.
764 * Removes view from the list of live views for the backend.
769 e_cal_backend_remove_view (ECalBackend *backend, EDataCalView *view)
771 g_return_if_fail (backend != NULL);
772 g_return_if_fail (E_IS_CAL_BACKEND (backend));
774 g_mutex_lock (backend->priv->views_mutex);
776 backend->priv->views = g_slist_remove (backend->priv->views, view);
778 g_mutex_unlock (backend->priv->views_mutex);
782 * e_cal_backend_foreach_view:
783 * @backend: an #ECalBackend
784 * @callback: callback to call
785 * @user_data: user_data passed into the @callback
787 * Calls @callback for each known calendar view of this @backend.
788 * @callback returns %FALSE to stop further processing.
791 e_cal_backend_foreach_view (ECalBackend *backend, gboolean (* callback) (EDataCalView *view, gpointer user_data), gpointer user_data)
795 gboolean stop = FALSE;
797 g_return_if_fail (backend != NULL);
798 g_return_if_fail (callback != NULL);
800 g_mutex_lock (backend->priv->views_mutex);
802 for (views = backend->priv->views; views && !stop; views = views->next) {
803 view = E_DATA_CAL_VIEW (views->data);
806 stop = !callback (view, user_data);
807 g_object_unref (view);
810 g_mutex_unlock (backend->priv->views_mutex);
814 * e_cal_backend_set_notification_proxy:
815 * @backend: an #ECalBackend
816 * @proxy: The calendar backend to act as notification proxy.
818 * Sets the backend that will act as notification proxy for the given backend.
821 e_cal_backend_set_notification_proxy (ECalBackend *backend, ECalBackend *proxy)
823 g_return_if_fail (E_IS_CAL_BACKEND (backend));
825 backend->priv->notification_proxy = proxy;
829 * e_cal_backend_set_online:
830 * @backend: A calendar backend
831 * @is_online: Whether is online
833 * Sets the online mode of the calendar
836 e_cal_backend_set_online (ECalBackend *backend, gboolean is_online)
838 g_return_if_fail (backend != NULL);
839 g_return_if_fail (E_IS_CAL_BACKEND (backend));
840 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->set_online != NULL);
842 (* E_CAL_BACKEND_GET_CLASS (backend)->set_online) (backend, is_online);
846 * e_cal_backend_open:
847 * @backend: an #ECalBackend
849 * @opid: the ID to use for this operation
850 * @cancellable: a #GCancellable for the operation
851 * @only_if_exists: Whether the calendar should be opened only if it already
852 * exists. If FALSE, a new calendar will be created when the specified @uri
855 * Opens a calendar backend with data from a calendar stored at the specified URI.
856 * This might be finished with e_data_cal_respond_open() or e_cal_backend_respond_opened(),
857 * though the overall opening phase finishes only after call
858 * of e_cal_backend_notify_opened() after which call the backend
859 * is either fully opened (including authentication against (remote)
860 * server/storage) or an error was encountered during this opening phase.
861 * 'opened' and 'opening' properties are updated automatically.
862 * The backend refuses all other operations until the opening phase is finished.
864 * The e_cal_backend_notify_opened() is called either from this function
865 * or from e_cal_backend_authenticate_user(), or after necessary steps
866 * initiated by these two functions.
868 * The opening phase usually works like this:
869 * 1) client requests open for the backend
870 * 2) server receives this request and calls e_cal_backend_open() - the opening phase begun
871 * 3) either the backend is opened during this call, and notifies client
872 * with e_cal_backend_notify_opened() about that. This is usually
873 * for local backends; their opening phase is finished
874 * 4) or the backend requires authentication, thus it notifies client
875 * about that with e_cal_backend_notify_auth_required() and is
876 * waiting for credentials, which will be received from client
877 * by e_cal_backend_authenticate_user() call. Backend's opening
878 * phase is still running in this case, thus it doesn't call
879 * e_cal_backend_notify_opened() within e_cal_backend_open() call.
880 * 5) when backend receives credentials in e_cal_backend_authenticate_user()
881 * then it tries to authenticate against a server/storage with them
882 * and only after it knows result of the authentication, whether user
883 * was or wasn't authenticated, it notifies client with the result
884 * by e_cal_backend_notify_opened() and it's opening phase is
885 * finished now. If there was no error returned then the backend is
886 * considered opened, otherwise it's considered closed. Use AuthenticationFailed
887 * error when the given credentials were rejected by the server/store, which
888 * will result in a re-prompt on the client side, otherwise use AuthenticationRequired
889 * if there was anything wrong with the given credentials. Set error's
890 * message to a reason for a re-prompt, it'll be shown to a user.
891 * 6) client checks error returned from e_cal_backend_notify_opened() and
892 * reprompts for a password if it was AuthenticationFailed. Otherwise
893 * considers backend opened based on the error presence (no error means success).
895 * In any case, the call of e_cal_backend_open() should be always finished
896 * with e_data_cal_respond_open(), which has no influence on the opening phase,
897 * or alternatively with e_cal_backend_respond_opened(). Never use authentication
898 * errors in e_data_cal_respond_open() to notify the client the authentication is
899 * required, there is e_cal_backend_notify_auth_required() for this.
902 e_cal_backend_open (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, gboolean only_if_exists)
904 g_return_if_fail (backend != NULL);
905 g_return_if_fail (E_IS_CAL_BACKEND (backend));
906 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->open != NULL);
908 g_mutex_lock (backend->priv->clients_mutex);
910 if (e_cal_backend_is_opened (backend)) {
911 g_mutex_unlock (backend->priv->clients_mutex);
913 e_data_cal_report_readonly (cal, backend->priv->readonly);
914 e_data_cal_report_online (cal, backend->priv->online);
916 e_cal_backend_respond_opened (backend, cal, opid, NULL);
917 } else if (e_cal_backend_is_opening (backend)) {
918 g_mutex_unlock (backend->priv->clients_mutex);
920 e_data_cal_respond_open (cal, opid, EDC_OPENING_ERROR);
922 backend->priv->opening = TRUE;
923 g_mutex_unlock (backend->priv->clients_mutex);
925 (* E_CAL_BACKEND_GET_CLASS (backend)->open) (backend, cal, opid, cancellable, only_if_exists);
930 * e_cal_backend_authenticate_user:
931 * @backend: an #ECalBackend
932 * @cancellable: a #GCancellable for the operation
933 * @credentials: #ECredentials to use for authentication
935 * Notifies @backend about @credentials provided by user to use
936 * for authentication. This notification is usually called during
937 * opening phase as a response to e_cal_backend_notify_auth_required()
938 * on the client side and it results in setting property 'opening' to %TRUE
939 * unless the backend is already opened. This function finishes opening
940 * phase, thus it should be finished with e_cal_backend_notify_opened().
942 * See information at e_cal_backend_open() for more details
943 * how the opening phase works.
946 e_cal_backend_authenticate_user (ECalBackend *backend,
947 GCancellable *cancellable,
948 ECredentials *credentials)
950 g_return_if_fail (E_IS_CAL_BACKEND (backend));
951 g_return_if_fail (credentials != NULL);
952 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->authenticate_user);
954 if (!e_cal_backend_is_opened (backend))
955 backend->priv->opening = TRUE;
957 (* E_CAL_BACKEND_GET_CLASS (backend)->authenticate_user) (backend, cancellable, credentials);
961 * e_cal_backend_remove:
962 * @backend: an #ECalBackend
964 * @opid: the ID to use for this operation
965 * @cancellable: a #GCancellable for the operation
967 * Removes the calendar being accessed by the given backend.
968 * This might be finished with e_data_cal_respond_remove().
971 e_cal_backend_remove (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable)
973 g_return_if_fail (backend != NULL);
974 g_return_if_fail (E_IS_CAL_BACKEND (backend));
975 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->remove != NULL);
977 if (e_cal_backend_is_opening (backend))
978 e_data_cal_respond_remove (cal, opid, EDC_OPENING_ERROR);
980 (* E_CAL_BACKEND_GET_CLASS (backend)->remove) (backend, cal, opid, cancellable);
984 * e_cal_backend_refresh:
985 * @backend: an #ECalBackend
987 * @opid: the ID to use for this operation
988 * @cancellable: a #GCancellable for the operation
990 * Refreshes the calendar being accessed by the given backend.
991 * This might be finished with e_data_cal_respond_refresh(),
992 * and it might be called as soon as possible; it doesn't mean
993 * that the refreshing is done after calling that, the backend
994 * is only notifying client whether it started the refresh process
1000 e_cal_backend_refresh (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable)
1002 g_return_if_fail (backend != NULL);
1003 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1005 if (e_cal_backend_is_opening (backend))
1006 e_data_cal_respond_refresh (cal, opid, EDC_OPENING_ERROR);
1007 else if (!E_CAL_BACKEND_GET_CLASS (backend)->refresh)
1008 e_data_cal_respond_refresh (cal, opid, EDC_ERROR (UnsupportedMethod));
1009 else if (!e_cal_backend_is_opened (backend))
1010 e_data_cal_respond_refresh (cal, opid, EDC_NOT_OPENED_ERROR);
1012 (* E_CAL_BACKEND_GET_CLASS (backend)->refresh) (backend, cal, opid, cancellable);
1016 * e_cal_backend_get_object:
1017 * @backend: an #ECalBackend
1018 * @cal: an #EDataCal
1019 * @opid: the ID to use for this operation
1020 * @cancellable: a #GCancellable for the operation
1021 * @uid: Unique identifier for a calendar object.
1022 * @rid: ID for the object's recurrence to get.
1024 * Queries a calendar backend for a calendar object based on its unique
1025 * identifier and its recurrence ID (if a recurrent appointment).
1026 * This might be finished with e_data_cal_respond_get_object().
1029 e_cal_backend_get_object (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *uid, const gchar *rid)
1031 g_return_if_fail (backend != NULL);
1032 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1033 g_return_if_fail (uid != NULL);
1034 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_object != NULL);
1036 if (e_cal_backend_is_opening (backend))
1037 e_data_cal_respond_get_object (cal, opid, EDC_OPENING_ERROR, NULL);
1038 else if (!e_cal_backend_is_opened (backend))
1039 e_data_cal_respond_get_object (cal, opid, EDC_NOT_OPENED_ERROR, NULL);
1041 (* E_CAL_BACKEND_GET_CLASS (backend)->get_object) (backend, cal, opid, cancellable, uid, rid);
1045 * e_cal_backend_get_object_list:
1046 * @backend: an #ECalBackend
1047 * @cal: an #EDataCal
1048 * @opid: the ID to use for this operation
1049 * @cancellable: a #GCancellable for the operation
1050 * @sexp: Expression to search for.
1052 * Calls the get_object_list method on the given backend.
1053 * This might be finished with e_data_cal_respond_get_object_list().
1056 e_cal_backend_get_object_list (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *sexp)
1058 g_return_if_fail (backend != NULL);
1059 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1060 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_object_list != NULL);
1062 if (e_cal_backend_is_opening (backend))
1063 e_data_cal_respond_get_object_list (cal, opid, EDC_OPENING_ERROR, NULL);
1064 else if (!e_cal_backend_is_opened (backend))
1065 e_data_cal_respond_get_object_list (cal, opid, EDC_NOT_OPENED_ERROR, NULL);
1067 (* E_CAL_BACKEND_GET_CLASS (backend)->get_object_list) (backend, cal, opid, cancellable, sexp);
1071 * e_cal_backend_get_free_busy:
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 * @users: List of users to get free/busy information for.
1077 * @start: Start time for query.
1078 * @end: End time for query.
1080 * Gets a free/busy object for the given time interval. Client side is
1081 * notified about free/busy objects throug e_data_cal_report_free_busy_data().
1082 * This might be finished with e_data_cal_respond_get_free_busy().
1085 e_cal_backend_get_free_busy (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const GSList *users, time_t start, time_t end)
1087 g_return_if_fail (backend != NULL);
1088 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1089 g_return_if_fail (start != -1 && end != -1);
1090 g_return_if_fail (start <= end);
1091 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_free_busy != NULL);
1093 if (e_cal_backend_is_opening (backend))
1094 e_data_cal_respond_get_free_busy (cal, opid, EDC_OPENING_ERROR);
1095 else if (!e_cal_backend_is_opened (backend))
1096 e_data_cal_respond_get_free_busy (cal, opid, EDC_NOT_OPENED_ERROR);
1098 (* E_CAL_BACKEND_GET_CLASS (backend)->get_free_busy) (backend, cal, opid, cancellable, users, start, end);
1102 * e_cal_backend_create_object:
1103 * @backend: an #ECalBackend
1104 * @cal: an #EDataCal
1105 * @opid: the ID to use for this operation
1106 * @cancellable: a #GCancellable for the operation
1107 * @calobj: The object to create.
1109 * Calls the create_object method on the given backend.
1110 * This might be finished with e_data_cal_respond_create_object().
1113 e_cal_backend_create_object (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *calobj)
1115 g_return_if_fail (backend != NULL);
1116 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1117 g_return_if_fail (calobj != NULL);
1119 if (e_cal_backend_is_opening (backend))
1120 e_data_cal_respond_create_object (cal, opid, EDC_OPENING_ERROR, NULL, NULL);
1121 else if (!E_CAL_BACKEND_GET_CLASS (backend)->create_object)
1122 e_data_cal_respond_create_object (cal, opid, EDC_ERROR (UnsupportedMethod), NULL, NULL);
1123 else if (!e_cal_backend_is_opened (backend))
1124 e_data_cal_respond_create_object (cal, opid, EDC_NOT_OPENED_ERROR, NULL, NULL);
1126 (* E_CAL_BACKEND_GET_CLASS (backend)->create_object) (backend, cal, opid, cancellable, calobj);
1130 * e_cal_backend_modify_object:
1131 * @backend: an #ECalBackend
1132 * @cal: an #EDataCal
1133 * @opid: the ID to use for this operation
1134 * @cancellable: a #GCancellable for the operation
1135 * @calobj: Object to be modified.
1136 * @mod: Type of modification.
1138 * Calls the modify_object method on the given backend.
1139 * This might be finished with e_data_cal_respond_modify_object().
1142 e_cal_backend_modify_object (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *calobj, CalObjModType mod)
1144 g_return_if_fail (backend != NULL);
1145 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1146 g_return_if_fail (calobj != NULL);
1148 if (e_cal_backend_is_opening (backend))
1149 e_data_cal_respond_modify_object (cal, opid, EDC_OPENING_ERROR, NULL, NULL);
1150 else if (!E_CAL_BACKEND_GET_CLASS (backend)->modify_object)
1151 e_data_cal_respond_modify_object (cal, opid, EDC_ERROR (UnsupportedMethod), NULL, NULL);
1152 else if (!e_cal_backend_is_opened (backend))
1153 e_data_cal_respond_modify_object (cal, opid, EDC_NOT_OPENED_ERROR, NULL, NULL);
1155 (* E_CAL_BACKEND_GET_CLASS (backend)->modify_object) (backend, cal, opid, cancellable, calobj, mod);
1159 * e_cal_backend_remove_object:
1160 * @backend: an #ECalBackend
1161 * @cal: an #EDataCal
1162 * @opid: the ID to use for this operation
1163 * @cancellable: a #GCancellable for the operation
1164 * @uid: Unique identifier of the object to remove.
1165 * @rid: A recurrence ID.
1166 * @mod: Type of removal.
1168 * Removes an object in a calendar backend. The backend will notify all of its
1169 * clients about the change.
1170 * This might be finished with e_data_cal_respond_remove_object().
1173 e_cal_backend_remove_object (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *uid, const gchar *rid, CalObjModType mod)
1175 g_return_if_fail (backend != NULL);
1176 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1177 g_return_if_fail (uid != NULL);
1178 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->remove_object != NULL);
1180 if (e_cal_backend_is_opening (backend))
1181 e_data_cal_respond_remove_object (cal, opid, EDC_OPENING_ERROR, NULL, NULL, NULL);
1182 else if (!e_cal_backend_is_opened (backend))
1183 e_data_cal_respond_remove_object (cal, opid, EDC_NOT_OPENED_ERROR, NULL, NULL, NULL);
1185 (* E_CAL_BACKEND_GET_CLASS (backend)->remove_object) (backend, cal, opid, cancellable, uid, rid, mod);
1189 * e_cal_backend_receive_objects:
1190 * @backend: an #ECalBackend
1191 * @cal: an #EDataCal
1192 * @opid: the ID to use for this operation
1193 * @cancellable: a #GCancellable for the operation
1194 * @calobj: iCalendar object.
1196 * Calls the receive_objects method on the given backend.
1197 * This might be finished with e_data_cal_respond_receive_objects().
1200 e_cal_backend_receive_objects (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *calobj)
1202 g_return_if_fail (backend != NULL);
1203 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1204 g_return_if_fail (calobj != NULL);
1205 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->receive_objects != NULL);
1207 if (e_cal_backend_is_opening (backend))
1208 e_data_cal_respond_receive_objects (cal, opid, EDC_OPENING_ERROR);
1209 else if (!e_cal_backend_is_opened (backend))
1210 e_data_cal_respond_receive_objects (cal, opid, EDC_NOT_OPENED_ERROR);
1212 (* E_CAL_BACKEND_GET_CLASS (backend)->receive_objects) (backend, cal, opid, cancellable, calobj);
1216 * e_cal_backend_send_objects:
1217 * @backend: an #ECalBackend
1218 * @cal: an #EDataCal
1219 * @opid: the ID to use for this operation
1220 * @cancellable: a #GCancellable for the operation
1221 * @calobj: iCalendar object to be sent.
1223 * Calls the send_objects method on the given backend.
1224 * This might be finished with e_data_cal_respond_send_objects().
1227 e_cal_backend_send_objects (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *calobj)
1229 g_return_if_fail (backend != NULL);
1230 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1231 g_return_if_fail (calobj != NULL);
1232 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->send_objects != NULL);
1234 if (e_cal_backend_is_opening (backend))
1235 e_data_cal_respond_send_objects (cal, opid, EDC_OPENING_ERROR, NULL, NULL);
1236 else if (!e_cal_backend_is_opened (backend))
1237 e_data_cal_respond_send_objects (cal, opid, EDC_NOT_OPENED_ERROR, NULL, NULL);
1239 (* E_CAL_BACKEND_GET_CLASS (backend)->send_objects) (backend, cal, opid, cancellable, calobj);
1243 * e_cal_backend_get_attachment_uris:
1244 * @backend: an #ECalBackend
1245 * @cal: an #EDataCal
1246 * @opid: the ID to use for this operation
1247 * @cancellable: a #GCancellable for the operation
1248 * @uid: Unique identifier for a calendar object.
1249 * @rid: ID for the object's recurrence to get.
1251 * Queries a calendar backend for attachments present in a calendar object based
1252 * on its unique identifier and its recurrence ID (if a recurrent appointment).
1253 * This might be finished with e_data_cal_respond_get_attachment_uris().
1256 e_cal_backend_get_attachment_uris (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *uid, const gchar *rid)
1258 g_return_if_fail (backend != NULL);
1259 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1260 g_return_if_fail (uid != NULL);
1261 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_attachment_uris != NULL);
1263 if (e_cal_backend_is_opening (backend))
1264 e_data_cal_respond_get_attachment_uris (cal, opid, EDC_OPENING_ERROR, NULL);
1265 else if (!e_cal_backend_is_opened (backend))
1266 e_data_cal_respond_get_attachment_uris (cal, opid, EDC_NOT_OPENED_ERROR, NULL);
1268 (* E_CAL_BACKEND_GET_CLASS (backend)->get_attachment_uris) (backend, cal, opid, cancellable, uid, rid);
1272 * e_cal_backend_discard_alarm:
1273 * @backend: an #ECalBackend
1274 * @cal: an #EDataCal
1275 * @opid: the ID to use for this operation
1276 * @cancellable: a #GCancellable for the operation
1277 * @uid: Unique identifier for a calendar object.
1278 * @rid: ID for the object's recurrence to discard alarm in.
1279 * @auid: Unique identifier of the alarm itself.
1281 * Discards alarm @auid from the object identified by @uid and @rid.
1282 * This might be finished with e_data_cal_respond_discard_alarm().
1283 * Default implementation of this method returns Not Supported error.
1286 e_cal_backend_discard_alarm (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *uid, const gchar *rid, const gchar *auid)
1288 g_return_if_fail (backend != NULL);
1289 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1290 g_return_if_fail (uid != NULL);
1291 g_return_if_fail (auid != NULL);
1293 if (e_cal_backend_is_opening (backend))
1294 e_data_cal_respond_discard_alarm (cal, opid, EDC_OPENING_ERROR);
1295 else if (!E_CAL_BACKEND_GET_CLASS (backend)->discard_alarm)
1296 e_data_cal_respond_discard_alarm (cal, opid, e_data_cal_create_error (NotSupported, NULL));
1297 else if (!e_cal_backend_is_opened (backend))
1298 e_data_cal_respond_discard_alarm (cal, opid, EDC_NOT_OPENED_ERROR);
1300 (* E_CAL_BACKEND_GET_CLASS (backend)->discard_alarm) (backend, cal, opid, cancellable, uid, rid, auid);
1304 * e_cal_backend_get_timezone:
1305 * @backend: an #ECalBackend
1306 * @cal: an #EDataCal
1307 * @opid: the ID to use for this operation
1308 * @cancellable: a #GCancellable for the operation
1309 * @tzid: Unique identifier of a VTIMEZONE object. Note that this must not be
1312 * Returns the icaltimezone* corresponding to the TZID, or NULL if the TZID
1314 * This might be finished with e_data_cal_respond_get_timezone().
1317 e_cal_backend_get_timezone (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *tzid)
1319 g_return_if_fail (backend != NULL);
1320 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1321 g_return_if_fail (tzid != NULL);
1322 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_timezone != NULL);
1324 if (e_cal_backend_is_opening (backend))
1325 e_data_cal_respond_get_timezone (cal, opid, EDC_OPENING_ERROR, NULL);
1326 else if (!e_cal_backend_is_opened (backend))
1327 e_data_cal_respond_get_timezone (cal, opid, EDC_NOT_OPENED_ERROR, NULL);
1329 (* E_CAL_BACKEND_GET_CLASS (backend)->get_timezone) (backend, cal, opid, cancellable, tzid);
1333 * e_cal_backend_add_timezone
1334 * @backend: an #ECalBackend
1335 * @cal: an #EDataCal
1336 * @opid: the ID to use for this operation
1337 * @cancellable: a #GCancellable for the operation
1338 * @tzobj: The timezone object, in a string.
1340 * Add a timezone object to the given backend.
1341 * This might be finished with e_data_cal_respond_add_timezone().
1344 e_cal_backend_add_timezone (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *tzobject)
1346 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1347 g_return_if_fail (tzobject != NULL);
1348 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->add_timezone != NULL);
1350 if (e_cal_backend_is_opening (backend))
1351 e_data_cal_respond_add_timezone (cal, opid, EDC_OPENING_ERROR);
1352 else if (!e_cal_backend_is_opened (backend))
1353 e_data_cal_respond_add_timezone (cal, opid, EDC_NOT_OPENED_ERROR);
1355 (* E_CAL_BACKEND_GET_CLASS (backend)->add_timezone) (backend, cal, opid, cancellable, tzobject);
1359 * e_cal_backend_internal_get_timezone:
1360 * @backend: an #ECalBackend
1361 * @tzid: ID of the timezone to get.
1363 * Calls the internal_get_timezone method on the given backend.
1366 e_cal_backend_internal_get_timezone (ECalBackend *backend, const gchar *tzid)
1368 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), NULL);
1369 g_return_val_if_fail (tzid != NULL, NULL);
1370 g_return_val_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->internal_get_timezone != NULL, NULL);
1372 return (* E_CAL_BACKEND_GET_CLASS (backend)->internal_get_timezone) (backend, tzid);
1376 * e_cal_backend_start_view:
1377 * @backend: an #ECalBackend
1378 * @view: The view to be started.
1380 * Starts a new live view on the given backend.
1383 e_cal_backend_start_view (ECalBackend *backend, EDataCalView *view)
1385 g_return_if_fail (backend != NULL);
1386 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1387 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->start_view != NULL);
1389 (* E_CAL_BACKEND_GET_CLASS (backend)->start_view) (backend, view);
1393 * e_cal_backend_stop_view:
1394 * @backend: an #ECalBackend
1395 * @view: The view to be stopped.
1397 * Stops a previously started live view on the given backend.
1402 e_cal_backend_stop_view (ECalBackend *backend, EDataCalView *view)
1404 g_return_if_fail (backend != NULL);
1405 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1407 /* backward compatibility, do not force each backend define this function */
1408 if (!E_CAL_BACKEND_GET_CLASS (backend)->stop_view)
1411 (* E_CAL_BACKEND_GET_CLASS (backend)->stop_view) (backend, view);
1415 object_created_cb (EDataCalView *view, gpointer calobj)
1417 if (e_data_cal_view_object_matches (view, calobj))
1418 e_data_cal_view_notify_objects_added_1 (view, calobj);
1424 * e_cal_backend_notify_object_created:
1425 * @backend: an #ECalBackend
1426 * @calobj: iCalendar representation of new object
1428 * Notifies each of the backend's listeners about a new object.
1430 * #e_data_cal_notify_object_created() calls this for you. You only need to
1431 * call e_cal_backend_notify_object_created() yourself to report objects
1432 * created by non-EDS clients.
1435 e_cal_backend_notify_object_created (ECalBackend *backend, const gchar *calobj)
1437 ECalBackendPrivate *priv;
1439 priv = backend->priv;
1441 if (priv->notification_proxy) {
1442 e_cal_backend_notify_object_created (priv->notification_proxy, calobj);
1446 e_cal_backend_foreach_view (backend, object_created_cb, (gpointer) calobj);
1450 * e_cal_backend_notify_objects_added:
1455 e_cal_backend_notify_objects_added (ECalBackend *backend, EDataCalView *view, const GSList *objects)
1457 e_data_cal_view_notify_objects_added (view, objects);
1461 match_view_and_notify (EDataCalView *view, const gchar *old_object, const gchar *object)
1463 gboolean old_match = FALSE, new_match = FALSE;
1466 old_match = e_data_cal_view_object_matches (view, old_object);
1468 new_match = e_data_cal_view_object_matches (view, object);
1469 if (old_match && new_match)
1470 e_data_cal_view_notify_objects_modified_1 (view, object);
1472 e_data_cal_view_notify_objects_added_1 (view, object);
1473 else if (old_match) {
1474 ECalComponent *comp = NULL;
1476 comp = e_cal_component_new_from_string (old_object);
1478 ECalComponentId *id = e_cal_component_get_id (comp);
1480 e_data_cal_view_notify_objects_removed_1 (view, id);
1482 e_cal_component_free_id (id);
1483 g_object_unref (comp);
1489 const gchar *old_object;
1490 const gchar *object;
1491 const ECalComponentId *id;
1495 call_match_and_notify (EDataCalView *view, gpointer user_data)
1497 struct call_data *cd = user_data;
1499 g_return_val_if_fail (user_data != NULL, FALSE);
1501 match_view_and_notify (view, cd->old_object, cd->object);
1507 * e_cal_backend_notify_object_modified:
1508 * @backend: an #ECalBackend
1509 * @old_object: iCalendar representation of the original form of the object
1510 * @object: iCalendar representation of the new form of the object
1512 * Notifies each of the backend's listeners about a modified object.
1514 * #e_data_cal_notify_object_modified() calls this for you. You only need to
1515 * call e_cal_backend_notify_object_modified() yourself to report objects
1516 * modified by non-EDS clients.
1519 e_cal_backend_notify_object_modified (ECalBackend *backend, const gchar *old_object, const gchar *object)
1521 ECalBackendPrivate *priv;
1522 struct call_data cd;
1524 priv = backend->priv;
1526 if (priv->notification_proxy) {
1527 e_cal_backend_notify_object_modified (priv->notification_proxy, old_object, object);
1531 cd.old_object = old_object;
1535 e_cal_backend_foreach_view (backend, call_match_and_notify, &cd);
1539 * e_cal_backend_notify_objects_modified:
1544 e_cal_backend_notify_objects_modified (ECalBackend *backend, EDataCalView *view, const GSList *objects)
1546 e_data_cal_view_notify_objects_modified (view, objects);
1550 object_removed_cb (EDataCalView *view, gpointer user_data)
1552 struct call_data *cd = user_data;
1554 g_return_val_if_fail (user_data != NULL, FALSE);
1556 if (cd->object == NULL) {
1557 /* if object == NULL, it means the object has been completely
1558 removed from the backend */
1559 if (!cd->old_object || e_data_cal_view_object_matches (view, cd->old_object))
1560 e_data_cal_view_notify_objects_removed_1 (view, cd->id);
1562 match_view_and_notify (view, cd->old_object, cd->object);
1568 * e_cal_backend_notify_object_removed:
1569 * @backend: an #ECalBackend
1570 * @id: the Id of the removed object
1571 * @old_object: iCalendar representation of the removed object
1572 * @new_object: iCalendar representation of the object after the removal. This
1573 * only applies to recurrent appointments that had an instance removed. In that
1574 * case, this function notifies a modification instead of a removal.
1576 * Notifies each of the backend's listeners about a removed object.
1578 * e_data_cal_notify_object_removed() calls this for you. You only need to
1579 * call e_cal_backend_notify_object_removed() yourself to report objects
1580 * removed by non-EDS clients.
1583 e_cal_backend_notify_object_removed (ECalBackend *backend, const ECalComponentId *id,
1584 const gchar *old_object, const gchar *object)
1586 ECalBackendPrivate *priv;
1587 struct call_data cd;
1589 priv = backend->priv;
1591 if (priv->notification_proxy) {
1592 e_cal_backend_notify_object_removed (priv->notification_proxy, id, old_object, object);
1596 cd.old_object = old_object;
1600 e_cal_backend_foreach_view (backend, object_removed_cb, &cd);
1604 * e_cal_backend_notify_objects_removed:
1609 e_cal_backend_notify_objects_removed (ECalBackend *backend, EDataCalView *view, const GSList *ids)
1611 e_data_cal_view_notify_objects_removed (view, ids);
1615 * e_cal_backend_notify_error:
1616 * @backend: an #ECalBackend
1617 * @message: Error message
1619 * Notifies each of the backend's listeners about an error
1622 e_cal_backend_notify_error (ECalBackend *backend, const gchar *message)
1624 ECalBackendPrivate *priv = backend->priv;
1627 if (priv->notification_proxy) {
1628 e_cal_backend_notify_error (priv->notification_proxy, message);
1632 g_mutex_lock (priv->clients_mutex);
1634 for (l = priv->clients; l; l = l->next)
1635 e_data_cal_report_error (l->data, message);
1637 g_mutex_unlock (priv->clients_mutex);
1641 * e_cal_backend_notify_readonly:
1642 * @backend: an #ECalBackend
1643 * @is_readonly: flag indicating readonly status
1645 * Notifies all backend's clients about the current readonly state.
1646 * Meant to be used by backend implementations.
1649 e_cal_backend_notify_readonly (ECalBackend *backend, gboolean is_readonly)
1651 ECalBackendPrivate *priv;
1654 priv = backend->priv;
1655 priv->readonly = is_readonly;
1657 if (priv->notification_proxy) {
1658 e_cal_backend_notify_readonly (priv->notification_proxy, is_readonly);
1662 g_mutex_lock (priv->clients_mutex);
1664 for (l = priv->clients; l; l = l->next)
1665 e_data_cal_report_readonly (l->data, is_readonly);
1667 g_mutex_unlock (priv->clients_mutex);
1671 * e_cal_backend_notify_online:
1672 * @backend: an #ECalBackend
1673 * @is_online: flag indicating whether @backend is connected and online
1675 * Notifies clients of @backend's connection status indicated by @is_online.
1676 * Meant to be used by backend implementations.
1679 e_cal_backend_notify_online (ECalBackend *backend, gboolean is_online)
1681 ECalBackendPrivate *priv;
1684 priv = backend->priv;
1685 priv->online = is_online;
1687 if (priv->notification_proxy) {
1688 e_cal_backend_notify_online (priv->notification_proxy, is_online);
1692 g_mutex_lock (priv->clients_mutex);
1694 for (clients = priv->clients; clients != NULL; clients = g_slist_next (clients))
1695 e_data_cal_report_online (E_DATA_CAL (clients->data), is_online);
1697 g_mutex_unlock (priv->clients_mutex);
1701 * e_cal_backend_notify_auth_required:
1702 * @backend: an #ECalBackend
1703 * @is_self: Use %TRUE to indicate the authentication is required
1704 * for the @backend, otheriwse the authentication is for any
1705 * other source. Having @credentials %NULL means @is_self
1707 * @credentials: an #ECredentials that contains extra information for
1708 * a source for which authentication is requested.
1709 * This parameter can be NULL to indicate "for this calendar".
1711 * Notifies clients that @backend requires authentication in order to
1712 * connect. This function call does not influence 'opening', but
1713 * influences 'opened' property, which is set to %FALSE when @is_self
1714 * is %TRUE or @credentials is %NULL. Opening phase is finished
1715 * by e_cal_backend_notify_opened() if this is requested for @backend.
1717 * See e_cal_backend_open() for a description how the whole opening
1720 * Meant to be used by backend implementations.
1723 e_cal_backend_notify_auth_required (ECalBackend *backend, gboolean is_self, const ECredentials *credentials)
1725 ECalBackendPrivate *priv;
1728 priv = backend->priv;
1730 if (priv->notification_proxy) {
1731 e_cal_backend_notify_auth_required (priv->notification_proxy, is_self, credentials);
1735 g_mutex_lock (priv->clients_mutex);
1737 if (is_self || !credentials)
1738 priv->opened = FALSE;
1740 for (clients = priv->clients; clients != NULL; clients = g_slist_next (clients))
1741 e_data_cal_report_auth_required (E_DATA_CAL (clients->data), credentials);
1743 g_mutex_unlock (priv->clients_mutex);
1747 * e_cal_backend_notify_opened:
1748 * @backend: an #ECalBackend
1749 * @error: a #GError corresponding to the error encountered during
1750 * the opening phase. Use %NULL for success. The @error is freed
1751 * automatically if not %NULL.
1753 * Notifies clients that @backend finished its opening phase.
1754 * See e_cal_backend_open() for more information how the opening
1755 * phase works. Calling this function changes 'opening' property,
1756 * same as 'opened'. 'opening' is set to %FALSE and the backend
1757 * is considered 'opened' only if the @error is %NULL.
1759 * See also: e_cal_backend_respond_opened()
1761 * Note: The @error is freed automatically if not %NULL.
1763 * Meant to be used by backend implementations.
1766 e_cal_backend_notify_opened (ECalBackend *backend, GError *error)
1768 ECalBackendPrivate *priv;
1771 priv = backend->priv;
1772 g_mutex_lock (priv->clients_mutex);
1774 priv->opening = FALSE;
1775 priv->opened = error == NULL;
1777 for (clients = priv->clients; clients != NULL; clients = g_slist_next (clients))
1778 e_data_cal_report_opened (E_DATA_CAL (clients->data), error);
1780 g_mutex_unlock (priv->clients_mutex);
1783 g_error_free (error);
1787 * e_cal_backend_respond_opened:
1788 * @backend: an #ECalBackend
1789 * @cal: an #EDataCal
1790 * @opid: an operation ID
1791 * @error: result error; can be %NULL, if it isn't then it's automatically freed
1793 * This is a replacement for e_data_cal_respond_open() for cases where
1794 * the finish of 'open' method call also finishes backend opening phase.
1795 * This function covers calling of both e_cal_backend_notify_opened() and
1796 * e_data_cal_respond_open() with the same @error.
1798 * See e_cal_backend_open() for more details how the opening phase works.
1801 e_cal_backend_respond_opened (ECalBackend *backend, EDataCal *cal, guint32 opid, GError *error)
1803 GError *copy = NULL;
1805 g_return_if_fail (backend != NULL);
1806 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1807 g_return_if_fail (cal != NULL);
1808 g_return_if_fail (opid != 0);
1811 copy = g_error_copy (error);
1813 e_cal_backend_notify_opened (backend, copy);
1814 e_data_cal_respond_open (cal, opid, error);
1818 * e_cal_backend_empty_cache:
1819 * @backend: an #ECalBackend
1820 * @cache: Backend's cache to empty.
1822 * Empties backend's cache with all notifications and so on, thus all listening
1823 * will know there is nothing in this backend.
1828 e_cal_backend_empty_cache (ECalBackend *backend, ECalBackendCache *cache)
1830 GList *comps_in_cache;
1832 g_return_if_fail (backend != NULL);
1833 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1838 g_return_if_fail (E_IS_CAL_BACKEND_CACHE (cache));
1840 e_file_cache_freeze_changes (E_FILE_CACHE (cache));
1842 for (comps_in_cache = e_cal_backend_cache_get_components (cache);
1844 comps_in_cache = comps_in_cache->next) {
1846 ECalComponentId *id;
1847 ECalComponent *comp = comps_in_cache->data;
1849 id = e_cal_component_get_id (comp);
1850 comp_str = e_cal_component_get_as_string (comp);
1852 e_cal_backend_cache_remove_component (cache, id->uid, id->rid);
1853 e_cal_backend_notify_object_removed (backend, id, comp_str, NULL);
1856 e_cal_component_free_id (id);
1857 g_object_unref (comp);
1860 g_list_free (comps_in_cache);
1862 e_file_cache_thaw_changes (E_FILE_CACHE (cache));