893d9256c25519e9cc1a06afa8805e91a03af8e4
[platform/upstream/evolution-data-server.git] / libebackend / e-server-side-source.c
1 /*
2  * e-server-side-source.c
3  *
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.
8  *
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.
13  *
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/>
16  *
17  */
18
19 /**
20  * SECTION: e-server-side-source
21  * @include: libebackend/libebackend.h
22  * @short_description: A server-side data source
23  *
24  * An #EServerSideSource is an #ESource with some additional capabilities
25  * exclusive to the registry D-Bus service.
26  **/
27
28 #include "e-server-side-source.h"
29
30 #include <config.h>
31 #include <glib/gi18n-lib.h>
32
33 /* Private D-Bus classes. */
34 #include <e-dbus-source.h>
35
36 #define E_SERVER_SIDE_SOURCE_GET_PRIVATE(obj) \
37         (G_TYPE_INSTANCE_GET_PRIVATE \
38         ((obj), E_TYPE_SERVER_SIDE_SOURCE, EServerSideSourcePrivate))
39
40 #define DBUS_OBJECT_PATH        E_SOURCE_REGISTRY_SERVER_OBJECT_PATH "/Source"
41
42 #define PRIMARY_GROUP_NAME      "Data Source"
43
44 typedef struct _AsyncContext AsyncContext;
45
46 struct _EServerSideSourcePrivate {
47         gpointer server;  /* weak pointer */
48
49         GNode node;
50         GFile *file;
51         gchar *uid;
52
53         /* For comparison. */
54         gchar *file_contents;
55
56         gboolean allow_auth_prompt;
57         gchar *write_directory;
58 };
59
60 struct _AsyncContext {
61         EDBusSourceRemoteCreatable *remote_creatable;
62         EDBusSourceRemoteDeletable *remote_deletable;
63         GDBusMethodInvocation *invocation;
64 };
65
66 enum {
67         PROP_0,
68         PROP_ALLOW_AUTH_PROMPT,
69         PROP_EXPORTED,
70         PROP_FILE,
71         PROP_REMOTE_CREATABLE,
72         PROP_REMOTE_DELETABLE,
73         PROP_REMOVABLE,
74         PROP_SERVER,
75         PROP_UID,
76         PROP_WRITABLE,
77         PROP_WRITE_DIRECTORY
78 };
79
80 static GInitableIface *initable_parent_interface;
81
82 /* Forward Declarations */
83 static void     e_server_side_source_initable_init
84                                                 (GInitableIface *interface);
85
86 G_DEFINE_TYPE_WITH_CODE (
87         EServerSideSource,
88         e_server_side_source,
89         E_TYPE_SOURCE,
90         G_IMPLEMENT_INTERFACE (
91                 G_TYPE_INITABLE,
92                 e_server_side_source_initable_init))
93
94 static void
95 async_context_free (AsyncContext *async_context)
96 {
97         if (async_context->remote_creatable != NULL)
98                 g_object_unref (async_context->remote_creatable);
99
100         if (async_context->remote_deletable != NULL)
101                 g_object_unref (async_context->remote_deletable);
102
103         if (async_context->invocation != NULL)
104                 g_object_unref (async_context->invocation);
105
106         g_slice_free (AsyncContext, async_context);
107 }
108
109 static gboolean
110 server_side_source_parse_data (GKeyFile *key_file,
111                                const gchar *data,
112                                gsize length,
113                                GError **error)
114 {
115         gboolean success;
116
117         success = g_key_file_load_from_data (
118                 key_file, data, length, G_KEY_FILE_NONE, error);
119
120         if (!success)
121                 return FALSE;
122
123         /* Make sure the key file has a [Data Source] group. */
124         if (!g_key_file_has_group (key_file, PRIMARY_GROUP_NAME)) {
125                 g_set_error (
126                         error, G_KEY_FILE_ERROR,
127                         G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
128                         _("Data source is missing a [%s] group"),
129                         PRIMARY_GROUP_NAME);
130                 return FALSE;
131         }
132
133         return TRUE;
134 }
135
136 static void
137 server_side_source_print_diff (ESource *source,
138                                const gchar *old_data,
139                                const gchar *new_data)
140 {
141         gchar **old_strv = NULL;
142         gchar **new_strv = NULL;
143         guint old_length = 0;
144         guint new_length = 0;
145         guint ii;
146
147         g_print ("Saving %s\n", e_source_get_uid (source));
148
149         if (old_data != NULL) {
150                 old_strv = g_strsplit (old_data, "\n", 0);
151                 old_length = g_strv_length (old_strv);
152         }
153
154         if (new_data != NULL) {
155                 new_strv = g_strsplit (new_data, "\n", 0);
156                 new_length = g_strv_length (new_strv);
157         }
158
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]);
163                 } else {
164                         g_print ("   : %s\n", old_strv[ii]);
165                 }
166         }
167
168         for (; ii < old_length; ii++)
169                 g_print (" - : %s\n", old_strv[ii]);
170
171         for (; ii < new_length; ii++)
172                 g_print (" + : %s\n", new_strv[ii]);
173
174         g_strfreev (old_strv);
175         g_strfreev (new_strv);
176 }
177
178 static gboolean
179 server_side_source_traverse_cb (GNode *node,
180                                 GQueue *queue)
181 {
182         g_queue_push_tail (queue, g_object_ref (node->data));
183
184         return FALSE;
185 }
186
187 static gboolean
188 server_side_source_allow_auth_prompt_cb (EDBusSource *interface,
189                                          GDBusMethodInvocation *invocation,
190                                          EServerSideSource *source)
191 {
192         e_server_side_source_set_allow_auth_prompt (source, TRUE);
193
194         e_dbus_source_complete_allow_auth_prompt (interface, invocation);
195
196         return TRUE;
197 }
198
199 static gboolean
200 server_side_source_remove_cb (EDBusSourceRemovable *interface,
201                               GDBusMethodInvocation *invocation,
202                               EServerSideSource *source)
203 {
204         GError *error = NULL;
205
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. */
210
211         e_source_remove_sync (E_SOURCE (source), NULL, &error);
212
213         if (error != NULL)
214                 g_dbus_method_invocation_take_error (invocation, error);
215         else
216                 e_dbus_source_removable_complete_remove (
217                         interface, invocation);
218
219         return TRUE;
220 }
221
222 static gboolean
223 server_side_source_write_cb (EDBusSourceWritable *interface,
224                              GDBusMethodInvocation *invocation,
225                              const gchar *data,
226                              ESource *source)
227 {
228         GKeyFile *key_file;
229         GDBusObject *dbus_object;
230         EDBusSource *dbus_source;
231         GError *error = NULL;
232
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. */
235
236         dbus_object = e_source_ref_dbus_object (source);
237         dbus_source = e_dbus_object_get_source (E_DBUS_OBJECT (dbus_object));
238
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);
243
244         /* Q: How does this trigger data being written to disk?
245          *
246          * A: Here's the sequence of events:
247          *
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.
255          */
256
257         if (error == NULL)
258                 e_dbus_source_set_data (dbus_source, data);
259
260         if (error != NULL)
261                 g_dbus_method_invocation_take_error (invocation, error);
262         else
263                 e_dbus_source_writable_complete_write (
264                         interface, invocation);
265
266         g_object_unref (dbus_source);
267         g_object_unref (dbus_object);
268
269         return TRUE;
270 }
271
272 /* Helper for server_side_source_remote_create_cb() */
273 static void
274 server_side_source_remote_create_done_cb (GObject *source_object,
275                                           GAsyncResult *result,
276                                           gpointer user_data)
277 {
278         ESource *source;
279         AsyncContext *async_context;
280         GError *error = NULL;
281
282         source = E_SOURCE (source_object);
283         async_context = (AsyncContext *) user_data;
284
285         e_source_remote_create_finish (source, result, &error);
286
287         if (error != NULL)
288                 g_dbus_method_invocation_take_error (
289                         async_context->invocation, error);
290         else
291                 e_dbus_source_remote_creatable_complete_create (
292                         async_context->remote_creatable,
293                         async_context->invocation);
294
295         async_context_free (async_context);
296 }
297
298 static gboolean
299 server_side_source_remote_create_cb (EDBusSourceRemoteCreatable *interface,
300                                      GDBusMethodInvocation *invocation,
301                                      const gchar *uid,
302                                      const gchar *data,
303                                      ESource *source)
304 {
305         EServerSideSource *server_side_source;
306         ESourceRegistryServer *server;
307         AsyncContext *async_context;
308         ESource *scratch_source;
309         GDBusObject *dbus_object;
310         EDBusSource *dbus_source;
311         GKeyFile *key_file;
312         GFile *file;
313         GError *error = NULL;
314
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. */
320
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);
325
326         if (error != NULL) {
327                 g_dbus_method_invocation_take_error (invocation, error);
328                 return TRUE;
329         }
330
331         server_side_source = E_SERVER_SIDE_SOURCE (source);
332         server = e_server_side_source_get_server (server_side_source);
333
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);
337
338         /* Sanity check. */
339         g_warn_if_fail (
340                 ((scratch_source != NULL) && (error == NULL)) ||
341                 ((scratch_source == NULL) && (error != NULL)));
342
343         if (error != NULL) {
344                 g_dbus_method_invocation_take_error (invocation, error);
345                 return TRUE;
346         }
347
348         dbus_object = e_source_ref_dbus_object (scratch_source);
349         dbus_source = e_dbus_object_get_source (E_DBUS_OBJECT (dbus_object));
350
351         e_dbus_source_set_data (dbus_source, data);
352
353         g_object_unref (dbus_object);
354         g_object_unref (dbus_source);
355
356         async_context = g_slice_new0 (AsyncContext);
357         async_context->remote_creatable = g_object_ref (interface);
358         async_context->invocation = g_object_ref (invocation);
359
360         e_source_remote_create (
361                 source, scratch_source, NULL,
362                 server_side_source_remote_create_done_cb,
363                 async_context);
364
365         g_object_unref (scratch_source);
366
367         return TRUE;
368 }
369
370 /* Helper for server_side_source_remote_delete_cb() */
371 static void
372 server_side_source_remote_delete_done_cb (GObject *source_object,
373                                           GAsyncResult *result,
374                                           gpointer user_data)
375 {
376         ESource *source;
377         AsyncContext *async_context;
378         GError *error = NULL;
379
380         source = E_SOURCE (source_object);
381         async_context = (AsyncContext *) user_data;
382
383         e_source_remote_delete_finish (source, result, &error);
384
385         if (error != NULL)
386                 g_dbus_method_invocation_take_error (
387                         async_context->invocation, error);
388         else
389                 e_dbus_source_remote_deletable_complete_delete (
390                         async_context->remote_deletable,
391                         async_context->invocation);
392
393         async_context_free (async_context);
394 }
395
396 static gboolean
397 server_side_source_remote_delete_cb (EDBusSourceRemoteDeletable *interface,
398                                      GDBusMethodInvocation *invocation,
399                                      ESource *source)
400 {
401         AsyncContext *async_context;
402
403         async_context = g_slice_new0 (AsyncContext);
404         async_context->remote_deletable = g_object_ref (interface);
405         async_context->invocation = g_object_ref (invocation);
406
407         e_source_remote_delete (
408                 source, NULL,
409                 server_side_source_remote_delete_done_cb,
410                 async_context);
411
412         return TRUE;
413 }
414
415 static void
416 server_side_source_set_file (EServerSideSource *source,
417                              GFile *file)
418 {
419         g_return_if_fail (file == NULL || G_IS_FILE (file));
420         g_return_if_fail (source->priv->file == NULL);
421
422         if (file != NULL)
423                 source->priv->file = g_object_ref (file);
424 }
425
426 static void
427 server_side_source_set_server (EServerSideSource *source,
428                                ESourceRegistryServer *server)
429 {
430         g_return_if_fail (E_IS_SOURCE_REGISTRY_SERVER (server));
431         g_return_if_fail (source->priv->server == NULL);
432
433         source->priv->server = server;
434
435         g_object_add_weak_pointer (
436                 G_OBJECT (server), &source->priv->server);
437 }
438
439 static void
440 server_side_source_set_uid (EServerSideSource *source,
441                             const gchar *uid)
442 {
443         g_return_if_fail (source->priv->uid == NULL);
444
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);
450 }
451
452 static void
453 server_side_source_set_property (GObject *object,
454                                  guint property_id,
455                                  const GValue *value,
456                                  GParamSpec *pspec)
457 {
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));
463                         return;
464
465                 case PROP_FILE:
466                         server_side_source_set_file (
467                                 E_SERVER_SIDE_SOURCE (object),
468                                 g_value_get_object (value));
469                         return;
470
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));
475                         return;
476
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));
481                         return;
482
483                 case PROP_REMOVABLE:
484                         e_server_side_source_set_removable (
485                                 E_SERVER_SIDE_SOURCE (object),
486                                 g_value_get_boolean (value));
487                         return;
488
489                 case PROP_SERVER:
490                         server_side_source_set_server (
491                                 E_SERVER_SIDE_SOURCE (object),
492                                 g_value_get_object (value));
493                         return;
494
495                 case PROP_UID:
496                         server_side_source_set_uid (
497                                 E_SERVER_SIDE_SOURCE (object),
498                                 g_value_get_string (value));
499                         return;
500
501                 case PROP_WRITABLE:
502                         e_server_side_source_set_writable (
503                                 E_SERVER_SIDE_SOURCE (object),
504                                 g_value_get_boolean (value));
505                         return;
506
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));
511                         return;
512         }
513
514         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
515 }
516
517 static void
518 server_side_source_get_property (GObject *object,
519                                  guint property_id,
520                                  GValue *value,
521                                  GParamSpec *pspec)
522 {
523         switch (property_id) {
524                 case PROP_ALLOW_AUTH_PROMPT:
525                         g_value_set_boolean (
526                                 value,
527                                 e_server_side_source_get_allow_auth_prompt (
528                                 E_SERVER_SIDE_SOURCE (object)));
529                         return;
530
531                 case PROP_EXPORTED:
532                         g_value_set_boolean (
533                                 value,
534                                 e_server_side_source_get_exported (
535                                 E_SERVER_SIDE_SOURCE (object)));
536                         return;
537
538                 case PROP_FILE:
539                         g_value_set_object (
540                                 value,
541                                 e_server_side_source_get_file (
542                                 E_SERVER_SIDE_SOURCE (object)));
543                         return;
544
545                 case PROP_REMOTE_CREATABLE:
546                         g_value_set_boolean (
547                                 value,
548                                 e_source_get_remote_creatable (
549                                 E_SOURCE (object)));
550                         return;
551
552                 case PROP_REMOTE_DELETABLE:
553                         g_value_set_boolean (
554                                 value,
555                                 e_source_get_remote_deletable (
556                                 E_SOURCE (object)));
557                         return;
558
559                 case PROP_REMOVABLE:
560                         g_value_set_boolean (
561                                 value,
562                                 e_source_get_removable (
563                                 E_SOURCE (object)));
564                         return;
565
566                 case PROP_SERVER:
567                         g_value_set_object (
568                                 value,
569                                 e_server_side_source_get_server (
570                                 E_SERVER_SIDE_SOURCE (object)));
571                         return;
572
573                 case PROP_UID:
574                         g_value_take_string (
575                                 value,
576                                 e_source_dup_uid (
577                                 E_SOURCE (object)));
578                         return;
579
580                 case PROP_WRITABLE:
581                         g_value_set_boolean (
582                                 value,
583                                 e_source_get_writable (
584                                 E_SOURCE (object)));
585                         return;
586
587                 case PROP_WRITE_DIRECTORY:
588                         g_value_set_string (
589                                 value,
590                                 e_server_side_source_get_write_directory (
591                                 E_SERVER_SIDE_SOURCE (object)));
592                         return;
593         }
594
595         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
596 }
597
598 static void
599 server_side_source_dispose (GObject *object)
600 {
601         EServerSideSourcePrivate *priv;
602
603         priv = E_SERVER_SIDE_SOURCE_GET_PRIVATE (object);
604
605         if (priv->server != NULL) {
606                 g_object_remove_weak_pointer (
607                         G_OBJECT (priv->server), &priv->server);
608                 priv->server = NULL;
609         }
610
611         if (priv->file != NULL) {
612                 g_object_unref (priv->file);
613                 priv->file = NULL;
614         }
615
616         /* Chain up to parent's dispose() method. */
617         G_OBJECT_CLASS (e_server_side_source_parent_class)->dispose (object);
618 }
619
620 static void
621 server_side_source_finalize (GObject *object)
622 {
623         EServerSideSourcePrivate *priv;
624
625         priv = E_SERVER_SIDE_SOURCE_GET_PRIVATE (object);
626
627         g_node_unlink (&priv->node);
628
629         g_free (priv->uid);
630         g_free (priv->file_contents);
631         g_free (priv->write_directory);
632
633         /* Chain up to parent's finalize() method. */
634         G_OBJECT_CLASS (e_server_side_source_parent_class)->finalize (object);
635 }
636
637 static void
638 server_side_source_changed (ESource *source)
639 {
640         GDBusObject *dbus_object;
641         EDBusSource *dbus_source;
642         gchar *old_data;
643         gchar *new_data;
644         GError *error = NULL;
645
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)))
648                 return;
649
650         dbus_object = e_source_ref_dbus_object (source);
651         dbus_source = e_dbus_object_get_source (E_DBUS_OBJECT (dbus_object));
652
653         old_data = e_dbus_source_dup_data (dbus_source);
654         new_data = e_source_to_string (source, NULL);
655
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);
661
662         g_free (old_data);
663         g_free (new_data);
664
665         g_object_unref (dbus_source);
666         g_object_unref (dbus_object);
667
668         /* This writes the "data" property to disk. */
669         e_source_write_sync (source, NULL, &error);
670
671         if (error != NULL) {
672                 g_warning ("%s: %s", G_STRFUNC, error->message);
673                 g_error_free (error);
674         }
675 }
676
677 static gboolean
678 server_side_source_remove_sync (ESource *source,
679                                 GCancellable *cancellable,
680                                 GError **error)
681 {
682         EAsyncClosure *closure;
683         GAsyncResult *result;
684         gboolean success;
685
686         closure = e_async_closure_new ();
687
688         e_source_remove (
689                 source, cancellable, e_async_closure_callback, closure);
690
691         result = e_async_closure_wait (closure);
692
693         success = e_source_remove_finish (source, result, error);
694
695         e_async_closure_free (closure);
696
697         return success;
698 }
699
700 static void
701 server_side_source_remove (ESource *source,
702                            GCancellable *cancellable,
703                            GAsyncReadyCallback callback,
704                            gpointer user_data)
705 {
706         EServerSideSourcePrivate *priv;
707         GSimpleAsyncResult *simple;
708         ESourceRegistryServer *server;
709         GQueue queue = G_QUEUE_INIT;
710         GList *list, *link;
711         GError *error = NULL;
712
713         /* XXX Yes we block here.  We do this operation
714          *     synchronously to keep the server code simple. */
715
716         priv = E_SERVER_SIDE_SOURCE_GET_PRIVATE (source);
717
718         simple = g_simple_async_result_new (
719                 G_OBJECT (source), callback, user_data,
720                 server_side_source_remove);
721
722         g_simple_async_result_set_check_cancellable (simple, cancellable);
723
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. */
727         g_node_traverse (
728                 &priv->node, G_POST_ORDER, G_TRAVERSE_ALL, -1,
729                 (GNodeTraverseFunc) server_side_source_traverse_cb, &queue);
730
731         /* Unexport the object and its descendants. */
732         server = E_SOURCE_REGISTRY_SERVER (priv->server);
733         e_source_registry_server_remove_source (server, source);
734
735         list = g_queue_peek_head_link (&queue);
736
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;
740                 GFile *file;
741
742                 child = E_SERVER_SIDE_SOURCE (link->data);
743                 file = e_server_side_source_get_file (child);
744
745                 if (file != NULL)
746                         g_file_delete (file, cancellable, &error);
747
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.
753                  *
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);
759
760                 if (error != NULL)
761                         goto exit;
762         }
763
764 exit:
765         while (!g_queue_is_empty (&queue))
766                 g_object_unref (g_queue_pop_head (&queue));
767
768         if (error != NULL)
769                 g_simple_async_result_take_error (simple, error);
770
771         g_simple_async_result_complete_in_idle (simple);
772         g_object_unref (simple);
773 }
774
775 static gboolean
776 server_side_source_remove_finish (ESource *source,
777                                   GAsyncResult *result,
778                                   GError **error)
779 {
780         GSimpleAsyncResult *simple;
781
782         g_return_val_if_fail (
783                 g_simple_async_result_is_valid (
784                 result, G_OBJECT (source),
785                 server_side_source_remove), FALSE);
786
787         simple = G_SIMPLE_ASYNC_RESULT (result);
788
789         /* Assume success unless a GError is set. */
790         return !g_simple_async_result_propagate_error (simple, error);
791 }
792
793 static gboolean
794 server_side_source_write_sync (ESource *source,
795                                GCancellable *cancellable,
796                                GError **error)
797 {
798         EAsyncClosure *closure;
799         GAsyncResult *result;
800         gboolean success;
801
802         closure = e_async_closure_new ();
803
804         e_source_write (
805                 source, cancellable, e_async_closure_callback, closure);
806
807         result = e_async_closure_wait (closure);
808
809         success = e_source_write_finish (source, result, error);
810
811         e_async_closure_free (closure);
812
813         return success;
814 }
815
816 static void
817 server_side_source_write (ESource *source,
818                           GCancellable *cancellable,
819                           GAsyncReadyCallback callback,
820                           gpointer user_data)
821 {
822         EServerSideSourcePrivate *priv;
823         GSimpleAsyncResult *simple;
824         GDBusObject *dbus_object;
825         EDBusSource *dbus_source;
826         gboolean replace_file;
827         const gchar *old_data;
828         gchar *new_data;
829         GError *error = NULL;
830
831         /* XXX Yes we block here.  We do this operation
832          *     synchronously to keep the server code simple. */
833
834         priv = E_SERVER_SIDE_SOURCE_GET_PRIVATE (source);
835
836         simple = g_simple_async_result_new (
837                 G_OBJECT (source), callback, user_data,
838                 server_side_source_write);
839
840         g_simple_async_result_set_check_cancellable (simple, cancellable);
841
842         dbus_object = e_source_ref_dbus_object (source);
843         dbus_source = e_dbus_object_get_source (E_DBUS_OBJECT (dbus_object));
844
845         old_data = priv->file_contents;
846         new_data = e_source_to_string (source, NULL);
847
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. */
854
855         replace_file =
856                 G_IS_FILE (priv->file) &&
857                 (g_strcmp0 (old_data, new_data) != 0);
858
859         if (replace_file) {
860                 GFile *file;
861                 GFile *write_directory;
862                 gchar *basename;
863
864                 g_warn_if_fail (priv->write_directory != NULL);
865
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);
869                 g_free (basename);
870
871                 if (!g_file_equal (file, priv->file)) {
872                         g_object_unref (priv->file);
873                         priv->file = g_object_ref (file);
874                 }
875
876                 server_side_source_print_diff (source, old_data, new_data);
877
878                 g_file_make_directory_with_parents (
879                         write_directory, cancellable, &error);
880
881                 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS))
882                         g_clear_error (&error);
883
884                 if (error == NULL)
885                         g_file_replace_contents (
886                                 file, new_data, strlen (new_data),
887                                 NULL, FALSE, G_FILE_CREATE_NONE,
888                                 NULL, cancellable, &error);
889
890                 if (error == NULL) {
891                         g_free (priv->file_contents);
892                         priv->file_contents = new_data;
893                         new_data = NULL;
894                 }
895
896                 g_object_unref (write_directory);
897                 g_object_unref (file);
898         }
899
900         g_free (new_data);
901
902         g_object_unref (dbus_source);
903         g_object_unref (dbus_object);
904
905         if (error != NULL)
906                 g_simple_async_result_take_error (simple, error);
907
908         g_simple_async_result_complete_in_idle (simple);
909         g_object_unref (simple);
910 }
911
912 static gboolean
913 server_side_source_write_finish (ESource *source,
914                                  GAsyncResult *result,
915                                  GError **error)
916 {
917         GSimpleAsyncResult *simple;
918
919         g_return_val_if_fail (
920                 g_simple_async_result_is_valid (
921                 result, G_OBJECT (source),
922                 server_side_source_write), FALSE);
923
924         simple = G_SIMPLE_ASYNC_RESULT (result);
925
926         /* Assume success unless a GError is set. */
927         return !g_simple_async_result_propagate_error (simple, error);
928 }
929
930 static gboolean
931 server_side_source_remote_create_sync (ESource *source,
932                                        ESource *scratch_source,
933                                        GCancellable *cancellable,
934                                        GError **error)
935 {
936         ECollectionBackend *backend;
937         ESourceRegistryServer *server;
938         EServerSideSource *server_side_source;
939         gboolean success;
940
941         if (!e_source_get_remote_creatable (source)) {
942                 g_set_error (
943                         error, G_IO_ERROR,
944                         G_IO_ERROR_NOT_SUPPORTED,
945                         _("Data source '%s' does not "
946                         "support creating remote resources"),
947                         e_source_get_display_name (source));
948                 return FALSE;
949         }
950
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);
954
955         if (backend == NULL) {
956                 g_set_error (
957                         error, G_IO_ERROR,
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));
962                 return FALSE;
963         }
964
965         success = e_collection_backend_create_resource_sync (
966                 backend, scratch_source, cancellable, error);
967
968         g_object_unref (backend);
969
970         return success;
971 }
972
973 static gboolean
974 server_side_source_remote_delete_sync (ESource *source,
975                                        GCancellable *cancellable,
976                                        GError **error)
977 {
978         ECollectionBackend *backend;
979         ESourceRegistryServer *server;
980         EServerSideSource *server_side_source;
981         gboolean success;
982
983         if (!e_source_get_remote_deletable (source)) {
984                 g_set_error (
985                         error, G_IO_ERROR,
986                         G_IO_ERROR_NOT_SUPPORTED,
987                         _("Data source '%s' does not "
988                         "support deleting remote resources"),
989                         e_source_get_display_name (source));
990                 return FALSE;
991         }
992
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);
996
997         if (backend == NULL) {
998                 g_set_error (
999                         error, G_IO_ERROR,
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));
1004                 return FALSE;
1005         }
1006
1007         success = e_collection_backend_delete_resource_sync (
1008                 backend, source, cancellable, error);
1009
1010         g_object_unref (backend);
1011
1012         return success;
1013 }
1014
1015 static gboolean
1016 server_side_source_initable_init (GInitable *initable,
1017                                   GCancellable *cancellable,
1018                                   GError **error)
1019 {
1020         EServerSideSource *source;
1021         GDBusObject *dbus_object;
1022         EDBusSource *dbus_source;
1023         GFile *file;
1024
1025         source = E_SERVER_SIDE_SOURCE (initable);
1026         file = e_server_side_source_get_file (source);
1027
1028         if (file != NULL) {
1029                 g_warn_if_fail (source->priv->uid == NULL);
1030                 source->priv->uid =
1031                         e_server_side_source_uid_from_file (file, error);
1032                 if (source->priv->uid == NULL)
1033                         return FALSE;
1034         }
1035
1036         if (source->priv->uid == NULL)
1037                 source->priv->uid = e_uid_new ();
1038
1039         dbus_source = e_dbus_source_skeleton_new ();
1040
1041         e_dbus_source_set_uid (dbus_source, source->priv->uid);
1042
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);
1047
1048         g_signal_connect (
1049                 dbus_source, "handle-allow-auth-prompt",
1050                 G_CALLBACK (server_side_source_allow_auth_prompt_cb), source);
1051
1052         g_object_unref (dbus_source);
1053
1054         if (!e_server_side_source_load (source, cancellable, error))
1055                 return FALSE;
1056
1057         /* Chain up to parent interface's init() method. */
1058         return initable_parent_interface->init (initable, cancellable, error);
1059 }
1060
1061 static void
1062 e_server_side_source_class_init (EServerSideSourceClass *class)
1063 {
1064         GObjectClass *object_class;
1065         ESourceClass *source_class;
1066
1067         g_type_class_add_private (class, sizeof (EServerSideSourcePrivate));
1068
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;
1074
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;
1085
1086         g_object_class_install_property (
1087                 object_class,
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",
1094                         TRUE,
1095                         G_PARAM_READWRITE |
1096                         G_PARAM_CONSTRUCT |
1097                         G_PARAM_STATIC_STRINGS));
1098
1099         g_object_class_install_property (
1100                 object_class,
1101                 PROP_EXPORTED,
1102                 g_param_spec_boolean (
1103                         "exported",
1104                         "Exported",
1105                         "Whether the source has been exported over D-Bus",
1106                         FALSE,
1107                         G_PARAM_READABLE |
1108                         G_PARAM_STATIC_STRINGS));
1109
1110         g_object_class_install_property (
1111                 object_class,
1112                 PROP_FILE,
1113                 g_param_spec_object (
1114                         "file",
1115                         "File",
1116                         "The key file for the data source",
1117                         G_TYPE_FILE,
1118                         G_PARAM_READWRITE |
1119                         G_PARAM_CONSTRUCT_ONLY |
1120                         G_PARAM_STATIC_STRINGS));
1121
1122         /* This overrides the "remote-creatable" property
1123          * in ESourceClass with a writable version. */
1124         g_object_class_install_property (
1125                 object_class,
1126                 PROP_REMOTE_CREATABLE,
1127                 g_param_spec_boolean (
1128                         "remote-creatable",
1129                         "Remote Creatable",
1130                         "Whether the data source "
1131                         "can create remote resources",
1132                         FALSE,
1133                         G_PARAM_READWRITE |
1134                         G_PARAM_STATIC_STRINGS));
1135
1136         /* This overrides the "remote-deletable" property
1137          * in ESourceClass with a writable version. */
1138         g_object_class_install_property (
1139                 object_class,
1140                 PROP_REMOTE_DELETABLE,
1141                 g_param_spec_boolean (
1142                         "remote-deletable",
1143                         "Remote Deletable",
1144                         "Whether the data source "
1145                         "can delete remote resources",
1146                         FALSE,
1147                         G_PARAM_READWRITE |
1148                         G_PARAM_STATIC_STRINGS));
1149
1150         /* This overrides the "removable" property
1151          * in ESourceClass with a writable version. */
1152         g_object_class_install_property (
1153                 object_class,
1154                 PROP_REMOVABLE,
1155                 g_param_spec_boolean (
1156                         "removable",
1157                         "Removable",
1158                         "Whether the data source is removable",
1159                         FALSE,
1160                         G_PARAM_READWRITE |
1161                         G_PARAM_STATIC_STRINGS));
1162
1163         g_object_class_install_property (
1164                 object_class,
1165                 PROP_SERVER,
1166                 g_param_spec_object (
1167                         "server",
1168                         "Server",
1169                         "The server to which the data source belongs",
1170                         E_TYPE_SOURCE_REGISTRY_SERVER,
1171                         G_PARAM_READWRITE |
1172                         G_PARAM_CONSTRUCT_ONLY |
1173                         G_PARAM_STATIC_STRINGS));
1174
1175         /* This overrides the "uid" property in
1176          * ESourceClass with a construct-only version. */
1177         g_object_class_install_property (
1178                 object_class,
1179                 PROP_UID,
1180                 g_param_spec_string (
1181                         "uid",
1182                         "UID",
1183                         "The unique identity of the data source",
1184                         NULL,
1185                         G_PARAM_READWRITE |
1186                         G_PARAM_CONSTRUCT_ONLY |
1187                         G_PARAM_STATIC_STRINGS));
1188
1189         /* This overrides the "writable" property
1190          * in ESourceClass with a writable version. */
1191         g_object_class_install_property (
1192                 object_class,
1193                 PROP_WRITABLE,
1194                 g_param_spec_boolean (
1195                         "writable",
1196                         "Writable",
1197                         "Whether the data source is writable",
1198                         FALSE,
1199                         G_PARAM_READWRITE |
1200                         G_PARAM_STATIC_STRINGS));
1201
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 (
1205                 object_class,
1206                 PROP_WRITE_DIRECTORY,
1207                 g_param_spec_string (
1208                         "write-directory",
1209                         "Write Directory",
1210                         "Directory in which to write changes to disk",
1211                         NULL,
1212                         G_PARAM_READWRITE |
1213                         G_PARAM_STATIC_STRINGS));
1214 }
1215
1216 static void
1217 e_server_side_source_initable_init (GInitableIface *interface)
1218 {
1219         initable_parent_interface = g_type_interface_peek_parent (interface);
1220
1221         interface->init = server_side_source_initable_init;
1222 }
1223
1224 static void
1225 e_server_side_source_init (EServerSideSource *source)
1226 {
1227         const gchar *user_dir;
1228
1229         source->priv = E_SERVER_SIDE_SOURCE_GET_PRIVATE (source);
1230
1231         source->priv->node.data = source;
1232
1233         user_dir = e_server_side_source_get_user_dir ();
1234         source->priv->write_directory = g_strdup (user_dir);
1235 }
1236
1237 /**
1238  * e_server_side_source_get_user_dir:
1239  *
1240  * Returns the directory where user-specific data source files are stored.
1241  *
1242  * Returns: the user-specific data source directory
1243  *
1244  * Since: 3.6
1245  **/
1246 const gchar *
1247 e_server_side_source_get_user_dir (void)
1248 {
1249         static gchar *dirname = NULL;
1250
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);
1255         }
1256
1257         return dirname;
1258 }
1259
1260 /**
1261  * e_server_side_source_new_user_file:
1262  * @uid: unique identifier for a data source, or %NULL
1263  *
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().
1267  *
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.
1270  *
1271  * Note the data source file itself is not created here, only its name.
1272  *
1273  * Returns: the #GFile for a new data source
1274  *
1275  * Since: 3.6
1276  **/
1277 GFile *
1278 e_server_side_source_new_user_file (const gchar *uid)
1279 {
1280         GFile *file;
1281         gchar *safe_uid;
1282         gchar *basename;
1283         gchar *filename;
1284         const gchar *user_dir;
1285
1286         if (uid == NULL)
1287                 safe_uid = e_uid_new ();
1288         else
1289                 safe_uid = g_strdup (uid);
1290         e_filename_make_safe (safe_uid);
1291
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);
1295
1296         file = g_file_new_for_path (filename);
1297
1298         g_free (basename);
1299         g_free (filename);
1300         g_free (safe_uid);
1301
1302         return file;
1303 }
1304
1305 /**
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
1309  *
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.
1313  *
1314  * Returns: the unique identity string for @file, or %NULL
1315  *
1316  * Since: 3.6
1317  **/
1318 gchar *
1319 e_server_side_source_uid_from_file (GFile *file,
1320                                     GError **error)
1321 {
1322         gchar *basename;
1323         gchar *uid = NULL;
1324
1325         g_return_val_if_fail (G_IS_FILE (file), FALSE);
1326
1327         basename = g_file_get_basename (file);
1328
1329         if (g_str_has_suffix (basename, ".source")) {
1330                 /* strlen(".source") --> 7 */
1331                 uid = g_strndup (basename, strlen (basename) - 7);
1332         } else {
1333                 g_set_error (
1334                         error, G_IO_ERROR,
1335                         G_IO_ERROR_INVALID_FILENAME,
1336                         _("File must have a '.source' extension"));
1337         }
1338
1339         g_free (basename);
1340
1341         return uid;
1342 }
1343
1344 /**
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
1349  *
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.
1354  *
1355  * Returns: a new #EServerSideSource, or %NULL
1356  *
1357  * Since: 3.6
1358  **/
1359 ESource *
1360 e_server_side_source_new (ESourceRegistryServer *server,
1361                           GFile *file,
1362                           GError **error)
1363 {
1364         EDBusObjectSkeleton *dbus_object;
1365         ESource *source;
1366
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);
1369
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);
1373
1374         source = g_initable_new (
1375                 E_TYPE_SERVER_SIDE_SOURCE, NULL, error,
1376                 "dbus-object", dbus_object,
1377                 "file", file, "server", server, NULL);
1378
1379         g_object_unref (dbus_object);
1380
1381         return source;
1382 }
1383
1384 /**
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
1389  *
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.
1393  *
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.
1398  *
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.
1402  *
1403  * Returns: a new memory-only #EServerSideSource, or %NULL
1404  *
1405  * Since: 3.6
1406  **/
1407 ESource *
1408 e_server_side_source_new_memory_only (ESourceRegistryServer *server,
1409                                       const gchar *uid,
1410                                       GError **error)
1411 {
1412         EDBusObjectSkeleton *dbus_object;
1413         ESource *source;
1414
1415         g_return_val_if_fail (E_IS_SOURCE_REGISTRY_SERVER (server), NULL);
1416
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);
1420
1421         source = g_initable_new (
1422                 E_TYPE_SERVER_SIDE_SOURCE, NULL, error,
1423                 "dbus-object", dbus_object,
1424                 "server", server, "uid", uid, NULL);
1425
1426         g_object_unref (dbus_object);
1427
1428         return source;
1429 }
1430
1431 /**
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
1436  *
1437  * Reloads data source content from the file pointed to by the
1438  * #EServerSideSource:file property.
1439  *
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.
1442  *
1443  * If a read error occurs or the file contains syntax errors, the function
1444  * sets @error and returns %FALSE.
1445  *
1446  * Returns: %TRUE on success, %FALSE on failure
1447  *
1448  * Since: 3.6
1449  **/
1450 gboolean
1451 e_server_side_source_load (EServerSideSource *source,
1452                            GCancellable *cancellable,
1453                            GError **error)
1454 {
1455         GDBusObject *dbus_object;
1456         EDBusSource *dbus_source;
1457         GKeyFile *key_file;
1458         GFile *file;
1459         gboolean success;
1460         gchar *data = NULL;
1461         gsize length;
1462         GError *local_error = NULL;
1463
1464         g_return_val_if_fail (E_IS_SERVER_SIDE_SOURCE (source), FALSE);
1465
1466         file = e_server_side_source_get_file (source);
1467
1468         if (file != NULL)
1469                 g_file_load_contents (
1470                         file, cancellable, &data,
1471                         &length, NULL, &local_error);
1472
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);
1476
1477         } else if (local_error != NULL) {
1478                 g_propagate_error (error, local_error);
1479                 return FALSE;
1480
1481         } else {
1482                 source->priv->file_contents = g_strdup (data);
1483         }
1484
1485         if (data == NULL) {
1486                 /* Create the bare minimum to pass parse_data(). */
1487                 data = g_strdup_printf ("[%s]", PRIMARY_GROUP_NAME);
1488                 length = strlen (data);
1489         }
1490
1491         key_file = g_key_file_new ();
1492
1493         success = server_side_source_parse_data (
1494                 key_file, data, length, error);
1495
1496         g_key_file_free (key_file);
1497
1498         if (!success) {
1499                 g_free (data);
1500                 return FALSE;
1501         }
1502
1503         /* Update the D-Bus interface properties. */
1504
1505         dbus_object = e_source_ref_dbus_object (E_SOURCE (source));
1506         dbus_source = e_dbus_object_get_source (E_DBUS_OBJECT (dbus_object));
1507
1508         e_dbus_source_set_data (dbus_source, data);
1509
1510         g_object_unref (dbus_source);
1511         g_object_unref (dbus_object);
1512
1513         g_free (data);
1514
1515         return TRUE;
1516 }
1517
1518 /**
1519  * e_server_side_source_get_file:
1520  * @source: an #EServerSideSource
1521  *
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.
1524  *
1525  * Returns: the #GFile for @source, or %NULL
1526  *
1527  * Since: 3.6
1528  **/
1529 GFile *
1530 e_server_side_source_get_file (EServerSideSource *source)
1531 {
1532         g_return_val_if_fail (E_IS_SERVER_SIDE_SOURCE (source), NULL);
1533
1534         return source->priv->file;
1535 }
1536
1537 /**
1538  * e_server_side_source_get_node:
1539  * @source: an #EServerSideSource
1540  *
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.
1545  *
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.
1548  *
1549  * Returns: a #GNode, or %NULL
1550  *
1551  * Since: 3.6
1552  **/
1553 GNode *
1554 e_server_side_source_get_node (EServerSideSource *source)
1555 {
1556         g_return_val_if_fail (E_IS_SERVER_SIDE_SOURCE (source), NULL);
1557
1558         return &source->priv->node;
1559 }
1560
1561 /**
1562  * e_server_side_source_get_server:
1563  * @source: an #EServerSideSource
1564  *
1565  * Returns the #ESourceRegistryServer to which @source belongs.
1566  *
1567  * Returns: the #ESourceRegistryServer for @source
1568  *
1569  * Since: 3.6
1570  **/
1571 ESourceRegistryServer *
1572 e_server_side_source_get_server (EServerSideSource *source)
1573 {
1574         g_return_val_if_fail (E_IS_SERVER_SIDE_SOURCE (source), NULL);
1575
1576         return source->priv->server;
1577 }
1578
1579 /**
1580  * e_server_side_source_get_allow_auth_prompt:
1581  * @source: an #EServerSideSource
1582  *
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.
1586  *
1587  * See e_server_side_source_set_allow_auth_prompt() for further
1588  * discussion.
1589  *
1590  * Returns: whether auth prompts are allowed for @source
1591  *
1592  * Since: 3.6
1593  **/
1594 gboolean
1595 e_server_side_source_get_allow_auth_prompt (EServerSideSource *source)
1596 {
1597         g_return_val_if_fail (E_IS_SERVER_SIDE_SOURCE (source), FALSE);
1598
1599         return source->priv->allow_auth_prompt;
1600 }
1601
1602 /**
1603  * e_server_side_source_set_allow_auth_prompt:
1604  * @source: an #EServerSideSource
1605  * @allow_auth_prompt: whether auth prompts are allowed for @source
1606  *
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.
1610  *
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.
1618  *
1619  * Since: 3.6
1620  **/
1621 void
1622 e_server_side_source_set_allow_auth_prompt (EServerSideSource *source,
1623                                             gboolean allow_auth_prompt)
1624 {
1625         g_return_if_fail (E_IS_SERVER_SIDE_SOURCE (source));
1626
1627         if ((source->priv->allow_auth_prompt ? 1 : 0) == (allow_auth_prompt ? 1 : 0))
1628                 return;
1629
1630         source->priv->allow_auth_prompt = allow_auth_prompt;
1631
1632         g_object_notify (G_OBJECT (source), "allow-auth-prompt");
1633 }
1634
1635 /**
1636  * e_server_side_source_get_exported:
1637  * @source: an #EServerSideSource
1638  *
1639  * Returns whether @source has been exported over D-Bus.
1640  *
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().
1645  *
1646  * Returns: whether @source has been exported
1647  *
1648  * Since: 3.6
1649  **/
1650 gboolean
1651 e_server_side_source_get_exported (EServerSideSource *source)
1652 {
1653         ESourceRegistryServer *server;
1654         ESource *exported_source;
1655         gboolean exported = FALSE;
1656         const gchar *uid;
1657
1658         g_return_val_if_fail (E_IS_SERVER_SIDE_SOURCE (source), FALSE);
1659
1660         uid = e_source_get_uid (E_SOURCE (source));
1661         server = e_server_side_source_get_server (source);
1662
1663         /* We're exported if we can look ourselves up in the registry. */
1664
1665         exported_source = e_source_registry_server_ref_source (server, uid);
1666         if (exported_source != NULL) {
1667                 exported = TRUE;
1668                 g_object_unref (exported_source);
1669         }
1670
1671         return exported;
1672 }
1673
1674 /**
1675  * e_server_side_source_get_write_directory:
1676  * @source: an #EServerSideSource
1677  *
1678  * Returns the local directory path where changes to @source are written.
1679  *
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.
1684  *
1685  * Returns: the directory where changes are written
1686  *
1687  * Since: 3.6
1688  **/
1689 const gchar *
1690 e_server_side_source_get_write_directory (EServerSideSource *source)
1691 {
1692         g_return_val_if_fail (E_IS_SERVER_SIDE_SOURCE (source), NULL);
1693
1694         return source->priv->write_directory;
1695 }
1696
1697 /**
1698  * e_server_side_source_set_write_directory:
1699  * @source: an #EServerSideSource
1700  * @write_directory: the directory where changes are to be written
1701  *
1702  * Sets the local directory path where changes to @source are to be written.
1703  *
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.
1708  *
1709  * Since: 3.6
1710  **/
1711 void
1712 e_server_side_source_set_write_directory (EServerSideSource *source,
1713                                           const gchar *write_directory)
1714 {
1715         g_return_if_fail (E_IS_SERVER_SIDE_SOURCE (source));
1716         g_return_if_fail (write_directory != NULL);
1717
1718         if (g_strcmp0 (source->priv->write_directory, write_directory) == 0)
1719                 return;
1720
1721         g_free (source->priv->write_directory);
1722         source->priv->write_directory = g_strdup (write_directory);
1723
1724         g_object_notify (G_OBJECT (source), "write-directory");
1725 }
1726
1727 /**
1728  * e_server_side_source_set_removable:
1729  * @source: an #EServerSideSource
1730  * @removable: whether to export the Removable interface
1731  *
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.
1737  *
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.
1740  *
1741  * Since: 3.6
1742  **/
1743 void
1744 e_server_side_source_set_removable (EServerSideSource *source,
1745                                     gboolean removable)
1746 {
1747         EDBusSourceRemovable *dbus_interface = NULL;
1748         GDBusObject *dbus_object;
1749         gboolean currently_removable;
1750
1751         g_return_if_fail (E_IS_SERVER_SIDE_SOURCE (source));
1752
1753         currently_removable = e_source_get_removable (E_SOURCE (source));
1754
1755         if (removable == currently_removable)
1756                 return;
1757
1758         if (removable) {
1759                 dbus_interface =
1760                         e_dbus_source_removable_skeleton_new ();
1761
1762                 g_signal_connect (
1763                         dbus_interface, "handle-remove",
1764                         G_CALLBACK (server_side_source_remove_cb), source);
1765         }
1766
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);
1771
1772         if (dbus_interface != NULL)
1773                 g_object_unref (dbus_interface);
1774
1775         g_object_notify (G_OBJECT (source), "removable");
1776 }
1777
1778 /**
1779  * e_server_side_source_set_writable:
1780  * @source: an #EServerSideSource
1781  * @writable: whether to export the Writable interface
1782  *
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.
1788  *
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.
1791  *
1792  * Since: 3.6
1793  **/
1794 void
1795 e_server_side_source_set_writable (EServerSideSource *source,
1796                                    gboolean writable)
1797 {
1798         EDBusSourceWritable *dbus_interface = NULL;
1799         GDBusObject *dbus_object;
1800         gboolean currently_writable;
1801
1802         g_return_if_fail (E_IS_SERVER_SIDE_SOURCE (source));
1803
1804         currently_writable = e_source_get_writable (E_SOURCE (source));
1805
1806         if (writable == currently_writable)
1807                 return;
1808
1809         if (writable) {
1810                 dbus_interface =
1811                         e_dbus_source_writable_skeleton_new ();
1812
1813                 g_signal_connect (
1814                         dbus_interface, "handle-write",
1815                         G_CALLBACK (server_side_source_write_cb), source);
1816         }
1817
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);
1822
1823         if (dbus_interface != NULL)
1824                 g_object_unref (dbus_interface);
1825
1826         g_object_notify (G_OBJECT (source), "writable");
1827 }
1828
1829 /**
1830  * e_server_side_source_set_remote_creatable:
1831  * @source: an #EServerSideSource
1832  * @remote_creatable: whether to export the RemoteCreatable interface
1833  *
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.
1836  *
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.
1841  *
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.
1845  *
1846  * Since: 3.6
1847  **/
1848 void
1849 e_server_side_source_set_remote_creatable (EServerSideSource *source,
1850                                            gboolean remote_creatable)
1851 {
1852         EDBusSourceRemoteCreatable *dbus_interface = NULL;
1853         GDBusObject *dbus_object;
1854         gboolean currently_remote_creatable;
1855
1856         g_return_if_fail (E_IS_SERVER_SIDE_SOURCE (source));
1857
1858         currently_remote_creatable =
1859                 e_source_get_remote_creatable (E_SOURCE (source));
1860
1861         if (remote_creatable == currently_remote_creatable)
1862                 return;
1863
1864         if (remote_creatable) {
1865                 dbus_interface =
1866                         e_dbus_source_remote_creatable_skeleton_new ();
1867
1868                 g_signal_connect (
1869                         dbus_interface, "handle-create",
1870                         G_CALLBACK (server_side_source_remote_create_cb),
1871                         source);
1872         }
1873
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);
1878
1879         if (dbus_interface != NULL)
1880                 g_object_unref (dbus_interface);
1881
1882         g_object_notify (G_OBJECT (source), "remote-creatable");
1883 }
1884
1885 /**
1886  * e_server_side_source_set_remote_deletable:
1887  * @source: an #EServerSideSource
1888  * @remote_deletable: whether to export the RemoteDeletable interface
1889  *
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.
1893  *
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.
1898  *
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.
1902  *
1903  * Since: 3.6
1904  **/
1905 void
1906 e_server_side_source_set_remote_deletable (EServerSideSource *source,
1907                                            gboolean remote_deletable)
1908 {
1909         EDBusSourceRemoteDeletable *dbus_interface = NULL;
1910         GDBusObject *dbus_object;
1911         gboolean currently_remote_deletable;
1912
1913         g_return_if_fail (E_IS_SERVER_SIDE_SOURCE (source));
1914
1915         currently_remote_deletable =
1916                 e_source_get_remote_deletable (E_SOURCE (source));
1917
1918         if (remote_deletable == currently_remote_deletable)
1919                 return;
1920
1921         if (remote_deletable) {
1922                 dbus_interface =
1923                         e_dbus_source_remote_deletable_skeleton_new ();
1924
1925                 g_signal_connect (
1926                         dbus_interface, "handle-delete",
1927                         G_CALLBACK (server_side_source_remote_delete_cb),
1928                         source);
1929         }
1930
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);
1935
1936         if (dbus_interface != NULL)
1937                 g_object_unref (dbus_interface);
1938
1939         g_object_notify (G_OBJECT (source), "remote-deletable");
1940 }
1941