1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* Evolution calendar - generic backend class
4 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
6 * Authors: Federico Mena-Quintero <federico@ximian.com>
7 * JP Rosevear <jpr@ximian.com>
8 * Rodrigo Moya <rodrigo@ximian.com>
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of version 2 of the GNU Lesser General Public
12 * License as published by the Free Software Foundation.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26 #include <glib/gi18n-lib.h>
28 #include <libedataserver/e-data-server-util.h>
30 #include "e-cal-backend.h"
31 #include "e-cal-backend-cache.h"
33 #define E_CAL_BACKEND_GET_PRIVATE(obj) \
34 (G_TYPE_INSTANCE_GET_PRIVATE \
35 ((obj), E_TYPE_CAL_BACKEND, ECalBackendPrivate))
37 #define EDC_ERROR(_code) e_data_cal_create_error (_code, NULL)
38 #define EDC_OPENING_ERROR e_data_cal_create_error (Busy, _("Cannot process, calendar backend is opening"))
39 #define EDC_NOT_OPENED_ERROR e_data_cal_create_error (NotOpened, NULL)
41 /* Private part of the CalBackend structure */
42 struct _ECalBackendPrivate {
43 /* The kind of components for this backend */
44 icalcomponent_kind kind;
46 gboolean opening, opened, readonly, removed;
48 /* URI, from source. This is cached, since we return const. */
53 /* List of Cal objects */
54 GMutex *clients_mutex;
60 /* ECalBackend to pass notifications on to */
61 ECalBackend *notification_proxy;
72 static void e_cal_backend_remove_client_private (ECalBackend *backend, EDataCal *cal, gboolean weak_unref);
74 G_DEFINE_TYPE (ECalBackend, e_cal_backend, E_TYPE_BACKEND);
77 cal_backend_set_default_cache_dir (ECalBackend *backend)
80 icalcomponent_kind kind;
81 const gchar *component_type;
82 const gchar *user_cache_dir;
86 user_cache_dir = e_get_user_cache_dir ();
88 kind = e_cal_backend_get_kind (backend);
89 source = e_backend_get_source (E_BACKEND (backend));
92 case ICAL_VEVENT_COMPONENT:
93 component_type = "calendar";
95 case ICAL_VTODO_COMPONENT:
96 component_type = "tasks";
98 case ICAL_VJOURNAL_COMPONENT:
99 component_type = "memos";
102 g_return_if_reached ();
105 /* Mangle the URI to not contain invalid characters. */
106 mangled_uri = g_strdelimit (e_source_get_uri (source), ":/", '_');
108 filename = g_build_filename (
109 user_cache_dir, component_type, mangled_uri, NULL);
110 e_cal_backend_set_cache_dir (backend, filename);
113 g_free (mangled_uri);
117 cal_backend_set_kind (ECalBackend *backend,
118 icalcomponent_kind kind)
120 backend->priv->kind = kind;
124 cal_backend_get_backend_property (ECalBackend *backend,
127 GCancellable *cancellable,
128 const gchar *prop_name)
130 g_return_if_fail (backend != NULL);
131 g_return_if_fail (E_IS_CAL_BACKEND (backend));
132 g_return_if_fail (cal != NULL);
133 g_return_if_fail (prop_name != NULL);
135 if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_OPENED)) {
136 e_data_cal_respond_get_backend_property (cal, opid, NULL, e_cal_backend_is_opened (backend) ? "TRUE" : "FALSE");
137 } else if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_OPENING)) {
138 e_data_cal_respond_get_backend_property (cal, opid, NULL, e_cal_backend_is_opening (backend) ? "TRUE" : "FALSE");
139 } else if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_ONLINE)) {
140 e_data_cal_respond_get_backend_property (cal, opid, NULL, e_backend_get_online (E_BACKEND (backend)) ? "TRUE" : "FALSE");
141 } else if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_READONLY)) {
142 e_data_cal_respond_get_backend_property (cal, opid, NULL, e_cal_backend_is_readonly (backend) ? "TRUE" : "FALSE");
143 } else if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CACHE_DIR)) {
144 e_data_cal_respond_get_backend_property (cal, opid, NULL, e_cal_backend_get_cache_dir (backend));
146 e_data_cal_respond_get_backend_property (cal, opid, e_data_cal_create_error_fmt (NotSupported, _("Unknown calendar property '%s'"), prop_name), NULL);
151 cal_backend_set_backend_property (ECalBackend *backend,
154 GCancellable *cancellable,
155 const gchar *prop_name,
156 const gchar *prop_value)
158 g_return_if_fail (backend != NULL);
159 g_return_if_fail (E_IS_CAL_BACKEND (backend));
160 g_return_if_fail (cal != NULL);
161 g_return_if_fail (prop_name != NULL);
163 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));
167 cal_backend_set_property (GObject *object,
172 switch (property_id) {
174 e_cal_backend_set_cache_dir (
175 E_CAL_BACKEND (object),
176 g_value_get_string (value));
179 cal_backend_set_kind (
180 E_CAL_BACKEND (object),
181 g_value_get_ulong (value));
185 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
189 cal_backend_get_property (GObject *object,
194 switch (property_id) {
197 value, e_cal_backend_get_cache_dir (
198 E_CAL_BACKEND (object)));
202 value, e_cal_backend_get_kind (
203 E_CAL_BACKEND (object)));
207 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
211 cal_backend_finalize (GObject *object)
213 ECalBackendPrivate *priv;
215 priv = E_CAL_BACKEND_GET_PRIVATE (object);
217 g_assert (priv->clients == NULL);
219 g_slist_free (priv->views);
220 /* should be NULL, anyway */
221 g_slist_free (priv->clients);
223 g_mutex_free (priv->clients_mutex);
224 g_mutex_free (priv->views_mutex);
226 g_free (priv->cache_dir);
228 /* Chain up to parent's finalize() method. */
229 G_OBJECT_CLASS (e_cal_backend_parent_class)->finalize (object);
233 cal_backend_constructed (GObject *object)
235 cal_backend_set_default_cache_dir (E_CAL_BACKEND (object));
237 G_OBJECT_CLASS (e_cal_backend_parent_class)->constructed (object);
241 e_cal_backend_class_init (ECalBackendClass *class)
243 GObjectClass *object_class;
245 g_type_class_add_private (class, sizeof (ECalBackendPrivate));
247 object_class = G_OBJECT_CLASS (class);
248 object_class->set_property = cal_backend_set_property;
249 object_class->get_property = cal_backend_get_property;
250 object_class->finalize = cal_backend_finalize;
251 object_class->constructed = cal_backend_constructed;
253 class->get_backend_property = cal_backend_get_backend_property;
254 class->set_backend_property = cal_backend_set_backend_property;
256 g_object_class_install_property (
259 g_param_spec_string (
266 g_object_class_install_property (
274 ICAL_XLICMIMEPART_COMPONENT,
277 G_PARAM_CONSTRUCT_ONLY));
281 e_cal_backend_init (ECalBackend *backend)
283 backend->priv = E_CAL_BACKEND_GET_PRIVATE (backend);
285 backend->priv->clients = NULL;
286 backend->priv->clients_mutex = g_mutex_new ();
288 backend->priv->views = NULL;
289 backend->priv->views_mutex = g_mutex_new ();
291 backend->priv->readonly = TRUE;
295 * e_cal_backend_get_kind:
296 * @backend: an #ECalBackend
298 * Gets the kind of components the given backend stores.
300 * Returns: The kind of components for this backend.
303 e_cal_backend_get_kind (ECalBackend *backend)
305 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), ICAL_NO_COMPONENT);
307 return backend->priv->kind;
311 * e_cal_backend_is_opened:
312 * @backend: an #ECalBackend
314 * Checks if @backend's storage has been opened (and
315 * authenticated, if necessary) and the backend itself
316 * is ready for accessing. This property is changed automatically
317 * within call of e_cal_backend_notify_opened().
319 * Returns: %TRUE if fully opened, %FALSE otherwise.
324 e_cal_backend_is_opened (ECalBackend *backend)
326 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), FALSE);
328 return backend->priv->opened;
332 * e_cal_backend_is_opening:
333 * @backend: an #ECalBackend
335 * Checks if @backend is processing its opening phase, which
336 * includes everything since the e_cal_backend_open() call,
337 * through authentication, up to e_cal_backend_notify_opened().
338 * This property is managed automatically and the backend deny
339 * every operation except of cancel and authenticate_user while
340 * it is being opening.
342 * Returns: %TRUE if opening phase is in the effect, %FALSE otherwise.
347 e_cal_backend_is_opening (ECalBackend *backend)
349 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), FALSE);
351 return backend->priv->opening;
355 * e_cal_backend_is_readonly:
356 * @backend: an #ECalBackend
358 * Returns: Whether is backend read-only. This value is the last used
359 * in a call of e_cal_backend_notify_readonly().
364 e_cal_backend_is_readonly (ECalBackend *backend)
366 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), FALSE);
368 return backend->priv->readonly;
372 * e_cal_backend_is_removed:
373 * @backend: an #ECalBackend
375 * Checks if @backend has been removed from its physical storage.
377 * Returns: %TRUE if @backend has been removed, %FALSE otherwise.
382 e_cal_backend_is_removed (ECalBackend *backend)
384 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), FALSE);
386 return backend->priv->removed;
390 * e_cal_backend_set_is_removed:
391 * @backend: an #ECalBackend
392 * @is_removed: A flag indicating whether the backend's storage was removed
394 * Sets the flag indicating whether @backend was removed to @is_removed.
395 * Meant to be used by backend implementations.
400 e_cal_backend_set_is_removed (ECalBackend *backend,
403 g_return_if_fail (E_IS_CAL_BACKEND (backend));
405 backend->priv->removed = is_removed;
409 * e_cal_backend_get_cache_dir:
410 * @backend: an #ECalBackend
412 * Returns the cache directory for the given backend.
414 * Returns: the cache directory for the backend
419 e_cal_backend_get_cache_dir (ECalBackend *backend)
421 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), NULL);
423 return backend->priv->cache_dir;
427 * e_cal_backend_set_cache_dir:
428 * @backend: an #ECalBackend
429 * @cache_dir: a local cache directory
431 * Sets the cache directory for the given backend.
433 * Note that #ECalBackend is initialized with a usable default based on
434 * #ECalBackend:source and #ECalBackend:kind properties. Backends should
435 * not override the default without good reason.
440 e_cal_backend_set_cache_dir (ECalBackend *backend,
441 const gchar *cache_dir)
443 g_return_if_fail (E_IS_CAL_BACKEND (backend));
444 g_return_if_fail (cache_dir != NULL);
446 g_free (backend->priv->cache_dir);
447 backend->priv->cache_dir = g_strdup (cache_dir);
449 g_object_notify (G_OBJECT (backend), "cache-dir");
453 * e_cal_backend_create_cache_filename:
454 * @backend: an #ECalBackend
455 * @uid: a component UID
456 * @filename: a filename to use; can be NULL
457 * @fileindex: index of a file; used only when @filename is NULL
459 * Returns: a filename for an attachment in a local cache dir. Free returned
460 * pointer with a g_free().
465 e_cal_backend_create_cache_filename (ECalBackend *backend,
467 const gchar *filename,
470 g_return_val_if_fail (backend != NULL, NULL);
471 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), NULL);
473 return e_filename_mkdir_encoded (e_cal_backend_get_cache_dir (backend), uid, filename, fileindex);
477 * e_cal_backend_get_backend_property:
478 * @backend: an #ECalBackend
480 * @opid: the ID to use for this operation
481 * @cancellable: a #GCancellable for the operation
482 * @prop_name: property name to get value of; cannot be NULL
484 * Calls the get_backend_property method on the given backend.
485 * This might be finished with e_data_cal_respond_get_backend_property().
486 * Default implementation takes care of common properties and returns
487 * an 'unsupported' error for any unknown properties. The subclass may
488 * always call this default implementation for properties which fetching
489 * it doesn't overwrite.
494 e_cal_backend_get_backend_property (ECalBackend *backend,
497 GCancellable *cancellable,
498 const gchar *prop_name)
500 g_return_if_fail (backend != NULL);
501 g_return_if_fail (E_IS_CAL_BACKEND (backend));
502 g_return_if_fail (prop_name != NULL);
503 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_backend_property != NULL);
505 (* E_CAL_BACKEND_GET_CLASS (backend)->get_backend_property) (backend, cal, opid, cancellable, prop_name);
509 * e_cal_backend_set_backend_property:
510 * @backend: an #ECalBackend
512 * @opid: the ID to use for this operation
513 * @cancellable: a #GCancellable for the operation
514 * @prop_name: property name to change; cannot be NULL
515 * @prop_value: value to set to @prop_name; cannot be NULL
517 * Calls the set_backend_property method on the given backend.
518 * This might be finished with e_data_cal_respond_set_backend_property().
519 * Default implementation simply returns an 'unsupported' error.
520 * The subclass may always call this default implementation for properties
521 * which fetching it doesn't overwrite.
526 e_cal_backend_set_backend_property (ECalBackend *backend,
529 GCancellable *cancellable,
530 const gchar *prop_name,
531 const gchar *prop_value)
533 g_return_if_fail (backend != NULL);
534 g_return_if_fail (E_IS_CAL_BACKEND (backend));
535 g_return_if_fail (prop_name != NULL);
536 g_return_if_fail (prop_value != NULL);
537 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->set_backend_property != NULL);
539 (* E_CAL_BACKEND_GET_CLASS (backend)->set_backend_property) (backend, cal, opid, cancellable, prop_name, prop_value);
543 cal_destroy_cb (gpointer data,
544 GObject *where_cal_was)
546 e_cal_backend_remove_client_private (E_CAL_BACKEND (data),
547 (EDataCal *) where_cal_was, FALSE);
551 * e_cal_backend_add_client:
552 * @backend: an #ECalBackend
555 * Adds a new client to the given backend. For any event, the backend will
556 * notify all clients added via this function.
559 e_cal_backend_add_client (ECalBackend *backend,
562 ECalBackendPrivate *priv;
564 g_return_if_fail (backend != NULL);
565 g_return_if_fail (E_IS_CAL_BACKEND (backend));
566 g_return_if_fail (cal != NULL);
567 g_return_if_fail (E_IS_DATA_CAL (cal));
569 priv = backend->priv;
571 g_object_weak_ref (G_OBJECT (cal), cal_destroy_cb, backend);
573 g_mutex_lock (priv->clients_mutex);
574 priv->clients = g_slist_append (priv->clients, cal);
575 g_mutex_unlock (priv->clients_mutex);
579 e_cal_backend_remove_client_private (ECalBackend *backend,
583 ECalBackendPrivate *priv;
585 /* XXX this needs a bit more thinking wrt the mutex - we
586 * should be holding it when we check to see if clients is
588 g_return_if_fail (backend != NULL);
589 g_return_if_fail (E_IS_CAL_BACKEND (backend));
590 g_return_if_fail (cal != NULL);
591 g_return_if_fail (E_IS_DATA_CAL (cal));
593 priv = backend->priv;
596 g_object_weak_unref (G_OBJECT (cal), cal_destroy_cb, backend);
599 g_mutex_lock (priv->clients_mutex);
600 priv->clients = g_slist_remove (priv->clients, cal);
601 g_mutex_unlock (priv->clients_mutex);
603 /* When all clients go away, notify the parent factory about it so that
604 * it may decide whether to kill the backend or not.
606 if (!priv->clients) {
607 priv->opening = FALSE;
608 e_backend_last_client_gone (E_BACKEND (backend));
613 * e_cal_backend_remove_client:
614 * @backend: an #ECalBackend
617 * Removes a client from the list of connected clients to the given backend.
620 e_cal_backend_remove_client (ECalBackend *backend,
623 e_cal_backend_remove_client_private (backend, cal, TRUE);
627 * e_cal_backend_add_view:
628 * @backend: an #ECalBackend
629 * @view: An #EDataCalView object.
631 * Adds a view to the list of live views being run by the given backend.
632 * Doing so means that any listener on the view will get notified of any
633 * change that affect the live view.
638 e_cal_backend_add_view (ECalBackend *backend,
641 g_return_if_fail (backend != NULL);
642 g_return_if_fail (E_IS_CAL_BACKEND (backend));
644 g_mutex_lock (backend->priv->views_mutex);
646 backend->priv->views = g_slist_append (backend->priv->views, view);
648 g_mutex_unlock (backend->priv->views_mutex);
652 * e_cal_backend_remove_view
653 * @backend: an #ECalBackend
654 * @view: An #EDataCalView object, previously added with @ref e_cal_backend_add_view.
656 * Removes view from the list of live views for the backend.
661 e_cal_backend_remove_view (ECalBackend *backend,
664 g_return_if_fail (backend != NULL);
665 g_return_if_fail (E_IS_CAL_BACKEND (backend));
667 g_mutex_lock (backend->priv->views_mutex);
669 backend->priv->views = g_slist_remove (backend->priv->views, view);
671 g_mutex_unlock (backend->priv->views_mutex);
675 * e_cal_backend_foreach_view:
676 * @backend: an #ECalBackend
677 * @callback: callback to call
678 * @user_data: user_data passed into the @callback
680 * Calls @callback for each known calendar view of this @backend.
681 * @callback returns %FALSE to stop further processing.
686 e_cal_backend_foreach_view (ECalBackend *backend,
687 gboolean (*callback) (EDataCalView *view,
693 gboolean stop = FALSE;
695 g_return_if_fail (backend != NULL);
696 g_return_if_fail (callback != NULL);
698 g_mutex_lock (backend->priv->views_mutex);
700 for (views = backend->priv->views; views && !stop; views = views->next) {
701 view = E_DATA_CAL_VIEW (views->data);
704 stop = !callback (view, user_data);
705 g_object_unref (view);
708 g_mutex_unlock (backend->priv->views_mutex);
712 * e_cal_backend_set_notification_proxy:
713 * @backend: an #ECalBackend
714 * @proxy: The calendar backend to act as notification proxy.
716 * Sets the backend that will act as notification proxy for the given backend.
721 e_cal_backend_set_notification_proxy (ECalBackend *backend,
724 g_return_if_fail (E_IS_CAL_BACKEND (backend));
726 backend->priv->notification_proxy = proxy;
730 * e_cal_backend_open:
731 * @backend: an #ECalBackend
733 * @opid: the ID to use for this operation
734 * @cancellable: a #GCancellable for the operation
735 * @only_if_exists: Whether the calendar should be opened only if it already
736 * exists. If FALSE, a new calendar will be created when the specified @uri
739 * Opens a calendar backend with data from a calendar stored at the specified URI.
740 * This might be finished with e_data_cal_respond_open() or e_cal_backend_respond_opened(),
741 * though the overall opening phase finishes only after call
742 * of e_cal_backend_notify_opened() after which call the backend
743 * is either fully opened (including authentication against (remote)
744 * server/storage) or an error was encountered during this opening phase.
745 * 'opened' and 'opening' properties are updated automatically.
746 * The backend refuses all other operations until the opening phase is finished.
748 * The e_cal_backend_notify_opened() is called either from this function
749 * or from e_cal_backend_authenticate_user(), or after necessary steps
750 * initiated by these two functions.
752 * The opening phase usually works like this:
753 * 1) client requests open for the backend
754 * 2) server receives this request and calls e_cal_backend_open() - the opening phase begun
755 * 3) either the backend is opened during this call, and notifies client
756 * with e_cal_backend_notify_opened() about that. This is usually
757 * for local backends; their opening phase is finished
758 * 4) or the backend requires authentication, thus it notifies client
759 * about that with e_cal_backend_notify_auth_required() and is
760 * waiting for credentials, which will be received from client
761 * by e_cal_backend_authenticate_user() call. Backend's opening
762 * phase is still running in this case, thus it doesn't call
763 * e_cal_backend_notify_opened() within e_cal_backend_open() call.
764 * 5) when backend receives credentials in e_cal_backend_authenticate_user()
765 * then it tries to authenticate against a server/storage with them
766 * and only after it knows result of the authentication, whether user
767 * was or wasn't authenticated, it notifies client with the result
768 * by e_cal_backend_notify_opened() and it's opening phase is
769 * finished now. If there was no error returned then the backend is
770 * considered opened, otherwise it's considered closed. Use AuthenticationFailed
771 * error when the given credentials were rejected by the server/store, which
772 * will result in a re-prompt on the client side, otherwise use AuthenticationRequired
773 * if there was anything wrong with the given credentials. Set error's
774 * message to a reason for a re-prompt, it'll be shown to a user.
775 * 6) client checks error returned from e_cal_backend_notify_opened() and
776 * reprompts for a password if it was AuthenticationFailed. Otherwise
777 * considers backend opened based on the error presence (no error means success).
779 * In any case, the call of e_cal_backend_open() should be always finished
780 * with e_data_cal_respond_open(), which has no influence on the opening phase,
781 * or alternatively with e_cal_backend_respond_opened(). Never use authentication
782 * errors in e_data_cal_respond_open() to notify the client the authentication is
783 * required, there is e_cal_backend_notify_auth_required() for this.
786 e_cal_backend_open (ECalBackend *backend,
789 GCancellable *cancellable,
790 gboolean only_if_exists)
792 g_return_if_fail (backend != NULL);
793 g_return_if_fail (E_IS_CAL_BACKEND (backend));
794 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->open != NULL);
796 g_mutex_lock (backend->priv->clients_mutex);
798 if (e_cal_backend_is_opened (backend)) {
801 g_mutex_unlock (backend->priv->clients_mutex);
803 e_data_cal_report_readonly (cal, backend->priv->readonly);
805 online = e_backend_get_online (E_BACKEND (backend));
806 e_data_cal_report_online (cal, online);
808 e_cal_backend_respond_opened (backend, cal, opid, NULL);
809 } else if (e_cal_backend_is_opening (backend)) {
810 g_mutex_unlock (backend->priv->clients_mutex);
812 e_data_cal_respond_open (cal, opid, EDC_OPENING_ERROR);
814 backend->priv->opening = TRUE;
815 g_mutex_unlock (backend->priv->clients_mutex);
817 (* E_CAL_BACKEND_GET_CLASS (backend)->open) (backend, cal, opid, cancellable, only_if_exists);
822 * e_cal_backend_authenticate_user:
823 * @backend: an #ECalBackend
824 * @cancellable: a #GCancellable for the operation
825 * @credentials: #ECredentials to use for authentication
827 * Notifies @backend about @credentials provided by user to use
828 * for authentication. This notification is usually called during
829 * opening phase as a response to e_cal_backend_notify_auth_required()
830 * on the client side and it results in setting property 'opening' to %TRUE
831 * unless the backend is already opened. This function finishes opening
832 * phase, thus it should be finished with e_cal_backend_notify_opened().
834 * See information at e_cal_backend_open() for more details
835 * how the opening phase works.
840 e_cal_backend_authenticate_user (ECalBackend *backend,
841 GCancellable *cancellable,
842 ECredentials *credentials)
844 g_return_if_fail (E_IS_CAL_BACKEND (backend));
845 g_return_if_fail (credentials != NULL);
846 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->authenticate_user);
848 if (!e_cal_backend_is_opened (backend))
849 backend->priv->opening = TRUE;
851 (* E_CAL_BACKEND_GET_CLASS (backend)->authenticate_user) (backend, cancellable, credentials);
855 * e_cal_backend_remove:
856 * @backend: an #ECalBackend
858 * @opid: the ID to use for this operation
859 * @cancellable: a #GCancellable for the operation
861 * Removes the calendar being accessed by the given backend.
862 * This might be finished with e_data_cal_respond_remove().
865 e_cal_backend_remove (ECalBackend *backend,
868 GCancellable *cancellable)
870 g_return_if_fail (backend != NULL);
871 g_return_if_fail (E_IS_CAL_BACKEND (backend));
872 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->remove != NULL);
874 if (e_cal_backend_is_opening (backend))
875 e_data_cal_respond_remove (cal, opid, EDC_OPENING_ERROR);
877 (* E_CAL_BACKEND_GET_CLASS (backend)->remove) (backend, cal, opid, cancellable);
881 * e_cal_backend_refresh:
882 * @backend: an #ECalBackend
884 * @opid: the ID to use for this operation
885 * @cancellable: a #GCancellable for the operation
887 * Refreshes the calendar being accessed by the given backend.
888 * This might be finished with e_data_cal_respond_refresh(),
889 * and it might be called as soon as possible; it doesn't mean
890 * that the refreshing is done after calling that, the backend
891 * is only notifying client whether it started the refresh process
897 e_cal_backend_refresh (ECalBackend *backend,
900 GCancellable *cancellable)
902 g_return_if_fail (backend != NULL);
903 g_return_if_fail (E_IS_CAL_BACKEND (backend));
905 if (e_cal_backend_is_opening (backend))
906 e_data_cal_respond_refresh (cal, opid, EDC_OPENING_ERROR);
907 else if (!E_CAL_BACKEND_GET_CLASS (backend)->refresh)
908 e_data_cal_respond_refresh (cal, opid, EDC_ERROR (UnsupportedMethod));
909 else if (!e_cal_backend_is_opened (backend))
910 e_data_cal_respond_refresh (cal, opid, EDC_NOT_OPENED_ERROR);
912 (* E_CAL_BACKEND_GET_CLASS (backend)->refresh) (backend, cal, opid, cancellable);
916 * e_cal_backend_get_object:
917 * @backend: an #ECalBackend
919 * @opid: the ID to use for this operation
920 * @cancellable: a #GCancellable for the operation
921 * @uid: Unique identifier for a calendar object.
922 * @rid: ID for the object's recurrence to get.
924 * Queries a calendar backend for a calendar object based on its unique
925 * identifier and its recurrence ID (if a recurrent appointment).
926 * This might be finished with e_data_cal_respond_get_object().
929 e_cal_backend_get_object (ECalBackend *backend,
932 GCancellable *cancellable,
936 g_return_if_fail (backend != NULL);
937 g_return_if_fail (E_IS_CAL_BACKEND (backend));
938 g_return_if_fail (uid != NULL);
939 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_object != NULL);
941 if (e_cal_backend_is_opening (backend))
942 e_data_cal_respond_get_object (cal, opid, EDC_OPENING_ERROR, NULL);
943 else if (!e_cal_backend_is_opened (backend))
944 e_data_cal_respond_get_object (cal, opid, EDC_NOT_OPENED_ERROR, NULL);
946 (* E_CAL_BACKEND_GET_CLASS (backend)->get_object) (backend, cal, opid, cancellable, uid, rid);
950 * e_cal_backend_get_object_list:
951 * @backend: an #ECalBackend
953 * @opid: the ID to use for this operation
954 * @cancellable: a #GCancellable for the operation
955 * @sexp: Expression to search for.
957 * Calls the get_object_list method on the given backend.
958 * This might be finished with e_data_cal_respond_get_object_list().
961 e_cal_backend_get_object_list (ECalBackend *backend,
964 GCancellable *cancellable,
967 g_return_if_fail (backend != NULL);
968 g_return_if_fail (E_IS_CAL_BACKEND (backend));
969 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_object_list != NULL);
971 if (e_cal_backend_is_opening (backend))
972 e_data_cal_respond_get_object_list (cal, opid, EDC_OPENING_ERROR, NULL);
973 else if (!e_cal_backend_is_opened (backend))
974 e_data_cal_respond_get_object_list (cal, opid, EDC_NOT_OPENED_ERROR, NULL);
976 (* E_CAL_BACKEND_GET_CLASS (backend)->get_object_list) (backend, cal, opid, cancellable, sexp);
980 * e_cal_backend_get_free_busy:
981 * @backend: an #ECalBackend
983 * @opid: the ID to use for this operation
984 * @cancellable: a #GCancellable for the operation
985 * @users: List of users to get free/busy information for.
986 * @start: Start time for query.
987 * @end: End time for query.
989 * Gets a free/busy object for the given time interval. Client side is
990 * notified about free/busy objects throug e_data_cal_report_free_busy_data().
991 * This might be finished with e_data_cal_respond_get_free_busy().
994 e_cal_backend_get_free_busy (ECalBackend *backend,
997 GCancellable *cancellable,
1002 g_return_if_fail (backend != NULL);
1003 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1004 g_return_if_fail (start != -1 && end != -1);
1005 g_return_if_fail (start <= end);
1006 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_free_busy != NULL);
1008 if (e_cal_backend_is_opening (backend))
1009 e_data_cal_respond_get_free_busy (cal, opid, EDC_OPENING_ERROR);
1010 else if (!e_cal_backend_is_opened (backend))
1011 e_data_cal_respond_get_free_busy (cal, opid, EDC_NOT_OPENED_ERROR);
1013 (* E_CAL_BACKEND_GET_CLASS (backend)->get_free_busy) (backend, cal, opid, cancellable, users, start, end);
1017 * e_cal_backend_create_object:
1018 * @backend: an #ECalBackend
1019 * @cal: an #EDataCal
1020 * @opid: the ID to use for this operation
1021 * @cancellable: a #GCancellable for the operation
1022 * @calobj: The object to create.
1024 * Calls the create_object method on the given backend.
1025 * This might be finished with e_data_cal_respond_create_object().
1028 e_cal_backend_create_object (ECalBackend *backend,
1031 GCancellable *cancellable,
1032 const gchar *calobj)
1034 g_return_if_fail (backend != NULL);
1035 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1036 g_return_if_fail (calobj != NULL);
1038 if (e_cal_backend_is_opening (backend))
1039 e_data_cal_respond_create_object (cal, opid, EDC_OPENING_ERROR, NULL, NULL);
1040 else if (!E_CAL_BACKEND_GET_CLASS (backend)->create_object)
1041 e_data_cal_respond_create_object (cal, opid, EDC_ERROR (UnsupportedMethod), NULL, NULL);
1042 else if (!e_cal_backend_is_opened (backend))
1043 e_data_cal_respond_create_object (cal, opid, EDC_NOT_OPENED_ERROR, NULL, NULL);
1045 (* E_CAL_BACKEND_GET_CLASS (backend)->create_object) (backend, cal, opid, cancellable, calobj);
1049 * e_cal_backend_modify_object:
1050 * @backend: an #ECalBackend
1051 * @cal: an #EDataCal
1052 * @opid: the ID to use for this operation
1053 * @cancellable: a #GCancellable for the operation
1054 * @calobj: Object to be modified.
1055 * @mod: Type of modification.
1057 * Calls the modify_object method on the given backend.
1058 * This might be finished with e_data_cal_respond_modify_object().
1061 e_cal_backend_modify_object (ECalBackend *backend,
1064 GCancellable *cancellable,
1065 const gchar *calobj,
1068 g_return_if_fail (backend != NULL);
1069 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1070 g_return_if_fail (calobj != NULL);
1072 if (e_cal_backend_is_opening (backend))
1073 e_data_cal_respond_modify_object (cal, opid, EDC_OPENING_ERROR, NULL, NULL);
1074 else if (!E_CAL_BACKEND_GET_CLASS (backend)->modify_object)
1075 e_data_cal_respond_modify_object (cal, opid, EDC_ERROR (UnsupportedMethod), NULL, NULL);
1076 else if (!e_cal_backend_is_opened (backend))
1077 e_data_cal_respond_modify_object (cal, opid, EDC_NOT_OPENED_ERROR, NULL, NULL);
1079 (* E_CAL_BACKEND_GET_CLASS (backend)->modify_object) (backend, cal, opid, cancellable, calobj, mod);
1083 * e_cal_backend_remove_object:
1084 * @backend: an #ECalBackend
1085 * @cal: an #EDataCal
1086 * @opid: the ID to use for this operation
1087 * @cancellable: a #GCancellable for the operation
1088 * @uid: Unique identifier of the object to remove.
1089 * @rid: A recurrence ID.
1090 * @mod: Type of removal.
1092 * Removes an object in a calendar backend. The backend will notify all of its
1093 * clients about the change.
1094 * This might be finished with e_data_cal_respond_remove_object().
1097 e_cal_backend_remove_object (ECalBackend *backend,
1100 GCancellable *cancellable,
1105 g_return_if_fail (backend != NULL);
1106 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1107 g_return_if_fail (uid != NULL);
1108 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->remove_object != NULL);
1110 if (e_cal_backend_is_opening (backend))
1111 e_data_cal_respond_remove_object (cal, opid, EDC_OPENING_ERROR, NULL, NULL, NULL);
1112 else if (!e_cal_backend_is_opened (backend))
1113 e_data_cal_respond_remove_object (cal, opid, EDC_NOT_OPENED_ERROR, NULL, NULL, NULL);
1115 (* E_CAL_BACKEND_GET_CLASS (backend)->remove_object) (backend, cal, opid, cancellable, uid, rid, mod);
1119 * e_cal_backend_receive_objects:
1120 * @backend: an #ECalBackend
1121 * @cal: an #EDataCal
1122 * @opid: the ID to use for this operation
1123 * @cancellable: a #GCancellable for the operation
1124 * @calobj: iCalendar object.
1126 * Calls the receive_objects method on the given backend.
1127 * This might be finished with e_data_cal_respond_receive_objects().
1130 e_cal_backend_receive_objects (ECalBackend *backend,
1133 GCancellable *cancellable,
1134 const gchar *calobj)
1136 g_return_if_fail (backend != NULL);
1137 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1138 g_return_if_fail (calobj != NULL);
1139 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->receive_objects != NULL);
1141 if (e_cal_backend_is_opening (backend))
1142 e_data_cal_respond_receive_objects (cal, opid, EDC_OPENING_ERROR);
1143 else if (!e_cal_backend_is_opened (backend))
1144 e_data_cal_respond_receive_objects (cal, opid, EDC_NOT_OPENED_ERROR);
1146 (* E_CAL_BACKEND_GET_CLASS (backend)->receive_objects) (backend, cal, opid, cancellable, calobj);
1150 * e_cal_backend_send_objects:
1151 * @backend: an #ECalBackend
1152 * @cal: an #EDataCal
1153 * @opid: the ID to use for this operation
1154 * @cancellable: a #GCancellable for the operation
1155 * @calobj: iCalendar object to be sent.
1157 * Calls the send_objects method on the given backend.
1158 * This might be finished with e_data_cal_respond_send_objects().
1161 e_cal_backend_send_objects (ECalBackend *backend,
1164 GCancellable *cancellable,
1165 const gchar *calobj)
1167 g_return_if_fail (backend != NULL);
1168 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1169 g_return_if_fail (calobj != NULL);
1170 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->send_objects != NULL);
1172 if (e_cal_backend_is_opening (backend))
1173 e_data_cal_respond_send_objects (cal, opid, EDC_OPENING_ERROR, NULL, NULL);
1174 else if (!e_cal_backend_is_opened (backend))
1175 e_data_cal_respond_send_objects (cal, opid, EDC_NOT_OPENED_ERROR, NULL, NULL);
1177 (* E_CAL_BACKEND_GET_CLASS (backend)->send_objects) (backend, cal, opid, cancellable, calobj);
1181 * e_cal_backend_get_attachment_uris:
1182 * @backend: an #ECalBackend
1183 * @cal: an #EDataCal
1184 * @opid: the ID to use for this operation
1185 * @cancellable: a #GCancellable for the operation
1186 * @uid: Unique identifier for a calendar object.
1187 * @rid: ID for the object's recurrence to get.
1189 * Queries a calendar backend for attachments present in a calendar object based
1190 * on its unique identifier and its recurrence ID (if a recurrent appointment).
1191 * This might be finished with e_data_cal_respond_get_attachment_uris().
1196 e_cal_backend_get_attachment_uris (ECalBackend *backend,
1199 GCancellable *cancellable,
1203 g_return_if_fail (backend != NULL);
1204 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1205 g_return_if_fail (uid != NULL);
1206 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_attachment_uris != NULL);
1208 if (e_cal_backend_is_opening (backend))
1209 e_data_cal_respond_get_attachment_uris (cal, opid, EDC_OPENING_ERROR, NULL);
1210 else if (!e_cal_backend_is_opened (backend))
1211 e_data_cal_respond_get_attachment_uris (cal, opid, EDC_NOT_OPENED_ERROR, NULL);
1213 (* E_CAL_BACKEND_GET_CLASS (backend)->get_attachment_uris) (backend, cal, opid, cancellable, uid, rid);
1217 * e_cal_backend_discard_alarm:
1218 * @backend: an #ECalBackend
1219 * @cal: an #EDataCal
1220 * @opid: the ID to use for this operation
1221 * @cancellable: a #GCancellable for the operation
1222 * @uid: Unique identifier for a calendar object.
1223 * @rid: ID for the object's recurrence to discard alarm in.
1224 * @auid: Unique identifier of the alarm itself.
1226 * Discards alarm @auid from the object identified by @uid and @rid.
1227 * This might be finished with e_data_cal_respond_discard_alarm().
1228 * Default implementation of this method returns Not Supported error.
1231 e_cal_backend_discard_alarm (ECalBackend *backend,
1234 GCancellable *cancellable,
1239 g_return_if_fail (backend != NULL);
1240 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1241 g_return_if_fail (uid != NULL);
1242 g_return_if_fail (auid != NULL);
1244 if (e_cal_backend_is_opening (backend))
1245 e_data_cal_respond_discard_alarm (cal, opid, EDC_OPENING_ERROR);
1246 else if (!E_CAL_BACKEND_GET_CLASS (backend)->discard_alarm)
1247 e_data_cal_respond_discard_alarm (cal, opid, e_data_cal_create_error (NotSupported, NULL));
1248 else if (!e_cal_backend_is_opened (backend))
1249 e_data_cal_respond_discard_alarm (cal, opid, EDC_NOT_OPENED_ERROR);
1251 (* E_CAL_BACKEND_GET_CLASS (backend)->discard_alarm) (backend, cal, opid, cancellable, uid, rid, auid);
1255 * e_cal_backend_get_timezone:
1256 * @backend: an #ECalBackend
1257 * @cal: an #EDataCal
1258 * @opid: the ID to use for this operation
1259 * @cancellable: a #GCancellable for the operation
1260 * @tzid: Unique identifier of a VTIMEZONE object. Note that this must not be
1263 * Returns the icaltimezone* corresponding to the TZID, or NULL if the TZID
1265 * This might be finished with e_data_cal_respond_get_timezone().
1268 e_cal_backend_get_timezone (ECalBackend *backend,
1271 GCancellable *cancellable,
1274 g_return_if_fail (backend != NULL);
1275 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1276 g_return_if_fail (tzid != NULL);
1277 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_timezone != NULL);
1279 if (e_cal_backend_is_opening (backend))
1280 e_data_cal_respond_get_timezone (cal, opid, EDC_OPENING_ERROR, NULL);
1281 else if (!e_cal_backend_is_opened (backend))
1282 e_data_cal_respond_get_timezone (cal, opid, EDC_NOT_OPENED_ERROR, NULL);
1284 (* E_CAL_BACKEND_GET_CLASS (backend)->get_timezone) (backend, cal, opid, cancellable, tzid);
1288 * e_cal_backend_add_timezone
1289 * @backend: an #ECalBackend
1290 * @cal: an #EDataCal
1291 * @opid: the ID to use for this operation
1292 * @cancellable: a #GCancellable for the operation
1293 * @tzobject: The timezone object, in a string.
1295 * Add a timezone object to the given backend.
1296 * This might be finished with e_data_cal_respond_add_timezone().
1299 e_cal_backend_add_timezone (ECalBackend *backend,
1302 GCancellable *cancellable,
1303 const gchar *tzobject)
1305 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1306 g_return_if_fail (tzobject != NULL);
1307 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->add_timezone != NULL);
1309 if (e_cal_backend_is_opening (backend))
1310 e_data_cal_respond_add_timezone (cal, opid, EDC_OPENING_ERROR);
1311 else if (!e_cal_backend_is_opened (backend))
1312 e_data_cal_respond_add_timezone (cal, opid, EDC_NOT_OPENED_ERROR);
1314 (* E_CAL_BACKEND_GET_CLASS (backend)->add_timezone) (backend, cal, opid, cancellable, tzobject);
1318 * e_cal_backend_internal_get_timezone:
1319 * @backend: an #ECalBackend
1320 * @tzid: ID of the timezone to get.
1322 * Calls the internal_get_timezone method on the given backend.
1325 e_cal_backend_internal_get_timezone (ECalBackend *backend,
1328 g_return_val_if_fail (E_IS_CAL_BACKEND (backend), NULL);
1329 g_return_val_if_fail (tzid != NULL, NULL);
1330 g_return_val_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->internal_get_timezone != NULL, NULL);
1332 return (* E_CAL_BACKEND_GET_CLASS (backend)->internal_get_timezone) (backend, tzid);
1336 * e_cal_backend_start_view:
1337 * @backend: an #ECalBackend
1338 * @view: The view to be started.
1340 * Starts a new live view on the given backend.
1345 e_cal_backend_start_view (ECalBackend *backend,
1348 g_return_if_fail (backend != NULL);
1349 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1350 g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->start_view != NULL);
1352 (* E_CAL_BACKEND_GET_CLASS (backend)->start_view) (backend, view);
1356 * e_cal_backend_stop_view:
1357 * @backend: an #ECalBackend
1358 * @view: The view to be stopped.
1360 * Stops a previously started live view on the given backend.
1365 e_cal_backend_stop_view (ECalBackend *backend,
1368 g_return_if_fail (backend != NULL);
1369 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1371 /* backward compatibility, do not force each backend define this function */
1372 if (!E_CAL_BACKEND_GET_CLASS (backend)->stop_view)
1375 (* E_CAL_BACKEND_GET_CLASS (backend)->stop_view) (backend, view);
1379 component_created_cb (EDataCalView *view,
1382 ECalComponent *comp = data;
1384 if (e_data_cal_view_component_matches (view, comp))
1385 e_data_cal_view_notify_components_added_1 (view, comp);
1391 * e_cal_backend_notify_component_created:
1392 * @backend: an #ECalBackend
1393 * @component: the newly created #ECalComponent
1395 * Notifies each of the backend's listeners about a new object.
1397 * Like e_cal_backend_notify_object_created() except takes an #ECalComponent
1398 * instead of an ical string representation and uses the #EDataCalView's
1399 * fields-of-interest to filter out unwanted information from ical strings
1400 * sent over the bus.
1405 e_cal_backend_notify_component_created (ECalBackend *backend,
1406 /* const */ ECalComponent *component)
1408 ECalBackendPrivate *priv;
1410 priv = backend->priv;
1412 if (priv->notification_proxy) {
1413 e_cal_backend_notify_component_created (priv->notification_proxy, component);
1417 e_cal_backend_foreach_view (backend, component_created_cb, component);
1421 match_view_and_notify_component (EDataCalView *view,
1422 ECalComponent *old_component,
1423 ECalComponent *new_component)
1425 gboolean old_match = FALSE, new_match = FALSE;
1428 old_match = e_data_cal_view_component_matches (view, old_component);
1430 new_match = e_data_cal_view_component_matches (view, new_component);
1432 if (old_match && new_match)
1433 e_data_cal_view_notify_components_modified_1 (view, new_component);
1435 e_data_cal_view_notify_components_added_1 (view, new_component);
1436 else if (old_match) {
1438 ECalComponentId *id = e_cal_component_get_id (old_component);
1440 e_data_cal_view_notify_objects_removed_1 (view, id);
1442 e_cal_component_free_id (id);
1446 struct component_call_data {
1447 ECalComponent *old_component;
1448 ECalComponent *new_component;
1449 const ECalComponentId *id;
1453 call_match_and_notify_component (EDataCalView *view,
1456 struct component_call_data *cd = user_data;
1458 g_return_val_if_fail (user_data != NULL, FALSE);
1460 match_view_and_notify_component (view, cd->old_component, cd->new_component);
1466 * e_cal_backend_notify_component_modified:
1467 * @backend: an #ECalBackend
1468 * @old_component: the #ECalComponent before the modification
1469 * @new_component: the #ECalComponent after the modification
1471 * Notifies each of the backend's listeners about a modified object.
1473 * Like e_cal_backend_notify_object_modified() except takes an #ECalComponent
1474 * instead of an ical string representation and uses the #EDataCalView's
1475 * fields-of-interest to filter out unwanted information from ical strings
1476 * sent over the bus.
1481 e_cal_backend_notify_component_modified (ECalBackend *backend,
1482 /* const */ ECalComponent *old_component,
1483 /* const */ ECalComponent *new_component)
1485 ECalBackendPrivate *priv;
1486 struct component_call_data cd;
1488 priv = backend->priv;
1490 if (priv->notification_proxy) {
1491 e_cal_backend_notify_component_modified (priv->notification_proxy, old_component, new_component);
1495 cd.old_component = old_component;
1496 cd.new_component = new_component;
1499 e_cal_backend_foreach_view (backend, call_match_and_notify_component, &cd);
1503 component_removed_cb (EDataCalView *view,
1506 struct component_call_data *cd = user_data;
1508 g_return_val_if_fail (user_data != NULL, FALSE);
1510 if (cd->new_component == NULL) {
1511 /* if object == NULL, it means the object has been completely
1512 * removed from the backend */
1513 if (!cd->old_component || e_data_cal_view_component_matches (view, cd->old_component))
1514 e_data_cal_view_notify_objects_removed_1 (view, cd->id);
1516 match_view_and_notify_component (view, cd->old_component, cd->new_component);
1522 * e_cal_backend_notify_component_removed:
1523 * @backend: an #ECalBackend
1524 * @id: the Id of the removed object
1525 * @old_component: the removed component
1526 * @new_component: the component after the removal. This only applies to recurrent
1527 * appointments that had an instance removed. In that case, this function
1528 * notifies a modification instead of a removal.
1530 * Notifies each of the backend's listeners about a removed object.
1532 * Like e_cal_backend_notify_object_removed() except takes an #ECalComponent
1533 * instead of an ical string representation and uses the #EDataCalView's
1534 * fields-of-interest to filter out unwanted information from ical strings
1535 * sent over the bus.
1540 e_cal_backend_notify_component_removed (ECalBackend *backend,
1541 const ECalComponentId *id,
1542 /* const */ ECalComponent *old_component,
1543 /* const */ ECalComponent *new_component)
1545 ECalBackendPrivate *priv;
1546 struct component_call_data cd;
1548 priv = backend->priv;
1550 if (priv->notification_proxy) {
1551 e_cal_backend_notify_component_removed (priv->notification_proxy, id, old_component, new_component);
1555 cd.old_component = old_component;
1556 cd.new_component = new_component;
1559 e_cal_backend_foreach_view (backend, component_removed_cb, &cd);
1563 object_created_cb (EDataCalView *view,
1566 const gchar *calobj = data;
1568 if (e_data_cal_view_object_matches (view, calobj))
1569 e_data_cal_view_notify_objects_added_1 (view, calobj);
1575 * e_cal_backend_notify_object_created:
1576 * @backend: an #ECalBackend
1577 * @calobj: the newly created object
1579 * Notifies each of the backend's listeners about a new object.
1581 * #e_data_cal_notify_object_created() calls this for you. You only need to
1582 * call e_cal_backend_notify_object_created() yourself to report objects
1583 * created by non-EDS clients.
1585 * Deprecated: 3.4: Use e_cal_backend_notify_component_created() instead.
1588 e_cal_backend_notify_object_created (ECalBackend *backend,
1589 const gchar *calobj)
1591 ECalBackendPrivate *priv;
1593 priv = backend->priv;
1595 if (priv->notification_proxy) {
1596 e_cal_backend_notify_object_created (priv->notification_proxy, calobj);
1600 e_cal_backend_foreach_view (backend, object_created_cb, (gpointer) calobj);
1604 * e_cal_backend_notify_objects_added:
1608 * Deprecated: 3.4: Use e_data_cal_view_notify_objects_added() instead.
1611 e_cal_backend_notify_objects_added (ECalBackend *backend,
1613 const GSList *objects)
1615 e_data_cal_view_notify_objects_added (view, objects);
1619 match_view_and_notify_object (EDataCalView *view,
1620 const gchar *old_object,
1621 const gchar *object)
1623 gboolean old_match = FALSE, new_match = FALSE;
1626 old_match = e_data_cal_view_object_matches (view, old_object);
1628 new_match = e_data_cal_view_object_matches (view, object);
1629 if (old_match && new_match)
1630 e_data_cal_view_notify_objects_modified_1 (view, object);
1632 e_data_cal_view_notify_objects_added_1 (view, object);
1633 else if (old_match) {
1634 ECalComponent *comp = NULL;
1636 comp = e_cal_component_new_from_string (old_object);
1638 ECalComponentId *id = e_cal_component_get_id (comp);
1640 e_data_cal_view_notify_objects_removed_1 (view, id);
1642 e_cal_component_free_id (id);
1643 g_object_unref (comp);
1648 struct object_call_data {
1649 const gchar *old_object;
1650 const gchar *object;
1651 const ECalComponentId *id;
1655 call_match_and_notify_object (EDataCalView *view,
1658 struct object_call_data *cd = user_data;
1660 g_return_val_if_fail (user_data != NULL, FALSE);
1662 match_view_and_notify_object (view, cd->old_object, cd->object);
1668 * e_cal_backend_notify_object_modified:
1669 * @backend: an #ECalBackend
1670 * @old_object: iCalendar representation of the original form of the object
1671 * @object: iCalendar representation of the new form of the object
1673 * Notifies each of the backend's listeners about a modified object.
1675 * #e_data_cal_notify_object_modified() calls this for you. You only need to
1676 * call e_cal_backend_notify_object_modified() yourself to report objects
1677 * modified by non-EDS clients.
1679 * Deprecated: 3.4: Use e_cal_backend_notify_component_modified() instead.
1682 e_cal_backend_notify_object_modified (ECalBackend *backend,
1683 const gchar *old_object,
1684 const gchar *object)
1686 ECalBackendPrivate *priv;
1687 struct object_call_data cd;
1689 priv = backend->priv;
1691 if (priv->notification_proxy) {
1692 e_cal_backend_notify_object_modified (priv->notification_proxy, old_object, object);
1696 cd.old_object = old_object;
1700 e_cal_backend_foreach_view (backend, call_match_and_notify_object, &cd);
1704 * e_cal_backend_notify_objects_modified:
1708 * Deprecated: 3.4: Use e_data_cal_view_notify_objects_modified() instead.
1711 e_cal_backend_notify_objects_modified (ECalBackend *backend,
1713 const GSList *objects)
1715 e_data_cal_view_notify_objects_modified (view, objects);
1719 object_removed_cb (EDataCalView *view,
1722 struct object_call_data *cd = user_data;
1724 g_return_val_if_fail (user_data != NULL, FALSE);
1726 if (cd->object == NULL) {
1727 /* if object == NULL, it means the object has been completely
1728 * removed from the backend */
1729 if (!cd->old_object || e_data_cal_view_object_matches (view, cd->old_object))
1730 e_data_cal_view_notify_objects_removed_1 (view, cd->id);
1732 match_view_and_notify_object (view, cd->old_object, cd->object);
1738 * e_cal_backend_notify_object_removed:
1739 * @backend: an #ECalBackend
1740 * @id: the Id of the removed object
1741 * @old_object: iCalendar representation of the removed object
1742 * @new_object: iCalendar representation of the object after the removal. This
1743 * only applies to recurrent appointments that had an instance removed. In that
1744 * case, this function notifies a modification instead of a removal.
1746 * Notifies each of the backend's listeners about a removed object.
1748 * e_data_cal_notify_object_removed() calls this for you. You only need to
1749 * call e_cal_backend_notify_object_removed() yourself to report objects
1750 * removed by non-EDS clients.
1752 * Deprecated: 3.4: Use e_cal_backend_notify_component_removed() instead.
1755 e_cal_backend_notify_object_removed (ECalBackend *backend,
1756 const ECalComponentId *id,
1757 const gchar *old_object,
1758 const gchar *new_object)
1760 ECalBackendPrivate *priv;
1761 struct object_call_data cd;
1763 priv = backend->priv;
1765 if (priv->notification_proxy) {
1766 e_cal_backend_notify_object_removed (priv->notification_proxy, id, old_object, new_object);
1770 cd.old_object = old_object;
1771 cd.object = new_object;
1774 e_cal_backend_foreach_view (backend, object_removed_cb, &cd);
1778 * e_cal_backend_notify_objects_removed:
1782 * Deprecated: 3.4: Use e_data_cal_view_notify_objects_removed() instead.
1785 e_cal_backend_notify_objects_removed (ECalBackend *backend,
1789 e_data_cal_view_notify_objects_removed (view, ids);
1793 * e_cal_backend_notify_error:
1794 * @backend: an #ECalBackend
1795 * @message: Error message
1797 * Notifies each of the backend's listeners about an error
1800 e_cal_backend_notify_error (ECalBackend *backend,
1801 const gchar *message)
1803 ECalBackendPrivate *priv = backend->priv;
1806 if (priv->notification_proxy) {
1807 e_cal_backend_notify_error (priv->notification_proxy, message);
1811 g_mutex_lock (priv->clients_mutex);
1813 for (l = priv->clients; l; l = l->next)
1814 e_data_cal_report_error (l->data, message);
1816 g_mutex_unlock (priv->clients_mutex);
1820 * e_cal_backend_notify_readonly:
1821 * @backend: an #ECalBackend
1822 * @is_readonly: flag indicating readonly status
1824 * Notifies all backend's clients about the current readonly state.
1825 * Meant to be used by backend implementations.
1828 e_cal_backend_notify_readonly (ECalBackend *backend,
1829 gboolean is_readonly)
1831 ECalBackendPrivate *priv;
1834 priv = backend->priv;
1835 priv->readonly = is_readonly;
1837 if (priv->notification_proxy) {
1838 e_cal_backend_notify_readonly (priv->notification_proxy, is_readonly);
1842 g_mutex_lock (priv->clients_mutex);
1844 for (l = priv->clients; l; l = l->next)
1845 e_data_cal_report_readonly (l->data, is_readonly);
1847 g_mutex_unlock (priv->clients_mutex);
1851 * e_cal_backend_notify_online:
1852 * @backend: an #ECalBackend
1853 * @is_online: flag indicating whether @backend is connected and online
1855 * Notifies clients of @backend's connection status indicated by @is_online.
1856 * Meant to be used by backend implementations.
1861 e_cal_backend_notify_online (ECalBackend *backend,
1864 ECalBackendPrivate *priv;
1867 priv = backend->priv;
1869 if (priv->notification_proxy) {
1870 e_cal_backend_notify_online (priv->notification_proxy, is_online);
1874 g_mutex_lock (priv->clients_mutex);
1876 for (clients = priv->clients; clients != NULL; clients = g_slist_next (clients))
1877 e_data_cal_report_online (E_DATA_CAL (clients->data), is_online);
1879 g_mutex_unlock (priv->clients_mutex);
1883 * e_cal_backend_notify_auth_required:
1884 * @backend: an #ECalBackend
1885 * @is_self: Use %TRUE to indicate the authentication is required
1886 * for the @backend, otheriwse the authentication is for any
1887 * other source. Having @credentials %NULL means @is_self
1889 * @credentials: an #ECredentials that contains extra information for
1890 * a source for which authentication is requested.
1891 * This parameter can be NULL to indicate "for this calendar".
1893 * Notifies clients that @backend requires authentication in order to
1894 * connect. This function call does not influence 'opening', but
1895 * influences 'opened' property, which is set to %FALSE when @is_self
1896 * is %TRUE or @credentials is %NULL. Opening phase is finished
1897 * by e_cal_backend_notify_opened() if this is requested for @backend.
1899 * See e_cal_backend_open() for a description how the whole opening
1902 * Meant to be used by backend implementations.
1905 e_cal_backend_notify_auth_required (ECalBackend *backend,
1907 const ECredentials *credentials)
1909 ECalBackendPrivate *priv;
1912 priv = backend->priv;
1914 if (priv->notification_proxy) {
1915 e_cal_backend_notify_auth_required (priv->notification_proxy, is_self, credentials);
1919 g_mutex_lock (priv->clients_mutex);
1921 if (is_self || !credentials)
1922 priv->opened = FALSE;
1924 for (clients = priv->clients; clients != NULL; clients = g_slist_next (clients))
1925 e_data_cal_report_auth_required (E_DATA_CAL (clients->data), credentials);
1927 g_mutex_unlock (priv->clients_mutex);
1931 * e_cal_backend_notify_opened:
1932 * @backend: an #ECalBackend
1933 * @error: a #GError corresponding to the error encountered during
1934 * the opening phase. Use %NULL for success. The @error is freed
1935 * automatically if not %NULL.
1937 * Notifies clients that @backend finished its opening phase.
1938 * See e_cal_backend_open() for more information how the opening
1939 * phase works. Calling this function changes 'opening' property,
1940 * same as 'opened'. 'opening' is set to %FALSE and the backend
1941 * is considered 'opened' only if the @error is %NULL.
1943 * See also: e_cal_backend_respond_opened()
1945 * Note: The @error is freed automatically if not %NULL.
1947 * Meant to be used by backend implementations.
1952 e_cal_backend_notify_opened (ECalBackend *backend,
1955 ECalBackendPrivate *priv;
1958 priv = backend->priv;
1959 g_mutex_lock (priv->clients_mutex);
1961 priv->opening = FALSE;
1962 priv->opened = error == NULL;
1964 for (clients = priv->clients; clients != NULL; clients = g_slist_next (clients))
1965 e_data_cal_report_opened (E_DATA_CAL (clients->data), error);
1967 g_mutex_unlock (priv->clients_mutex);
1970 g_error_free (error);
1974 * e_cal_backend_notify_property_changed:
1975 * @backend: an #ECalBackend
1976 * @prop_name: property name, which changed
1977 * @prop_value: new property value
1979 * Notifies client about property value change.
1984 e_cal_backend_notify_property_changed (ECalBackend *backend,
1985 const gchar *prop_name,
1986 const gchar *prop_value)
1988 ECalBackendPrivate *priv;
1991 g_return_if_fail (backend != NULL);
1992 g_return_if_fail (E_IS_CAL_BACKEND (backend));
1993 g_return_if_fail (backend->priv != NULL);
1994 g_return_if_fail (prop_name != NULL);
1995 g_return_if_fail (*prop_name != '\0');
1996 g_return_if_fail (prop_value != NULL);
1998 priv = backend->priv;
1999 g_mutex_lock (priv->clients_mutex);
2001 for (clients = priv->clients; clients != NULL; clients = g_slist_next (clients))
2002 e_data_cal_report_backend_property_changed (E_DATA_CAL (clients->data), prop_name, prop_value);
2004 g_mutex_unlock (priv->clients_mutex);
2008 * e_cal_backend_respond_opened:
2009 * @backend: an #ECalBackend
2010 * @cal: an #EDataCal
2011 * @opid: an operation ID
2012 * @error: result error; can be %NULL, if it isn't then it's automatically freed
2014 * This is a replacement for e_data_cal_respond_open() for cases where
2015 * the finish of 'open' method call also finishes backend opening phase.
2016 * This function covers calling of both e_cal_backend_notify_opened() and
2017 * e_data_cal_respond_open() with the same @error.
2019 * See e_cal_backend_open() for more details how the opening phase works.
2024 e_cal_backend_respond_opened (ECalBackend *backend,
2029 GError *copy = NULL;
2031 g_return_if_fail (backend != NULL);
2032 g_return_if_fail (E_IS_CAL_BACKEND (backend));
2033 g_return_if_fail (cal != NULL);
2034 g_return_if_fail (opid != 0);
2037 copy = g_error_copy (error);
2039 e_cal_backend_notify_opened (backend, copy);
2040 e_data_cal_respond_open (cal, opid, error);
2044 * e_cal_backend_empty_cache:
2045 * @backend: an #ECalBackend
2046 * @cache: Backend's cache to empty.
2048 * Empties backend's cache with all notifications and so on, thus all listening
2049 * will know there is nothing in this backend.
2054 e_cal_backend_empty_cache (ECalBackend *backend,
2055 ECalBackendCache *cache)
2057 GList *comps_in_cache;
2059 g_return_if_fail (backend != NULL);
2060 g_return_if_fail (E_IS_CAL_BACKEND (backend));
2065 g_return_if_fail (E_IS_CAL_BACKEND_CACHE (cache));
2067 e_file_cache_freeze_changes (E_FILE_CACHE (cache));
2069 for (comps_in_cache = e_cal_backend_cache_get_components (cache);
2071 comps_in_cache = comps_in_cache->next) {
2072 ECalComponentId *id;
2073 ECalComponent *comp = comps_in_cache->data;
2075 id = e_cal_component_get_id (comp);
2077 e_cal_backend_cache_remove_component (cache, id->uid, id->rid);
2079 e_cal_backend_notify_component_removed (backend, id, comp, NULL);
2081 e_cal_component_free_id (id);
2082 g_object_unref (comp);
2085 g_list_free (comps_in_cache);
2087 e_file_cache_thaw_changes (E_FILE_CACHE (cache));