~ubuntu-branches/ubuntu/saucy/evolution-data-server/saucy

« back to all changes in this revision

Viewing changes to libebackend/e-source-registry-server.c

  • Committer: Package Import Robot
  • Author(s): Chris Coulson
  • Date: 2012-10-08 12:58:16 UTC
  • mfrom: (181.1.7 quantal)
  • Revision ID: package-import@ubuntu.com-20121008125816-i3n76e8c0m64e7xp
Tags: 3.6.0-0ubuntu2
* Fix LP: #1038047 part 1 - Don't abort in e_source_registry_new* when a
  problem occurs connecting to the Dbus service
  - add debian/patches/dont-abort-in-e_source_registry_new.patch
  - update debian/patches/series
* Fix LP: #1038047 part 2 - libedataserver depends on
  evolution-data-server-common to ensure that the GSettings schemas are
  present
  - update debian/control

Show diffs side-by-side

added added

removed removed

Lines of Context:
57
57
 * sources with a [Collection] extension. */
58
58
#define BACKEND_DATA_KEY "__e_collection_backend__"
59
59
 
 
60
typedef struct _AuthRequest AuthRequest;
 
61
 
60
62
struct _ESourceRegistryServerPrivate {
 
63
        GMainContext *main_context;
 
64
 
61
65
        GDBusObjectManagerServer *object_manager;
62
66
        EDBusSourceManager *source_manager;
63
67
 
70
74
 
71
75
        /* In pseudo-Python notation:
72
76
         *
73
 
         * auth_queue = [ UID, ... ]
74
 
         * auth_table = { UID : [ authenticator, ... ] }
75
 
         * active_auth_table_queue = auth_table[auth_queue[0]]
76
 
         * active_auth = active_auth_table_queue[0]
 
77
         * running_auths = { UID : AuthRequest }
 
78
         * waiting_auths = { UID : [ AuthRequest, ... ] }
77
79
         *
78
80
         * We process all authenticators for a given source UID at once.
79
81
         * The thought being after the first authenticator for a given UID
83
85
         * the user decides not to cache the secret at all, in which case
84
86
         * he gets what he asked for: lots of annoying prompts.
85
87
         */
86
 
        GQueue *auth_queue;
87
 
        GHashTable *auth_table;
88
 
        GQueue *active_auth_table_queue;
89
 
        EAuthenticationSession *active_auth;
90
 
        GCancellable *auth_cancellable;
 
88
        GMutex *auth_lock;
 
89
        GHashTable *running_auths;
 
90
        GHashTable *waiting_auths;
91
91
 
92
92
        guint authentication_count;
93
93
};
94
94
 
 
95
struct _AuthRequest {
 
96
        volatile gint ref_count;
 
97
        EAuthenticationSession *session;
 
98
        GSimpleAsyncResult *simple;
 
99
        ESource *source;  /* may be NULL */
 
100
        GCancellable *cancellable;
 
101
};
 
102
 
95
103
enum {
96
104
        LOAD_ERROR,
97
105
        FILES_LOADED,
102
110
 
103
111
/* Forward Declarations */
104
112
static void     source_registry_server_maybe_start_auth_session
105
 
                                                (ESourceRegistryServer *server);
 
113
                                                (ESourceRegistryServer *server,
 
114
                                                 const gchar *uid);
106
115
 
107
116
static guint signals[LAST_SIGNAL];
108
117
 
111
120
        e_source_registry_server,
112
121
        E_TYPE_DATA_FACTORY)
113
122
 
 
123
static AuthRequest *
 
124
auth_request_new (EAuthenticationSession *session,
 
125
                  GSimpleAsyncResult *simple,
 
126
                  GCancellable *cancellable)
 
127
{
 
128
        ESourceRegistryServer *server;
 
129
        AuthRequest *request;
 
130
        const gchar *uid;
 
131
 
 
132
        server = e_authentication_session_get_server (session);
 
133
        uid = e_authentication_session_get_source_uid (session);
 
134
 
 
135
        request = g_slice_new0 (AuthRequest);
 
136
        request->ref_count = 1;
 
137
        request->session = g_object_ref (session);
 
138
        request->simple = g_object_ref (simple);
 
139
 
 
140
        /* This will return NULL if the authenticating data source
 
141
         * has not yet been submitted to the D-Bus registry server. */
 
142
        request->source = e_source_registry_server_ref_source (server, uid);
 
143
 
 
144
        if (G_IS_CANCELLABLE (cancellable))
 
145
                request->cancellable = g_object_ref (cancellable);
 
146
 
 
147
        return request;
 
148
}
 
149
 
 
150
static AuthRequest *
 
151
auth_request_ref (AuthRequest *request)
 
