2 * e-collection-backend.c
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) version 3.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with the program; if not, see <http://www.gnu.org/licenses/>
20 * SECTION: e-collection-backend
21 * @include: libebackend/libebackend.h
22 * @short_description: An abstract base class for a data source
25 * #ECollectionBackend is an abstract base class for backends which
26 * manage a collection of data sources which collectively represent the
27 * resources on a remote server. The resources can include any number
28 * of private and shared email stores, calendars and address books.
30 * The backend's job is to synchronize local representations of remote
31 * resources by adding and removing #EServerSideSource instances in an
32 * #ESourceRegistryServer. If possible the backend should also listen
33 * for notifications of newly-added or deleted resources on the remote
34 * server or else poll the remote server at regular intervals and then
35 * update the data source collection accordingly.
37 * As most remote servers require authentication, the backend may also
38 * wish to implement the #ESourceAuthenticator interface so it can submit
39 * its own #EAuthenticationSession instances to the #ESourceRegistryServer.
42 #include "e-collection-backend.h"
45 #include <glib/gi18n-lib.h>
47 #include <libedataserver/libedataserver.h>
49 #include <libebackend/e-server-side-source.h>
50 #include <libebackend/e-source-registry-server.h>
52 #define E_COLLECTION_BACKEND_GET_PRIVATE(obj) \
53 (G_TYPE_INSTANCE_GET_PRIVATE \
54 ((obj), E_TYPE_COLLECTION_BACKEND, ECollectionBackendPrivate))
56 struct _ECollectionBackendPrivate {
61 GMutex *children_lock;
65 /* Resource ID -> ESource */
66 GHashTable *unclaimed_resources;
67 GMutex *unclaimed_resources_lock;
69 gulong source_added_handler_id;
70 gulong source_removed_handler_id;
84 static guint signals[LAST_SIGNAL];
86 G_DEFINE_ABSTRACT_TYPE (
92 collection_backend_children_insert (ECollectionBackend *backend,
95 g_mutex_lock (backend->priv->children_lock);
97 g_hash_table_add (backend->priv->children, g_object_ref (source));
99 g_mutex_unlock (backend->priv->children_lock);
103 collection_backend_children_remove (ECollectionBackend *backend,
108 g_mutex_lock (backend->priv->children_lock);
110 removed = g_hash_table_remove (backend->priv->children, source);
112 g_mutex_unlock (backend->priv->children_lock);
118 collection_backend_children_list (ECollectionBackend *backend)
122 g_mutex_lock (backend->priv->children_lock);
124 list = g_hash_table_get_keys (backend->priv->children);
126 for (link = list; link != NULL; link = g_list_next (link))
127 g_object_ref (link->data);
129 g_mutex_unlock (backend->priv->children_lock);
135 collection_backend_new_user_file (ECollectionBackend *backend)
141 const gchar *cache_dir;
143 /* This is like e_server_side_source_new_user_file()
144 * except that it uses the backend's cache directory. */
146 safe_uid = e_uid_new ();
147 e_filename_make_safe (safe_uid);
149 cache_dir = e_collection_backend_get_cache_dir (backend);
150 basename = g_strconcat (safe_uid, ".source", NULL);
151 filename = g_build_filename (cache_dir, basename, NULL);
153 file = g_file_new_for_path (filename);
163 collection_backend_new_source (ECollectionBackend *backend,
167 ESourceRegistryServer *server;
168 ESource *child_source;
169 ESource *collection_source;
170 EServerSideSource *server_side_source;
171 const gchar *cache_dir;
172 const gchar *collection_uid;
174 server = e_collection_backend_ref_server (backend);
175 child_source = e_server_side_source_new (server, file, error);
176 g_object_unref (server);
178 if (child_source == NULL)
181 server_side_source = E_SERVER_SIDE_SOURCE (child_source);
183 /* Clients may change the source but may not remove it. */
184 e_server_side_source_set_writable (server_side_source, TRUE);
185 e_server_side_source_set_removable (server_side_source, FALSE);
187 /* Changes should be written back to the cache directory. */
188 cache_dir = e_collection_backend_get_cache_dir (backend);
189 e_server_side_source_set_write_directory (
190 server_side_source, cache_dir);
192 /* Configure the child source as a collection member. */
193 collection_source = e_backend_get_source (E_BACKEND (backend));
194 collection_uid = e_source_get_uid (collection_source);
195 e_source_set_parent (child_source, collection_uid);
201 collection_backend_load_resources (ECollectionBackend *backend)
203 ESourceRegistryServer *server;
204 ECollectionBackendClass *class;
208 const gchar *cache_dir;
209 GError *error = NULL;
211 /* This is based on e_source_registry_server_load_file()
212 * and e_source_registry_server_load_directory(). */
214 class = E_COLLECTION_BACKEND_GET_CLASS (backend);
215 g_return_if_fail (class->dup_resource_id != NULL);
217 cache_dir = e_collection_backend_get_cache_dir (backend);
219 dir = g_dir_open (cache_dir, 0, &error);
221 g_warn_if_fail (dir == NULL);
222 g_warning ("%s: %s", G_STRFUNC, error->message);
223 g_error_free (error);
227 g_return_if_fail (dir != NULL);
229 file = g_file_new_for_path (cache_dir);
230 server = e_collection_backend_ref_server (backend);
232 g_mutex_lock (backend->priv->unclaimed_resources_lock);
234 while ((name = g_dir_read_name (dir)) != NULL) {
239 /* Ignore files with no ".source" suffix. */
240 if (!g_str_has_suffix (name, ".source"))
243 child = g_file_get_child (file, name);
244 source = collection_backend_new_source (backend, child, &error);
245 g_object_unref (child);
248 g_warn_if_fail (source == NULL);
249 g_warning ("%s: %s", G_STRFUNC, error->message);
250 g_error_free (error);
254 g_return_if_fail (E_IS_SERVER_SIDE_SOURCE (source));
256 resource_id = class->dup_resource_id (backend, source);
258 /* Hash table takes ownership of the resource ID. */
259 if (resource_id != NULL)
260 g_hash_table_insert (
261 backend->priv->unclaimed_resources,
262 resource_id, g_object_ref (source));
264 g_object_unref (source);
267 g_mutex_unlock (backend->priv->unclaimed_resources_lock);
269 g_object_unref (file);
270 g_object_unref (server);
274 collection_backend_claim_resource (ECollectionBackend *backend,
275 const gchar *resource_id,
278 GHashTable *unclaimed_resources;
281 g_mutex_lock (backend->priv->unclaimed_resources_lock);
283 unclaimed_resources = backend->priv->unclaimed_resources;
284 source = g_hash_table_lookup (unclaimed_resources, resource_id);
286 if (source != NULL) {
287 g_object_ref (source);
288 g_hash_table_remove (unclaimed_resources, resource_id);
290 GFile *file = collection_backend_new_user_file (backend);
291 source = collection_backend_new_source (backend, file, error);
292 g_object_unref (file);
295 g_mutex_unlock (backend->priv->unclaimed_resources_lock);
301 collection_backend_child_is_calendar (ESource *child_source)
303 const gchar *extension_name;
305 extension_name = E_SOURCE_EXTENSION_CALENDAR;
306 if (e_source_has_extension (child_source, extension_name))
309 extension_name = E_SOURCE_EXTENSION_MEMO_LIST;
310 if (e_source_has_extension (child_source, extension_name))
313 extension_name = E_SOURCE_EXTENSION_TASK_LIST;
314 if (e_source_has_extension (child_source, extension_name))
321 collection_backend_child_is_contacts (ESource *child_source)
323 const gchar *extension_name;
325 extension_name = E_SOURCE_EXTENSION_ADDRESS_BOOK;
326 if (e_source_has_extension (child_source, extension_name))
333 collection_backend_child_is_mail (ESource *child_source)
335 const gchar *extension_name;
337 extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT;
338 if (e_source_has_extension (child_source, extension_name))
341 extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY;
342 if (e_source_has_extension (child_source, extension_name))
345 extension_name = E_SOURCE_EXTENSION_MAIL_TRANSPORT;
346 if (e_source_has_extension (child_source, extension_name))
353 collection_backend_bind_child_enabled (ECollectionBackend *backend,
354 ESource *child_source)
356 ESource *collection_source;
357 ESourceCollection *extension;
358 const gchar *extension_name;
360 /* See if the child source's "enabled" property can be
361 * bound to any ESourceCollection "enabled" properties. */
363 extension_name = E_SOURCE_EXTENSION_COLLECTION;
364 collection_source = e_backend_get_source (E_BACKEND (backend));
365 extension = e_source_get_extension (collection_source, extension_name);
367 if (collection_backend_child_is_calendar (child_source)) {
368 g_object_bind_property (
369 extension, "calendar-enabled",
370 child_source, "enabled",
371 G_BINDING_SYNC_CREATE);
375 if (collection_backend_child_is_contacts (child_source)) {
376 g_object_bind_property (
377 extension, "contacts-enabled",
378 child_source, "enabled",
379 G_BINDING_SYNC_CREATE);
383 if (collection_backend_child_is_mail (child_source)) {
384 g_object_bind_property (
385 extension, "mail-enabled",
386 child_source, "enabled",
387 G_BINDING_SYNC_CREATE);
393 collection_backend_source_added_cb (ESourceRegistryServer *server,
395 ECollectionBackend *backend)
397 ESource *collection_source;
398 ESource *parent_source;
401 /* If the newly-added source is our own child, emit "child-added". */
403 collection_source = e_backend_get_source (E_BACKEND (backend));
405 uid = e_source_get_parent (source);
409 parent_source = e_source_registry_server_ref_source (server, uid);
410 g_return_if_fail (parent_source != NULL);
412 if (e_source_equal (collection_source, parent_source))
413 g_signal_emit (backend, signals[CHILD_ADDED], 0, source);
415 g_object_unref (parent_source);
419 collection_backend_source_removed_cb (ESourceRegistryServer *server,
421 ECollectionBackend *backend)
423 ESource *collection_source;
424 ESource *parent_source;
427 /* If the removed source was our own child, emit "child-removed".
428 * Note that the source is already unlinked from the GNode tree. */
430 collection_source = e_backend_get_source (E_BACKEND (backend));
432 uid = e_source_get_parent (source);
436 parent_source = e_source_registry_server_ref_source (server, uid);
437 g_return_if_fail (parent_source != NULL);
439 if (e_source_equal (collection_source, parent_source))
440 g_signal_emit (backend, signals[CHILD_REMOVED], 0, source);
442 g_object_unref (parent_source);
446 collection_backend_populate_idle_cb (gpointer user_data)
448 ECollectionBackend *backend;
449 ECollectionBackendClass *class;
451 backend = E_COLLECTION_BACKEND (user_data);
453 class = E_COLLECTION_BACKEND_GET_CLASS (backend);
454 g_return_val_if_fail (class->populate != NULL, FALSE);
456 class->populate (backend);
462 collection_backend_set_server (ECollectionBackend *backend,
463 ESourceRegistryServer *server)
465 g_return_if_fail (E_IS_SOURCE_REGISTRY_SERVER (server));
467 g_weak_ref_set (&backend->priv->server, server);
471 collection_backend_set_property (GObject *object,
476 switch (property_id) {
478 collection_backend_set_server (
479 E_COLLECTION_BACKEND (object),
480 g_value_get_object (value));
484 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
488 collection_backend_get_property (GObject *object,
493 switch (property_id) {
495 g_value_take_object (
497 e_collection_backend_ref_server (
498 E_COLLECTION_BACKEND (object)));
502 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
506 collection_backend_dispose (GObject *object)
508 ECollectionBackendPrivate *priv;
509 ESourceRegistryServer *server;
511 priv = E_COLLECTION_BACKEND_GET_PRIVATE (object);
513 server = g_weak_ref_get (&priv->server);
514 if (server != NULL) {
515 g_signal_handler_disconnect (
516 server, priv->source_added_handler_id);
517 g_signal_handler_disconnect (
518 server, priv->source_removed_handler_id);
519 g_weak_ref_set (&priv->server, NULL);
520 g_object_unref (server);
523 g_mutex_lock (priv->children_lock);
524 g_hash_table_remove_all (priv->children);
525 g_mutex_unlock (priv->children_lock);
527 g_mutex_lock (priv->unclaimed_resources_lock);
528 g_hash_table_remove_all (priv->unclaimed_resources);
529 g_mutex_unlock (priv->unclaimed_resources_lock);
531 /* Chain up to parent's dispose() method. */
532 G_OBJECT_CLASS (e_collection_backend_parent_class)->dispose (object);
536 collection_backend_finalize (GObject *object)
538 ECollectionBackendPrivate *priv;
540 priv = E_COLLECTION_BACKEND_GET_PRIVATE (object);
542 g_hash_table_destroy (priv->children);
543 g_mutex_free (priv->children_lock);
545 g_hash_table_destroy (priv->unclaimed_resources);
546 g_mutex_free (priv->unclaimed_resources_lock);
548 /* Chain up to parent's finalize() method. */
549 G_OBJECT_CLASS (e_collection_backend_parent_class)->finalize (object);
553 collection_backend_constructed (GObject *object)
555 ECollectionBackend *backend;
556 ESourceRegistryServer *server;
559 const gchar *collection_uid;
560 const gchar *user_cache_dir;
563 backend = E_COLLECTION_BACKEND (object);
565 /* Chain up to parent's constructed() method. */
566 G_OBJECT_CLASS (e_collection_backend_parent_class)->
567 constructed (object);
569 source = e_backend_get_source (E_BACKEND (backend));
571 /* Determine the backend's cache directory. */
573 user_cache_dir = e_get_user_cache_dir ();
574 collection_uid = e_source_get_uid (source);
575 backend->priv->cache_dir = g_build_filename (
576 user_cache_dir, "sources", collection_uid, NULL);
577 g_mkdir_with_parents (backend->priv->cache_dir, 0700);
579 /* This requires the cache directory to be set. */
580 collection_backend_load_resources (backend);
582 /* Emit "child-added" signals for the children we already have. */
584 node = e_server_side_source_get_node (E_SERVER_SIDE_SOURCE (source));
585 node = g_node_first_child (node);
587 while (node != NULL) {
588 ESource *child = E_SOURCE (node->data);
589 g_signal_emit (backend, signals[CHILD_ADDED], 0, child);
590 node = g_node_next_sibling (node);
593 /* Listen for "source-added" and "source-removed" signals
594 * from the server, which may trigger our own "child-added"
595 * and "child-removed" signals. */
597 server = e_collection_backend_ref_server (backend);
599 handler_id = g_signal_connect (
600 server, "source-added",
601 G_CALLBACK (collection_backend_source_added_cb), backend);
603 backend->priv->source_added_handler_id = handler_id;
605 handler_id = g_signal_connect (
606 server, "source-removed",
607 G_CALLBACK (collection_backend_source_removed_cb), backend);
609 backend->priv->source_removed_handler_id = handler_id;
611 g_object_unref (server);
613 /* Populate the newly-added collection from an idle callback
614 * so persistent child sources have a chance to be added first. */
618 collection_backend_populate_idle_cb,
619 g_object_ref (backend),
620 (GDestroyNotify) g_object_unref);
624 collection_backend_authenticate_sync (EBackend *backend,
625 ESourceAuthenticator *auth,
626 GCancellable *cancellable,
629 ECollectionBackend *collection_backend;
630 ESourceRegistryServer *server;
631 EAuthenticationSession *session;
636 source = e_backend_get_source (backend);
637 uid = e_source_get_uid (source);
639 collection_backend = E_COLLECTION_BACKEND (backend);
640 server = e_collection_backend_ref_server (collection_backend);
641 session = e_authentication_session_new (server, auth, uid);
643 success = e_source_registry_server_authenticate_sync (
644 server, session, cancellable, error);
646 g_object_unref (session);
647 g_object_unref (server);
653 collection_backend_populate (ECollectionBackend *backend)
655 /* Placeholder so subclasses can safely chain up. */
659 collection_backend_dup_resource_id (ECollectionBackend *backend,
662 const gchar *extension_name;
663 gchar *resource_id = NULL;
665 extension_name = E_SOURCE_EXTENSION_RESOURCE;
667 if (e_source_has_extension (source, extension_name)) {
668 ESourceResource *extension;
670 extension = e_source_get_extension (source, extension_name);
671 resource_id = e_source_resource_dup_identity (extension);
678 collection_backend_child_added (ECollectionBackend *backend,
679 ESource *child_source)
681 collection_backend_children_insert (backend, child_source);
682 collection_backend_bind_child_enabled (backend, child_source);
684 /* Collection children are not removable. */
685 e_server_side_source_set_removable (
686 E_SERVER_SIDE_SOURCE (child_source), FALSE);
690 collection_backend_child_removed (ECollectionBackend *backend,
691 ESource *child_source)
693 collection_backend_children_remove (backend, child_source);
697 collection_backend_create_resource_sync (ECollectionBackend *backend,
699 GCancellable *cancellable,
702 EAsyncClosure *closure;
703 GAsyncResult *result;
706 closure = e_async_closure_new ();
708 e_collection_backend_create_resource (
709 backend, source, cancellable,
710 e_async_closure_callback, closure);
712 result = e_async_closure_wait (closure);
714 success = e_collection_backend_create_resource_finish (
715 backend, result, error);
717 e_async_closure_free (closure);
723 collection_backend_create_resource (ECollectionBackend *backend,
725 GCancellable *cancellable,
726 GAsyncReadyCallback callback,
729 GSimpleAsyncResult *simple;
731 simple = g_simple_async_result_new_error (
732 G_OBJECT (backend), callback, user_data,
733 G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
734 _("%s does not support creating remote resources"),
735 G_OBJECT_TYPE_NAME (backend));
737 g_simple_async_result_complete_in_idle (simple);
739 g_object_unref (simple);
743 collection_backend_create_resource_finish (ECollectionBackend *backend,
744 GAsyncResult *result,
747 GSimpleAsyncResult *simple;
749 simple = G_SIMPLE_ASYNC_RESULT (result);
751 /* Assume success unless a GError is set. */
752 return !g_simple_async_result_propagate_error (simple, error);
756 collection_backend_delete_resource_sync (ECollectionBackend *backend,
758 GCancellable *cancellable,
761 EAsyncClosure *closure;
762 GAsyncResult *result;
765 closure = e_async_closure_new ();
767 e_collection_backend_delete_resource (
768 backend, source, cancellable,
769 e_async_closure_callback, closure);
771 result = e_async_closure_wait (closure);
773 success = e_collection_backend_delete_resource_finish (
774 backend, result, error);
776 e_async_closure_free (closure);
782 collection_backend_delete_resource (ECollectionBackend *backend,
784 GCancellable *cancellable,
785 GAsyncReadyCallback callback,
788 GSimpleAsyncResult *simple;
790 simple = g_simple_async_result_new_error (
791 G_OBJECT (backend), callback, user_data,
792 G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
793 _("%s does not support deleting remote resources"),
794 G_OBJECT_TYPE_NAME (backend));
796 g_simple_async_result_complete_in_idle (simple);
798 g_object_unref (simple);
802 collection_backend_delete_resource_finish (ECollectionBackend *backend,
803 GAsyncResult *result,
806 GSimpleAsyncResult *simple;
808 simple = G_SIMPLE_ASYNC_RESULT (result);
810 /* Assume success unless a GError is set. */
811 return !g_simple_async_result_propagate_error (simple, error);
815 e_collection_backend_class_init (ECollectionBackendClass *class)
817 GObjectClass *object_class;
818 EBackendClass *backend_class;
820 g_type_class_add_private (class, sizeof (ECollectionBackendPrivate));
822 object_class = G_OBJECT_CLASS (class);
823 object_class->set_property = collection_backend_set_property;
824 object_class->get_property = collection_backend_get_property;
825 object_class->dispose = collection_backend_dispose;
826 object_class->finalize = collection_backend_finalize;
827 object_class->constructed = collection_backend_constructed;
829 backend_class = E_BACKEND_CLASS (class);
830 backend_class->authenticate_sync = collection_backend_authenticate_sync;
832 class->populate = collection_backend_populate;
833 class->dup_resource_id = collection_backend_dup_resource_id;
834 class->child_added = collection_backend_child_added;
835 class->child_removed = collection_backend_child_removed;
836 class->create_resource_sync = collection_backend_create_resource_sync;
837 class->create_resource = collection_backend_create_resource;
838 class->create_resource_finish = collection_backend_create_resource_finish;
839 class->delete_resource_sync = collection_backend_delete_resource_sync;
840 class->delete_resource = collection_backend_delete_resource;
841 class->delete_resource_finish = collection_backend_delete_resource_finish;
843 g_object_class_install_property (
846 g_param_spec_object (
849 "The server to which the backend belongs",
850 E_TYPE_SOURCE_REGISTRY_SERVER,
852 G_PARAM_CONSTRUCT_ONLY |
853 G_PARAM_STATIC_STRINGS));
856 * ECollectionBackend::child-added:
857 * @backend: the #ECollectionBackend which emitted the signal
858 * @child_source: the newly-added child #EServerSideSource
860 * Emitted when an #EServerSideSource is added to @backend's
861 * #ECollectionBackend:server as a child of @backend's collection
864 * You can think of this as a filtered version of
865 * #ESourceRegistryServer's #ESourceRegistryServer::source-added
866 * signal which only lets through sources relevant to @backend.
868 signals[CHILD_ADDED] = g_signal_new (
870 G_OBJECT_CLASS_TYPE (object_class),
872 G_STRUCT_OFFSET (ECollectionBackendClass, child_added),
874 g_cclosure_marshal_VOID__OBJECT,
876 E_TYPE_SERVER_SIDE_SOURCE);
879 * ECollectionBackend::child-removed:
880 * @backend: the #ECollectionBackend which emitted the signal
881 * @child_source: the child #EServerSideSource that got removed
883 * Emitted when an #EServerSideSource that is a child of
884 * @backend's collection #EBackend:source is removed from
885 * @backend's #ECollectionBackend:server.
887 * You can think of this as a filtered version of
888 * #ESourceRegistryServer's #ESourceRegistryServer::source-removed
889 * signal which only lets through sources relevant to @backend.
891 signals[CHILD_REMOVED] = g_signal_new (
893 G_OBJECT_CLASS_TYPE (object_class),
895 G_STRUCT_OFFSET (ECollectionBackendClass, child_removed),
897 g_cclosure_marshal_VOID__OBJECT,
899 E_TYPE_SERVER_SIDE_SOURCE);
903 e_collection_backend_init (ECollectionBackend *backend)
905 GHashTable *children;
906 GHashTable *unclaimed_resources;
908 children = g_hash_table_new_full (
909 (GHashFunc) e_source_hash,
910 (GEqualFunc) e_source_equal,
911 (GDestroyNotify) g_object_unref,
912 (GDestroyNotify) NULL);
914 unclaimed_resources = g_hash_table_new_full (
915 (GHashFunc) g_str_hash,
916 (GEqualFunc) g_str_equal,
917 (GDestroyNotify) g_free,
918 (GDestroyNotify) g_object_unref);
920 backend->priv = E_COLLECTION_BACKEND_GET_PRIVATE (backend);
921 backend->priv->children = children;
922 backend->priv->children_lock = g_mutex_new ();
923 backend->priv->unclaimed_resources = unclaimed_resources;
924 backend->priv->unclaimed_resources_lock = g_mutex_new ();
928 * e_collection_backend_new_child:
929 * @backend: an #ECollectionBackend
930 * @resource_id: a stable and unique resource ID
932 * Creates a new #EServerSideSource as a child of the collection
933 * #EBackend:source owned by @backend. If possible, the #EServerSideSource
934 * is drawn from a cache of previously used sources indexed by @resource_id
935 * so that locally cached data from previous sessions can be reused.
937 * The returned data source should be passed to
938 * e_source_registry_server_add_source() to export it over D-Bus.
940 * Return: a newly-created data source
945 e_collection_backend_new_child (ECollectionBackend *backend,
946 const gchar *resource_id)
948 ESource *collection_source;
949 ESource *child_source;
950 GError *error = NULL;
952 g_return_val_if_fail (E_IS_COLLECTION_BACKEND (backend), NULL);
953 g_return_val_if_fail (resource_id != NULL, NULL);
955 /* This being a newly-created or existing data source, claiming
956 * it should never fail but we'll check for errors just the same.
957 * It's unlikely enough that we don't need a GError parameter. */
958 child_source = collection_backend_claim_resource (
959 backend, resource_id, &error);
962 g_warn_if_fail (child_source == NULL);
963 g_warning ("%s: %s", G_STRFUNC, error->message);
964 g_error_free (error);
968 collection_source = e_backend_get_source (E_BACKEND (backend));
970 g_print ("%s: Pairing %s with resource %s\n",
971 e_source_get_display_name (collection_source),
972 e_source_get_uid (child_source), resource_id);
978 * e_collection_backend_ref_server:
979 * @backend: an #ECollectionBackend
981 * Returns the #ESourceRegistryServer to which @backend belongs.
983 * The returned #ESourceRegistryServer is referenced for thread-safety.
984 * Unreference the #ESourceRegistryServer with g_object_unref() when
987 * Returns: the #ESourceRegisterServer for @backend
991 ESourceRegistryServer *
992 e_collection_backend_ref_server (ECollectionBackend *backend)
994 g_return_val_if_fail (E_IS_COLLECTION_BACKEND (backend), NULL);
996 return g_weak_ref_get (&backend->priv->server);
1000 * e_collection_backend_get_cache_dir:
1001 * @backend: an #ECollectionBackend
1003 * Returns the private cache directory path for @backend, which is named
1004 * after the #ESource:uid of @backend's collection #EBackend:source.
1006 * The cache directory is meant to store key files for backend-created
1007 * data sources. See also: e_server_side_source_set_write_directory()
1009 * Returns: the cache directory for @backend
1014 e_collection_backend_get_cache_dir (ECollectionBackend *backend)
1016 g_return_val_if_fail (E_IS_COLLECTION_BACKEND (backend), NULL);
1018 return backend->priv->cache_dir;
1022 * e_collection_backend_list_calendar_sources:
1023 * @backend: an #ECollectionBackend
1025 * Returns a list of calendar sources belonging to the data source
1026 * collection managed by @backend.
1028 * The sources returned in the list are referenced for thread-safety.
1029 * They must each be unreferenced with g_object_unref() when finished
1030 * with them. Free the returned #GList itself with g_list_free().
1032 * An easy way to free the list properly in one step is as follows:
1035 * g_list_free_full (list, g_object_unref);
1038 * Returns: a list of calendar sources
1043 e_collection_backend_list_calendar_sources (ECollectionBackend *backend)
1045 GList *result_list = NULL;
1048 g_return_val_if_fail (E_IS_COLLECTION_BACKEND (backend), NULL);
1050 list = collection_backend_children_list (backend);
1052 for (link = list; link != NULL; link = g_list_next (link)) {
1053 ESource *child_source = E_SOURCE (link->data);
1054 if (collection_backend_child_is_calendar (child_source))
1055 result_list = g_list_prepend (
1056 result_list, g_object_ref (child_source));
1059 g_list_free_full (list, (GDestroyNotify) g_object_unref);
1061 return g_list_reverse (result_list);
1065 * e_collection_backend_list_contacts_sources:
1066 * @backend: an #ECollectionBackend
1068 * Returns a list of address book sources belonging to the data source
1069 * collection managed by @backend.
1071 * The sources returned in the list are referenced for thread-safety.
1072 * They must each be unreferenced with g_object_unref() when finished
1073 * with them. Free the returned #GList itself with g_list_free().
1075 * An easy way to free the list properly in one step is as follows:
1078 * g_list_free_full (list, g_object_unref);
1081 * Returns: a list of address book sources
1086 e_collection_backend_list_contacts_sources (ECollectionBackend *backend)
1088 GList *result_list = NULL;
1091 g_return_val_if_fail (E_IS_COLLECTION_BACKEND (backend), NULL);
1093 list = collection_backend_children_list (backend);
1095 for (link = list; link != NULL; link = g_list_next (link)) {
1096 ESource *child_source = E_SOURCE (link->data);
1097 if (collection_backend_child_is_contacts (child_source))
1098 result_list = g_list_prepend (
1099 result_list, g_object_ref (child_source));
1102 g_list_free_full (list, (GDestroyNotify) g_object_unref);
1104 return g_list_reverse (result_list);
1108 * e_collection_backend_list_mail_sources:
1109 * @backend: an #ECollectionBackend
1111 * Returns a list of mail sources belonging to the data source collection
1112 * managed by @backend.
1114 * The sources returned in the list are referenced for thread-safety.
1115 * They must each be unreferenced with g_object_unref() when finished
1116 * with them. Free the returned #GList itself with g_list_free().
1118 * An easy way to free the list properly in one step is as follows:
1121 * g_list_free_full (list, g_object_unref);
1124 * Returns: a list of mail sources
1129 e_collection_backend_list_mail_sources (ECollectionBackend *backend)
1131 GList *result_list = NULL;
1134 g_return_val_if_fail (E_IS_COLLECTION_BACKEND (backend), NULL);
1136 list = collection_backend_children_list (backend);
1138 for (link = list; link != NULL; link = g_list_next (link)) {
1139 ESource *child_source = E_SOURCE (link->data);
1140 if (collection_backend_child_is_mail (child_source))
1141 result_list = g_list_prepend (
1142 result_list, g_object_ref (child_source));
1145 g_list_free_full (list, (GDestroyNotify) g_object_unref);
1147 return g_list_reverse (result_list);
1151 * e_collection_backend_create_resource_sync
1152 * @backend: an #ECollectionBackend
1153 * @source: an #ESource
1154 * @cancellable: optional #GCancellable object, or %NULL
1155 * @error: return location for a #GError, or %NULL
1157 * Creates a server-side resource described by @source. For example, if
1158 * @source describes a new calendar, an equivalent calendar is created on
1161 * It is the implementor's responsibility to examine @source and determine
1162 * what the equivalent server-side resource would be. If this cannot be
1163 * determined without ambiguity, the function must return an error.
1165 * After the server-side resource is successfully created, the implementor
1166 * must also add an #ESource to @backend's #ECollectionBackend:server. This
1167 * can either be done immediately or in response to some "resource created"
1168 * notification from the server. The added #ESource can be @source itself
1169 * or a different #ESource instance that describes the new resource.
1170 * implementor's responsibility to add an #ESource to.
1175 e_collection_backend_create_resource_sync (ECollectionBackend *backend,
1177 GCancellable *cancellable,
1180 ECollectionBackendClass *class;
1182 g_return_val_if_fail (E_IS_COLLECTION_BACKEND (backend), FALSE);
1183 g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
1185 class = E_COLLECTION_BACKEND_GET_CLASS (backend);
1186 g_return_val_if_fail (class->create_resource_sync != NULL, FALSE);
1188 return class->create_resource_sync (
1189 backend, source, cancellable, error);
1193 e_collection_backend_create_resource (ECollectionBackend *backend,
1195 GCancellable *cancellable,
1196 GAsyncReadyCallback callback,
1199 ECollectionBackendClass *class;
1201 g_return_if_fail (E_IS_COLLECTION_BACKEND (backend));
1202 g_return_if_fail (E_IS_SOURCE (source));
1204 class = E_COLLECTION_BACKEND_GET_CLASS (backend);
1205 g_return_if_fail (class->create_resource != NULL);
1207 class->create_resource (
1208 backend, source, cancellable, callback, user_data);
1212 e_collection_backend_create_resource_finish (ECollectionBackend *backend,
1213 GAsyncResult *result,
1216 ECollectionBackendClass *class;
1218 g_return_val_if_fail (E_IS_COLLECTION_BACKEND (backend), FALSE);
1219 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
1221 class = E_COLLECTION_BACKEND_GET_CLASS (backend);
1222 g_return_val_if_fail (class->create_resource_finish != NULL, FALSE);
1224 return class->create_resource_finish (backend, result, error);
1228 e_collection_backend_delete_resource_sync (ECollectionBackend *backend,
1230 GCancellable *cancellable,
1233 ECollectionBackendClass *class;
1235 g_return_val_if_fail (E_IS_COLLECTION_BACKEND (backend), FALSE);
1236 g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
1238 class = E_COLLECTION_BACKEND_GET_CLASS (backend);
1239 g_return_val_if_fail (class->delete_resource_sync != NULL, FALSE);
1241 return class->delete_resource_sync (
1242 backend, source, cancellable, error);
1246 e_collection_backend_delete_resource (ECollectionBackend *backend,
1248 GCancellable *cancellable,
1249 GAsyncReadyCallback callback,
1252 ECollectionBackendClass *class;
1254 g_return_if_fail (E_IS_COLLECTION_BACKEND (backend));
1255 g_return_if_fail (E_IS_SOURCE (source));
1257 class = E_COLLECTION_BACKEND_GET_CLASS (backend);
1258 g_return_if_fail (class->delete_resource != NULL);
1260 return class->delete_resource (
1261 backend, source, cancellable, callback, user_data);
1265 e_collection_backend_delete_resource_finish (ECollectionBackend *backend,
1266 GAsyncResult *result,
1269 ECollectionBackendClass *class;
1271 g_return_val_if_fail (E_IS_COLLECTION_BACKEND (backend), FALSE);
1272 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
1274 class = E_COLLECTION_BACKEND_GET_CLASS (backend);
1275 g_return_val_if_fail (class->delete_resource_finish != NULL, FALSE);
1277 return class->delete_resource_finish (backend, result, error);