2 * e-server-side-source.c
4 * This library is free software you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation.
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this library; if not, see <http://www.gnu.org/licenses/>.
19 * SECTION: e-server-side-source
20 * @include: libebackend/libebackend.h
21 * @short_description: A server-side data source
23 * An #EServerSideSource is an #ESource with some additional capabilities
24 * exclusive to the registry D-Bus service.
27 #include "e-server-side-source.h"
30 #include <glib/gi18n-lib.h>
32 /* Private D-Bus classes. */
33 #include <e-dbus-source.h>
35 #define E_SERVER_SIDE_SOURCE_GET_PRIVATE(obj) \
36 (G_TYPE_INSTANCE_GET_PRIVATE \
37 ((obj), E_TYPE_SERVER_SIDE_SOURCE, EServerSideSourcePrivate))
39 #define DBUS_OBJECT_PATH E_SOURCE_REGISTRY_SERVER_OBJECT_PATH "/Source"
41 #define PRIMARY_GROUP_NAME "Data Source"
43 typedef struct _AsyncContext AsyncContext;
45 struct _EServerSideSourcePrivate {
46 gpointer server; /* weak pointer */
47 GWeakRef oauth2_support;
55 gboolean allow_auth_prompt;
56 GType auth_session_type;
57 gchar *write_directory;
60 struct _AsyncContext {
61 EDBusSourceRemoteCreatable *remote_creatable;
62 EDBusSourceRemoteDeletable *remote_deletable;
63 EDBusSourceOAuth2Support *oauth2_support;
64 GDBusMethodInvocation *invocation;
69 PROP_ALLOW_AUTH_PROMPT,
70 PROP_AUTH_SESSION_TYPE,
74 PROP_REMOTE_CREATABLE,
75 PROP_REMOTE_DELETABLE,
82 static GInitableIface *initable_parent_interface;
84 /* Forward Declarations */
85 static void e_server_side_source_initable_init
86 (GInitableIface *iface);
88 G_DEFINE_TYPE_WITH_CODE (
92 G_IMPLEMENT_INTERFACE (
94 e_server_side_source_initable_init))
97 async_context_free (AsyncContext *async_context)
99 if (async_context->remote_creatable != NULL)
100 g_object_unref (async_context->remote_creatable);
102 if (async_context->remote_deletable != NULL)
103 g_object_unref (async_context->remote_deletable);
105 if (async_context->oauth2_support != NULL)
106 g_object_unref (async_context->oauth2_support);
108 if (async_context->invocation != NULL)
109 g_object_unref (async_context->invocation);
111 g_slice_free (AsyncContext, async_context);
115 server_side_source_parse_data (GKeyFile *key_file,
122 success = g_key_file_load_from_data (
123 key_file, data, length, G_KEY_FILE_NONE, error);
128 /* Make sure the key file has a [Data Source] group. */
129 if (!g_key_file_has_group (key_file, PRIMARY_GROUP_NAME)) {
131 error, G_KEY_FILE_ERROR,
132 G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
133 _("Data source is missing a [%s] group"),
142 server_side_source_print_diff (ESource *source,
143 const gchar *old_data,
144 const gchar *new_data)
146 gchar **old_strv = NULL;
147 gchar **new_strv = NULL;
148 guint old_length = 0;
149 guint new_length = 0;
152 g_print ("Saving %s\n", e_source_get_uid (source));
154 if (old_data != NULL) {
155 old_strv = g_strsplit (old_data, "\n", 0);
156 old_length = g_strv_length (old_strv);
159 if (new_data != NULL) {
160 new_strv = g_strsplit (new_data, "\n", 0);
161 new_length = g_strv_length (new_strv);
164 for (ii = 0; ii < MIN (old_length, new_length); ii++) {
165 if (g_strcmp0 (old_strv[ii], new_strv[ii]) != 0) {
166 g_print (" - : %s\n", old_strv[ii]);
167 g_print (" + : %s\n", new_strv[ii]);
169 g_print (" : %s\n", old_strv[ii]);
173 for (; ii < old_length; ii++)
174 g_print (" - : %s\n", old_strv[ii]);
176 for (; ii < new_length; ii++)
177 g_print (" + : %s\n", new_strv[ii]);
179 g_strfreev (old_strv);
180 g_strfreev (new_strv);
184 server_side_source_traverse_cb (GNode *node,
187 g_queue_push_tail (queue, g_object_ref (node->data));
193 server_side_source_allow_auth_prompt_cb (EDBusSource *dbus_interface,
194 GDBusMethodInvocation *invocation,
195 EServerSideSource *source)
197 e_server_side_source_set_allow_auth_prompt (source, TRUE);
199 e_dbus_source_complete_allow_auth_prompt (dbus_interface, invocation);
205 server_side_source_remove_cb (EDBusSourceRemovable *dbus_interface,
206 GDBusMethodInvocation *invocation,
207 EServerSideSource *source)
209 GError *error = NULL;
211 /* Note we don't need to verify the source is removable here
212 * since if it isn't, the remove() method won't be available.
213 * Descendants of the source are removed whether they export
214 * a remove() method or not. */
216 e_source_remove_sync (E_SOURCE (source), NULL, &error);
219 g_dbus_method_invocation_take_error (invocation, error);
221 e_dbus_source_removable_complete_remove (
222 dbus_interface, invocation);
228 server_side_source_write_cb (EDBusSourceWritable *dbus_interface,
229 GDBusMethodInvocation *invocation,
234 GDBusObject *dbus_object;
235 EDBusSource *dbus_source;
236 GError *error = NULL;
238 /* Note we don't need to verify the source is writable here
239 * since if it isn't, the write() method won't be available. */
241 dbus_object = e_source_ref_dbus_object (source);
242 dbus_source = e_dbus_object_get_source (E_DBUS_OBJECT (dbus_object));
244 /* Validate the raw data before making the changes live. */
245 key_file = g_key_file_new ();
246 server_side_source_parse_data (key_file, data, strlen (data), &error);
247 g_key_file_free (key_file);
249 /* Q: How does this trigger data being written to disk?
251 * A: Here's the sequence of events:
253 * 1) We set the EDBusSource:data property.
254 * 2) ESource picks up the "notify::data" signal and parses
255 * the raw data, which triggers an ESource:changed signal.
256 * 3) Our changed() method schedules an idle callback.
257 * 4) The idle callback calls e_source_write_sync().
258 * 5) e_source_write_sync() calls e_dbus_source_dup_data()
259 * and synchronously writes the resulting string to disk.
261 * XXX: This should be done more straigtforward, because rely
262 * on two different signals and having actual data file
263 * save in 5 steps is ridiculous, not talking that
264 * the returned GError from this D-Bus call doesn't handle
265 * errors from actual file save, which can also break, thus
266 * the caller doesn't know about any real problem during saving
267 * and thinks that everything went fine.
271 e_dbus_source_set_data (dbus_source, data);
273 /* Make sure the ESource::changed signal is called, otherwise
274 * the above Q&A doesn't work and changed data are not saved. */
275 e_source_changed (source);
279 g_dbus_method_invocation_take_error (invocation, error);
281 e_dbus_source_writable_complete_write (
282 dbus_interface, invocation);
284 g_object_unref (dbus_source);
285 g_object_unref (dbus_object);
290 /* Helper for server_side_source_remote_create_cb() */
292 server_side_source_remote_create_done_cb (GObject *source_object,
293 GAsyncResult *result,
297 AsyncContext *async_context;
298 GError *error = NULL;
300 source = E_SOURCE (source_object);
301 async_context = (AsyncContext *) user_data;
303 e_source_remote_create_finish (source, result, &error);
306 g_dbus_method_invocation_take_error (
307 async_context->invocation, error);
309 e_dbus_source_remote_creatable_complete_create (
310 async_context->remote_creatable,
311 async_context->invocation);
313 async_context_free (async_context);
317 server_side_source_remote_create_cb (EDBusSourceRemoteCreatable *dbus_interface,
318 GDBusMethodInvocation *invocation,
323 EServerSideSource *server_side_source;
324 ESourceRegistryServer *server;
325 AsyncContext *async_context;
326 ESource *scratch_source;
327 GDBusObject *dbus_object;
328 EDBusSource *dbus_source;
331 GError *error = NULL;
333 /* Create a new EServerSideSource from 'uid' and 'data' but
334 * DO NOT add it to the ESourceRegistryServer yet. It's up
335 * to the ECollectionBackend whether to use source as given
336 * or create its own equivalent EServerSideSource, possibly
337 * in response to a notification from a remote server. */
339 /* Validate the raw data. */
340 key_file = g_key_file_new ();
341 server_side_source_parse_data (key_file, data, strlen (data), &error);
342 g_key_file_free (key_file);
345 g_dbus_method_invocation_take_error (invocation, error);
349 server_side_source = E_SERVER_SIDE_SOURCE (source);
350 server = e_server_side_source_get_server (server_side_source);
352 file = e_server_side_source_new_user_file (uid);
353 scratch_source = e_server_side_source_new (server, file, &error);
354 g_object_unref (file);
358 ((scratch_source != NULL) && (error == NULL)) ||
359 ((scratch_source == NULL) && (error != NULL)));
362 g_dbus_method_invocation_take_error (invocation, error);
366 dbus_object = e_source_ref_dbus_object (scratch_source);
367 dbus_source = e_dbus_object_get_source (E_DBUS_OBJECT (dbus_object));
369 e_dbus_source_set_data (dbus_source, data);
371 g_object_unref (dbus_object);
372 g_object_unref (dbus_source);
374 async_context = g_slice_new0 (AsyncContext);
375 async_context->remote_creatable = g_object_ref (dbus_interface);
376 async_context->invocation = g_object_ref (invocation);
378 e_source_remote_create (
379 source, scratch_source, NULL,
380 server_side_source_remote_create_done_cb,
383 g_object_unref (scratch_source);
388 /* Helper for server_side_source_remote_delete_cb() */
390 server_side_source_remote_delete_done_cb (GObject *source_object,
391 GAsyncResult *result,
395 AsyncContext *async_context;
396 GError *error = NULL;
398 source = E_SOURCE (source_object);
399 async_context = (AsyncContext *) user_data;
401 e_source_remote_delete_finish (source, result, &error);
404 g_dbus_method_invocation_take_error (
405 async_context->invocation, error);
407 e_dbus_source_remote_deletable_complete_delete (
408 async_context->remote_deletable,
409 async_context->invocation);
411 async_context_free (async_context);
415 server_side_source_remote_delete_cb (EDBusSourceRemoteDeletable *dbus_interface,
416 GDBusMethodInvocation *invocation,
419 AsyncContext *async_context;
421 async_context = g_slice_new0 (AsyncContext);
422 async_context->remote_deletable = g_object_ref (dbus_interface);
423 async_context->invocation = g_object_ref (invocation);
425 e_source_remote_delete (
427 server_side_source_remote_delete_done_cb,
433 /* Helper for server_side_source_get_access_token_cb() */
435 server_side_source_get_access_token_done_cb (GObject *source_object,
436 GAsyncResult *result,
440 AsyncContext *async_context;
441 gchar *access_token = NULL;
443 GError *error = NULL;
445 source = E_SOURCE (source_object);
446 async_context = (AsyncContext *) user_data;
448 e_source_get_oauth2_access_token_finish (
449 source, result, &access_token, &expires_in, &error);
453 ((access_token != NULL) && (error == NULL)) ||
454 ((access_token == NULL) && (error != NULL)));
457 g_dbus_method_invocation_take_error (
458 async_context->invocation, error);
460 e_dbus_source_oauth2_support_complete_get_access_token (
461 async_context->oauth2_support,
462 async_context->invocation,
463 access_token, expires_in);
465 g_free (access_token);
467 async_context_free (async_context);
471 server_side_source_get_access_token_cb (EDBusSourceOAuth2Support *dbus_interface,
472 GDBusMethodInvocation *invocation,
475 AsyncContext *async_context;
477 async_context = g_slice_new0 (AsyncContext);
478 async_context->oauth2_support = g_object_ref (dbus_interface);
479 async_context->invocation = g_object_ref (invocation);
481 e_source_get_oauth2_access_token (
483 server_side_source_get_access_token_done_cb,
490 server_side_source_set_file (EServerSideSource *source,
493 g_return_if_fail (file == NULL || G_IS_FILE (file));
494 g_return_if_fail (source->priv->file == NULL);
497 source->priv->file = g_object_ref (file);
501 server_side_source_set_server (EServerSideSource *source,
502 ESourceRegistryServer *server)
504 g_return_if_fail (E_IS_SOURCE_REGISTRY_SERVER (server));
505 g_return_if_fail (source->priv->server == NULL);
507 source->priv->server = server;
509 g_object_add_weak_pointer (
510 G_OBJECT (server), &source->priv->server);
514 server_side_source_set_property (GObject *object,
519 switch (property_id) {
520 case PROP_ALLOW_AUTH_PROMPT:
521 e_server_side_source_set_allow_auth_prompt (
522 E_SERVER_SIDE_SOURCE (object),
523 g_value_get_boolean (value));
526 case PROP_AUTH_SESSION_TYPE:
527 e_server_side_source_set_auth_session_type (
528 E_SERVER_SIDE_SOURCE (object),
529 g_value_get_gtype (value));
533 server_side_source_set_file (
534 E_SERVER_SIDE_SOURCE (object),
535 g_value_get_object (value));
538 case PROP_OAUTH2_SUPPORT:
539 e_server_side_source_set_oauth2_support (
540 E_SERVER_SIDE_SOURCE (object),
541 g_value_get_object (value));
544 case PROP_REMOTE_CREATABLE:
545 e_server_side_source_set_remote_creatable (
546 E_SERVER_SIDE_SOURCE (object),
547 g_value_get_boolean (value));
550 case PROP_REMOTE_DELETABLE:
551 e_server_side_source_set_remote_deletable (
552 E_SERVER_SIDE_SOURCE (object),
553 g_value_get_boolean (value));
557 e_server_side_source_set_removable (
558 E_SERVER_SIDE_SOURCE (object),
559 g_value_get_boolean (value));
563 server_side_source_set_server (
564 E_SERVER_SIDE_SOURCE (object),
565 g_value_get_object (value));
569 e_server_side_source_set_writable (
570 E_SERVER_SIDE_SOURCE (object),
571 g_value_get_boolean (value));
574 case PROP_WRITE_DIRECTORY:
575 e_server_side_source_set_write_directory (
576 E_SERVER_SIDE_SOURCE (object),
577 g_value_get_string (value));
581 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
585 server_side_source_get_property (GObject *object,
590 switch (property_id) {
591 case PROP_ALLOW_AUTH_PROMPT:
592 g_value_set_boolean (
594 e_server_side_source_get_allow_auth_prompt (
595 E_SERVER_SIDE_SOURCE (object)));
598 case PROP_AUTH_SESSION_TYPE:
601 e_server_side_source_get_auth_session_type (
602 E_SERVER_SIDE_SOURCE (object)));
606 g_value_set_boolean (
608 e_server_side_source_get_exported (
609 E_SERVER_SIDE_SOURCE (object)));
615 e_server_side_source_get_file (
616 E_SERVER_SIDE_SOURCE (object)));
619 case PROP_OAUTH2_SUPPORT:
620 g_value_take_object (
622 e_server_side_source_ref_oauth2_support (
623 E_SERVER_SIDE_SOURCE (object)));
626 case PROP_REMOTE_CREATABLE:
627 g_value_set_boolean (
629 e_source_get_remote_creatable (
633 case PROP_REMOTE_DELETABLE:
634 g_value_set_boolean (
636 e_source_get_remote_deletable (
641 g_value_set_boolean (
643 e_source_get_removable (
650 e_server_side_source_get_server (
651 E_SERVER_SIDE_SOURCE (object)));
655 g_value_set_boolean (
657 e_source_get_writable (
661 case PROP_WRITE_DIRECTORY:
664 e_server_side_source_get_write_directory (
665 E_SERVER_SIDE_SOURCE (object)));
669 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
673 server_side_source_dispose (GObject *object)
675 EServerSideSourcePrivate *priv;
677 priv = E_SERVER_SIDE_SOURCE_GET_PRIVATE (object);
679 if (priv->server != NULL) {
680 g_object_remove_weak_pointer (
681 G_OBJECT (priv->server), &priv->server);
685 g_weak_ref_set (&priv->oauth2_support, NULL);
687 if (priv->file != NULL) {
688 g_object_unref (priv->file);
692 /* Chain up to parent's dispose() method. */
693 G_OBJECT_CLASS (e_server_side_source_parent_class)->dispose (object);
697 server_side_source_finalize (GObject *object)
699 EServerSideSourcePrivate *priv;
701 priv = E_SERVER_SIDE_SOURCE_GET_PRIVATE (object);
703 g_node_unlink (&priv->node);
705 g_free (priv->file_contents);
706 g_free (priv->write_directory);
708 /* Chain up to parent's finalize() method. */
709 G_OBJECT_CLASS (e_server_side_source_parent_class)->finalize (object);
713 server_side_source_changed (ESource *source)
715 GDBusObject *dbus_object;
716 EDBusSource *dbus_source;
719 GError *error = NULL;
721 /* Do not write changes to disk until the source has been exported. */
722 if (!e_server_side_source_get_exported (E_SERVER_SIDE_SOURCE (source)))
725 dbus_object = e_source_ref_dbus_object (source);
726 dbus_source = e_dbus_object_get_source (E_DBUS_OBJECT (dbus_object));
728 old_data = e_dbus_source_dup_data (dbus_source);
729 new_data = e_source_to_string (source, NULL);
731 /* Setting the "data" property triggers the ESource::changed,
732 * signal, which invokes this callback, which sets the "data"
733 * property, etc. This breaks an otherwise infinite loop. */
734 if (g_strcmp0 (old_data, new_data) != 0)
735 e_dbus_source_set_data (dbus_source, new_data);
740 g_object_unref (dbus_source);
741 g_object_unref (dbus_object);
743 /* This writes the "data" property to disk. */
744 e_source_write_sync (source, NULL, &error);
747 g_warning ("%s: %s", G_STRFUNC, error->message);
748 g_error_free (error);
753 server_side_source_remove_sync (ESource *source,
754 GCancellable *cancellable,
757 EAsyncClosure *closure;
758 GAsyncResult *result;
761 closure = e_async_closure_new ();
764 source, cancellable, e_async_closure_callback, closure);
766 result = e_async_closure_wait (closure);
768 success = e_source_remove_finish (source, result, error);
770 e_async_closure_free (closure);
776 server_side_source_remove (ESource *source,
777 GCancellable *cancellable,
778 GAsyncReadyCallback callback,
781 EServerSideSourcePrivate *priv;
782 GSimpleAsyncResult *simple;
783 ESourceRegistryServer *server;
784 GQueue queue = G_QUEUE_INIT;
786 GError *error = NULL;
788 /* XXX Yes we block here. We do this operation
789 * synchronously to keep the server code simple. */
791 priv = E_SERVER_SIDE_SOURCE_GET_PRIVATE (source);
793 simple = g_simple_async_result_new (
794 G_OBJECT (source), callback, user_data,
795 server_side_source_remove);
797 g_simple_async_result_set_check_cancellable (simple, cancellable);
799 /* Collect the source and its descendants into a queue.
800 * Do this before unexporting so we hold references to
801 * all the removed sources. */
803 &priv->node, G_POST_ORDER, G_TRAVERSE_ALL, -1,
804 (GNodeTraverseFunc) server_side_source_traverse_cb, &queue);
806 /* Unexport the object and its descendants. */
807 server = E_SOURCE_REGISTRY_SERVER (priv->server);
808 e_source_registry_server_remove_source (server, source);
810 list = g_queue_peek_head_link (&queue);
812 /* Delete the key file for each source in the queue. */
813 for (link = list; link != NULL; link = g_list_next (link)) {
814 EServerSideSource *child;
817 child = E_SERVER_SIDE_SOURCE (link->data);
818 file = e_server_side_source_get_file (child);
821 g_file_delete (file, cancellable, &error);
823 /* XXX Even though e_source_registry_server_remove_source()
824 * is called first, the object path is unexported from
825 * an idle callback some time after we have deleted the
826 * key file. That creates a small window of time where
827 * the file is deleted but the object is still exported.
829 * If a client calls e_source_remove() during that small
830 * window of time, we still want to report a successful
831 * removal, so disregard G_IO_ERROR_NOT_FOUND. */
832 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
833 g_clear_error (&error);
840 while (!g_queue_is_empty (&queue))
841 g_object_unref (g_queue_pop_head (&queue));
844 g_simple_async_result_take_error (simple, error);
846 g_simple_async_result_complete_in_idle (simple);
847 g_object_unref (simple);
851 server_side_source_remove_finish (ESource *source,
852 GAsyncResult *result,
855 GSimpleAsyncResult *simple;
857 g_return_val_if_fail (
858 g_simple_async_result_is_valid (
859 result, G_OBJECT (source),
860 server_side_source_remove), FALSE);
862 simple = G_SIMPLE_ASYNC_RESULT (result);
864 /* Assume success unless a GError is set. */
865 return !g_simple_async_result_propagate_error (simple, error);
869 server_side_source_write_sync (ESource *source,
870 GCancellable *cancellable,
873 EAsyncClosure *closure;
874 GAsyncResult *result;
877 closure = e_async_closure_new ();
880 source, cancellable, e_async_closure_callback, closure);
882 result = e_async_closure_wait (closure);
884 success = e_source_write_finish (source, result, error);
886 e_async_closure_free (closure);
892 server_side_source_write (ESource *source,
893 GCancellable *cancellable,
894 GAsyncReadyCallback callback,
897 EServerSideSourcePrivate *priv;
898 GSimpleAsyncResult *simple;
899 GDBusObject *dbus_object;
900 EDBusSource *dbus_source;
901 gboolean replace_file;
902 const gchar *old_data;
904 GError *error = NULL;
906 /* XXX Yes we block here. We do this operation
907 * synchronously to keep the server code simple. */
909 priv = E_SERVER_SIDE_SOURCE_GET_PRIVATE (source);
911 simple = g_simple_async_result_new (
912 G_OBJECT (source), callback, user_data,
913 server_side_source_write);
915 g_simple_async_result_set_check_cancellable (simple, cancellable);
917 dbus_object = e_source_ref_dbus_object (source);
918 dbus_source = e_dbus_object_get_source (E_DBUS_OBJECT (dbus_object));
920 old_data = priv->file_contents;
921 new_data = e_source_to_string (source, NULL);
923 /* When writing source data to disk, we always write to the
924 * source's specified "write-directory" even if the key file
925 * was originally read from a different directory. To avoid
926 * polluting the write directory with key files identical to
927 * the original, we check that the data has actually changed
928 * before writing a copy to disk. */
931 G_IS_FILE (priv->file) &&
932 (g_strcmp0 (old_data, new_data) != 0);
936 GFile *write_directory;
939 g_warn_if_fail (priv->write_directory != NULL);
941 basename = g_file_get_basename (priv->file);
942 write_directory = g_file_new_for_path (priv->write_directory);
943 file = g_file_get_child (write_directory, basename);
946 if (!g_file_equal (file, priv->file)) {
947 g_object_unref (priv->file);
948 priv->file = g_object_ref (file);
951 server_side_source_print_diff (source, old_data, new_data);
953 g_file_make_directory_with_parents (
954 write_directory, cancellable, &error);
956 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS))
957 g_clear_error (&error);
960 g_file_replace_contents (
961 file, new_data, strlen (new_data),
962 NULL, FALSE, G_FILE_CREATE_NONE,
963 NULL, cancellable, &error);
966 g_free (priv->file_contents);
967 priv->file_contents = new_data;
971 g_object_unref (write_directory);
972 g_object_unref (file);
977 g_object_unref (dbus_source);
978 g_object_unref (dbus_object);
981 g_simple_async_result_take_error (simple, error);
983 g_simple_async_result_complete_in_idle (simple);
984 g_object_unref (simple);
988 server_side_source_write_finish (ESource *source,
989 GAsyncResult *result,
992 GSimpleAsyncResult *simple;
994 g_return_val_if_fail (
995 g_simple_async_result_is_valid (
996 result, G_OBJECT (source),
997 server_side_source_write), FALSE);
999 simple = G_SIMPLE_ASYNC_RESULT (result);
1001 /* Assume success unless a GError is set. */
1002 return !g_simple_async_result_propagate_error (simple, error);
1006 server_side_source_remote_create_sync (ESource *source,
1007 ESource *scratch_source,
1008 GCancellable *cancellable,
1011 ECollectionBackend *backend;
1012 ESourceRegistryServer *server;
1013 EServerSideSource *server_side_source;
1016 if (!e_source_get_remote_creatable (source)) {
1019 G_IO_ERROR_NOT_SUPPORTED,
1020 _("Data source '%s' does not "
1021 "support creating remote resources"),
1022 e_source_get_display_name (source));
1026 server_side_source = E_SERVER_SIDE_SOURCE (source);
1027 server = e_server_side_source_get_server (server_side_source);
1028 backend = e_source_registry_server_ref_backend (server, source);
1030 if (backend == NULL) {
1033 G_IO_ERROR_NOT_SUPPORTED,
1034 _("Data source '%s' has no collection "
1035 "backend to create the remote resource"),
1036 e_source_get_display_name (source));
1040 success = e_collection_backend_create_resource_sync (
1041 backend, scratch_source, cancellable, error);
1043 g_object_unref (backend);
1049 server_side_source_remote_delete_sync (ESource *source,
1050 GCancellable *cancellable,
1053 ECollectionBackend *backend;
1054 ESourceRegistryServer *server;
1055 EServerSideSource *server_side_source;
1058 if (!e_source_get_remote_deletable (source)) {
1061 G_IO_ERROR_NOT_SUPPORTED,
1062 _("Data source '%s' does not "
1063 "support deleting remote resources"),
1064 e_source_get_display_name (source));
1068 server_side_source = E_SERVER_SIDE_SOURCE (source);
1069 server = e_server_side_source_get_server (server_side_source);
1070 backend = e_source_registry_server_ref_backend (server, source);
1072 if (backend == NULL) {
1075 G_IO_ERROR_NOT_SUPPORTED,
1076 _("Data source '%s' has no collection "
1077 "backend to delete the remote resource"),
1078 e_source_get_display_name (source));
1082 success = e_collection_backend_delete_resource_sync (
1083 backend, source, cancellable, error);
1085 g_object_unref (backend);
1091 server_side_source_get_oauth2_access_token_sync (ESource *source,
1092 GCancellable *cancellable,
1093 gchar **out_access_token,
1094 gint *out_expires_in,
1097 EOAuth2Support *oauth2_support;
1100 oauth2_support = e_server_side_source_ref_oauth2_support (
1101 E_SERVER_SIDE_SOURCE (source));
1103 if (oauth2_support == NULL) {
1106 G_IO_ERROR_NOT_SUPPORTED,
1107 _("Data source '%s' does not "
1108 "support OAuth 2.0 authentication"),
1109 e_source_get_display_name (source));
1113 success = e_oauth2_support_get_access_token_sync (
1114 oauth2_support, source, cancellable,
1115 out_access_token, out_expires_in, error);
1117 g_object_unref (oauth2_support);
1123 server_side_source_initable_init (GInitable *initable,
1124 GCancellable *cancellable,
1127 EServerSideSource *source;
1128 GDBusObject *dbus_object;
1129 EDBusSource *dbus_source;
1132 source = E_SERVER_SIDE_SOURCE (initable);
1134 dbus_source = e_dbus_source_skeleton_new ();
1136 uid = e_source_dup_uid (E_SOURCE (source));
1139 e_dbus_source_set_uid (dbus_source, uid);
1142 dbus_object = e_source_ref_dbus_object (E_SOURCE (source));
1143 e_dbus_object_skeleton_set_source (
1144 E_DBUS_OBJECT_SKELETON (dbus_object), dbus_source);
1145 g_object_unref (dbus_object);
1148 dbus_source, "handle-allow-auth-prompt",
1149 G_CALLBACK (server_side_source_allow_auth_prompt_cb), source);
1151 g_object_unref (dbus_source);
1153 if (!e_server_side_source_load (source, cancellable, error))
1156 /* Chain up to parent interface's init() method. */
1157 return initable_parent_interface->init (initable, cancellable, error);
1161 e_server_side_source_class_init (EServerSideSourceClass *class)
1163 GObjectClass *object_class;
1164 ESourceClass *source_class;
1166 g_type_class_add_private (class, sizeof (EServerSideSourcePrivate));
1168 object_class = G_OBJECT_CLASS (class);
1169 object_class->set_property = server_side_source_set_property;
1170 object_class->get_property = server_side_source_get_property;
1171 object_class->dispose = server_side_source_dispose;
1172 object_class->finalize = server_side_source_finalize;
1174 source_class = E_SOURCE_CLASS (class);
1175 source_class->changed = server_side_source_changed;
1176 source_class->remove_sync = server_side_source_remove_sync;
1177 source_class->remove = server_side_source_remove;
1178 source_class->remove_finish = server_side_source_remove_finish;
1179 source_class->write_sync = server_side_source_write_sync;
1180 source_class->write = server_side_source_write;
1181 source_class->write_finish = server_side_source_write_finish;
1182 source_class->remote_create_sync =
1183 server_side_source_remote_create_sync;
1184 source_class->remote_delete_sync =
1185 server_side_source_remote_delete_sync;
1186 source_class->get_oauth2_access_token_sync =
1187 server_side_source_get_oauth2_access_token_sync;
1189 g_object_class_install_property (
1191 PROP_ALLOW_AUTH_PROMPT,
1192 g_param_spec_boolean (
1193 "allow-auth-prompt",
1194 "Allow Auth Prompt",
1195 "Whether authentication sessions may "
1196 "interrupt the user for a password",
1200 G_PARAM_STATIC_STRINGS));
1202 g_object_class_install_property (
1204 PROP_AUTH_SESSION_TYPE,
1205 g_param_spec_gtype (
1206 "auth-session-type",
1207 "Auth Session Type",
1208 "The type of authentication session "
1209 "to instantiate for this source",
1210 E_TYPE_AUTHENTICATION_SESSION,
1212 G_PARAM_STATIC_STRINGS));
1214 g_object_class_install_property (
1217 g_param_spec_boolean (
1220 "Whether the source has been exported over D-Bus",
1223 G_PARAM_STATIC_STRINGS));
1225 g_object_class_install_property (
1228 g_param_spec_object (
1231 "The key file for the data source",
1234 G_PARAM_CONSTRUCT_ONLY |
1235 G_PARAM_STATIC_STRINGS));
1237 g_object_class_install_property (
1239 PROP_OAUTH2_SUPPORT,
1240 g_param_spec_object (
1243 "The object providing OAuth 2.0 support",
1244 E_TYPE_OAUTH2_SUPPORT,
1246 G_PARAM_STATIC_STRINGS));
1248 /* This overrides the "remote-creatable" property
1249 * in ESourceClass with a writable version. */
1250 g_object_class_install_property (
1252 PROP_REMOTE_CREATABLE,
1253 g_param_spec_boolean (
1256 "Whether the data source "
1257 "can create remote resources",
1260 G_PARAM_STATIC_STRINGS));
1262 /* This overrides the "remote-deletable" property
1263 * in ESourceClass with a writable version. */
1264 g_object_class_install_property (
1266 PROP_REMOTE_DELETABLE,
1267 g_param_spec_boolean (
1270 "Whether the data source "
1271 "can delete remote resources",
1274 G_PARAM_STATIC_STRINGS));
1276 /* This overrides the "removable" property
1277 * in ESourceClass with a writable version. */
1278 g_object_class_install_property (
1281 g_param_spec_boolean (
1284 "Whether the data source is removable",
1287 G_PARAM_STATIC_STRINGS));
1289 g_object_class_install_property (
1292 g_param_spec_object (
1295 "The server to which the data source belongs",
1296 E_TYPE_SOURCE_REGISTRY_SERVER,
1298 G_PARAM_CONSTRUCT_ONLY |
1299 G_PARAM_STATIC_STRINGS));
1301 /* This overrides the "writable" property
1302 * in ESourceClass with a writable version. */
1303 g_object_class_install_property (
1306 g_param_spec_boolean (
1309 "Whether the data source is writable",
1312 G_PARAM_STATIC_STRINGS));
1314 /* Do not use G_PARAM_CONSTRUCT. We initialize the
1315 * property ourselves in e_server_side_source_init(). */
1316 g_object_class_install_property (
1318 PROP_WRITE_DIRECTORY,
1319 g_param_spec_string (
1322 "Directory in which to write changes to disk",
1325 G_PARAM_STATIC_STRINGS));
1329 e_server_side_source_initable_init (GInitableIface *iface)
1331 initable_parent_interface = g_type_interface_peek_parent (iface);
1333 iface->init = server_side_source_initable_init;
1337 e_server_side_source_init (EServerSideSource *source)
1339 const gchar *user_dir;
1341 source->priv = E_SERVER_SIDE_SOURCE_GET_PRIVATE (source);
1343 source->priv->node.data = source;
1345 user_dir = e_server_side_source_get_user_dir ();
1346 source->priv->write_directory = g_strdup (user_dir);
1348 source->priv->auth_session_type = E_TYPE_AUTHENTICATION_SESSION;
1352 * e_server_side_source_get_user_dir:
1354 * Returns the directory where user-specific data source files are stored.
1356 * Returns: the user-specific data source directory
1361 e_server_side_source_get_user_dir (void)
1363 static gchar *dirname = NULL;
1365 if (G_UNLIKELY (dirname == NULL)) {
1366 const gchar *config_dir = e_get_user_config_dir ();
1367 dirname = g_build_filename (config_dir, "sources", NULL);
1368 g_mkdir_with_parents (dirname, 0700);
1375 * e_server_side_source_new_user_file:
1376 * @uid: unique identifier for a data source, or %NULL
1378 * Generates a unique file name for a new user-specific data source.
1379 * If @uid is non-%NULL it will be used in the basename of the file,
1380 * otherwise a unique basename will be generated using e_uid_new().
1382 * The returned #GFile can then be passed to e_server_side_source_new().
1383 * Unreference the #GFile with g_object_unref() when finished with it.
1385 * Note the data source file itself is not created here, only its name.
1387 * Returns: the #GFile for a new data source
1392 e_server_side_source_new_user_file (const gchar *uid)
1398 const gchar *user_dir;
1401 safe_uid = e_uid_new ();
1403 safe_uid = g_strdup (uid);
1404 e_filename_make_safe (safe_uid);
1406 user_dir = e_server_side_source_get_user_dir ();
1407 basename = g_strconcat (safe_uid, ".source", NULL);
1408 filename = g_build_filename (user_dir, basename, NULL);
1410 file = g_file_new_for_path (filename);
1420 * e_server_side_source_uid_from_file:
1421 * @file: a #GFile for a data source
1422 * @error: return location for a #GError, or %NULL
1424 * Extracts a unique identity string from the base name of @file.
1425 * If the base name of @file is missing a '.source' extension, the
1426 * function sets @error and returns %NULL.
1428 * Returns: the unique identity string for @file, or %NULL
1433 e_server_side_source_uid_from_file (GFile *file,
1439 g_return_val_if_fail (G_IS_FILE (file), FALSE);
1441 basename = g_file_get_basename (file);
1443 if (*basename == '.') {
1444 /* ignore hidden files */
1445 } else if (g_str_has_suffix (basename, ".source")) {
1446 /* strlen(".source") --> 7 */
1447 uid = g_strndup (basename, strlen (basename) - 7);
1451 G_IO_ERROR_INVALID_FILENAME,
1452 _("File must have a '.source' extension"));
1461 * e_server_side_source_new:
1462 * @server: an #ESourceRegistryServer
1463 * @file: a #GFile, or %NULL
1464 * @error: return location for a #GError, or %NULL
1466 * Creates a new #EServerSideSource which belongs to @server. If @file
1467 * is non-%NULL and points to an existing file, the #EServerSideSource is
1468 * initialized from the file content. If a read error occurs or the file
1469 * contains syntax errors, the function sets @error and returns %NULL.
1471 * Returns: a new #EServerSideSource, or %NULL
1476 e_server_side_source_new (ESourceRegistryServer *server,
1480 EDBusObjectSkeleton *dbus_object;
1484 g_return_val_if_fail (E_IS_SOURCE_REGISTRY_SERVER (server), NULL);
1485 g_return_val_if_fail (file == NULL || G_IS_FILE (file), NULL);
1487 /* Extract a UID from the GFile, if we were given one. */
1489 uid = e_server_side_source_uid_from_file (file, error);
1494 /* XXX This is an awkward way of initializing the "dbus-object"
1495 * property, but e_source_ref_dbus_object() needs to work. */
1496 dbus_object = e_dbus_object_skeleton_new (DBUS_OBJECT_PATH);
1498 source = g_initable_new (
1499 E_TYPE_SERVER_SIDE_SOURCE, NULL, error,
1500 "dbus-object", dbus_object,
1501 "file", file, "server", server,
1504 g_object_unref (dbus_object);
1511 * e_server_side_source_new_memory_only:
1512 * @server: an #ESourceRegistryServer
1513 * @uid: a unique identifier, or %NULL
1514 * @error: return location for a #GError, or %NULL
1516 * Creates a memory-only #EServerSideSource which belongs to @server.
1517 * No on-disk key file is created for this data source, so it will not
1518 * be remembered across sessions.
1520 * Data source collections are often populated with memory-only data
1521 * sources to serve as proxies for resources discovered on a remote server.
1522 * These data sources are usually neither #EServerSideSource:writable nor
1523 * #EServerSideSource:removable by clients, at least not directly.
1525 * If an error occurs while instantiating the #EServerSideSource, the
1526 * function sets @error and returns %NULL. Although at this time there
1527 * are no known error conditions for memory-only data sources.
1529 * Returns: a new memory-only #EServerSideSource, or %NULL
1534 e_server_side_source_new_memory_only (ESourceRegistryServer *server,
1538 EDBusObjectSkeleton *dbus_object;
1541 g_return_val_if_fail (E_IS_SOURCE_REGISTRY_SERVER (server), NULL);
1543 /* XXX This is an awkward way of initializing the "dbus-object"
1544 * property, but e_source_ref_dbus_object() needs to work. */
1545 dbus_object = e_dbus_object_skeleton_new (DBUS_OBJECT_PATH);
1547 source = g_initable_new (
1548 E_TYPE_SERVER_SIDE_SOURCE, NULL, error,
1549 "dbus-object", dbus_object,
1550 "server", server, "uid", uid, NULL);
1552 g_object_unref (dbus_object);
1558 * e_server_side_source_load:
1559 * @source: an #EServerSideSource
1560 * @cancellable: optional #GCancellable object, or %NULL
1561 * @error: return location for a #GError, or %NULL
1563 * Reloads data source content from the file pointed to by the
1564 * #EServerSideSource:file property.
1566 * If the #EServerSideSource:file property is %NULL or the file it points
1567 * to does not exist, the function does nothing and returns %TRUE.
1569 * If a read error occurs or the file contains syntax errors, the function
1570 * sets @error and returns %FALSE.
1572 * Returns: %TRUE on success, %FALSE on failure
1577 e_server_side_source_load (EServerSideSource *source,
1578 GCancellable *cancellable,
1581 GDBusObject *dbus_object;
1582 EDBusSource *dbus_source;
1588 GError *local_error = NULL;
1590 g_return_val_if_fail (E_IS_SERVER_SIDE_SOURCE (source), FALSE);
1592 file = e_server_side_source_get_file (source);
1595 g_file_load_contents (
1596 file, cancellable, &data,
1597 &length, NULL, &local_error);
1599 /* Disregard G_IO_ERROR_NOT_FOUND and treat it as a successful load. */
1600 if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) {
1601 g_error_free (local_error);
1603 } else if (local_error != NULL) {
1604 g_propagate_error (error, local_error);
1608 source->priv->file_contents = g_strdup (data);
1612 /* Create the bare minimum to pass parse_data(). */
1613 data = g_strdup_printf ("[%s]", PRIMARY_GROUP_NAME);
1614 length = strlen (data);
1617 key_file = g_key_file_new ();
1619 success = server_side_source_parse_data (
1620 key_file, data, length, error);
1622 g_key_file_free (key_file);
1629 /* Update the D-Bus interface properties. */
1631 dbus_object = e_source_ref_dbus_object (E_SOURCE (source));
1632 dbus_source = e_dbus_object_get_source (E_DBUS_OBJECT (dbus_object));
1634 e_dbus_source_set_data (dbus_source, data);
1636 g_object_unref (dbus_source);
1637 g_object_unref (dbus_object);
1645 * e_server_side_source_get_file:
1646 * @source: an #EServerSideSource
1648 * Returns the #GFile from which data source content is loaded and to
1649 * which changes are saved. Note the @source may not have a #GFile.
1651 * Returns: the #GFile for @source, or %NULL
1656 e_server_side_source_get_file (EServerSideSource *source)
1658 g_return_val_if_fail (E_IS_SERVER_SIDE_SOURCE (source), NULL);
1660 return source->priv->file;
1664 * e_server_side_source_get_node:
1665 * @source: an #EServerSideSource
1667 * Returns the #GNode representing the @source's hierarchical placement,
1668 * or %NULL if @source has not been placed in the data source hierarchy.
1669 * The data member of the #GNode points back to @source. This is an easy
1670 * way to traverse ancestor and descendant data sources.
1672 * Note that accessing other data sources this way is not thread-safe,
1673 * and this therefore function may be replaced at some later date.
1675 * Returns: a #GNode, or %NULL
1680 e_server_side_source_get_node (EServerSideSource *source)
1682 g_return_val_if_fail (E_IS_SERVER_SIDE_SOURCE (source), NULL);
1684 return &source->priv->node;
1688 * e_server_side_source_get_server:
1689 * @source: an #EServerSideSource
1691 * Returns the #ESourceRegistryServer to which @source belongs.
1693 * Returns: the #ESourceRegistryServer for @source
1697 ESourceRegistryServer *
1698 e_server_side_source_get_server (EServerSideSource *source)
1700 g_return_val_if_fail (E_IS_SERVER_SIDE_SOURCE (source), NULL);
1702 return source->priv->server;
1706 * e_server_side_source_get_allow_auth_prompt:
1707 * @source: an #EServerSideSource
1709 * Returns whether an authentication prompt is allowed to be shown
1710 * for @source. #EAuthenticationSession will honor this setting by
1711 * dismissing the session if it can't find a valid stored password.
1713 * See e_server_side_source_set_allow_auth_prompt() for further
1716 * Returns: whether auth prompts are allowed for @source
1721 e_server_side_source_get_allow_auth_prompt (EServerSideSource *source)
1723 g_return_val_if_fail (E_IS_SERVER_SIDE_SOURCE (source), FALSE);
1725 return source->priv->allow_auth_prompt;
1729 * e_server_side_source_set_allow_auth_prompt:
1730 * @source: an #EServerSideSource
1731 * @allow_auth_prompt: whether auth prompts are allowed for @source
1733 * Sets whether an authentication prompt is allowed to be shown for @source.
1734 * #EAuthenticationSession will honor this setting by dismissing the session
1735 * if it can't find a valid stored password.
1737 * If the user declines to provide a password for @source when prompted
1738 * by an #EAuthenticationSession, the #ESourceRegistryServer will set this
1739 * property to %FALSE to suppress any further prompting, which would likely
1740 * annoy the user. However when an #ESourceRegistry instance is created by
1741 * a client application, the first thing it does is reset this property to
1742 * %TRUE for all registered data sources. So suppressing authentication
1743 * prompts is only ever temporary.
1748 e_server_side_source_set_allow_auth_prompt (EServerSideSource *source,
1749 gboolean allow_auth_prompt)
1751 g_return_if_fail (E_IS_SERVER_SIDE_SOURCE (source));
1753 if (source->priv->allow_auth_prompt == allow_auth_prompt)
1756 source->priv->allow_auth_prompt = allow_auth_prompt;
1758 g_object_notify (G_OBJECT (source), "allow-auth-prompt");
1762 * e_server_side_source_get_auth_session_type:
1763 * @source: an #EServerSideSource
1765 * Returns the type of authentication session to use for @source,
1766 * which will get passed to e_source_registry_server_authenticate().
1768 * This defaults to the #GType for #EAuthenticationSession.
1770 * Returns: the type of authentication session to use for @source
1775 e_server_side_source_get_auth_session_type (EServerSideSource *source)
1777 g_return_val_if_fail (
1778 E_IS_SERVER_SIDE_SOURCE (source),
1779 E_TYPE_AUTHENTICATION_SESSION);
1781 return source->priv->auth_session_type;
1785 * e_server_side_source_set_auth_session_type:
1786 * @source: an #EServerSideSource
1787 * @auth_session_type: the type of authentication session to use for @source
1789 * Sets the type of authentication session to use for @source, which will
1790 * get passed to e_source_registry_server_authenticate().
1792 * @auth_session_type must be derived from #EAuthenticationSession, or else
1793 * the function will reject the #GType with a runtime warning.
1795 * This defaults to the #GType for #EAuthenticationSession.
1800 e_server_side_source_set_auth_session_type (EServerSideSource *source,
1801 GType auth_session_type)
1803 g_return_if_fail (E_IS_SERVER_SIDE_SOURCE (source));
1805 if (!g_type_is_a (auth_session_type, E_TYPE_AUTHENTICATION_SESSION)) {
1807 "Invalid auth session type '%s' for source '%s'",
1808 g_type_name (auth_session_type),
1809 e_source_get_display_name (E_SOURCE (source)));
1813 if (auth_session_type == source->priv->auth_session_type)
1816 source->priv->auth_session_type = auth_session_type;
1818 g_object_notify (G_OBJECT (source), "auth-session-type");
1822 * e_server_side_source_get_exported:
1823 * @source: an #EServerSideSource
1825 * Returns whether @source has been exported over D-Bus.
1827 * The function returns %FALSE after @source is initially created, %TRUE
1828 * after passing @source to e_source_registry_add_source() (provided that
1829 * @source's #ESource:parent is also exported), and %FALSE after passing
1830 * @source to e_source_registry_remove_source().
1832 * Returns: whether @source has been exported
1837 e_server_side_source_get_exported (EServerSideSource *source)
1839 ESourceRegistryServer *server;
1840 ESource *exported_source;
1841 gboolean exported = FALSE;
1844 g_return_val_if_fail (E_IS_SERVER_SIDE_SOURCE (source), FALSE);
1846 uid = e_source_get_uid (E_SOURCE (source));
1847 server = e_server_side_source_get_server (source);
1849 /* We're exported if we can look ourselves up in the registry. */
1851 exported_source = e_source_registry_server_ref_source (server, uid);
1852 if (exported_source != NULL) {
1854 g_object_unref (exported_source);
1861 * e_server_side_source_get_write_directory:
1862 * @source: an #EServerSideSource
1864 * Returns the local directory path where changes to @source are written.
1866 * By default, changes are written to the local directory path returned by
1867 * e_server_side_source_get_user_dir(), but an #ECollectionBackend may wish
1868 * to override this to use its own private cache directory for data sources
1869 * it creates automatically.
1871 * Returns: the directory where changes are written
1876 e_server_side_source_get_write_directory (EServerSideSource *source)
1878 g_return_val_if_fail (E_IS_SERVER_SIDE_SOURCE (source), NULL);
1880 return source->priv->write_directory;
1884 * e_server_side_source_set_write_directory:
1885 * @source: an #EServerSideSource
1886 * @write_directory: the directory where changes are to be written
1888 * Sets the local directory path where changes to @source are to be written.
1890 * By default, changes are written to the local directory path returned by
1891 * e_server_side_source_get_user_dir(), but an #ECollectionBackend may wish
1892 * to override this to use its own private cache directory for data sources
1893 * it creates automatically.
1898 e_server_side_source_set_write_directory (EServerSideSource *source,
1899 const gchar *write_directory)
1901 g_return_if_fail (E_IS_SERVER_SIDE_SOURCE (source));
1902 g_return_if_fail (write_directory != NULL);
1904 if (g_strcmp0 (source->priv->write_directory, write_directory) == 0)
1907 g_free (source->priv->write_directory);
1908 source->priv->write_directory = g_strdup (write_directory);
1910 g_object_notify (G_OBJECT (source), "write-directory");
1914 * e_server_side_source_set_removable:
1915 * @source: an #EServerSideSource
1916 * @removable: whether to export the Removable interface
1918 * Sets whether to allow registry clients to remove @source and its
1919 * descendants. If %TRUE, the Removable D-Bus interface is exported at
1920 * the object path for @source. If %FALSE, the Removable D-Bus interface
1921 * is unexported at the object path for @source, and any attempt by clients
1922 * to call e_source_remove() will fail.
1924 * Note this is only enforced for clients of the registry D-Bus service.
1925 * The service itself may remove any data source at any time.
1930 e_server_side_source_set_removable (EServerSideSource *source,
1933 EDBusSourceRemovable *dbus_interface = NULL;
1934 GDBusObject *dbus_object;
1935 gboolean currently_removable;
1937 g_return_if_fail (E_IS_SERVER_SIDE_SOURCE (source));
1939 currently_removable = e_source_get_removable (E_SOURCE (source));
1941 if (removable == currently_removable)
1946 e_dbus_source_removable_skeleton_new ();
1949 dbus_interface, "handle-remove",
1950 G_CALLBACK (server_side_source_remove_cb), source);
1953 dbus_object = e_source_ref_dbus_object (E_SOURCE (source));
1954 e_dbus_object_skeleton_set_source_removable (
1955 E_DBUS_OBJECT_SKELETON (dbus_object), dbus_interface);
1956 g_object_unref (dbus_object);
1958 if (dbus_interface != NULL)
1959 g_object_unref (dbus_interface);
1961 g_object_notify (G_OBJECT (source), "removable");
1965 * e_server_side_source_set_writable:
1966 * @source: an #EServerSideSource
1967 * @writable: whether to export the Writable interface
1969 * Sets whether to allow registry clients to alter the content of @source.
1970 * If %TRUE, the Writable D-Bus interface is exported at the object path
1971 * for @source. If %FALSE, the Writable D-Bus interface is unexported at
1972 * the object path for @source, and any attempt by clients to call
1973 * e_source_write() will fail.
1975 * Note this is only enforced for clients of the registry D-Bus service.
1976 * The service itself can write to any data source at any time.
1981 e_server_side_source_set_writable (EServerSideSource *source,
1984 EDBusSourceWritable *dbus_interface = NULL;
1985 GDBusObject *dbus_object;
1986 gboolean currently_writable;
1988 g_return_if_fail (E_IS_SERVER_SIDE_SOURCE (source));
1990 currently_writable = e_source_get_writable (E_SOURCE (source));
1992 if (writable == currently_writable)
1997 e_dbus_source_writable_skeleton_new ();
2000 dbus_interface, "handle-write",
2001 G_CALLBACK (server_side_source_write_cb), source);
2004 dbus_object = e_source_ref_dbus_object (E_SOURCE (source));
2005 e_dbus_object_skeleton_set_source_writable (
2006 E_DBUS_OBJECT_SKELETON (dbus_object), dbus_interface);
2007 g_object_unref (dbus_object);
2009 if (dbus_interface != NULL)
2010 g_object_unref (dbus_interface);
2012 g_object_notify (G_OBJECT (source), "writable");
2016 * e_server_side_source_set_remote_creatable:
2017 * @source: an #EServerSideSource
2018 * @remote_creatable: whether to export the RemoteCreatable interface
2020 * Indicates whether @source can be used to create resources on a remote
2021 * server. Typically this is only set to %TRUE for collection sources.
2023 * If %TRUE, the RemoteCreatable D-Bus interface is exported at the object
2024 * path for @source. If %FALSE, the RemoteCreatable D-Bus interface is
2025 * unexported at the object path for @source, and any attempt by clients
2026 * to call e_source_remote_create() will fail.
2028 * Unlike the #ESource:removable and #ESource:writable properties, this
2029 * is enforced for both clients of the registry D-Bus service and within
2030 * the registry D-Bus service itself.
2035 e_server_side_source_set_remote_creatable (EServerSideSource *source,
2036 gboolean remote_creatable)
2038 EDBusSourceRemoteCreatable *dbus_interface = NULL;
2039 GDBusObject *dbus_object;
2040 gboolean currently_remote_creatable;
2042 g_return_if_fail (E_IS_SERVER_SIDE_SOURCE (source));
2044 currently_remote_creatable =
2045 e_source_get_remote_creatable (E_SOURCE (source));
2047 if (remote_creatable == currently_remote_creatable)
2050 if (remote_creatable) {
2052 e_dbus_source_remote_creatable_skeleton_new ();
2055 dbus_interface, "handle-create",
2056 G_CALLBACK (server_side_source_remote_create_cb),
2060 dbus_object = e_source_ref_dbus_object (E_SOURCE (source));
2061 e_dbus_object_skeleton_set_source_remote_creatable (
2062 E_DBUS_OBJECT_SKELETON (dbus_object), dbus_interface);
2063 g_object_unref (dbus_object);
2065 if (dbus_interface != NULL)
2066 g_object_unref (dbus_interface);
2068 g_object_notify (G_OBJECT (source), "remote-creatable");
2072 * e_server_side_source_set_remote_deletable:
2073 * @source: an #EServerSideSource
2074 * @remote_deletable: whether to export the RemoteDeletable interface
2076 * Indicates whether @source can be used to delete resources on a remote
2077 * server. Typically this is only set to %TRUE for sources created by an
2078 * #ECollectionBackend to represent a remote resource.
2080 * If %TRUE, the RemoteDeletable D-Bus interface is exported at the object
2081 * path for @source. If %FALSE, the RemoteDeletable D-Bus interface is
2082 * unexported at the object path for @source, and any attempt by clients
2083 * to call e_source_remote_delete() will fail.
2085 * Unlike the #ESource:removable and #ESource:writable properties, this
2086 * is enforced for both clients of the registry D-Bus server and within
2087 * the registry D-Bus service itself.
2092 e_server_side_source_set_remote_deletable (EServerSideSource *source,
2093 gboolean remote_deletable)
2095 EDBusSourceRemoteDeletable *dbus_interface = NULL;
2096 GDBusObject *dbus_object;
2097 gboolean currently_remote_deletable;
2099 g_return_if_fail (E_IS_SERVER_SIDE_SOURCE (source));
2101 currently_remote_deletable =
2102 e_source_get_remote_deletable (E_SOURCE (source));
2104 if (remote_deletable == currently_remote_deletable)
2107 if (remote_deletable) {
2109 e_dbus_source_remote_deletable_skeleton_new ();
2112 dbus_interface, "handle-delete",
2113 G_CALLBACK (server_side_source_remote_delete_cb),
2117 dbus_object = e_source_ref_dbus_object (E_SOURCE (source));
2118 e_dbus_object_skeleton_set_source_remote_deletable (
2119 E_DBUS_OBJECT_SKELETON (dbus_object), dbus_interface);
2120 g_object_unref (dbus_object);
2122 if (dbus_interface != NULL)
2123 g_object_unref (dbus_interface);
2125 g_object_notify (G_OBJECT (source), "remote-deletable");
2129 * e_server_side_source_ref_oauth2_support:
2130 * @source: an #EServerSideSource
2132 * Returns the object implementing the #EOAuth2SupportInterface,
2133 * or %NULL if @source does not support OAuth 2.0 authentication.
2135 * The returned #EOAuth2Support object is referenced for thread-safety.
2136 * Unreference the object with g_object_unref() when finished with it.
2138 * Returns: an #EOAuth2Support object, or %NULL
2143 e_server_side_source_ref_oauth2_support (EServerSideSource *source)
2145 g_return_val_if_fail (E_IS_SERVER_SIDE_SOURCE (source), NULL);
2147 return g_weak_ref_get (&source->priv->oauth2_support);
2151 * e_server_side_source_set_oauth2_support:
2152 * @source: an #EServerSideSource
2153 * @oauth2_support: an #EOAuth2Support object, or %NULL
2155 * Indicates whether @source supports OAuth 2.0 authentication.
2157 * If @oauth2_support is non-%NULL, the OAuth2Support D-Bus interface is
2158 * exported at the object path for @source. If @oauth2_support is %NULL,
2159 * the OAuth2Support D-Bus interface is unexported at the object path for
2160 * @source, and any attempt by clients to call
2161 * e_source_get_oauth2_access_token() will fail.
2163 * Requests for OAuth 2.0 access tokens are forwarded to @oauth2_support,
2164 * which implements the #EOAuth2SupportInterface.
2169 e_server_side_source_set_oauth2_support (EServerSideSource *source,
2170 EOAuth2Support *oauth2_support)
2172 EDBusSourceOAuth2Support *dbus_interface = NULL;
2173 GDBusObject *dbus_object;
2175 g_return_if_fail (E_IS_SERVER_SIDE_SOURCE (source));
2177 if (oauth2_support != NULL) {
2178 g_return_if_fail (E_IS_OAUTH2_SUPPORT (oauth2_support));
2181 e_dbus_source_oauth2_support_skeleton_new ();
2184 dbus_interface, "handle-get-access-token",
2185 G_CALLBACK (server_side_source_get_access_token_cb),
2189 g_weak_ref_set (&source->priv->oauth2_support, oauth2_support);
2191 dbus_object = e_source_ref_dbus_object (E_SOURCE (source));
2192 e_dbus_object_skeleton_set_source_oauth2_support (
2193 E_DBUS_OBJECT_SKELETON (dbus_object), dbus_interface);
2194 g_object_unref (dbus_object);
2196 if (dbus_interface != NULL)
2197 g_object_unref (dbus_interface);
2199 g_object_notify (G_OBJECT (source), "oauth2-support");