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 kind of components for this backend */
40 icalcomponent_kind kind;
42 gboolean opening, opened, readonly, removed;
44 /* URI, from source. This is cached, since we return const. */
49 /* List of Cal objects */
50 GMutex *clients_mutex;
56 /* ECalBackend to pass notifications on to */
57 ECalBackend *notification_proxy;
68 static void e_cal_backend_remove_client_private (ECalBackend *backend, EDataCal *cal, gboolean weak_unref);
70 G_DEFINE_TYPE (ECalBackend, e_cal_backend, E_TYPE_BACKEND);
73 cal_backend_set_default_cache_dir (ECalBackend *backend)
76 icalcomponent_kind kind;
77 const gchar *component_type;
78 const gchar *user_cache_dir;
82 user_cache_dir = e_get_user_cache_dir ();
84 kind = e_cal_backend_get_kind (backend);
85 source = e_backend_get_source (E_BACKEND (backend));
88 case ICAL_VEVENT_COMPONENT:
89 component_type = "calendar";
91 case ICAL_VTODO_COMPONENT:
92 component_type = "tasks";
94 case ICAL_VJOURNAL_COMPONENT:
95 component_type = "memos";
98 g_return_if_reached ();
101 /* Mangle the URI to not contain invalid characters. */
102 mangled_uri = g_strdelimit (e_source_get_uri (source), ":/", '_');
104 filename = g_build_filename (
105 user_cache_dir, component_type, mangled_uri, NULL);
106 e_cal_backend_set_cache_dir (backend, filename);
109 g_free (mangled_uri);
113 cal_backend_set_kind (ECalBackend *backend,
114 icalcomponent_kind kind)
116 backend->priv->kind = kind;
120 cal_backend_get_backend_property (ECalBackend *backend,
123 GCancellable *cancellable,
124 const gchar *prop_name)
126 g_return_if_fail (backend != NULL);
127 g_return_if_fail (E_IS_CAL_BACKEND (backend));
128 g_return_if_fail (cal != NULL);
129 g_return_if_fail (prop_name != NULL);
131 if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_OPENED)) {
132 e_data_cal_respond_get_backend_property (cal, opid, NULL, e_cal_backend_is_opened (backend) ? "TRUE" : "FALSE");
133 } else if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_OPENING)) {
134 e_data_cal_respond_get_backend_property (cal, opid, NULL, e_cal_backend_is_opening (backend) ? "TRUE" : "FALSE");
135 } else if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_ONLINE)) {
136 e_data_cal_respond_get_backend_property (cal, opid, NULL, e_backend_get_online (E_BACKEND (backend)) ? "TRUE" : "FALSE");
137 } else if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_READONLY)) {
138 e_data_cal_respond_get_backend_property (cal, opid, NULL, e_cal_backend_is_readonly (backend) ? "TRUE" : "FALSE");
139 } else if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CACHE_DIR)) {
140 e_data_cal_respond_get_backend_property (cal, opid, NULL, e_cal_backend_get_cache_dir (backend));
142 e_data_cal_respond_get_backend_property (cal, opid, e_data_cal_create_error_fmt (NotSupported, _("Unknown calendar property '%s'"), prop_name), NULL);
147 cal_backend_set_backend_property (ECalBackend *backend,
150 GCancellable *cancellable,
151 const gchar *prop_name,
152 const gchar *prop_value)
154 g_return_if_fail (backend != NULL);
155 g_return_if_fail (E_IS_CAL_BACKEND (backend));
156 g_return_if_fail (cal != NULL);
157 g_return_if_fail (prop_name != NULL);
159 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));
163 cal_backend_set_property (GObject *object,
168 switch (property_id) {
170 e_cal_backend_set_cache_dir (
171 E_CAL_BACKEND (object),
172 g_value_get_string (value));
175 cal_backend_set_kind (
176 E_CAL_BACKEND (object),
177 g_value_get_ulong (value));
181 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
185 cal_backend_get_property (GObject *object,
190 switch (property_id) {
193 value, e_cal_backend_get_cache_dir (
194 E_CAL_BACKEND (object)));
198 value, e_cal_backend_get_kind (
199 E_CAL_BACKEND (object)));
203 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
207 cal_backend_finalize (GObject *object)
209 ECalBackendPrivate *priv;
211 priv = E_CAL_BACKEND (object)->priv;
213 g_assert (priv->clients == NULL);
215 g_slist_free (priv->views);
216 /* should be NULL, anyway */
217 g_slist_free (priv->clients);
219 g_mutex_free (priv->clients_mutex);
220 g_mutex_free (priv->views_mutex);
222 g_free (priv->cache_dir);
224 /* Chain up to parent's finalize() method. */
225 G_OBJECT_CLASS (e_cal_backend_parent_class)->finalize (object);
229 cal_backend_constructed (GObject *object)
231 cal_backend_set_default_cache_dir (E_CAL_BACKEND (object));
233 G_OBJECT_CLASS (e_cal_backend_parent_class)->constructed (object);
237 e_cal_backend_class_init (ECalBackendClass *klass)
239 GObjectClass *object_class;
241 g_type_class_add_private (klass, sizeof (ECalBackendPrivate));
243 object_class = G_OBJECT_CLASS (klass);
244 object_class->set_property = cal_backend_set_property;
245 object_class->get_property = cal_backend_get_property;
246 object_class->finalize = cal_backend_finalize;
247 object_class->constructed = cal_backend_constructed;
249 klass->get_backend_property = cal_backend_get_backend_property;
250 klass->set_backend_property = cal_backend_set_backend_property;
252 g_object_class_install_property (
255 g_param_spec_string (
262 g_object_class_install_property (
270 ICAL_XLICMIMEPART_COMPONENT,
273 G_PARAM_CONSTRUCT_ONLY));
277 e_cal_backend_init (ECalBackend *backend)
279 backend->priv = G_TYPE_INSTANCE_GET_PRIVATE (
280 backend, E_TYPE_CAL_BACKEND, ECalBackendPrivate);
282 backend->priv->clients = NULL;
283 backend->priv->clients_mutex = g_mutex_new ();
285 backend->priv->views = NULL;
286 backend->priv->views_mutex = g_mutex_new ();
288 backend->priv->readonly = TRUE;
292 * e_cal_backend_get_kind:
293 * @backend: an #ECalBackend
295 * Gets the kind of components the given backend stores.
297 * Returns: The kind of components for this backend.
300 e_cal_backend_get_kind (ECalBackend *backend)
302 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), ICAL_NO_COMPONENT);
304 return backend->priv->kind;
308 * e_cal_backend_is_opened:
309 * @backend: an #ECalBackend
311 * Checks if @backend's storage has been opened (and
312 * authenticated, if necessary) and the backend itself
313 * is ready for accessing. This property is changed automatically
314 * within call of e_cal_backend_notify_opened().
316 * Returns: %TRUE if fully opened, %FALSE otherwise.
321 e_cal_backend_is_opened (ECalBackend *backend)
323 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), FALSE);
325 return backend->priv->opened;
329 * e_cal_backend_is_opening:
330 * @backend: an #ECalBackend
332 * Checks if @backend is processing its opening phase, which
333 * includes everything since the e_cal_backend_open() call,
334 * through authentication, up to e_cal_backend_notify_opened().
335 * This property is managed automatically and the backend deny
336 * every operation except of cancel and authenticate_user while
337 * it is being opening.
339 * Returns: %TRUE if opening phase is in the effect, %FALSE otherwise.
344 e_cal_backend_is_opening (ECalBackend *backend)
346 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), FALSE);
348 return backend->priv->opening;
352 * e_cal_backend_is_readonly:
353 * @backend: an #ECalBackend
355 * Returns: Whether is backend read-only. This value is the last used
356 * in a call of e_cal_backend_notify_readonly().
361 e_cal_backend_is_readonly (ECalBackend *backend)
363 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), FALSE);
365 return backend->priv->readonly;
369 * e_cal_backend_is_removed:
370 * @backend: an #ECalBackend
372 * Checks if @backend has been removed from its physical storage.
374 * Returns: %TRUE if @backend has been removed, %FALSE otherwise.
379 e_cal_backend_is_removed (ECalBackend *backend)
381 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), FALSE);
383 return backend->priv->removed;
387 * e_cal_backend_set_is_removed:
388 * @backend: an #ECalBackend
389 * @is_removed: A flag indicating whether the backend's storage was removed
391 * Sets the flag indicating whether @backend was removed to @is_removed.
392 * Meant to be used by backend implementations.
397 e_cal_backend_set_is_removed (ECalBackend *backend,
400 g_return_if_fail (E_IS_CAL_BACKEND (backend));
402 backend->priv->removed = is_removed;
406 * e_cal_backend_get_cache_dir:
407 * @backend: an #ECalBackend
409 * Returns the cache directory for the given backend.
411 * Returns: the cache directory for the backend
416 e_cal_backend_get_cache_dir (ECalBackend *backend)
418 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), NULL);
420 return backend->priv->cache_dir;
424 * e_cal_backend_set_cache_dir:
425 * @backend: an #ECalBackend
426 * @cache_dir: a local cache directory
428 * Sets the cache directory for the given backend.
430 * Note that #ECalBackend is initialized with a usable default based on
431 * #ECalBackend:source and #ECalBackend:kind properties. Backends should
432 * not override the default without good reason.
437 e_cal_backend_set_cache_dir (ECalBackend *backend,
438 const gchar *cache_dir)
440 g_return_if_fail (E_IS_CAL_BACKEND (backend));
441 g_return_if_fail (cache_dir != NULL);
443 g_free (backend->priv->cache_dir);
444 backend->priv->cache_dir = g_strdup (cache_dir);
446 g_object_notify (G_OBJECT (backend), "cache-dir");
450 * e_cal_backend_create_cache_filename:
451 * @backend: an #ECalBackend
452 * @uid: a component UID
453 * @filename: a filename to use; can be NULL
454 * @fileindex: index of a file; used only when @filename is NULL
456 * Returns: a filename for an attachment in a local cache dir. Free returned
457 * pointer with a g_free().
462 e_cal_backend_create_cache_filename (ECalBackend *backend,
464 const gchar *filename,
467 g_return_val_if_fail (backend != NULL, NULL);
468 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), NULL);
470 return e_filename_mkdir_encoded (e_cal_backend_get_cache_dir (backend), uid, filename, fileindex);
474 * e_cal_backend_get_backend_property:
475 * @backend: an #ECalBackend
477 * @opid: the ID to use for this operation
478 * @cancellable: a #GCancellable for the operation
479 * @prop_name: property name to get value of; cannot be NULL
481 * Calls the get_backend_property method on the given backend.
482 * This might be finished with e_data_cal_respond_get_backend_property().
483 * Default implementation takes care of common properties and returns
484 * an 'unsupported' error for any unknown properties. The subclass may
485 * always call this default implementation for properties which fetching
486 * it doesn't overwrite.
491 e_cal_backend_get_backend_property (ECalBackend *backend,
494 GCancellable *cancellable,
495 const gchar *prop_name)
497 g_return_if_fail (backend != NULL);
498 g_return_if_fail (E_IS_CAL_BACKEND (backend));
499 g_return_if_fail (prop_name != NULL);
500 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_backend_property != NULL);
502 (* E_CAL_BACKEND_GET_CLASS (backend)->get_backend_property) (backend, cal, opid, cancellable, prop_name);
506 * e_cal_backend_set_backend_property:
507 * @backend: an #ECalBackend
509 * @opid: the ID to use for this operation
510 * @cancellable: a #GCancellable for the operation
511 * @prop_name: property name to change; cannot be NULL
512 * @prop_value: value to set to @prop_name; cannot be NULL
514 * Calls the set_backend_property method on the given backend.
515 * This might be finished with e_data_cal_respond_set_backend_property().
516 * Default implementation simply returns an 'unsupported' error.
517 * The subclass may always call this default implementation for properties
518 * which fetching it doesn't overwrite.
523 e_cal_backend_set_backend_property (ECalBackend *backend,
526 GCancellable *cancellable,
527 const gchar *prop_name,
528 const gchar *prop_value)
530 g_return_if_fail (backend != NULL);
531 g_return_if_fail (E_IS_CAL_BACKEND (backend));
532 g_return_if_fail (prop_name != NULL);
533 g_return_if_fail (prop_value != NULL);
534 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->set_backend_property != NULL);
536 (* E_CAL_BACKEND_GET_CLASS (backend)->set_backend_property) (backend, cal, opid, cancellable, prop_name, prop_value);
540 cal_destroy_cb (gpointer data,
541 GObject *where_cal_was)
543 e_cal_backend_remove_client_private (E_CAL_BACKEND (data),
544 (EDataCal *) where_cal_was, FALSE);
548 * e_cal_backend_add_client:
549 * @backend: an #ECalBackend
552 * Adds a new client to the given backend. For any event, the backend will
553 * notify all clients added via this function.
556 e_cal_backend_add_client (ECalBackend *backend,
559 ECalBackendPrivate *priv;
561 g_return_if_fail (backend != NULL);
562 g_return_if_fail (E_IS_CAL_BACKEND (backend));
563 g_return_if_fail (cal != NULL);
564 g_return_if_fail (E_IS_DATA_CAL (cal));
566 priv = backend->priv;
568 g_object_weak_ref (G_OBJECT (cal), cal_destroy_cb, backend);
570 g_mutex_lock (priv->clients_mutex);
571 priv->clients = g_slist_append (priv->clients, cal);
572 g_mutex_unlock (priv->clients_mutex);
576 e_cal_backend_remove_client_private (ECalBackend *backend,
580 ECalBackendPrivate *priv;
582 /* XXX this needs a bit more thinking wrt the mutex - we
583 * should be holding it when we check to see if clients is
585 g_return_if_fail (backend != NULL);
586 g_return_if_fail (E_IS_CAL_BACKEND (backend));
587 g_return_if_fail (cal != NULL);
588 g_return_if_fail (E_IS_DATA_CAL (cal));
590 priv = backend->priv;
593 g_object_weak_unref (G_OBJECT (cal), cal_destroy_cb, backend);
596 g_mutex_lock (priv->clients_mutex);
597 priv->clients = g_slist_remove (priv->clients, cal);
598 g_mutex_unlock (priv->clients_mutex);
600 /* When all clients go away, notify the parent factory about it so that
601 * it may decide whether to kill the backend or not.
603 if (!priv->clients) {
604 priv->opening = FALSE;
605 e_backend_last_client_gone (E_BACKEND (backend));
610 * e_cal_backend_remove_client:
611 * @backend: an #ECalBackend
614 * Removes a client from the list of connected clients to the given backend.
617 e_cal_backend_remove_client (ECalBackend *backend,
620 e_cal_backend_remove_client_private (backend, cal, TRUE);
624 * e_cal_backend_add_view:
625 * @backend: an #ECalBackend
626 * @view: An #EDataCalView object.
628 * Adds a view to the list of live views being run by the given backend.
629 * Doing so means that any listener on the view will get notified of any
630 * change that affect the live view.
635 e_cal_backend_add_view (ECalBackend *backend,
638 g_return_if_fail (backend != NULL);
639 g_return_if_fail (E_IS_CAL_BACKEND (backend));
641 g_mutex_lock (backend->priv->views_mutex);
643 backend->priv->views = g_slist_append (backend->priv->views, view);
645 g_mutex_unlock (backend->priv->views_mutex);
649 * e_cal_backend_remove_view
650 * @backend: an #ECalBackend
651 * @view: An #EDataCalView object, previously added with @ref e_cal_backend_add_view.
653 * Removes view from the list of live views for the backend.
658 e_cal_backend_remove_view (ECalBackend *backend,
661 g_return_if_fail (backend != NULL);
662 g_return_if_fail (E_IS_CAL_BACKEND (backend));
664 g_mutex_lock (backend->priv->views_mutex);
666 backend->priv->views = g_slist_remove (backend->priv->views, view);
668 g_mutex_unlock (backend->priv->views_mutex);
672 * e_cal_backend_foreach_view:
673 * @backend: an #ECalBackend
674 * @callback: callback to call
675 * @user_data: user_data passed into the @callback
677 * Calls @callback for each known calendar view of this @backend.
678 * @callback returns %FALSE to stop further processing.
683 e_cal_backend_foreach_view (ECalBackend *backend,
684 gboolean (*callback) (EDataCalView *view,
690 gboolean stop = FALSE;
692 g_return_if_fail (backend != NULL);
693 g_return_if_fail (callback != NULL);
695 g_mutex_lock (backend->priv->views_mutex);
697 for (views = backend->priv->views; views && !stop; views = views->next) {
698 view = E_DATA_CAL_VIEW (views->data);
701 stop = !callback (view, user_data);
702 g_object_unref (view);
705 g_mutex_unlock (backend->priv->views_mutex);
709 * e_cal_backend_set_notification_proxy:
710 * @backend: an #ECalBackend
711 * @proxy: The calendar backend to act as notification proxy.
713 * Sets the backend that will act as notification proxy for the given backend.
718 e_cal_backend_set_notification_proxy (ECalBackend *backend,
721 g_return_if_fail (E_IS_CAL_BACKEND (backend));
723 backend->priv->notification_proxy = proxy;
727 * e_cal_backend_open:
728 * @backend: an #ECalBackend
730 * @opid: the ID to use for this operation
731 * @cancellable: a #GCancellable for the operation
732 * @only_if_exists: Whether the calendar should be opened only if it already
733 * exists. If FALSE, a new calendar will be created when the specified @uri
736 * Opens a calendar backend with data from a calendar stored at the specified URI.
737 * This might be finished with e_data_cal_respond_open() or e_cal_backend_respond_opened(),
738 * though the overall opening phase finishes only after call
739 * of e_cal_backend_notify_opened() after which call the backend
740 * is either fully opened (including authentication against (remote)
741 * server/storage) or an error was encountered during this opening phase.
742 * 'opened' and 'opening' properties are updated automatically.
743 * The backend refuses all other operations until the opening phase is finished.
745 * The e_cal_backend_notify_opened() is called either from this function
746 * or from e_cal_backend_authenticate_user(), or after necessary steps
747 * initiated by these two functions.
749 * The opening phase usually works like this:
750 * 1) client requests open for the backend
751 * 2) server receives this request and calls e_cal_backend_open() - the opening phase begun
752 * 3) either the backend is opened during this call, and notifies client
753 * with e_cal_backend_notify_opened() about that. This is usually
754 * for local backends; their opening phase is finished
755 * 4) or the backend requires authentication, thus it notifies client
756 * about that with e_cal_backend_notify_auth_required() and is
757 * waiting for credentials, which will be received from client
758 * by e_cal_backend_authenticate_user() call. Backend's opening
759 * phase is still running in this case, thus it doesn't call
760 * e_cal_backend_notify_opened() within e_cal_backend_open() call.
761 * 5) when backend receives credentials in e_cal_backend_authenticate_user()
762 * then it tries to authenticate against a server/storage with them
763 * and only after it knows result of the authentication, whether user
764 * was or wasn't authenticated, it notifies client with the result
765 * by e_cal_backend_notify_opened() and it's opening phase is
766 * finished now. If there was no error returned then the backend is
767 * considered opened, otherwise it's considered closed. Use AuthenticationFailed
768 * error when the given credentials were rejected by the server/store, which
769 * will result in a re-prompt on the client side, otherwise use AuthenticationRequired
770 * if there was anything wrong with the given credentials. Set error's
771 * message to a reason for a re-prompt, it'll be shown to a user.
772 * 6) client checks error returned from e_cal_backend_notify_opened() and
773 * reprompts for a password if it was AuthenticationFailed. Otherwise
774 * considers backend opened based on the error presence (no error means success).
776 * In any case, the call of e_cal_backend_open() should be always finished
777 * with e_data_cal_respond_open(), which has no influence on the opening phase,
778 * or alternatively with e_cal_backend_respond_opened(). Never use authentication
779 * errors in e_data_cal_respond_open() to notify the client the authentication is
780 * required, there is e_cal_backend_notify_auth_required() for this.
783 e_cal_backend_open (ECalBackend *backend,
786 GCancellable *cancellable,
787 gboolean only_if_exists)
789 g_return_if_fail (backend != NULL);
790 g_return_if_fail (E_IS_CAL_BACKEND (backend));
791 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->open != NULL);
793 g_mutex_lock (backend->priv->clients_mutex);
795 if (e_cal_backend_is_opened (backend)) {
798 g_mutex_unlock (backend->priv->clients_mutex);
800 e_data_cal_report_readonly (cal, backend->priv->readonly);
802 online = e_backend_get_online (E_BACKEND (backend));
803 e_data_cal_report_online (cal, online);
805 e_cal_backend_respond_opened (backend, cal, opid, NULL);
806 } else if (e_cal_backend_is_opening (backend)) {
807 g_mutex_unlock (backend->priv->clients_mutex);
809 e_data_cal_respond_open (cal, opid, EDC_OPENING_ERROR);
811 backend->priv->opening = TRUE;
812 g_mutex_unlock (backend->priv->clients_mutex);
814 (* E_CAL_BACKEND_GET_CLASS (backend)->open) (backend, cal, opid, cancellable, only_if_exists);
819 * e_cal_backend_authenticate_user:
820 * @backend: an #ECalBackend
821 * @cancellable: a #GCancellable for the operation
822 * @credentials: #ECredentials to use for authentication
824 * Notifies @backend about @credentials provided by user to use
825 * for authentication. This notification is usually called during
826 * opening phase as a response to e_cal_backend_notify_auth_required()
827 * on the client side and it results in setting property 'opening' to %TRUE
828 * unless the backend is already opened. This function finishes opening
829 * phase, thus it should be finished with e_cal_backend_notify_opened().
831 * See information at e_cal_backend_open() for more details
832 * how the opening phase works.
837 e_cal_backend_authenticate_user (ECalBackend *backend,
838 GCancellable *cancellable,
839 ECredentials *credentials)
841 g_return_if_fail (E_IS_CAL_BACKEND (backend));
842 g_return_if_fail (credentials != NULL);
843 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->authenticate_user);
845 if (!e_cal_backend_is_opened (backend))
846 backend->priv->opening = TRUE;
848 (* E_CAL_BACKEND_GET_CLASS (backend)->authenticate_user) (backend, cancellable, credentials);
852 * e_cal_backend_remove:
853 * @backend: an #ECalBackend
855 * @opid: the ID to use for this operation
856 * @cancellable: a #GCancellable for the operation
858 * Removes the calendar being accessed by the given backend.
859 * This might be finished with e_data_cal_respond_remove().
862 e_cal_backend_remove (ECalBackend *backend,
865 GCancellable *cancellable)
867 g_return_if_fail (backend != NULL);
868 g_return_if_fail (E_IS_CAL_BACKEND (backend));
869 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->remove != NULL);
871 if (e_cal_backend_is_opening (backend))
872 e_data_cal_respond_remove (cal, opid, EDC_OPENING_ERROR);
874 (* E_CAL_BACKEND_GET_CLASS (backend)->remove) (backend, cal, opid, cancellable);
878 * e_cal_backend_refresh:
879 * @backend: an #ECalBackend
881 * @opid: the ID to use for this operation
882 * @cancellable: a #GCancellable for the operation
884 * Refreshes the calendar being accessed by the given backend.
885 * This might be finished with e_data_cal_respond_refresh(),
886 * and it might be called as soon as possible; it doesn't mean
887 * that the refreshing is done after calling that, the backend
888 * is only notifying client whether it started the refresh process
894 e_cal_backend_refresh (ECalBackend *backend,
897 GCancellable *cancellable)
899 g_return_if_fail (backend != NULL);
900 g_return_if_fail (E_IS_CAL_BACKEND (backend));
902 if (e_cal_backend_is_opening (backend))
903 e_data_cal_respond_refresh (cal, opid, EDC_OPENING_ERROR);
904 else if (!E_CAL_BACKEND_GET_CLASS (backend)->refresh)
905 e_data_cal_respond_refresh (cal, opid, EDC_ERROR (UnsupportedMethod));
906 else if (!e_cal_backend_is_opened (backend))
907 e_data_cal_respond_refresh (cal, opid, EDC_NOT_OPENED_ERROR);
909 (* E_CAL_BACKEND_GET_CLASS (backend)->refresh) (backend, cal, opid, cancellable);
913 * e_cal_backend_get_object:
914 * @backend: an #ECalBackend
916 * @opid: the ID to use for this operation
917 * @cancellable: a #GCancellable for the operation
918 * @uid: Unique identifier for a calendar object.
919 * @rid: ID for the object's recurrence to get.
921 * Queries a calendar backend for a calendar object based on its unique
922 * identifier and its recurrence ID (if a recurrent appointment).
923 * This might be finished with e_data_cal_respond_get_object().
926 e_cal_backend_get_object (ECalBackend *backend,
929 GCancellable *cancellable,
933 g_return_if_fail (backend != NULL);
934 g_return_if_fail (E_IS_CAL_BACKEND (backend));
935 g_return_if_fail (uid != NULL);
936 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_object != NULL);
938 if (e_cal_backend_is_opening (backend))
939 e_data_cal_respond_get_object (cal, opid, EDC_OPENING_ERROR, NULL);
940 else if (!e_cal_backend_is_opened (backend))
941 e_data_cal_respond_get_object (cal, opid, EDC_NOT_OPENED_ERROR, NULL);
943 (* E_CAL_BACKEND_GET_CLASS (backend)->get_object) (backend, cal, opid, cancellable, uid, rid);
947 * e_cal_backend_get_object_list:
948 * @backend: an #ECalBackend
950 * @opid: the ID to use for this operation
951 * @cancellable: a #GCancellable for the operation
952 * @sexp: Expression to search for.
954 * Calls the get_object_list method on the given backend.
955 * This might be finished with e_data_cal_respond_get_object_list().
958 e_cal_backend_get_object_list (ECalBackend *backend,
961 GCancellable *cancellable,
964 g_return_if_fail (backend != NULL);
965 g_return_if_fail (E_IS_CAL_BACKEND (backend));
966 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_object_list != NULL);
968 if (e_cal_backend_is_opening (backend))
969 e_data_cal_respond_get_object_list (cal, opid, EDC_OPENING_ERROR, NULL);
970 else if (!e_cal_backend_is_opened (backend))
971 e_data_cal_respond_get_object_list (cal, opid, EDC_NOT_OPENED_ERROR, NULL);
973 (* E_CAL_BACKEND_GET_CLASS (backend)->get_object_list) (backend, cal, opid, cancellable, sexp);
977 * e_cal_backend_get_free_busy:
978 * @backend: an #ECalBackend
980 * @opid: the ID to use for this operation
981 * @cancellable: a #GCancellable for the operation
982 * @users: List of users to get free/busy information for.
983 * @start: Start time for query.
984 * @end: End time for query.
986 * Gets a free/busy object for the given time interval. Client side is
987 * notified about free/busy objects throug e_data_cal_report_free_busy_data().
988 * This might be finished with e_data_cal_respond_get_free_busy().
991 e_cal_backend_get_free_busy (ECalBackend *backend,
994 GCancellable *cancellable,
999 g_return_if_fail (backend != NULL);
1000 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1001 g_return_if_fail (start != -1 && end != -1);
1002 g_return_if_fail (start <= end);
1003 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_free_busy != NULL);
1005 if (e_cal_backend_is_opening (backend))
1006 e_data_cal_respond_get_free_busy (cal, opid, EDC_OPENING_ERROR);
1007 else if (!e_cal_backend_is_opened (backend))
1008 e_data_cal_respond_get_free_busy (cal, opid, EDC_NOT_OPENED_ERROR);
1010 (* E_CAL_BACKEND_GET_CLASS (backend)->get_free_busy) (backend, cal, opid, cancellable, users, start, end);
1014 * e_cal_backend_create_object:
1015 * @backend: an #ECalBackend
1016 * @cal: an #EDataCal
1017 * @opid: the ID to use for this operation
1018 * @cancellable: a #GCancellable for the operation
1019 * @calobj: The object to create.
1021 * Calls the create_object method on the given backend.
1022 * This might be finished with e_data_cal_respond_create_object().
1025 e_cal_backend_create_object (ECalBackend *backend,
1028 GCancellable *cancellable,
1029 const gchar *calobj)
1031 g_return_if_fail (backend != NULL);
1032 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1033 g_return_if_fail (calobj != NULL);
1035 if (e_cal_backend_is_opening (backend))
1036 e_data_cal_respond_create_object (cal, opid, EDC_OPENING_ERROR, NULL, NULL);
1037 else if (!E_CAL_BACKEND_GET_CLASS (backend)->create_object)
1038 e_data_cal_respond_create_object (cal, opid, EDC_ERROR (UnsupportedMethod), NULL, NULL);
1039 else if (!e_cal_backend_is_opened (backend))
1040 e_data_cal_respond_create_object (cal, opid, EDC_NOT_OPENED_ERROR, NULL, NULL);
1042 (* E_CAL_BACKEND_GET_CLASS (backend)->create_object) (backend, cal, opid, cancellable, calobj);
1046 * e_cal_backend_modify_object:
1047 * @backend: an #ECalBackend
1048 * @cal: an #EDataCal
1049 * @opid: the ID to use for this operation
1050 * @cancellable: a #GCancellable for the operation
1051 * @calobj: Object to be modified.
1052 * @mod: Type of modification.
1054 * Calls the modify_object method on the given backend.
1055 * This might be finished with e_data_cal_respond_modify_object().
1058 e_cal_backend_modify_object (ECalBackend *backend,
1061 GCancellable *cancellable,
1062 const gchar *calobj,
1065 g_return_if_fail (backend != NULL);
1066 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1067 g_return_if_fail (calobj != NULL);
1069 if (e_cal_backend_is_opening (backend))
1070 e_data_cal_respond_modify_object (cal, opid, EDC_OPENING_ERROR, NULL, NULL);
1071 else if (!E_CAL_BACKEND_GET_CLASS (backend)->modify_object)
1072 e_data_cal_respond_modify_object (cal, opid, EDC_ERROR (UnsupportedMethod), NULL, NULL);
1073 else if (!e_cal_backend_is_opened (backend))
1074 e_data_cal_respond_modify_object (cal, opid, EDC_NOT_OPENED_ERROR, NULL, NULL);
1076 (* E_CAL_BACKEND_GET_CLASS (backend)->modify_object) (backend, cal, opid, cancellable, calobj, mod);
1080 * e_cal_backend_remove_object:
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 * @uid: Unique identifier of the object to remove.
1086 * @rid: A recurrence ID.
1087 * @mod: Type of removal.
1089 * Removes an object in a calendar backend. The backend will notify all of its
1090 * clients about the change.
1091 * This might be finished with e_data_cal_respond_remove_object().
1094 e_cal_backend_remove_object (ECalBackend *backend,
1097 GCancellable *cancellable,
1102 g_return_if_fail (backend != NULL);
1103 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1104 g_return_if_fail (uid != NULL);
1105 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->remove_object != NULL);
1107 if (e_cal_backend_is_opening (backend))
1108 e_data_cal_respond_remove_object (cal, opid, EDC_OPENING_ERROR, NULL, NULL, NULL);
1109 else if (!e_cal_backend_is_opened (backend))
1110 e_data_cal_respond_remove_object (cal, opid, EDC_NOT_OPENED_ERROR, NULL, NULL, NULL);
1112 (* E_CAL_BACKEND_GET_CLASS (backend)->remove_object) (backend, cal, opid, cancellable, uid, rid, mod);
1116 * e_cal_backend_receive_objects:
1117 * @backend: an #ECalBackend
1118 * @cal: an #EDataCal
1119 * @opid: the ID to use for this operation
1120 * @cancellable: a #GCancellable for the operation
1121 * @calobj: iCalendar object.
1123 * Calls the receive_objects method on the given backend.
1124 * This might be finished with e_data_cal_respond_receive_objects().
1127 e_cal_backend_receive_objects (ECalBackend *backend,
1130 GCancellable *cancellable,
1131 const gchar *calobj)
1133 g_return_if_fail (backend != NULL);
1134 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1135 g_return_if_fail (calobj != NULL);
1136 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->receive_objects != NULL);
1138 if (e_cal_backend_is_opening (backend))
1139 e_data_cal_respond_receive_objects (cal, opid, EDC_OPENING_ERROR);
1140 else if (!e_cal_backend_is_opened (backend))
1141 e_data_cal_respond_receive_objects (cal, opid, EDC_NOT_OPENED_ERROR);
1143 (* E_CAL_BACKEND_GET_CLASS (backend)->receive_objects) (backend, cal, opid, cancellable, calobj);
1147 * e_cal_backend_send_objects:
1148 * @backend: an #ECalBackend
1149 * @cal: an #EDataCal
1150 * @opid: the ID to use for this operation
1151 * @cancellable: a #GCancellable for the operation
1152 * @calobj: iCalendar object to be sent.
1154 * Calls the send_objects method on the given backend.
1155 * This might be finished with e_data_cal_respond_send_objects().
1158 e_cal_backend_send_objects (ECalBackend *backend,
1161 GCancellable *cancellable,
1162 const gchar *calobj)
1164 g_return_if_fail (backend != NULL);
1165 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1166 g_return_if_fail (calobj != NULL);
1167 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->send_objects != NULL);
1169 if (e_cal_backend_is_opening (backend))
1170 e_data_cal_respond_send_objects (cal, opid, EDC_OPENING_ERROR, NULL, NULL);
1171 else if (!e_cal_backend_is_opened (backend))
1172 e_data_cal_respond_send_objects (cal, opid, EDC_NOT_OPENED_ERROR, NULL, NULL);
1174 (* E_CAL_BACKEND_GET_CLASS (backend)->send_objects) (backend, cal, opid, cancellable, calobj);
1178 * e_cal_backend_get_attachment_uris:
1179 * @backend: an #ECalBackend
1180 * @cal: an #EDataCal
1181 * @opid: the ID to use for this operation
1182 * @cancellable: a #GCancellable for the operation
1183 * @uid: Unique identifier for a calendar object.
1184 * @rid: ID for the object's recurrence to get.
1186 * Queries a calendar backend for attachments present in a calendar object based
1187 * on its unique identifier and its recurrence ID (if a recurrent appointment).
1188 * This might be finished with e_data_cal_respond_get_attachment_uris().
1193 e_cal_backend_get_attachment_uris (ECalBackend *backend,
1196 GCancellable *cancellable,
1200 g_return_if_fail (backend != NULL);
1201 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1202 g_return_if_fail (uid != NULL);
1203 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_attachment_uris != NULL);
1205 if (e_cal_backend_is_opening (backend))
1206 e_data_cal_respond_get_attachment_uris (cal, opid, EDC_OPENING_ERROR, NULL);
1207 else if (!e_cal_backend_is_opened (backend))
1208 e_data_cal_respond_get_attachment_uris (cal, opid, EDC_NOT_OPENED_ERROR, NULL);
1210 (* E_CAL_BACKEND_GET_CLASS (backend)->get_attachment_uris) (backend, cal, opid, cancellable, uid, rid);
1214 * e_cal_backend_discard_alarm:
1215 * @backend: an #ECalBackend
1216 * @cal: an #EDataCal
1217 * @opid: the ID to use for this operation
1218 * @cancellable: a #GCancellable for the operation
1219 * @uid: Unique identifier for a calendar object.
1220 * @rid: ID for the object's recurrence to discard alarm in.
1221 * @auid: Unique identifier of the alarm itself.
1223 * Discards alarm @auid from the object identified by @uid and @rid.
1224 * This might be finished with e_data_cal_respond_discard_alarm().
1225 * Default implementation of this method returns Not Supported error.
1228 e_cal_backend_discard_alarm (ECalBackend *backend,
1231 GCancellable *cancellable,
1236 g_return_if_fail (backend != NULL);
1237 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1238 g_return_if_fail (uid != NULL);
1239 g_return_if_fail (auid != NULL);
1241 if (e_cal_backend_is_opening (backend))
1242 e_data_cal_respond_discard_alarm (cal, opid, EDC_OPENING_ERROR);
1243 else if (!E_CAL_BACKEND_GET_CLASS (backend)->discard_alarm)
1244 e_data_cal_respond_discard_alarm (cal, opid, e_data_cal_create_error (NotSupported, NULL));
1245 else if (!e_cal_backend_is_opened (backend))
1246 e_data_cal_respond_discard_alarm (cal, opid, EDC_NOT_OPENED_ERROR);
1248 (* E_CAL_BACKEND_GET_CLASS (backend)->discard_alarm) (backend, cal, opid, cancellable, uid, rid, auid);
1252 * e_cal_backend_get_timezone:
1253 * @backend: an #ECalBackend
1254 * @cal: an #EDataCal
1255 * @opid: the ID to use for this operation
1256 * @cancellable: a #GCancellable for the operation
1257 * @tzid: Unique identifier of a VTIMEZONE object. Note that this must not be
1260 * Returns the icaltimezone* corresponding to the TZID, or NULL if the TZID
1262 * This might be finished with e_data_cal_respond_get_timezone().
1265 e_cal_backend_get_timezone (ECalBackend *backend,
1268 GCancellable *cancellable,
1271 g_return_if_fail (backend != NULL);
1272 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1273 g_return_if_fail (tzid != NULL);
1274 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_timezone != NULL);
1276 if (e_cal_backend_is_opening (backend))
1277 e_data_cal_respond_get_timezone (cal, opid, EDC_OPENING_ERROR, NULL);
1278 else if (!e_cal_backend_is_opened (backend))
1279 e_data_cal_respond_get_timezone (cal, opid, EDC_NOT_OPENED_ERROR, NULL);
1281 (* E_CAL_BACKEND_GET_CLASS (backend)->get_timezone) (backend, cal, opid, cancellable, tzid);
1285 * e_cal_backend_add_timezone
1286 * @backend: an #ECalBackend
1287 * @cal: an #EDataCal
1288 * @opid: the ID to use for this operation
1289 * @cancellable: a #GCancellable for the operation
1290 * @tzobject: The timezone object, in a string.
1292 * Add a timezone object to the given backend.
1293 * This might be finished with e_data_cal_respond_add_timezone().
1296 e_cal_backend_add_timezone (ECalBackend *backend,
1299 GCancellable *cancellable,
1300 const gchar *tzobject)
1302 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1303 g_return_if_fail (tzobject != NULL);
1304 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->add_timezone != NULL);
1306 if (e_cal_backend_is_opening (backend))
1307 e_data_cal_respond_add_timezone (cal, opid, EDC_OPENING_ERROR);
1308 else if (!e_cal_backend_is_opened (backend))
1309 e_data_cal_respond_add_timezone (cal, opid, EDC_NOT_OPENED_ERROR);
1311 (* E_CAL_BACKEND_GET_CLASS (backend)->add_timezone) (backend, cal, opid, cancellable, tzobject);
1315 * e_cal_backend_internal_get_timezone:
1316 * @backend: an #ECalBackend
1317 * @tzid: ID of the timezone to get.
1319 * Calls the internal_get_timezone method on the given backend.
1322 e_cal_backend_internal_get_timezone (ECalBackend *backend,
1325 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), NULL);
1326 g_return_val_if_fail (tzid != NULL, NULL);
1327 g_return_val_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->internal_get_timezone != NULL, NULL);
1329 return (* E_CAL_BACKEND_GET_CLASS (backend)->internal_get_timezone) (backend, tzid);
1333 * e_cal_backend_start_view:
1334 * @backend: an #ECalBackend
1335 * @view: The view to be started.
1337 * Starts a new live view on the given backend.
1342 e_cal_backend_start_view (ECalBackend *backend,
1345 g_return_if_fail (backend != NULL);
1346 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1347 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->start_view != NULL);
1349 (* E_CAL_BACKEND_GET_CLASS (backend)->start_view) (backend, view);
1353 * e_cal_backend_stop_view:
1354 * @backend: an #ECalBackend
1355 * @view: The view to be stopped.
1357 * Stops a previously started live view on the given backend.
1362 e_cal_backend_stop_view (ECalBackend *backend,
1365 g_return_if_fail (backend != NULL);
1366 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1368 /* backward compatibility, do not force each backend define this function */
1369 if (!E_CAL_BACKEND_GET_CLASS (backend)->stop_view)
1372 (* E_CAL_BACKEND_GET_CLASS (backend)->stop_view) (backend, view);
1376 component_created_cb (EDataCalView *view,
1379 ECalComponent *comp = data;
1381 if (e_data_cal_view_component_matches (view, comp))
1382 e_data_cal_view_notify_components_added_1 (view, comp);
1388 * e_cal_backend_notify_component_created:
1389 * @backend: an #ECalBackend
1390 * @component: the newly created #ECalComponent
1392 * Notifies each of the backend's listeners about a new object.
1394 * Like e_cal_backend_notify_object_created() except takes an #ECalComponent
1395 * instead of an ical string representation and uses the #EDataCalView's
1396 * fields-of-interest to filter out unwanted information from ical strings
1397 * sent over the bus.
1402 e_cal_backend_notify_component_created (ECalBackend *backend,
1403 /* const */ ECalComponent *component)
1405 ECalBackendPrivate *priv;
1407 priv = backend->priv;
1409 if (priv->notification_proxy) {
1410 e_cal_backend_notify_component_created (priv->notification_proxy, component);
1414 e_cal_backend_foreach_view (backend, component_created_cb, component);
1418 match_view_and_notify_component (EDataCalView *view,
1419 ECalComponent *old_component,
1420 ECalComponent *new_component)
1422 gboolean old_match = FALSE, new_match = FALSE;
1425 old_match = e_data_cal_view_component_matches (view, old_component);
1427 new_match = e_data_cal_view_component_matches (view, new_component);
1429 if (old_match && new_match)
1430 e_data_cal_view_notify_components_modified_1 (view, new_component);
1432 e_data_cal_view_notify_components_added_1 (view, new_component);
1433 else if (old_match) {
1435 ECalComponentId *id = e_cal_component_get_id (old_component);
1437 e_data_cal_view_notify_objects_removed_1 (view, id);
1439 e_cal_component_free_id (id);
1443 struct component_call_data {
1444 ECalComponent *old_component;
1445 ECalComponent *new_component;
1446 const ECalComponentId *id;
1450 call_match_and_notify_component (EDataCalView *view,
1453 struct component_call_data *cd = user_data;
1455 g_return_val_if_fail (user_data != NULL, FALSE);
1457 match_view_and_notify_component (view, cd->old_component, cd->new_component);
1463 * e_cal_backend_notify_component_modified:
1464 * @backend: an #ECalBackend
1465 * @old_component: the #ECalComponent before the modification
1466 * @new_component: the #ECalComponent after the modification
1468 * Notifies each of the backend's listeners about a modified object.
1470 * Like e_cal_backend_notify_object_modified() except takes an #ECalComponent
1471 * instead of an ical string representation and uses the #EDataCalView's
1472 * fields-of-interest to filter out unwanted information from ical strings
1473 * sent over the bus.
1478 e_cal_backend_notify_component_modified (ECalBackend *backend,
1479 /* const */ ECalComponent *old_component,
1480 /* const */ ECalComponent *new_component)
1482 ECalBackendPrivate *priv;
1483 struct component_call_data cd;
1485 priv = backend->priv;
1487 if (priv->notification_proxy) {
1488 e_cal_backend_notify_component_modified (priv->notification_proxy, old_component, new_component);
1492 cd.old_component = old_component;
1493 cd.new_component = new_component;
1496 e_cal_backend_foreach_view (backend, call_match_and_notify_component, &cd);
1500 component_removed_cb (EDataCalView *view,
1503 struct component_call_data *cd = user_data;
1505 g_return_val_if_fail (user_data != NULL, FALSE);
1507 if (cd->new_component == NULL) {
1508 /* if object == NULL, it means the object has been completely
1509 * removed from the backend */
1510 if (!cd->old_component || e_data_cal_view_component_matches (view, cd->old_component))
1511 e_data_cal_view_notify_objects_removed_1 (view, cd->id);
1513 match_view_and_notify_component (view, cd->old_component, cd->new_component);
1519 * e_cal_backend_notify_component_removed:
1520 * @backend: an #ECalBackend
1521 * @id: the Id of the removed object
1522 * @old_component: the removed component
1523 * @new_component: the component after the removal. This only applies to recurrent
1524 * appointments that had an instance removed. In that case, this function
1525 * notifies a modification instead of a removal.
1527 * Notifies each of the backend's listeners about a removed object.
1529 * Like e_cal_backend_notify_object_removed() except takes an #ECalComponent
1530 * instead of an ical string representation and uses the #EDataCalView's
1531 * fields-of-interest to filter out unwanted information from ical strings
1532 * sent over the bus.
1537 e_cal_backend_notify_component_removed (ECalBackend *backend,
1538 const ECalComponentId *id,
1539 /* const */ ECalComponent *old_component,
1540 /* const */ ECalComponent *new_component)
1542 ECalBackendPrivate *priv;
1543 struct component_call_data cd;
1545 priv = backend->priv;
1547 if (priv->notification_proxy) {
1548 e_cal_backend_notify_component_removed (priv->notification_proxy, id, old_component, new_component);
1552 cd.old_component = old_component;
1553 cd.new_component = new_component;
1556 e_cal_backend_foreach_view (backend, component_removed_cb, &cd);
1560 object_created_cb (EDataCalView *view,
1563 const gchar *calobj = data;
1565 if (e_data_cal_view_object_matches (view, calobj))
1566 e_data_cal_view_notify_objects_added_1 (view, calobj);
1572 * e_cal_backend_notify_object_created:
1573 * @backend: an #ECalBackend
1574 * @calobj: the newly created object
1576 * Notifies each of the backend's listeners about a new object.
1578 * #e_data_cal_notify_object_created() calls this for you. You only need to
1579 * call e_cal_backend_notify_object_created() yourself to report objects
1580 * created by non-EDS clients.
1582 * Deprecated: 3.4: Use e_cal_backend_notify_component_created() instead.
1585 e_cal_backend_notify_object_created (ECalBackend *backend,
1586 const gchar *calobj)
1588 ECalBackendPrivate *priv;
1590 priv = backend->priv;
1592 if (priv->notification_proxy) {
1593 e_cal_backend_notify_object_created (priv->notification_proxy, calobj);
1597 e_cal_backend_foreach_view (backend, object_created_cb, (gpointer) calobj);
1601 * e_cal_backend_notify_objects_added:
1605 * Deprecated: 3.4: Use e_data_cal_view_notify_objects_added() instead.
1608 e_cal_backend_notify_objects_added (ECalBackend *backend,
1610 const GSList *objects)
1612 e_data_cal_view_notify_objects_added (view, objects);
1616 match_view_and_notify_object (EDataCalView *view,
1617 const gchar *old_object,
1618 const gchar *object)
1620 gboolean old_match = FALSE, new_match = FALSE;
1623 old_match = e_data_cal_view_object_matches (view, old_object);
1625 new_match = e_data_cal_view_object_matches (view, object);
1626 if (old_match && new_match)
1627 e_data_cal_view_notify_objects_modified_1 (view, object);
1629 e_data_cal_view_notify_objects_added_1 (view, object);
1630 else if (old_match) {
1631 ECalComponent *comp = NULL;
1633 comp = e_cal_component_new_from_string (old_object);
1635 ECalComponentId *id = e_cal_component_get_id (comp);
1637 e_data_cal_view_notify_objects_removed_1 (view, id);
1639 e_cal_component_free_id (id);
1640 g_object_unref (comp);
1645 struct object_call_data {
1646 const gchar *old_object;
1647 const gchar *object;
1648 const ECalComponentId *id;
1652 call_match_and_notify_object (EDataCalView *view,
1655 struct object_call_data *cd = user_data;
1657 g_return_val_if_fail (user_data != NULL, FALSE);
1659 match_view_and_notify_object (view, cd->old_object, cd->object);
1665 * e_cal_backend_notify_object_modified:
1666 * @backend: an #ECalBackend
1667 * @old_object: iCalendar representation of the original form of the object
1668 * @object: iCalendar representation of the new form of the object
1670 * Notifies each of the backend's listeners about a modified object.
1672 * #e_data_cal_notify_object_modified() calls this for you. You only need to
1673 * call e_cal_backend_notify_object_modified() yourself to report objects
1674 * modified by non-EDS clients.
1676 * Deprecated: 3.4: Use e_cal_backend_notify_component_modified() instead.
1679 e_cal_backend_notify_object_modified (ECalBackend *backend,
1680 const gchar *old_object,
1681 const gchar *object)
1683 ECalBackendPrivate *priv;
1684 struct object_call_data cd;
1686 priv = backend->priv;
1688 if (priv->notification_proxy) {
1689 e_cal_backend_notify_object_modified (priv->notification_proxy, old_object, object);
1693 cd.old_object = old_object;
1697 e_cal_backend_foreach_view (backend, call_match_and_notify_object, &cd);
1701 * e_cal_backend_notify_objects_modified:
1705 * Deprecated: 3.4: Use e_data_cal_view_notify_objects_modified() instead.
1708 e_cal_backend_notify_objects_modified (ECalBackend *backend,
1710 const GSList *objects)
1712 e_data_cal_view_notify_objects_modified (view, objects);
1716 object_removed_cb (EDataCalView *view,
1719 struct object_call_data *cd = user_data;
1721 g_return_val_if_fail (user_data != NULL, FALSE);
1723 if (cd->object == NULL) {
1724 /* if object == NULL, it means the object has been completely
1725 * removed from the backend */
1726 if (!cd->old_object || e_data_cal_view_object_matches (view, cd->old_object))
1727 e_data_cal_view_notify_objects_removed_1 (view, cd->id);
1729 match_view_and_notify_object (view, cd->old_object, cd->object);
1735 * e_cal_backend_notify_object_removed:
1736 * @backend: an #ECalBackend
1737 * @id: the Id of the removed object
1738 * @old_object: iCalendar representation of the removed object
1739 * @new_object: iCalendar representation of the object after the removal. This
1740 * only applies to recurrent appointments that had an instance removed. In that
1741 * case, this function notifies a modification instead of a removal.
1743 * Notifies each of the backend's listeners about a removed object.
1745 * e_data_cal_notify_object_removed() calls this for you. You only need to
1746 * call e_cal_backend_notify_object_removed() yourself to report objects
1747 * removed by non-EDS clients.
1749 * Deprecated: 3.4: Use e_cal_backend_notify_component_removed() instead.
1752 e_cal_backend_notify_object_removed (ECalBackend *backend,
1753 const ECalComponentId *id,
1754 const gchar *old_object,
1755 const gchar *new_object)
1757 ECalBackendPrivate *priv;
1758 struct object_call_data cd;
1760 priv = backend->priv;
1762 if (priv->notification_proxy) {
1763 e_cal_backend_notify_object_removed (priv->notification_proxy, id, old_object, new_object);
1767 cd.old_object = old_object;
1768 cd.object = new_object;
1771 e_cal_backend_foreach_view (backend, object_removed_cb, &cd);
1775 * e_cal_backend_notify_objects_removed:
1779 * Deprecated: 3.4: Use e_data_cal_view_notify_objects_removed() instead.
1782 e_cal_backend_notify_objects_removed (ECalBackend *backend,
1786 e_data_cal_view_notify_objects_removed (view, ids);
1790 * e_cal_backend_notify_error:
1791 * @backend: an #ECalBackend
1792 * @message: Error message
1794 * Notifies each of the backend's listeners about an error
1797 e_cal_backend_notify_error (ECalBackend *backend,
1798 const gchar *message)
1800 ECalBackendPrivate *priv = backend->priv;
1803 if (priv->notification_proxy) {
1804 e_cal_backend_notify_error (priv->notification_proxy, message);
1808 g_mutex_lock (priv->clients_mutex);
1810 for (l = priv->clients; l; l = l->next)
1811 e_data_cal_report_error (l->data, message);
1813 g_mutex_unlock (priv->clients_mutex);
1817 * e_cal_backend_notify_readonly:
1818 * @backend: an #ECalBackend
1819 * @is_readonly: flag indicating readonly status
1821 * Notifies all backend's clients about the current readonly state.
1822 * Meant to be used by backend implementations.
1825 e_cal_backend_notify_readonly (ECalBackend *backend,
1826 gboolean is_readonly)
1828 ECalBackendPrivate *priv;
1831 priv = backend->priv;
1832 priv->readonly = is_readonly;
1834 if (priv->notification_proxy) {
1835 e_cal_backend_notify_readonly (priv->notification_proxy, is_readonly);
1839 g_mutex_lock (priv->clients_mutex);
1841 for (l = priv->clients; l; l = l->next)
1842 e_data_cal_report_readonly (l->data, is_readonly);
1844 g_mutex_unlock (priv->clients_mutex);
1848 * e_cal_backend_notify_online:
1849 * @backend: an #ECalBackend
1850 * @is_online: flag indicating whether @backend is connected and online
1852 * Notifies clients of @backend's connection status indicated by @is_online.
1853 * Meant to be used by backend implementations.
1858 e_cal_backend_notify_online (ECalBackend *backend,
1861 ECalBackendPrivate *priv;
1864 priv = backend->priv;
1866 if (priv->notification_proxy) {
1867 e_cal_backend_notify_online (priv->notification_proxy, is_online);
1871 g_mutex_lock (priv->clients_mutex);
1873 for (clients = priv->clients; clients != NULL; clients = g_slist_next (clients))
1874 e_data_cal_report_online (E_DATA_CAL (clients->data), is_online);
1876 g_mutex_unlock (priv->clients_mutex);
1880 * e_cal_backend_notify_auth_required:
1881 * @backend: an #ECalBackend
1882 * @is_self: Use %TRUE to indicate the authentication is required
1883 * for the @backend, otheriwse the authentication is for any
1884 * other source. Having @credentials %NULL means @is_self
1886 * @credentials: an #ECredentials that contains extra information for
1887 * a source for which authentication is requested.
1888 * This parameter can be NULL to indicate "for this calendar".
1890 * Notifies clients that @backend requires authentication in order to
1891 * connect. This function call does not influence 'opening', but
1892 * influences 'opened' property, which is set to %FALSE when @is_self
1893 * is %TRUE or @credentials is %NULL. Opening phase is finished
1894 * by e_cal_backend_notify_opened() if this is requested for @backend.
1896 * See e_cal_backend_open() for a description how the whole opening
1899 * Meant to be used by backend implementations.
1902 e_cal_backend_notify_auth_required (ECalBackend *backend,
1904 const ECredentials *credentials)
1906 ECalBackendPrivate *priv;
1909 priv = backend->priv;
1911 if (priv->notification_proxy) {
1912 e_cal_backend_notify_auth_required (priv->notification_proxy, is_self, credentials);
1916 g_mutex_lock (priv->clients_mutex);
1918 if (is_self || !credentials)
1919 priv->opened = FALSE;
1921 for (clients = priv->clients; clients != NULL; clients = g_slist_next (clients))
1922 e_data_cal_report_auth_required (E_DATA_CAL (clients->data), credentials);
1924 g_mutex_unlock (priv->clients_mutex);
1928 * e_cal_backend_notify_opened:
1929 * @backend: an #ECalBackend
1930 * @error: a #GError corresponding to the error encountered during
1931 * the opening phase. Use %NULL for success. The @error is freed
1932 * automatically if not %NULL.
1934 * Notifies clients that @backend finished its opening phase.
1935 * See e_cal_backend_open() for more information how the opening
1936 * phase works. Calling this function changes 'opening' property,
1937 * same as 'opened'. 'opening' is set to %FALSE and the backend
1938 * is considered 'opened' only if the @error is %NULL.
1940 * See also: e_cal_backend_respond_opened()
1942 * Note: The @error is freed automatically if not %NULL.
1944 * Meant to be used by backend implementations.
1949 e_cal_backend_notify_opened (ECalBackend *backend,
1952 ECalBackendPrivate *priv;
1955 priv = backend->priv;
1956 g_mutex_lock (priv->clients_mutex);
1958 priv->opening = FALSE;
1959 priv->opened = error == NULL;
1961 for (clients = priv->clients; clients != NULL; clients = g_slist_next (clients))
1962 e_data_cal_report_opened (E_DATA_CAL (clients->data), error);
1964 g_mutex_unlock (priv->clients_mutex);
1967 g_error_free (error);
1971 * e_cal_backend_notify_property_changed:
1972 * @backend: an #ECalBackend
1973 * @prop_name: property name, which changed
1974 * @prop_value: new property value
1976 * Notifies client about property value change.
1981 e_cal_backend_notify_property_changed (ECalBackend *backend,
1982 const gchar *prop_name,
1983 const gchar *prop_value)
1985 ECalBackendPrivate *priv;
1988 g_return_if_fail (backend != NULL);
1989 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1990 g_return_if_fail (backend->priv != NULL);
1991 g_return_if_fail (prop_name != NULL);
1992 g_return_if_fail (*prop_name != '\0');
1993 g_return_if_fail (prop_value != NULL);
1995 priv = backend->priv;
1996 g_mutex_lock (priv->clients_mutex);
1998 for (clients = priv->clients; clients != NULL; clients = g_slist_next (clients))
1999 e_data_cal_report_backend_property_changed (E_DATA_CAL (clients->data), prop_name, prop_value);
2001 g_mutex_unlock (priv->clients_mutex);
2005 * e_cal_backend_respond_opened:
2006 * @backend: an #ECalBackend
2007 * @cal: an #EDataCal
2008 * @opid: an operation ID
2009 * @error: result error; can be %NULL, if it isn't then it's automatically freed
2011 * This is a replacement for e_data_cal_respond_open() for cases where
2012 * the finish of 'open' method call also finishes backend opening phase.
2013 * This function covers calling of both e_cal_backend_notify_opened() and
2014 * e_data_cal_respond_open() with the same @error.
2016 * See e_cal_backend_open() for more details how the opening phase works.
2021 e_cal_backend_respond_opened (ECalBackend *backend,
2026 GError *copy = NULL;
2028 g_return_if_fail (backend != NULL);
2029 g_return_if_fail (E_IS_CAL_BACKEND (backend));
2030 g_return_if_fail (cal != NULL);
2031 g_return_if_fail (opid != 0);
2034 copy = g_error_copy (error);
2036 e_cal_backend_notify_opened (backend, copy);
2037 e_data_cal_respond_open (cal, opid, error);
2041 * e_cal_backend_empty_cache:
2042 * @backend: an #ECalBackend
2043 * @cache: Backend's cache to empty.
2045 * Empties backend's cache with all notifications and so on, thus all listening
2046 * will know there is nothing in this backend.
2051 e_cal_backend_empty_cache (ECalBackend *backend,
2052 ECalBackendCache *cache)
2054 GList *comps_in_cache;
2056 g_return_if_fail (backend != NULL);
2057 g_return_if_fail (E_IS_CAL_BACKEND (backend));
2062 g_return_if_fail (E_IS_CAL_BACKEND_CACHE (cache));
2064 e_file_cache_freeze_changes (E_FILE_CACHE (cache));
2066 for (comps_in_cache = e_cal_backend_cache_get_components (cache);
2068 comps_in_cache = comps_in_cache->next) {
2069 ECalComponentId *id;
2070 ECalComponent *comp = comps_in_cache->data;
2072 id = e_cal_component_get_id (comp);
2074 e_cal_backend_cache_remove_component (cache, id->uid, id->rid);
2076 e_cal_backend_notify_component_removed (backend, id, comp, NULL);
2078 e_cal_component_free_id (id);
2079 g_object_unref (comp);
2082 g_list_free (comps_in_cache);
2084 e_file_cache_thaw_changes (E_FILE_CACHE (cache));