152
{
 
153
        g_return_val_if_fail (request != NULL, NULL);
 
154
        g_return_val_if_fail (request->ref_count > 0, NULL);
 
155
 
 
156
        g_atomic_int_inc (&request->ref_count);
 
157
 
 
158
        return request;
 
159
}
 
160
 
 
161
static void
 
162
auth_request_unref (AuthRequest *request)
 
163
{
 
164
        g_return_if_fail (request != NULL);
 
165
        g_return_if_fail (request->ref_count > 0);
 
166
 
 
167
        if (g_atomic_int_dec_and_test (&request->ref_count)) {
 
168
 
 
169
                g_object_unref (request->session);
 
170
                g_object_unref (request->simple);
 
171
 
 
172
                if (request->source != NULL)
 
173
                        g_object_unref (request->source);
 
174
 
 
175
                if (request->cancellable != NULL)
 
176
                        g_object_unref (request->cancellable);
 
177
 
 
178
                g_slice_free (AuthRequest, request);
 
179
        }
 
180
}
 
181
 
114
182
/* GDestroyNotify callback for 'sources' values */
115
183
static void
116
184
unref_data_source (ESource *source)
120
188
        g_object_unref (source);
121
189
}
122
190
 
123
 
/* GDestroyNotify callback for 'auth_table' values */
 
191
/* GDestroyNotify callback for 'waiting_auths' values */
124
192
static void
125
193
free_auth_queue (GQueue *queue)
126
194
{
303
371
        return array;
304
372
}
305
373
 
306
 
static GQueue *
307
 
source_registry_server_auth_table_lookup (ESourceRegistryServer *server,
308
 
                                          const gchar *uid)
309
 
{
310
 
        GHashTable *hash_table;
 
374
static void
 
375
source_request_server_auth_request_cancel_all (ESourceRegistryServer *server)
 
376
{
 
377
        GHashTableIter iter;
 
378
        gpointer value;
 
379
 
 
380
        g_mutex_lock (server->priv->auth_lock);
 
381
 
 
382
        g_hash_table_iter_init (&iter, server->priv->waiting_auths);
 
383
 
 
384
        while (g_hash_table_iter_next (&iter, NULL, &value)) {
 
385
                GQueue *queue = value;
 
386
                GList *list, *link;
 
387
 
 
388
                list = g_queue_peek_head_link (queue);
 
389
 
 
390
                for (link = list; link != NULL; link = g_list_next (link)) {
 
391
                        AuthRequest *request = link->data;
 
392
                        g_cancellable_cancel (request->cancellable);
 
393
                }
 
394
        }
 
395
 
 
396
        g_hash_table_iter_init (&iter, server->priv->running_auths);
 
397
 
 
398
        while (g_hash_table_iter_next (&iter, NULL, &value)) {
 
399
                AuthRequest *request = value;
 
400
                g_cancellable_cancel (request->cancellable);
 
401
        }
 
402
 
 
403
        g_mutex_unlock (server->priv->auth_lock);
 
404
}
 
405
 
 
406
static void
 
407
source_registry_server_auth_request_push (ESourceRegistryServer *server,
 
408
                                          const gchar *uid,
 
409
                                          AuthRequest *request)
 
410
{
311
411
        GQueue *queue;
312
412
 
313
 
        hash_table = server->priv->auth_table;
314
 
        queue = g_hash_table_lookup (hash_table, uid);
 
413
        g_return_if_fail (uid != NULL);
 
414
 
 
415
        g_mutex_lock (server->priv->auth_lock);
 
416
 
 
417
        queue = g_hash_table_lookup (server->priv->waiting_auths, uid);
315
418
 
316
419
        if (queue == NULL) {
317
420
                queue = g_queue_new ();
318
 
                g_hash_table_insert (hash_table, g_strdup (uid), queue);
319
 
        }
320
 
 
321
 
        return queue;
 
421
                g_hash_table_insert (
 
422
                        server->priv->waiting_auths,
 
423
                        g_strdup (uid), queue);
 
424
        }
 
425
 
 
426
        g_queue_push_tail (queue, auth_request_ref (request));
 
427
 
 
428
        g_mutex_unlock (server->priv->auth_lock);
 
429
}
 
430
 
 
431
static AuthRequest *
 
432
source_registry_server_auth_request_next (ESourceRegistryServer *server,
 
433
                                          const gchar *uid)
 
