2 * e-server-side-source.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-server-side-source
21 * @include: libebackend/libebackend.h
22 * @short_description: A server-side data source
24 * An #EServerSideSource is an #ESource with some additional capabilities
25 * exclusive to the registry D-Bus service.
28 #include "e-server-side-source.h"
31 #include <glib/gi18n-lib.h>
33 /* Private D-Bus classes. */
34 #include <e-dbus-source.h>
36 #define E_SERVER_SIDE_SOURCE_GET_PRIVATE(obj) \
37 (G_TYPE_INSTANCE_GET_PRIVATE \
38 ((obj), E_TYPE_SERVER_SIDE_SOURCE, EServerSideSourcePrivate))
40 #define DBUS_OBJECT_PATH E_SOURCE_REGISTRY_SERVER_OBJECT_PATH "/Source"
42 #define PRIMARY_GROUP_NAME "Data Source"
44 typedef struct _AsyncContext AsyncContext;
46 struct _EServerSideSourcePrivate {
47 gpointer server; /* weak pointer */
56 gboolean allow_auth_prompt;
57 gchar *write_directory;
60 struct _AsyncContext {
61 EDBusSourceRemoteCreatable *remote_creatable;
62 EDBusSourceRemoteDeletable *remote_deletable;
63 GDBusMethodInvocation *invocation;
68 PROP_ALLOW_AUTH_PROMPT,
71 PROP_REMOTE_CREATABLE,
72 PROP_REMOTE_DELETABLE,
80 static GInitableIface *initable_parent_interface;
82 /* Forward Declarations */
83 static void e_server_side_source_initable_init
84 (GInitableIface *interface);
86 G_DEFINE_TYPE_WITH_CODE (
90 G_IMPLEMENT_INTERFACE (
92 e_server_side_source_initable_init))
95 async_context_free (AsyncContext *async_context)
97 if (async_context->remote_creatable != NULL)
98 g_object_unref (async_context->remote_creatable);
100 if (async_context->remote_deletable != NULL)
101 g_object_unref (async_context->remote_deletable);
103 if (async_context->invocation != NULL)
104 g_object_unref (async_context->invocation);
106 g_slice_free (AsyncContext, async_context);
110 server_side_source_parse_data (GKeyFile *key_file,
117 success = g_key_file_load_from_data (
118 key_file, data, length, G_KEY_FILE_NONE, error);
123 /* Make sure the key file has a [Data Source] group. */
124 if (!g_key_file_has_group (key_file, PRIMARY_GROUP_NAME)) {
126 error, G_KEY_FILE_ERROR,
127 G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
128 _("Data source is missing a [%s] group"),
137 server_side_source_print_diff (ESource *source,
138 const gchar *old_data,
139 const gchar *new_data)
141 gchar **old_strv = NULL;
142 gchar **new_strv = NULL;
143 guint old_length = 0;
144 guint new_length = 0;
147 g_print ("Saving %s\n", e_source_get_uid (source));
149 if (old_data != NULL) {
150 old_strv = g_strsplit (old_data, "\n", 0);
151 old_length = g_strv_length (old_strv);
154 if (new_data != NULL) {
155 new_strv = g_strsplit (new_data, "\n", 0);
156 new_length = g_strv_length (new_strv);
159 for (ii = 0; ii < MIN (old_length, new_length); ii++) {
160 if (g_strcmp0 (old_strv[ii], new_strv[ii]) != 0) {
161 g_print (" - : %s\n", old_strv[ii]);
162 g_print (" + : %s\n", new_strv[ii]);
164 g_print (" : %s\n", old_strv[ii]);
168 for (; ii < old_length; ii++)
169 g_print (" - : %s\n", old_strv[ii]);
171 for (; ii < new_length; ii++)
172 g_print (" + : %s\n", new_strv[ii]);
174 g_strfreev (old_strv);
175 g_strfreev (new_strv);
179 server_side_source_traverse_cb (GNode *node,
182 g_queue_push_tail (queue, g_object_ref (node->data));
188 server_side_source_allow_auth_prompt_cb (EDBusSource *interface,
189 GDBusMethodInvocation *invocation,
190 EServerSideSource *source)
192 e_server_side_source_set_allow_auth_prompt (source, TRUE);
194 e_dbus_source_complete_allow_auth_prompt (interface, invocation);
200 server_side_source_remove_cb (EDBusSourceRemovable *interface,
201 GDBusMethodInvocation *invocation,
202 EServerSideSource *source)
204 GError *error = NULL;
206 /* Note we don't need to verify the source is removable here
207 * since if it isn't, the remove() method won't be available.
208 * Descendants of the source are removed whether they export
209 * a remove() method or not. */
211 e_source_remove_sync (E_SOURCE (source), NULL, &error);
214 g_dbus_method_invocation_take_error (invocation, error);
216 e_dbus_source_removable_complete_remove (
217 interface, invocation);
223 server_side_source_write_cb (EDBusSourceWritable *interface,
224 GDBusMethodInvocation *invocation,
229 GDBusObject *dbus_object;
230 EDBusSource *dbus_source;
231 GError *error = NULL;
233 /* Note we don't need to verify the source is writable here
234 * since if it isn't, the write() method won't be available. */
236 dbus_object = e_source_ref_dbus_object (source);
237 dbus_source = e_dbus_object_get_source (E_DBUS_OBJECT (dbus_object));
239 /* Validate the raw data before making the changes live. */
240 key_file = g_key_file_new ();
241 server_side_source_parse_data (key_file, data, strlen (data), &error);
242 g_key_file_free (key_file);
244 /* Q: How does this trigger data being written to disk?
246 * A: Here's the sequence of events:
248 * 1) We set the EDBusSource:data property.
249 * 2) ESource picks up the "notify::data" signal and parses
250 * the raw data, which triggers an ESource:changed signal.
251 * 3) Our changed() method schedules an idle callback.
252 * 4) The idle callback calls e_source_write_sync().
253 * 5) e_source_write_sync() calls e_dbus_source_dup_data()
254 * and synchronously writes the resulting string to disk.
258 e_dbus_source_set_data (dbus_source, data);
261 g_dbus_method_invocation_take_error (invocation, error);
263 e_dbus_source_writable_complete_write (
264 interface, invocation);
266 g_object_unref (dbus_source);
267 g_object_unref (dbus_object);
272 /* Helper for server_side_source_remote_create_cb() */
274 server_side_source_remote_create_done_cb (GObject *source_object,
275 GAsyncResult *result,
279 AsyncContext *async_context;
280 GError *error = NULL;
282 source = E_SOURCE (source_object);
283 async_context = (AsyncContext *) user_data;
285 e_source_remote_create_finish (source, result, &error);
288 g_dbus_method_invocation_take_error (
289 async_context->invocation, error);
291 e_dbus_source_remote_creatable_complete_create (
292 async_context->remote_creatable,
293 async_context->invocation);
295 async_context_free (async_context);
299 server_side_source_remote_create_cb (EDBusSourceRemoteCreatable *interface,
300 GDBusMethodInvocation *invocation,
305 EServerSideSource *server_side_source;
306 ESourceRegistryServer *server;
307 AsyncContext *async_context;
308 ESource *scratch_source;
309 GDBusObject *dbus_object;
310 EDBusSource *dbus_source;
313 GError *error = NULL;
315 /* Create a new EServerSideSource from 'uid' and 'data' but
316 * DO NOT add it to the ESourceRegistryServer yet. It's up
317 * to the ECollectionBackend whether to use source as given
318 * or create its own equivalent EServerSideSource, possibly
319 * in response to a notification from a remote server. */
321 /* Validate the raw data. */
322 key_file = g_key_file_new ();
323 server_side_source_parse_data (key_file, data, strlen (data), &error);
324 g_key_file_free (key_file);
327 g_dbus_method_invocation_take_error (invocation, error);
331 server_side_source = E_SERVER_SIDE_SOURCE (source);
332 server = e_server_side_source_get_server (server_side_source);
334 file = e_server_side_source_new_user_file (uid);
335 scratch_source = e_server_side_source_new (server, file, &error);
336 g_object_unref (file);
340 ((scratch_source != NULL) && (error == NULL)) ||
341 ((scratch_source == NULL) && (error != NULL)));
344 g_dbus_method_invocation_take_error (invocation, error);
348 dbus_object = e_source_ref_dbus_object (scratch_source);
349 dbus_source = e_dbus_object_get_source (E_DBUS_OBJECT (dbus_object));
351 e_dbus_source_set_data (dbus_source, data);
353 g_object_unref (dbus_object);
354 g_object_unref (dbus_source);
356 async_context = g_slice_new0 (AsyncContext);
357 async_context->remote_creatable = g_object_ref (interface);
358 async_context->invocation = g_object_ref (invocation);
360 e_source_remote_create (
361 source, scratch_source, NULL,
362 server_side_source_remote_create_done_cb,
365 g_object_unref (scratch_source);
370 /* Helper for server_side_source_remote_delete_cb() */
372 server_side_source_remote_delete_done_cb (GObject *source_object,
373 GAsyncResult *result,
377 AsyncContext *async_context;
378 GError *error = NULL;
380 source = E_SOURCE (source_object);
381 async_context = (AsyncContext *) user_data;
383 e_source_remote_delete_finish (source, result, &error);
386 g_dbus_method_invocation_take_error (
387 async_context->invocation, error);
389 e_dbus_source_remote_deletable_complete_delete (
390 async_context->remote_deletable,
391 async_context->invocation);
393 async_context_free (async_context);
397 server_side_source_remote_delete_cb (EDBusSourceRemoteDeletable *interface,
398 GDBusMethodInvocation *invocation,
401 AsyncContext *async_context;
403 async_context = g_slice_new0 (AsyncContext);
404 async_context->remote_deletable = g_object_ref (interface);
405 async_context->invocation = g_object_ref (invocation);
407 e_source_remote_delete (
409 server_side_source_remote_delete_done_cb,
416 server_side_source_set_file (EServerSideSource *source,
419 g_return_if_fail (file == NULL || G_IS_FILE (file));
420 g_return_if_fail (source->priv->file == NULL);
423 source->priv->file = g_object_ref (file);
427 server_side_source_set_server (EServerSideSource *source,
428 ESourceRegistryServer *server)
430 g_return_if_fail (E_IS_SOURCE_REGISTRY_SERVER (server));
431 g_return_if_fail (source->priv->server == NULL);
433 source->priv->server = server;
435 g_object_add_weak_pointer (
436 G_OBJECT (server), &source->priv->server);
440 server_side_source_set_uid (EServerSideSource *source,
443 g_return_if_fail (source->priv->uid == NULL);
445 /* It's okay for this to be NULL, in fact if we're given a
446 * GFile the UID is derived from its basename anyway. This
447 * is just for memory-only sources in a collection backend,
448 * which don't have a GFile. */
449 source->priv->uid = g_strdup (uid);
453 server_side_source_set_property (GObject *object,
458 switch (property_id) {
459 case PROP_ALLOW_AUTH_PROMPT:
460 e_server_side_source_set_allow_auth_prompt (
461 E_SERVER_SIDE_SOURCE (object),
462 g_value_get_boolean (value));
466 server_side_source_set_file (
467 E_SERVER_SIDE_SOURCE (object),
468 g_value_get_object (value));
471 case PROP_REMOTE_CREATABLE:
472 e_server_side_source_set_remote_creatable (
473 E_SERVER_SIDE_SOURCE (object),
474 g_value_get_boolean (value));
477 case PROP_REMOTE_DELETABLE:
478 e_server_side_source_set_remote_deletable (
479 E_SERVER_SIDE_SOURCE (object),
480 g_value_get_boolean (value));
484 e_server_side_source_set_removable (
485 E_SERVER_SIDE_SOURCE (object),
486 g_value_get_boolean (value));
490 server_side_source_set_server (
491 E_SERVER_SIDE_SOURCE (object),
492 g_value_get_object (value));
496 server_side_source_set_uid (
497 E_SERVER_SIDE_SOURCE (object),
498 g_value_get_string (value));
502 e_server_side_source_set_writable (
503 E_SERVER_SIDE_SOURCE (object),
504 g_value_get_boolean (value));
507 case PROP_WRITE_DIRECTORY:
508 e_server_side_source_set_write_directory (
509 E_SERVER_SIDE_SOURCE (object),
510 g_value_get_string (value));
514 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
518 server_side_source_get_property (GObject *object,
523 switch (property_id) {
524 case PROP_ALLOW_AUTH_PROMPT:
525 g_value_set_boolean (
527 e_server_side_source_get_allow_auth_prompt (
528 E_SERVER_SIDE_SOURCE (object)));
532 g_value_set_boolean (
534 e_server_side_source_get_exported (
535 E_SERVER_SIDE_SOURCE (object)));
541 e_server_side_source_get_file (
542 E_SERVER_SIDE_SOURCE (object)));
545 case PROP_REMOTE_CREATABLE:
546 g_value_set_boolean (
548 e_source_get_remote_creatable (
552 case PROP_REMOTE_DELETABLE:
553 g_value_set_boolean (
555 e_source_get_remote_deletable (
560 g_value_set_boolean (
562 e_source_get_removable (
569 e_server_side_source_get_server (
570 E_SERVER_SIDE_SOURCE (object)));
574 g_value_take_string (
581 g_value_set_boolean (
583 e_source_get_writable (
587 case PROP_WRITE_DIRECTORY:
590 e_server_side_source_get_write_directory (
591 E_SERVER_SIDE_SOURCE (object)));
595 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
599 server_side_source_dispose (GObject *object)
601 EServerSideSourcePrivate *priv;
603 priv = E_SERVER_SIDE_SOURCE_GET_PRIVATE (object);
605 if (priv->server != NULL) {
606 g_object_remove_weak_pointer (
607 G_OBJECT (priv->server), &priv->server);
611 if (priv->file != NULL) {
612 g_object_unref (priv->file);
616 /* Chain up to parent's dispose() method. */
617 G_OBJECT_CLASS (e_server_side_source_parent_class)->dispose (object);
621 server_side_source_finalize (GObject *object)
623 EServerSideSourcePrivate *priv;
625 priv = E_SERVER_SIDE_SOURCE_GET_PRIVATE (object);
627 g_node_unlink (&priv->node);
630 g_free (priv->file_contents);
631 g_free (priv->write_directory);
633 /* Chain up to parent's finalize() method. */
634 G_OBJECT_CLASS (e_server_side_source_parent_class)->finalize (object);
638 server_side_source_changed (ESource *source)
640 GDBusObject *dbus_object;
641 EDBusSource *dbus_source;
644 GError *error = NULL;
646 /* Do not write changes to disk until the source has been exported. */
647 if (!e_server_side_source_get_exported (E_SERVER_SIDE_SOURCE (source)))
650 dbus_object = e_source_ref_dbus_object (source);
651 dbus_source = e_dbus_object_get_source (E_DBUS_OBJECT (dbus_object));
653 old_data = e_dbus_source_dup_data (dbus_source);
654 new_data = e_source_to_string (source, NULL);
656 /* Setting the "data" property triggers the ESource::changed,
657 * signal, which invokes this callback, which sets the "data"
658 * property, etc. This breaks an otherwise infinite loop. */
659 if (g_strcmp0 (old_data, new_data) != 0)
660 e_dbus_source_set_data (dbus_source, new_data);
665 g_object_unref (dbus_source);
666 g_object_unref (dbus_object);
668 /* This writes the "data" property to disk. */
669 e_source_write_sync (source, NULL, &error);
672 g_warning ("%s: %s", G_STRFUNC, error->message);
673 g_error_free (error);
678 server_side_source_remove_sync (ESource *source,
679 GCancellable *cancellable,
682 EAsyncClosure *closure;
683 GAsyncResult *result;
686 closure = e_async_closure_new ();
689 source, cancellable, e_async_closure_callback, closure);
691 result = e_async_closure_wait (closure);
693 success = e_source_remove_finish (source, result, error);
695 e_async_closure_free (closure);
701 server_side_source_remove (ESource *source,
702 GCancellable *cancellable,
703 GAsyncReadyCallback callback,
706 EServerSideSourcePrivate *priv;
707 GSimpleAsyncResult *simple;
708 ESourceRegistryServer *server;
709 GQueue queue = G_QUEUE_INIT;
711 GError *error = NULL;
713 /* XXX Yes we block here. We do this operation
714 * synchronously to keep the server code simple. */
716 priv = E_SERVER_SIDE_SOURCE_GET_PRIVATE (source);
718 simple = g_simple_async_result_new (
719 G_OBJECT (source), callback, user_data,
720 server_side_source_remove);
722 g_simple_async_result_set_check_cancellable (simple, cancellable);
724 /* Collect the source and its descendants into a queue.
725 * Do this before unexporting so we hold references to
726 * all the removed sources. */
728 &priv->node, G_POST_ORDER, G_TRAVERSE_ALL, -1,
729 (GNodeTraverseFunc) server_side_source_traverse_cb, &queue);
731 /* Unexport the object and its descendants. */
732 server = E_SOURCE_REGISTRY_SERVER (priv->server);
733 e_source_registry_server_remove_source (server, source);
735 list = g_queue_peek_head_link (&queue);
737 /* Delete the key file for each source in the queue. */
738 for (link = list; link != NULL; link = g_list_next (link)) {
739 EServerSideSource *child;
742 child = E_SERVER_SIDE_SOURCE (link->data);
743 file = e_server_side_source_get_file (child);
746 g_file_delete (file, cancellable, &error);
748 /* XXX Even though e_source_registry_server_remove_source()
749 * is called first, the object path is unexported from
750 * an idle callback some time after we have deleted the
751 * key file. That creates a small window of time where
752 * the file is deleted but the object is still exported.
754 * If a client calls e_source_remove() during that small
755 * window of time, we still want to report a successful
756 * removal, so disregard G_IO_ERROR_NOT_FOUND. */
757 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
758 g_clear_error (&error);
765 while (!g_queue_is_empty (&queue))
766 g_object_unref (g_queue_pop_head (&queue));
769 g_simple_async_result_take_error (simple, error);
771 g_simple_async_result_complete_in_idle (simple);
772 g_object_unref (simple);
776 server_side_source_remove_finish (ESource *source,
777 GAsyncResult *result,
780 GSimpleAsyncResult *simple;
782 g_return_val_if_fail (
783 g_simple_async_result_is_valid (
784 result, G_OBJECT (source),
785 server_side_source_remove), FALSE);
787 simple = G_SIMPLE_ASYNC_RESULT (result);
789 /* Assume success unless a GError is set. */
790 return !g_simple_async_result_propagate_error (simple, error);
794 server_side_source_write_sync (ESource *source,
795 GCancellable *cancellable,
798 EAsyncClosure *closure;
799 GAsyncResult *result;
802 closure = e_async_closure_new ();
805 source, cancellable, e_async_closure_callback, closure);
807 result = e_async_closure_wait (closure);
809 success = e_source_write_finish (source, result, error);
811 e_async_closure_free (closure);
817 server_side_source_write (ESource *source,
818 GCancellable *cancellable,
819 GAsyncReadyCallback callback,
822 EServerSideSourcePrivate *priv;
823 GSimpleAsyncResult *simple;
824 GDBusObject *dbus_object;
825 EDBusSource *dbus_source;
826 gboolean replace_file;
827 const gchar *old_data;
829 GError *error = NULL;
831 /* XXX Yes we block here. We do this operation
832 * synchronously to keep the server code simple. */
834 priv = E_SERVER_SIDE_SOURCE_GET_PRIVATE (source);
836 simple = g_simple_async_result_new (
837 G_OBJECT (source), callback, user_data,
838 server_side_source_write);
840 g_simple_async_result_set_check_cancellable (simple, cancellable);
842 dbus_object = e_source_ref_dbus_object (source);
843 dbus_source = e_dbus_object_get_source (E_DBUS_OBJECT (dbus_object));
845 old_data = priv->file_contents;
846 new_data = e_source_to_string (source, NULL);
848 /* When writing source data to disk, we always write to the
849 * source's specified "write-directory" even if the key file
850 * was originally read from a different directory. To avoid
851 * polluting the write directory with key files identical to
852 * the original, we check that the data has actually changed
853 * before writing a copy to disk. */
856 G_IS_FILE (priv->file) &&
857 (g_strcmp0 (old_data, new_data) != 0);
861 GFile *write_directory;
864 g_warn_if_fail (priv->write_directory != NULL);
866 basename = g_file_get_basename (priv->file);
867 write_directory = g_file_new_for_path (priv->write_directory);
868 file = g_file_get_child (write_directory, basename);
871 if (!g_file_equal (file, priv->file)) {
872 g_object_unref (priv->file);
873 priv->file = g_object_ref (file);
876 server_side_source_print_diff (source, old_data, new_data);
878 g_file_make_directory_with_parents (
879 write_directory, cancellable, &error);
881 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS))
882 g_clear_error (&error);
885 g_file_replace_contents (
886 file, new_data, strlen (new_data),
887 NULL, FALSE, G_FILE_CREATE_NONE,
888 NULL, cancellable, &error);
891 g_free (priv->file_contents);
892 priv->file_contents = new_data;
896 g_object_unref (write_directory);
897 g_object_unref (file);
902 g_object_unref (dbus_source);
903 g_object_unref (dbus_object);
906 g_simple_async_result_take_error (simple, error);
908 g_simple_async_result_complete_in_idle (simple);
909 g_object_unref (simple);
913 server_side_source_write_finish (ESource *source,
914 GAsyncResult *result,
917 GSimpleAsyncResult *simple;
919 g_return_val_if_fail (
920 g_simple_async_result_is_valid (
921 result, G_OBJECT (source),
922 server_side_source_write), FALSE);
924 simple = G_SIMPLE_ASYNC_RESULT (result);
926 /* Assume success unless a GError is set. */
927 return !g_simple_async_result_propagate_error (simple, error);
931 server_side_source_remote_create_sync (ESource *source,
932 ESource *scratch_source,
933 GCancellable *cancellable,
936 ECollectionBackend *backend;
937 ESourceRegistryServer *server;
938 EServerSideSource *server_side_source;
941 if (!e_source_get_remote_creatable (source)) {
944 G_IO_ERROR_NOT_SUPPORTED,
945 _("Data source '%s' does not "
946 "support creating remote resources"),
947 e_source_get_display_name (source));
951 server_side_source = E_SERVER_SIDE_SOURCE (source);
952 server = e_server_side_source_get_server (server_side_source);
953 backend = e_source_registry_server_ref_backend (server, source);
955 if (backend == NULL) {
958 G_IO_ERROR_NOT_SUPPORTED,
959 _("Data source '%s' has no collection "
960 "backend to create the remote resource"),
961 e_source_get_display_name (source));
965 success = e_collection_backend_create_resource_sync (
966 backend, scratch_source, cancellable, error);
968 g_object_unref (backend);
974 server_side_source_remote_delete_sync (ESource *source,
975 GCancellable *cancellable,
978 ECollectionBackend *backend;
979 ESourceRegistryServer *server;
980 EServerSideSource *server_side_source;
983 if (!e_source_get_remote_deletable (source)) {
986 G_IO_ERROR_NOT_SUPPORTED,
987 _("Data source '%s' does not "
988 "support deleting remote resources"),
989 e_source_get_display_name (source));
993 server_side_source = E_SERVER_SIDE_SOURCE (source);
994 server = e_server_side_source_get_server (server_side_source);
995 backend = e_source_registry_server_ref_backend (server, source);
997 if (backend == NULL) {
1000 G_IO_ERROR_NOT_SUPPORTED,
1001 _("Data source '%s' has no collection "
1002 "backend to delete the remote resource"),
1003 e_source_get_display_name (source));
1007 success = e_collection_backend_delete_resource_sync (
1008 backend, source, cancellable, error);
1010 g_object_unref (backend);
1016 server_side_source_initable_init (GInitable *initable,
1017 GCancellable *cancellable,
1020 EServerSideSource *source;
1021 GDBusObject *dbus_object;
1022 EDBusSource *dbus_source;
1025 source = E_SERVER_SIDE_SOURCE (initable);
1026 file = e_server_side_source_get_file (source);
1029 g_warn_if_fail (source->priv->uid == NULL);
1031 e_server_side_source_uid_from_file (file, error);
1032 if (source->priv->uid == NULL)
1036 if (source->priv->uid == NULL)
1037 source->priv->uid = e_uid_new ();
1039 dbus_source = e_dbus_source_skeleton_new ();
1041 e_dbus_source_set_uid (dbus_source, source->priv->uid);
1043 dbus_object = e_source_ref_dbus_object (E_SOURCE (source));
1044 e_dbus_object_skeleton_set_source (
1045 E_DBUS_OBJECT_SKELETON (dbus_object), dbus_source);
1046 g_object_unref (dbus_object);
1049 dbus_source, "handle-allow-auth-prompt",
1050 G_CALLBACK (server_side_source_allow_auth_prompt_cb), source);
1052 g_object_unref (dbus_source);
1054 if (!e_server_side_source_load (source, cancellable, error))
1057 /* Chain up to parent interface's init() method. */
1058 return initable_parent_interface->init (initable, cancellable, error);
1062 e_server_side_source_class_init (EServerSideSourceClass *class)
1064 GObjectClass *object_class;
1065 ESourceClass *source_class;
1067 g_type_class_add_private (class, sizeof (EServerSideSourcePrivate));
1069 object_class = G_OBJECT_CLASS (class);
1070 object_class->set_property = server_side_source_set_property;
1071 object_class->get_property = server_side_source_get_property;
1072 object_class->dispose = server_side_source_dispose;
1073 object_class->finalize = server_side_source_finalize;
1075 source_class = E_SOURCE_CLASS (class);
1076 source_class->changed = server_side_source_changed;
1077 source_class->remove_sync = server_side_source_remove_sync;
1078 source_class->remove = server_side_source_remove;
1079 source_class->remove_finish = server_side_source_remove_finish;
1080 source_class->write_sync = server_side_source_write_sync;
1081 source_class->write = server_side_source_write;
1082 source_class->write_finish = server_side_source_write_finish;
1083 source_class->remote_create_sync = server_side_source_remote_create_sync;
1084 source_class->remote_delete_sync = server_side_source_remote_delete_sync;
1086 g_object_class_install_property (
1088 PROP_ALLOW_AUTH_PROMPT,
1089 g_param_spec_boolean (
1090 "allow-auth-prompt",
1091 "Allow Auth Prompt",
1092 "Whether authentication sessions may "
1093 "interrupt the user for a password",
1097 G_PARAM_STATIC_STRINGS));
1099 g_object_class_install_property (
1102 g_param_spec_boolean (
1105 "Whether the source has been exported over D-Bus",
1108 G_PARAM_STATIC_STRINGS));
1110 g_object_class_install_property (
1113 g_param_spec_object (
1116 "The key file for the data source",
1119 G_PARAM_CONSTRUCT_ONLY |
1120 G_PARAM_STATIC_STRINGS));
1122 /* This overrides the "remote-creatable" property
1123 * in ESourceClass with a writable version. */
1124 g_object_class_install_property (
1126 PROP_REMOTE_CREATABLE,
1127 g_param_spec_boolean (
1130 "Whether the data source "
1131 "can create remote resources",
1134 G_PARAM_STATIC_STRINGS));
1136 /* This overrides the "remote-deletable" property
1137 * in ESourceClass with a writable version. */
1138 g_object_class_install_property (
1140 PROP_REMOTE_DELETABLE,
1141 g_param_spec_boolean (
1144 "Whether the data source "
1145 "can delete remote resources",
1148 G_PARAM_STATIC_STRINGS));
1150 /* This overrides the "removable" property
1151 * in ESourceClass with a writable version. */
1152 g_object_class_install_property (
1155 g_param_spec_boolean (
1158 "Whether the data source is removable",
1161 G_PARAM_STATIC_STRINGS));
1163 g_object_class_install_property (
1166 g_param_spec_object (
1169 "The server to which the data source belongs",
1170 E_TYPE_SOURCE_REGISTRY_SERVER,
1172 G_PARAM_CONSTRUCT_ONLY |
1173 G_PARAM_STATIC_STRINGS));
1175 /* This overrides the "uid" property in
1176 * ESourceClass with a construct-only version. */
1177 g_object_class_install_property (
1180 g_param_spec_string (
1183 "The unique identity of the data source",
1186 G_PARAM_CONSTRUCT_ONLY |
1187 G_PARAM_STATIC_STRINGS));
1189 /* This overrides the "writable" property
1190 * in ESourceClass with a writable version. */
1191 g_object_class_install_property (
1194 g_param_spec_boolean (
1197 "Whether the data source is writable",
1200 G_PARAM_STATIC_STRINGS));
1202 /* Do not use G_PARAM_CONSTRUCT. We initialize the
1203 * property ourselves in e_server_side_source_init(). */
1204 g_object_class_install_property (
1206 PROP_WRITE_DIRECTORY,
1207 g_param_spec_string (
1210 "Directory in which to write changes to disk",
1213 G_PARAM_STATIC_STRINGS));
1217 e_server_side_source_initable_init (GInitableIface *interface)
1219 initable_parent_interface = g_type_interface_peek_parent (interface);
1221 interface->init = server_side_source_initable_init;
1225 e_server_side_source_init (EServerSideSource *source)
1227 const gchar *user_dir;
1229 source->priv = E_SERVER_SIDE_SOURCE_GET_PRIVATE (source);
1231 source->priv->node.data = source;
1233 user_dir = e_server_side_source_get_user_dir ();
1234 source->priv->write_directory = g_strdup (user_dir);
1238 * e_server_side_source_get_user_dir:
1240 * Returns the directory where user-specific data source files are stored.
1242 * Returns: the user-specific data source directory
1247 e_server_side_source_get_user_dir (void)
1249 static gchar *dirname = NULL;
1251 if (G_UNLIKELY (dirname == NULL)) {
1252 const gchar *config_dir = e_get_user_config_dir ();
1253 dirname = g_build_filename (config_dir, "sources", NULL);
1254 g_mkdir_with_parents (dirname, 0700);
1261 * e_server_side_source_new_user_file:
1262 * @uid: unique identifier for a data source, or %NULL
1264 * Generates a unique file name for a new user-specific data source.
1265 * If @uid is non-%NULL it will be used in the basename of the file,
1266 * otherwise a unique basename will be generated using e_uid_new().
1268 * The returned #GFile can then be passed to e_server_side_source_new().
1269 * Unreference the #GFile with g_object_unref() when finished with it.
1271 * Note the data source file itself is not created here, only its name.
1273 * Returns: the #GFile for a new data source
1278 e_server_side_source_new_user_file (const gchar *uid)
1284 const gchar *user_dir;
1287 safe_uid = e_uid_new ();
1289 safe_uid = g_strdup (uid);
1290 e_filename_make_safe (safe_uid);
1292 user_dir = e_server_side_source_get_user_dir ();
1293 basename = g_strconcat (safe_uid, ".source", NULL);
1294 filename = g_build_filename (user_dir, basename, NULL);
1296 file = g_file_new_for_path (filename);
1306 * e_server_side_source_uid_from_file:
1307 * @file: a #GFile for a data source
1308 * @error: return location for a #GError, or %NULL
1310 * Extracts a unique identity string from the base name of @file.
1311 * If the base name of @file is missing a '.source' extension, the
1312 * function sets @error and returns %NULL.
1314 * Returns: the unique identity string for @file, or %NULL
1319 e_server_side_source_uid_from_file (GFile *file,
1325 g_return_val_if_fail (G_IS_FILE (file), FALSE);
1327 basename = g_file_get_basename (file);
1329 if (g_str_has_suffix (basename, ".source")) {
1330 /* strlen(".source") --> 7 */
1331 uid = g_strndup (basename, strlen (basename) - 7);
1335 G_IO_ERROR_INVALID_FILENAME,
1336 _("File must have a '.source' extension"));
1345 * e_server_side_source_new:
1346 * @server: an #ESourceRegistryServer
1347 * @file: a #GFile, or %NULL
1348 * @error: return location for a #GError, or %NULL
1350 * Creates a new #EServerSideSource which belongs to @server. If @file
1351 * is non-%NULL and points to an existing file, the #EServerSideSource is
1352 * initialized from the file content. If a read error occurs or the file
1353 * contains syntax errors, the function sets @error and returns %NULL.
1355 * Returns: a new #EServerSideSource, or %NULL
1360 e_server_side_source_new (ESourceRegistryServer *server,
1364 EDBusObjectSkeleton *dbus_object;
1367 g_return_val_if_fail (E_IS_SOURCE_REGISTRY_SERVER (server), NULL);
1368 g_return_val_if_fail (file == NULL || G_IS_FILE (file), NULL);
1370 /* XXX This is an awkward way of initializing the "dbus-object"
1371 * property, but e_source_ref_dbus_object() needs to work. */
1372 dbus_object = e_dbus_object_skeleton_new (DBUS_OBJECT_PATH);
1374 source = g_initable_new (
1375 E_TYPE_SERVER_SIDE_SOURCE, NULL, error,
1376 "dbus-object", dbus_object,
1377 "file", file, "server", server, NULL);
1379 g_object_unref (dbus_object);
1385 * e_server_side_source_new_memory_only:
1386 * @server: an #ESourceRegistryServer
1387 * @uid: a unique identifier, or %NULL
1388 * @error: return location for a #GError, or %NULL
1390 * Creates a memory-only #EServerSideSource which belongs to @server.
1391 * No on-disk key file is created for this data source, so it will not
1392 * be remembered across sessions.
1394 * Data source collections are often populated with memory-only data
1395 * sources to serve as proxies for resources discovered on a remote server.
1396 * These data sources are usually neither #EServerSideSource:writable nor
1397 * #EServerSideSource:removable by clients, at least not directly.
1399 * If an error occurs while instantiating the #EServerSideSource, the
1400 * function sets @error and returns %NULL. Although at this time there
1401 * are no known error conditions for memory-only data sources.
1403 * Returns: a new memory-only #EServerSideSource, or %NULL
1408 e_server_side_source_new_memory_only (ESourceRegistryServer *server,
1412 EDBusObjectSkeleton *dbus_object;
1415 g_return_val_if_fail (E_IS_SOURCE_REGISTRY_SERVER (server), NULL);
1417 /* XXX This is an awkward way of initializing the "dbus-object"
1418 * property, but e_source_ref_dbus_object() needs to work. */
1419 dbus_object = e_dbus_object_skeleton_new (DBUS_OBJECT_PATH);
1421 source = g_initable_new (
1422 E_TYPE_SERVER_SIDE_SOURCE, NULL, error,
1423 "dbus-object", dbus_object,
1424 "server", server, "uid", uid, NULL);
1426 g_object_unref (dbus_object);
1432 * e_server_side_source_load:
1433 * @source: an #EServerSideSource
1434 * @cancellable: optional #GCancellable object, or %NULL
1435 * @error: return location for a #GError, or %NULL
1437 * Reloads data source content from the file pointed to by the
1438 * #EServerSideSource:file property.
1440 * If the #EServerSideSource:file property is %NULL or the file it points
1441 * to does not exist, the function does nothing and returns %TRUE.
1443 * If a read error occurs or the file contains syntax errors, the function
1444 * sets @error and returns %FALSE.
1446 * Returns: %TRUE on success, %FALSE on failure
1451 e_server_side_source_load (EServerSideSource *source,
1452 GCancellable *cancellable,
1455 GDBusObject *dbus_object;
1456 EDBusSource *dbus_source;
1462 GError *local_error = NULL;
1464 g_return_val_if_fail (E_IS_SERVER_SIDE_SOURCE (source), FALSE);
1466 file = e_server_side_source_get_file (source);
1469 g_file_load_contents (
1470 file, cancellable, &data,
1471 &length, NULL, &local_error);
1473 /* Disregard G_IO_ERROR_NOT_FOUND and treat it as a successful load. */
1474 if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) {
1475 g_error_free (local_error);
1477 } else if (local_error != NULL) {
1478 g_propagate_error (error, local_error);
1482 source->priv->file_contents = g_strdup (data);
1486 /* Create the bare minimum to pass parse_data(). */
1487 data = g_strdup_printf ("[%s]", PRIMARY_GROUP_NAME);
1488 length = strlen (data);
1491 key_file = g_key_file_new ();
1493 success = server_side_source_parse_data (
1494 key_file, data, length, error);
1496 g_key_file_free (key_file);
1503 /* Update the D-Bus interface properties. */
1505 dbus_object = e_source_ref_dbus_object (E_SOURCE (source));
1506 dbus_source = e_dbus_object_get_source (E_DBUS_OBJECT (dbus_object));
1508 e_dbus_source_set_data (dbus_source, data);
1510 g_object_unref (dbus_source);
1511 g_object_unref (dbus_object);
1519 * e_server_side_source_get_file:
1520 * @source: an #EServerSideSource
1522 * Returns the #GFile from which data source content is loaded and to
1523 * which changes are saved. Note the @source may not have a #GFile.
1525 * Returns: the #GFile for @source, or %NULL
1530 e_server_side_source_get_file (EServerSideSource *source)
1532 g_return_val_if_fail (E_IS_SERVER_SIDE_SOURCE (source), NULL);
1534 return source->priv->file;
1538 * e_server_side_source_get_node:
1539 * @source: an #EServerSideSource
1541 * Returns the #GNode representing the @source's hierarchical placement,
1542 * or %NULL if @source has not been placed in the data source hierarchy.
1543 * The data member of the #GNode points back to @source. This is an easy
1544 * way to traverse ancestor and descendant data sources.
1546 * Note that accessing other data sources this way is not thread-safe,
1547 * and this therefore function may be replaced at some later date.
1549 * Returns: a #GNode, or %NULL
1554 e_server_side_source_get_node (EServerSideSource *source)
1556 g_return_val_if_fail (E_IS_SERVER_SIDE_SOURCE (source), NULL);
1558 return &source->priv->node;
1562 * e_server_side_source_get_server:
1563 * @source: an #EServerSideSource
1565 * Returns the #ESourceRegistryServer to which @source belongs.
1567 * Returns: the #ESourceRegistryServer for @source
1571 ESourceRegistryServer *
1572 e_server_side_source_get_server (EServerSideSource *source)
1574 g_return_val_if_fail (E_IS_SERVER_SIDE_SOURCE (source), NULL);
1576 return source->priv->server;
1580 * e_server_side_source_get_allow_auth_prompt:
1581 * @source: an #EServerSideSource
1583 * Returns whether an authentication prompt is allowed to be shown
1584 * for @source. #EAuthenticationSession will honor this setting by
1585 * dismissing the session if it can't find a valid stored password.
1587 * See e_server_side_source_set_allow_auth_prompt() for further
1590 * Returns: whether auth prompts are allowed for @source
1595 e_server_side_source_get_allow_auth_prompt (EServerSideSource *source)
1597 g_return_val_if_fail (E_IS_SERVER_SIDE_SOURCE (source), FALSE);
1599 return source->priv->allow_auth_prompt;
1603 * e_server_side_source_set_allow_auth_prompt:
1604 * @source: an #EServerSideSource
1605 * @allow_auth_prompt: whether auth prompts are allowed for @source
1607 * Sets whether an authentication prompt is allowed to be shown for @source.
1608 * #EAuthenticationSession will honor this setting by dismissing the session
1609 * if it can't find a valid stored password.
1611 * If the user declines to provide a password for @source when prompted
1612 * by an #EAuthenticationSession, the #ESourceRegistryServer will set this
1613 * property to %FALSE to suppress any further prompting, which would likely
1614 * annoy the user. However when an #ESourceRegistry instance is created by
1615 * a client application, the first thing it does is reset this property to
1616 * %TRUE for all registered data sources. So suppressing authentication
1617 * prompts is only ever temporary.
1622 e_server_side_source_set_allow_auth_prompt (EServerSideSource *source,
1623 gboolean allow_auth_prompt)
1625 g_return_if_fail (E_IS_SERVER_SIDE_SOURCE (source));
1627 if ((source->priv->allow_auth_prompt ? 1 : 0) == (allow_auth_prompt ? 1 : 0))
1630 source->priv->allow_auth_prompt = allow_auth_prompt;
1632 g_object_notify (G_OBJECT (source), "allow-auth-prompt");
1636 * e_server_side_source_get_exported:
1637 * @source: an #EServerSideSource
1639 * Returns whether @source has been exported over D-Bus.
1641 * The function returns %FALSE after @source is initially created, %TRUE
1642 * after passing @source to e_source_registry_add_source() (provided that
1643 * @source's #ESource:parent is also exported), and %FALSE after passing
1644 * @source to e_source_registry_remove_source().
1646 * Returns: whether @source has been exported
1651 e_server_side_source_get_exported (EServerSideSource *source)
1653 ESourceRegistryServer *server;
1654 ESource *exported_source;
1655 gboolean exported = FALSE;
1658 g_return_val_if_fail (E_IS_SERVER_SIDE_SOURCE (source), FALSE);
1660 uid = e_source_get_uid (E_SOURCE (source));
1661 server = e_server_side_source_get_server (source);
1663 /* We're exported if we can look ourselves up in the registry. */
1665 exported_source = e_source_registry_server_ref_source (server, uid);
1666 if (exported_source != NULL) {
1668 g_object_unref (exported_source);
1675 * e_server_side_source_get_write_directory:
1676 * @source: an #EServerSideSource
1678 * Returns the local directory path where changes to @source are written.
1680 * By default, changes are written to the local directory path returned by
1681 * e_server_side_source_get_user_dir(), but an #ECollectionBackend may wish
1682 * to override this to use its own private cache directory for data sources
1683 * it creates automatically.
1685 * Returns: the directory where changes are written
1690 e_server_side_source_get_write_directory (EServerSideSource *source)
1692 g_return_val_if_fail (E_IS_SERVER_SIDE_SOURCE (source), NULL);
1694 return source->priv->write_directory;
1698 * e_server_side_source_set_write_directory:
1699 * @source: an #EServerSideSource
1700 * @write_directory: the directory where changes are to be written
1702 * Sets the local directory path where changes to @source are to be written.
1704 * By default, changes are written to the local directory path returned by
1705 * e_server_side_source_get_user_dir(), but an #ECollectionBackend may wish
1706 * to override this to use its own private cache directory for data sources
1707 * it creates automatically.
1712 e_server_side_source_set_write_directory (EServerSideSource *source,
1713 const gchar *write_directory)
1715 g_return_if_fail (E_IS_SERVER_SIDE_SOURCE (source));
1716 g_return_if_fail (write_directory != NULL);
1718 if (g_strcmp0 (source->priv->write_directory, write_directory) == 0)
1721 g_free (source->priv->write_directory);
1722 source->priv->write_directory = g_strdup (write_directory);
1724 g_object_notify (G_OBJECT (source), "write-directory");
1728 * e_server_side_source_set_removable:
1729 * @source: an #EServerSideSource
1730 * @removable: whether to export the Removable interface
1732 * Sets whether to allow registry clients to remove @source and its
1733 * descendants. If %TRUE, the Removable D-Bus interface is exported at
1734 * the object path for @source. If %FALSE, the Removable D-Bus interface
1735 * is unexported at the object path for @source, and any attempt by clients
1736 * to call e_source_remove() will fail.
1738 * Note this is only enforced for clients of the registry D-Bus service.
1739 * The service itself may remove any data source at any time.
1744 e_server_side_source_set_removable (EServerSideSource *source,
1747 EDBusSourceRemovable *dbus_interface = NULL;
1748 GDBusObject *dbus_object;
1749 gboolean currently_removable;
1751 g_return_if_fail (E_IS_SERVER_SIDE_SOURCE (source));
1753 currently_removable = e_source_get_removable (E_SOURCE (source));
1755 if (removable == currently_removable)
1760 e_dbus_source_removable_skeleton_new ();
1763 dbus_interface, "handle-remove",
1764 G_CALLBACK (server_side_source_remove_cb), source);
1767 dbus_object = e_source_ref_dbus_object (E_SOURCE (source));
1768 e_dbus_object_skeleton_set_source_removable (
1769 E_DBUS_OBJECT_SKELETON (dbus_object), dbus_interface);
1770 g_object_unref (dbus_object);
1772 if (dbus_interface != NULL)
1773 g_object_unref (dbus_interface);
1775 g_object_notify (G_OBJECT (source), "removable");
1779 * e_server_side_source_set_writable:
1780 * @source: an #EServerSideSource
1781 * @writable: whether to export the Writable interface
1783 * Sets whether to allow registry clients to alter the content of @source.
1784 * If %TRUE, the Writable D-Bus interface is exported at the object path
1785 * for @source. If %FALSE, the Writable D-Bus interface is unexported at
1786 * the object path for @source, and any attempt by clients to call
1787 * e_source_write() will fail.
1789 * Note this is only enforced for clients of the registry D-Bus service.
1790 * The service itself can write to any data source at any time.
1795 e_server_side_source_set_writable (EServerSideSource *source,
1798 EDBusSourceWritable *dbus_interface = NULL;
1799 GDBusObject *dbus_object;
1800 gboolean currently_writable;
1802 g_return_if_fail (E_IS_SERVER_SIDE_SOURCE (source));
1804 currently_writable = e_source_get_writable (E_SOURCE (source));
1806 if (writable == currently_writable)
1811 e_dbus_source_writable_skeleton_new ();
1814 dbus_interface, "handle-write",
1815 G_CALLBACK (server_side_source_write_cb), source);
1818 dbus_object = e_source_ref_dbus_object (E_SOURCE (source));
1819 e_dbus_object_skeleton_set_source_writable (
1820 E_DBUS_OBJECT_SKELETON (dbus_object), dbus_interface);
1821 g_object_unref (dbus_object);
1823 if (dbus_interface != NULL)
1824 g_object_unref (dbus_interface);
1826 g_object_notify (G_OBJECT (source), "writable");
1830 * e_server_side_source_set_remote_creatable:
1831 * @source: an #EServerSideSource
1832 * @remote_creatable: whether to export the RemoteCreatable interface
1834 * Indicates whether @source can be used to create resources on a remote
1835 * server. Typically this is only set to %TRUE for collection sources.
1837 * If %TRUE, the RemoteCreatable D-Bus interface is exported at the object
1838 * path for @source. If %FALSE, the RemoteCreatable D-Bus interface is
1839 * unexported at the object path for @source, and any attempt by clients
1840 * to call e_source_remote_create() will fail.
1842 * Unlike the #ESource:removable and #ESource:writable properties, this
1843 * is enforced for both clients of the registry D-Bus service and within
1844 * the registry D-Bus service itself.
1849 e_server_side_source_set_remote_creatable (EServerSideSource *source,
1850 gboolean remote_creatable)
1852 EDBusSourceRemoteCreatable *dbus_interface = NULL;
1853 GDBusObject *dbus_object;
1854 gboolean currently_remote_creatable;
1856 g_return_if_fail (E_IS_SERVER_SIDE_SOURCE (source));
1858 currently_remote_creatable =
1859 e_source_get_remote_creatable (E_SOURCE (source));
1861 if (remote_creatable == currently_remote_creatable)
1864 if (remote_creatable) {
1866 e_dbus_source_remote_creatable_skeleton_new ();
1869 dbus_interface, "handle-create",
1870 G_CALLBACK (server_side_source_remote_create_cb),
1874 dbus_object = e_source_ref_dbus_object (E_SOURCE (source));
1875 e_dbus_object_skeleton_set_source_remote_creatable (
1876 E_DBUS_OBJECT_SKELETON (dbus_object), dbus_interface);
1877 g_object_unref (dbus_object);
1879 if (dbus_interface != NULL)
1880 g_object_unref (dbus_interface);
1882 g_object_notify (G_OBJECT (source), "remote-creatable");
1886 * e_server_side_source_set_remote_deletable:
1887 * @source: an #EServerSideSource
1888 * @remote_deletable: whether to export the RemoteDeletable interface
1890 * Indicates whether @source can be used to delete resources on a remote
1891 * server. Typically this is only set to %TRUE for sources created by an
1892 * #ECollectionBackend to represent a remote resource.
1894 * If %TRUE, the RemoteDeletable D-Bus interface is exported at the object
1895 * path for @source. If %FALSE, the RemoteDeletable D-Bus interface is
1896 * unexported at the object path for @source, and any attempt by clients
1897 * to call e_source_remote_delete() will fail.
1899 * Unlike the #ESource:removable and #ESource:writable properties, this
1900 * is enforced for both clients of the registry D-Bus server and within
1901 * the registry D-Bus service itself.
1906 e_server_side_source_set_remote_deletable (EServerSideSource *source,
1907 gboolean remote_deletable)
1909 EDBusSourceRemoteDeletable *dbus_interface = NULL;
1910 GDBusObject *dbus_object;
1911 gboolean currently_remote_deletable;
1913 g_return_if_fail (E_IS_SERVER_SIDE_SOURCE (source));
1915 currently_remote_deletable =
1916 e_source_get_remote_deletable (E_SOURCE (source));
1918 if (remote_deletable == currently_remote_deletable)
1921 if (remote_deletable) {
1923 e_dbus_source_remote_deletable_skeleton_new ();
1926 dbus_interface, "handle-delete",
1927 G_CALLBACK (server_side_source_remote_delete_cb),
1931 dbus_object = e_source_ref_dbus_object (E_SOURCE (source));
1932 e_dbus_object_skeleton_set_source_remote_deletable (
1933 E_DBUS_OBJECT_SKELETON (dbus_object), dbus_interface);
1934 g_object_unref (dbus_object);
1936 if (dbus_interface != NULL)
1937 g_object_unref (dbus_interface);
1939 g_object_notify (G_OBJECT (source), "remote-deletable");