434
{
 
435
        AuthRequest *request = NULL;
 
436
 
 
437
        g_return_val_if_fail (uid != NULL, NULL);
 
438
 
 
439
        g_mutex_lock (server->priv->auth_lock);
 
440
 
 
441
        /* If we're already busy processing an authentication request
 
442
         * for this UID, the next request will have to wait in line. */
 
443
        if (!g_hash_table_contains (server->priv->running_auths, uid)) {
 
444
                GQueue *queue;
 
445
 
 
446
                queue = g_hash_table_lookup (
 
447
                        server->priv->waiting_auths, uid);
 
448
 
 
449
                if (queue != NULL)
 
450
                        request = g_queue_pop_head (queue);
 
451
 
 
452
                if (request != NULL)
 
453
                        g_hash_table_insert (
 
454
                                server->priv->running_auths,
 
455
                                g_strdup (uid),
 
456
                                auth_request_ref (request));
 
457
        }
 
458
 
 
459
        g_mutex_unlock (server->priv->auth_lock);
 
460
 
 
461
        return request;
 
462
}
 
463
 
 
464
static void
 
465
source_registry_server_auth_request_done (ESourceRegistryServer *server,
 
466
                                          const gchar *uid)
 
467
{
 
468
        g_return_if_fail (uid != NULL);
 
469
 
 
470
        g_mutex_lock (server->priv->auth_lock);
 
471
 
 
472
        g_hash_table_remove (server->priv->running_auths, uid);
 
473
 
 
474
        g_mutex_unlock (server->priv->auth_lock);
322
475
}
323
476
 
324
477
static void
326
479
                                        GAsyncResult *result,
327
480
                                        gpointer user_data)
328
481
{
 
482
        ESourceRegistryServer *server;
329
483
        EAuthenticationSession *session;
330
 
        ESourceRegistryServer *server;
331
484
        EAuthenticationSessionResult auth_result;
332
 
        GQueue *queue;
 
485
        AuthRequest *request;
333
486
        const gchar *uid;
334
487
        GError *error = NULL;
335
488
 
336
489
        session = E_AUTHENTICATION_SESSION (source_object);
337
 
        server = E_SOURCE_REGISTRY_SERVER (user_data);
 
490
        request = (AuthRequest *) user_data;
338
491
 
339
492
        auth_result = e_authentication_session_execute_finish (
340
493
                session, result, &error);
341
494
 
342
495
        if (error != NULL) {
343
 
                g_warning ("%s: %s", G_STRFUNC, error->message);
344
 
                g_error_free (error);
 
496
                g_warn_if_fail (auth_result == E_AUTHENTICATION_SESSION_ERROR);
 
497
                g_simple_async_result_take_error (request->simple, error);
345
498
        }
346
499
 
347
 
        uid = e_authentication_session_get_source_uid (session);
348
 
        g_return_if_fail (uid != NULL);
349
 
 
350
 
        /* Authentication dismissals may require additional handling. */
 
500
        /* Authentication dismissals require additional handling. */
351
501
        if (auth_result == E_AUTHENTICATION_SESSION_DISMISSED) {
352
502
                ESourceAuthenticator *authenticator;
353
 
                ESource *source;
354
503
 
355
504
                /* If the authenticator is an EAuthenticationMediator,
356
505
                 * have it emit a "dismissed" signal to the client. */
360
509
                        e_authentication_mediator_dismiss (
361
510
                                E_AUTHENTICATION_MEDIATOR (authenticator));
362
511
 
363
 
                /* This will return NULL if the authenticating data source
364
 
                 * has not yet been submitted to the D-Bus registry service. */
365
 
                source = e_source_registry_server_ref_source (server, uid);
366
 
                if (source != NULL) {
367
 
                        /* Prevent further user interruptions. */
 
512
                /* Prevent further user interruptions. */
 
513
                if (request->source != NULL)
368
514
                        e_server_side_source_set_allow_auth_prompt (
369
 
                                E_SERVER_SIDE_SOURCE (source), FALSE);
370
 
                        g_object_unref (source);
371
 
                }
 
515
                                E_SERVER_SIDE_SOURCE (request->source), FALSE);
 
516
 
 
517
                /* e_source_registry_server_authenticate_finish() should
 
518
                 * return an error since authentication did not complete. */
 
519
                g_simple_async_result_set_error (
 
520
                        request->simple,
 
521
                        G_IO_ERROR, G_IO_ERROR_CANCELLED,
 
522
                        _("The user declined to authenticate"));
372
523
        }
373
524
 
374
 
        queue = source_registry_server_auth_table_lookup (server, uid);
375
 
 
376
 
        /* Remove the completed auth session from its queue. */
377
 
        if (g_queue_remove (queue, session))
378
 
                g_object_unref (session);
379
 
 
380
 
        /* If the completed auth session was the active one,
381
 
         * clear the active pointer for the next auth session. */
382
 
        if (session == server->priv->active_auth)
383
 
                server->priv->active_auth = NULL;
384
 
 
385
 
        source_registry_server_maybe_start_auth_session (server);
386
 
 
387
 
        g_object_unref (server);
 
525
        g_simple_async_result_complete_in_idle (request->simple);
 
526
 
 
527
        server = e_authentication_session_get_server (session);
 
528
        uid = e_authentication_session_get_source_uid (session);
 
529
 
 
530
        source_registry_server_auth_request_done (server, uid);
 
531
        source_registry_server_maybe_start_auth_session (server, uid);
 
532
 
 
533
        auth_request_unref (request);
388
534
}
389
535
 
390
 
static void
391
 
source_registry_server_maybe_start_auth_session (ESourceRegistryServer *server)
 
536
static gboolean
 
537
source_registry_server_start_auth_session_idle_cb (gpointer user_data)
392
538
{
393
 
        GQueue *queue;
394
 
 
395
 
        if (server->priv->active_auth != NULL)
396
 
                return;
397
 
 
398
 
        if (g_cancellable_is_cancelled (server->priv->auth_cancellable))
399
 
                return;
400
 
 
401
 
        /* Check if there's any authenticators left in the active
402
 
         * auth table queue.  If the user provided a valid secret
403
 
         * and elected to save it in the keyring, or if the user
404
 
         * dismissed the authentication prompt, then we should be
405
 
         * able to process the remaining authenticators quickly. */
406
 
        if (server->priv->active_auth_table_queue != NULL &&
407
 
            !g_queue_is_empty (server->priv->active_auth_table_queue)) {
408
 
                queue = server->priv->active_auth_table_queue;
409
 
                server->priv->active_auth = g_queue_peek_head (queue);
410
 
 
411
 
        /* Otherwise find the next non-empty auth table queue to
412
 
         * be processed, according to the UIDs in the auth queue. */
413
 
        } else while (!g_queue_is_empty (server->priv->auth_queue)) {
414
 
                gchar *uid;
415
 
 
416
 
                uid = g_queue_pop_head (server->priv->auth_queue);
417
 
                queue = source_registry_server_auth_table_lookup (server, uid);
418
 
                g_free (uid);
419
 
 
420
 
                if (!g_queue_is_empty (queue)) {
421
 
                        server->priv->active_auth_table_queue = queue;
422
 
                        server->priv->active_auth = g_queue_peek_head (queue);
423
 
                        break;
424
 
                }
425
 
        }
426
 
 
427
 
        /* Initiate the new active authenicator.  This signals it to
 
539
        AuthRequest *request = user_data;
 
540
 
 
541
        /* Execute the new active auth session.  This signals it to
428
542
         * respond with a cached secret in the keyring if it can, or
429
543
         * else show an authentication prompt and wait for input. */
430
 
        if (server->priv->active_auth != NULL)
431
 
                e_authentication_session_execute (
432
 
                        server->priv->active_auth,
433
 
                        G_PRIORITY_DEFAULT,
434
 
                        server->priv->auth_cancellable,
435
 
                        source_registry_server_auth_session_cb,
436
 
                        g_object_ref (server));
437
 
        else
438
 
                server->priv->active_auth_table_queue = NULL;
 
544
        e_authentication_session_execute (
 
545
                request->session,
 
546
                G_PRIORITY_DEFAULT,
 
547
                request->cancellable,
 
548
                source_registry_server_auth_session_cb,
 
549
                auth_request_ref (request));
 
550
 
 
551
        return FALSE;
 
552
}
 
553
 
 
554
static void
 
555
source_registry_server_maybe_start_auth_session (ESourceRegistryServer *server,
 
556
                                                 const gchar *uid)
 
557
{
 
558
        AuthRequest *request;
 
559
 
 
560
        /* We own the returned reference, unless we get NULL. */
 
561
        request = source_registry_server_auth_request_next (server, uid);
 
562
 
 
563
        if (request != NULL) {
 
564
                GSource *idle_source;
 
565
 
 
566
                /* Process the next AuthRequest from an idle callback
 
567
                 * on our own GMainContext, since the current thread-
 
568
                 * default GMainContext may only be temporary. */
 
569
                idle_source = g_idle_source_new ();
 
570
                g_source_set_callback (
 
571
                        idle_source,
 
572
                        source_registry_server_start_auth_session_idle_cb,
 
573
                        auth_request_ref (request),
 
574
                        (GDestroyNotify) auth_request_unref);
 
575
                g_source_attach (idle_source, server->priv->main_context);
 
576
                g_source_unref (idle_source);
 
577
 
 
578
                auth_request_unref (request);
 
579
        }
 
580
}
 
581
 
 
582
static void
 
583
source_registry_server_authenticate_done_cb (GObject *source_object,
 
584
                                             GAsyncResult *result,
 
585
                                             gpointer user_data)
 
586
{
 
587
        GError *error = NULL;
 
588
 
 
589
        e_source_registry_server_authenticate_finish (
 
590
                E_SOURCE_REGISTRY_SERVER (source_object), result, &error);
 
591
 
 
592
        /* Ignore cancellations. */
 
593
        if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
 
594
                g_error_free (error);
 
595
 
 
596
        } else if (error != NULL) {
 
597
                g_warning ("%s: %s", G_STRFUNC, error->message);
 
598
                g_error_free (error);
 
599
        }
439
600
}
440
601
 
441
602
static void
456
617
        if (error == NULL) {
457
618
                ESourceRegistryServer *server;
458
619
 
459
 
                /* This references the session and adds it to a queue. */
460
620
                server = e_authentication_session_get_server (session);
461
 
                e_source_registry_server_queue_auth_session (server, session);
 
621
 
 
622
                /* Client is ready and waiting to test passwords, so
 
623
                 * execute the authentication session as soon as all
 
624
                 * other authentication sessions for this same data
 
625
                 * source are finished.
 
626
                 *
 
627
                 * XXX Note this asynchronous operation is not cancellable
 
628
                 *     but it does time out on its own after a few minutes. */
 
629
                e_source_registry_server_authenticate (
 
630
                        server, session, NULL,
 
631
                        source_registry_server_authenticate_done_cb, NULL);
462
632
 
463
633
        } else {
464
634
                /* Most likely the client went dark and the operation
558
728
{
559
729
        ESource *source = NULL;
560
730
        GFile *file;
 
731
        GFile *parent;
561
732
        GKeyFile *key_file;
562
733
        gboolean success;
563
734
        gsize length;
 
735
        GError *local_error = NULL;
564
736
 
565
737
        g_return_val_if_fail (uid != NULL, FALSE);
566
738
        g_return_val_if_fail (data != NULL, FALSE);
602
774
 
603
775
        file = e_server_side_source_new_user_file (uid);
604
776
 
 
777
        /* Create the directory where we'll be writing. */
 
778
 
 
779
        parent = g_file_get_parent (file);
 
780
        g_file_make_directory_with_parents (parent, NULL, &local_error);
 
781
        g_object_unref (parent);
 
782
 
 
783
        if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_EXISTS))
 
784
                g_clear_error (&local_error);
 
785
 
 
786
        if (local_error != NULL) {
 
787
                g_propagate_error (error, local_error);
 
788
                success = FALSE;
 
789
        }
 
790
 
605
791
        /* Write the data to disk.  The file monitor should eventually
606
792
         * notice the new file and call e_source_registry_server_load_file()
607
793
         * per design, but we're going to beat it to the punch since we
610
796
         * it will simply get back the EDBusSourceObject we've already
611
797
         * created and exported. */
612
798
 
613
 
        success = g_file_replace_contents (
614
 
                file, data, length, NULL, FALSE,
615
 
                G_FILE_CREATE_PRIVATE, NULL, NULL, error);
 
799
        if (success)
 
800
                success = g_file_replace_contents (
 
801
                        file, data, length, NULL, FALSE,
 
802
                        G_FILE_CREATE_PRIVATE, NULL, NULL, error);
616
803
 
617
804
        if (success) {
618
805
                ESourcePermissionFlags flags;
661
848
 
662
849
        if (error != NULL)
663
850
                g_dbus_method_invocation_take_error (invocation, error);
664
 
 
665
 
        e_dbus_source_manager_complete_create_sources (interface, invocation);
 
851
        else
 
852
                e_dbus_source_manager_complete_create_sources (
 
853
                        interface, invocation);
666
854
 
667
855
        return TRUE;
668
856
}
825
1013
 
826
1014
        priv = E_SOURCE_REGISTRY_SERVER_GET_PRIVATE (object);
827
1015
 
 
1016
        if (priv->main_context != NULL) {
 
1017
                g_main_context_unref (priv->main_context);
 
1018
                priv->main_context = NULL;
 
1019
        }
 
1020
 
828
1021
        if (priv->object_manager != NULL) {
829
1022
                g_object_unref (priv->object_manager);
830
1023
                priv->object_manager = NULL;
839
1032
        g_hash_table_remove_all (priv->orphans);
840
1033
        g_hash_table_remove_all (priv->monitors);
841
1034
 
842
 
        g_hash_table_remove_all (priv->auth_table);
843
 
 
844
 
        if (priv->auth_cancellable != NULL) {
845
 
                g_object_unref (priv->auth_cancellable);
846
 
                priv->auth_cancellable = NULL;
847
 
        }
 
1035
        g_hash_table_remove_all (priv->running_auths);
 
1036
        g_hash_table_remove_all (priv->waiting_auths);
848
1037
 
849
1038
        /* Chain up to parent's dispose() method. */
850
1039
        G_OBJECT_CLASS (e_source_registry_server_parent_class)->
865
1054
        g_mutex_free (priv->sources_lock);
866
1055
        g_mutex_free (priv->orphans_lock);
867
1056
 
868
 
        g_queue_free_full (priv->auth_queue, (GDestroyNotify) g_free);
869
 
        g_hash_table_destroy (priv->auth_table);
 
1057
        g_mutex_free (priv->auth_lock);
 
1058
        g_hash_table_destroy (priv->running_auths);
 
1059
        g_hash_table_destroy (priv->waiting_auths);
870
1060
 
871
1061
        /* Chain up to parent's finalize() method. */
872
1062
        G_OBJECT_CLASS (e_source_registry_server_parent_class)->
909
1099
 
910
1100
        priv = E_SOURCE_REGISTRY_SERVER_GET_PRIVATE (server);
911
1101
 
912
 
        /* Cancel any active authentication session. */
913
 
        g_cancellable_cancel (priv->auth_cancellable);
 
1102
        source_request_server_auth_request_cancel_all (
 
1103
                E_SOURCE_REGISTRY_SERVER (server));
914
1104
 
915
1105
        /* This makes the object manager unexport all objects. */
916
1106
        g_dbus_object_manager_server_set_connection (
1121
1311
        GHashTable *sources;
1122
1312
        GHashTable *orphans;
1123
1313
        GHashTable *monitors;
1124
 
        GHashTable *auth_table;
 
1314
        GHashTable *running_auths;
 
1315
        GHashTable *waiting_auths;
1125
1316
        const gchar *object_path;
1126
1317
 
1127
1318
        object_path = E_SOURCE_REGISTRY_SERVER_OBJECT_PATH;
1149
1340
                (GDestroyNotify) g_object_unref,
1150
1341
                (GDestroyNotify) g_object_unref);
1151
1342
 
1152
 
        auth_table = g_hash_table_new_full (
 
1343
        running_auths = g_hash_table_new_full (
 
1344
                (GHashFunc) g_str_hash,
 
1345
                (GEqualFunc) g_str_equal,
 
1346
                (GDestroyNotify) g_free,
 
1347
                (GDestroyNotify) auth_request_unref);
 
1348
 
 
1349
        waiting_auths = g_hash_table_new_full (
1153
1350
                (GHashFunc) g_str_hash,
1154
1351
                (GEqualFunc) g_str_equal,
1155
1352
                (GDestroyNotify) g_free,
1156
1353
                (GDestroyNotify) free_auth_queue);
1157
1354
 
1158
1355
        server->priv = E_SOURCE_REGISTRY_SERVER_GET_PRIVATE (server);
 
1356
        server->priv->main_context = g_main_context_ref_thread_default ();
1159
1357
        server->priv->object_manager = object_manager;
1160
1358
        server->priv->source_manager = source_manager;
1161
1359
        server->priv->sources = sources;
1163
1361
        server->priv->monitors = monitors;
1164
1362
        server->priv->sources_lock = g_mutex_new ();
1165
1363
        server->priv->orphans_lock = g_mutex_new ();
1166
 
        server->priv->auth_queue = g_queue_new ();
1167
 
        server->priv->auth_table = auth_table;
1168
 
        server->priv->auth_cancellable = g_cancellable_new ();
 
1364
        server->priv->auth_lock = g_mutex_new ();
 
1365
        server->priv->waiting_auths = waiting_auths;
 
1366
        server->priv->running_auths = running_auths;
1169
1367
 
1170
1368
        g_signal_connect (
1171
1369
                source_manager, "handle-authenticate",
1351
1549
}
1352
1550
 
1353
1551
/**
1354
 
 * e_source_registry_server_queue_auth_session:
1355
 
 * @server: an #ESourceRegistryServer
1356
 
 * @session: an #EDBusSourceAuthenticator
1357
 
 *
1358
 
 * Queues an authentication session.  When its turn comes, and if necessary,
1359
 
 * the user will be prompted for a secret.  Sessions are queued this way to
1360
 
 * prevent user prompts from piling up on the screen.
1361
 
 *
1362
 
 * Since: 3.6
1363
 
 **/
1364
 
void
1365
 
e_source_registry_server_queue_auth_session (ESourceRegistryServer *server,
1366
 
                                             EAuthenticationSession *session)
1367
 
{
1368
 
        const gchar *uid;
1369
 
        GQueue *queue;
1370
 
 
1371
 
        g_return_if_fail (E_IS_SOURCE_REGISTRY_SERVER (server));
1372
 
        g_return_if_fail (E_IS_AUTHENTICATION_SESSION (session));
1373
 
 
1374
 
        uid = e_authentication_session_get_source_uid (session);
1375
 
        g_return_if_fail (uid != NULL);
1376
 
 
1377
 
        /* Add the session to the appropriate queue. */
1378
 
        queue = source_registry_server_auth_table_lookup (server, uid);
1379
 
        g_queue_push_tail (queue, g_object_ref (session));
1380
 
 
1381
 
        /* Blindly push the UID onto the processing queue. */
1382
 
        g_queue_push_tail (server->priv->auth_queue, g_strdup (uid));
1383
 
 
1384
 
        source_registry_server_maybe_start_auth_session (server);
1385
 
}
1386
 
 
1387
 
/**
1388
1552
 * e_source_registry_server_load_all:
1389
1553
 * @server: an #ESourceRegistryServer
1390
1554
 * @error: return location for a #GError, or %NULL
1752
1916
}
1753
1917
 
1754
1918
/**
 
1919
 * e_source_registry_server_ref_backend:
 
1920
 * @server: an #ESourceRegistryServer
 
1921
 * @source: an #ESource
 
1922
 *
 
1923
 * Returns the #ECollectionBackend associated with @source, or %NULL if
 
1924
 * there is no #ECollectionBackend associated with @source.
 
1925
 *
 
1926
 * An #ESource is associated with an #ECollectionBackend if the #ESource has
 
1927
 * an #ESourceCollection extension, or if it is a hierarchical descendant of
 
1928
 * another #ESource which has an #ESourceCollection extension.
 
1929
 *
 
1930
 * The returned #ECollectionBackend is referenced for thread-safety.
 
1931
 * Unreference the #ECollectionBackend with g_object_unref() when finished
 
1932
 * with it.
 
1933
 *
 
1934
 * Returns: the #ECollectionBackend for @source, or %NULL
 
1935
 *
 
1936
 * Since: 3.6
 
1937
 **/
 
1938
ECollectionBackend *
 
1939
e_source_registry_server_ref_backend (ESourceRegistryServer *server,
 
1940
                                      ESource *source)
 
1941
{
 
1942
        ECollectionBackend *backend = NULL;
 
1943
        const gchar *extension_name;
 
1944
 
 
1945
        g_return_val_if_fail (E_IS_SOURCE_REGISTRY_SERVER (server), NULL);
 
1946
        g_return_val_if_fail (E_IS_SOURCE (source), NULL);
 
1947
 
 
1948
        /* XXX If ESourceRegistryServer ever grows a function similar to
 
1949
         *     e_source_registry_find_extension() then we could just use
 
1950
         *     that, but despite this use case I think the need for such
 
1951
         *     a function is not sufficiently strong yet. */
 
1952
 
 
1953
        extension_name = E_SOURCE_EXTENSION_COLLECTION;
 
1954
 
 
1955
        g_object_ref (source);
 
1956
 
 
1957
        while (!e_source_has_extension (source, extension_name)) {
 
1958
                gchar *uid;
 
1959
 
 
1960
                uid = e_source_dup_parent (source);
 
1961
 
 
1962
                g_object_unref (source);
 
1963
                source = NULL;
 
1964
 
 
1965
                if (uid != NULL) {
 
1966
                        source = e_source_registry_server_ref_source (
 
1967
                                server, uid);
 
1968
                        g_free (uid);
 
1969
                }
 
1970
 
 
1971
                if (source == NULL)
 
1972
                        break;
 
1973
        }
 
1974
 
 
1975
        if (source != NULL) {
 
1976
                backend = g_object_get_data (
 
1977
                        G_OBJECT (source), BACKEND_DATA_KEY);
 
1978
                if (backend != NULL)
 
1979
                        g_object_ref (backend);
 
1980
                g_object_unref (source);
 
1981
        }
 
1982
 
 
1983
        return backend;
 
1984
}
 
1985
 
 
1986
/**
1755
1987
 * e_source_registry_server_ref_backend_factory:
1756
1988
 * @server: an #ESourceRegistryServer
1757
1989
 * @source: an #ESource
1805
2037
        return E_COLLECTION_BACKEND_FACTORY (factory);
1806
2038
}
1807
2039
 
 
2040
/**
 
2041
 * e_source_registry_server_authenticate_sync:
 
2042
 * @server: an #ESourceRegistryServer
 
2043
 * @session: an #EAuthenticationSession
 
2044
 * @cancellable: optional #GCancellable object, or %NULL
 
2045
 * @error: return location for a #GError, or %NULL
 
2046
 *
 
2047
 * Queues the @session behind any ongoing or pending authentication
 
2048
 * sessions for the same data source, and eventually executes @session
 
2049
 * (see e_authentication_session_execute_sync() for more details).
 
2050
 *
 
2051
 * This function blocks until @session is finished executing.  For a
 
2052
 * non-blocking variation see e_source_registry_server_authenticate().
 
2053
 *
 
2054
 * If an error occurs, the function sets @error and returns %FALSE.
 
2055
 *
 
2056
 * Returns: %TRUE on success, %FALSE on failure
 
2057
 *
 
2058
 * Since: 3.6
 
2059
 **/
 
2060
gboolean
 
2061
e_source_registry_server_authenticate_sync (ESourceRegistryServer *server,
 
2062
                                            EAuthenticationSession *session,
 
2063
                                            GCancellable *cancellable,
 
2064
                                            GError **error)
 
2065
{
 
2066
        EAsyncClosure *closure;
 
2067
        GAsyncResult *result;
 
2068
        gboolean success;
 
2069
 
 
2070
        g_return_val_if_fail (E_IS_SOURCE_REGISTRY_SERVER (server), FALSE);
 
2071
        g_return_val_if_fail (E_IS_AUTHENTICATION_SESSION (session), FALSE);
 
2072
 
 
2073
        closure = e_async_closure_new ();
 
2074
 
 
2075
        e_source_registry_server_authenticate (
 
2076
                server, session, cancellable,
 
2077
                e_async_closure_callback, closure);
 
2078
 
 
2079
        result = e_async_closure_wait (closure);
 
2080
 
 
2081
        success = e_source_registry_server_authenticate_finish (
 
2082
                server, result, error);
 
2083
 
 
2084
        e_async_closure_free (closure);
 
2085
 
 
2086
        return success;
 
2087
}
 
2088
 
 
2089
/**
 
2090
 * e_source_registry_server_authenticate:
 
2091
 * @server: an #ESourceRegistryServer
 
2092
 * @session: an #EAuthenticationSession
 
2093
 * @cancellable: optional #GCancellable object, or %NULL
 
2094
 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
 
2095
 * @user_data: data to pass to the callback function
 
2096
 *
 
2097
 * Queues the @session behind any ongoing or pending authentication
 
2098
 * sessions for the same data source, and eventually executes @session
 
2099
 * (see e_authentication_session_execute_sync() for more details).
 
2100
 *
 
2101
 * This function returns immediately after enqueuing @session.  When
 
2102
 * @session is finished executing, @callback will be called.  You can
 
2103
 * then call e_source_registry_server_authenticate_finish() to get the
 
2104
 * result of the operation.
 
2105
 *
 
2106
 * Since: 3.6
 
2107
 **/
 
2108
void
 
2109
e_source_registry_server_authenticate (ESourceRegistryServer *server,
 
2110
                                       EAuthenticationSession *session,
 
2111
                                       GCancellable *cancellable,
 
2112
                                       GAsyncReadyCallback callback,
 
2113
                                       gpointer user_data)
 
2114
{
 
2115
        GSimpleAsyncResult *simple;
 
2116
        AuthRequest *request;
 
2117
        const gchar *uid;
 
2118
 
 
2119
        g_return_if_fail (E_IS_SOURCE_REGISTRY_SERVER (server));
 
2120
        g_return_if_fail (E_IS_AUTHENTICATION_SESSION (session));
 
2121
 
 
2122
        uid = e_authentication_session_get_source_uid (session);
 
2123
        g_return_if_fail (uid != NULL);
 
2124
 
 
2125
        simple = g_simple_async_result_new (
 
2126
                G_OBJECT (server), callback, user_data,
 
2127
                e_source_registry_server_authenticate);
 
2128
 
 
2129
        g_simple_async_result_set_check_cancellable (simple, cancellable);
 
2130
 
 
2131
        request = auth_request_new (session, simple, cancellable);
 
2132
        source_registry_server_auth_request_push (server, uid, request);
 
2133
        auth_request_unref (request);
 
2134
 
 
2135
        source_registry_server_maybe_start_auth_session (server, uid);
 
2136
 
 
2137
        g_object_unref (simple);
 
2138
}
 
2139
 
 
2140
/**
 
2141
 * e_source_registry_server_authenticate_finish:
 
2142
 * @server: an #ESourceRegistryServer
 
2143
 * @result: a #GAsyncResult
 
2144
 * @error: return location for a #GError, or %NULL
 
2145
 *
 
2146
 * Finishes the operation started with e_source_registry_server_authenticate().
 
2147
 * If an error occurred, the function will set @error and return %FALSE.
 
2148
 *
 
2149
 * Returns: %TRUE on success, %FALSE on failure
 
2150
 *
 
2151
 * Since: 3.6
 
2152
 **/
 
2153
gboolean
 
2154
e_source_registry_server_authenticate_finish (ESourceRegistryServer *server,
 
2155
                                              GAsyncResult *result,
 
2156
                                              GError **error)
 
2157
{
 
2158
        GSimpleAsyncResult *simple;
 
2159
 
 
2160
        g_return_val_if_fail (
 
2161
                g_simple_async_result_is_valid (
 
2162
                result, G_OBJECT (server),
 
2163
                e_source_registry_server_authenticate), FALSE);
 
2164
 
 
2165
        simple = G_SIMPLE_ASYNC_RESULT (result);
 
2166
 
 
2167
        /* Assume success unless a GError is set. */
 
2168
        return !g_simple_async_result_propagate_error (simple, error);
 
2169
}
 
2170