2 * Copyright (C) 2015 Red Hat, Inc. (www.redhat.com)
4 * This library is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation.
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this library. If not, see <http://www.gnu.org/licenses/>.
18 #include "evolution-data-server-config.h"
21 #include <glib/gi18n-lib.h>
23 #include <camel/camel.h>
24 #include <libedataserver/libedataserver.h>
26 #include "e-credentials-prompter.h"
28 /* built-in credentials prompter implementations */
29 #include "e-credentials-prompter-impl-password.h"
30 #include "e-credentials-prompter-impl-oauth2.h"
32 typedef struct _ProcessPromptData
{
34 ECredentialsPrompterImpl
*prompter_impl
;
37 ESourceConnectionStatus connection_status
; /* of the auth_source */
38 gboolean remember_password
; /* of the cred_source, to check for changes */
39 gulong notify_handler_id
;
41 ENamedParameters
*credentials
;
42 gboolean allow_source_save
;
43 GSimpleAsyncResult
*async_result
;
46 struct _ECredentialsPrompterPrivate
{
47 ESourceRegistry
*registry
;
48 ESourceCredentialsProvider
*provider
;
50 GCancellable
*cancellable
;
52 GMutex disabled_auto_prompt_lock
;
53 GHashTable
*disabled_auto_prompt
; /* gchar *source_uid ~> 1; Source UIDs for which the auto-prompt is disabled */
55 GMutex prompters_lock
;
56 GHashTable
*prompters
; /* gchar *method ~> ECredentialsPrompterImpl *impl */
57 GHashTable
*known_prompters
; /* gpointer [ECredentialsPrompterImpl] ~> UINT known instances; the prompter_impl is not referenced */
59 GRecMutex queue_lock
; /* guards all queue and schedule related properties */
60 GSList
*queue
; /* ProcessPromptData * */
61 ProcessPromptData
*processing_prompt
;
62 gulong schedule_idle_id
;
77 static guint signals
[LAST_SIGNAL
];
79 G_DEFINE_TYPE_WITH_CODE (ECredentialsPrompter
, e_credentials_prompter
, G_TYPE_OBJECT
,
80 G_IMPLEMENT_INTERFACE (E_TYPE_EXTENSIBLE
, NULL
))
83 process_prompt_data_free (gpointer ptr
)
85 ProcessPromptData
*ppd
= ptr
;
88 if (ppd
->notify_handler_id
> 0)
89 g_signal_handler_disconnect (ppd
->auth_source
, ppd
->notify_handler_id
);
91 if (ppd
->async_result
) {
92 ECredentialsPrompter
*prompter
;
94 prompter
= g_weak_ref_get (ppd
->prompter
);
96 e_credentials_prompter_complete_prompt_call (prompter
, ppd
->async_result
, ppd
->auth_source
, NULL
, NULL
);
97 g_clear_object (&prompter
);
101 e_weak_ref_free (ppd
->prompter
);
102 g_clear_object (&ppd
->prompter_impl
);
103 g_clear_object (&ppd
->auth_source
);
104 g_clear_object (&ppd
->cred_source
);
105 g_free (ppd
->error_text
);
106 e_named_parameters_free (ppd
->credentials
);
111 typedef struct _LookupSourceDetailsData
{
112 ESource
*auth_source
; /* an ESource which asked for credentials */
113 ESource
*cred_source
; /* this might be auth_source or a parent collection source, if applicable, from where the credentials come */
114 ENamedParameters
*credentials
; /* actual stored credentials */
115 } LookupSourceDetailsData
;
118 lookup_source_details_data_free (gpointer ptr
)
120 LookupSourceDetailsData
*data
= ptr
;
123 g_clear_object (&data
->auth_source
);
124 g_clear_object (&data
->cred_source
);
125 e_named_parameters_free (data
->credentials
);
131 credentials_prompter_lookup_source_details_thread (GTask
*task
,
132 gpointer source_object
,
134 GCancellable
*cancellable
)
136 ESource
*source
, *cred_source
= NULL
;
137 ECredentialsPrompter
*prompter
;
138 ESourceCredentialsProvider
*provider
;
139 ENamedParameters
*credentials
= NULL
;
140 GError
*local_error
= NULL
;
142 g_return_if_fail (E_IS_SOURCE (source_object
));
144 source
= E_SOURCE (source_object
);
146 prompter
= g_weak_ref_get (task_data
);
150 provider
= e_credentials_prompter_get_provider (prompter
);
151 cred_source
= e_source_credentials_provider_ref_credentials_source (provider
, source
);
153 e_source_credentials_provider_lookup_sync (provider
, cred_source
? cred_source
: source
, cancellable
, &credentials
, &local_error
);
155 /* Interested only in the cancelled error, which means the prompter is freed. */
156 if (local_error
!= NULL
&& g_error_matches (local_error
, G_IO_ERROR
, G_IO_ERROR_CANCELLED
)) {
157 g_task_return_error (task
, local_error
);
160 LookupSourceDetailsData
*data
;
162 data
= g_new0 (LookupSourceDetailsData
, 1);
163 data
->auth_source
= g_object_ref (source
);
164 data
->cred_source
= g_object_ref (cred_source
? cred_source
: source
); /* always set both, for simplicity */
165 data
->credentials
= credentials
; /* NULL for no credentials available */
167 /* To not be freed below. */
170 g_task_return_pointer (task
, data
, lookup_source_details_data_free
);
173 e_named_parameters_free (credentials
);
174 g_clear_object (&cred_source
);
175 g_clear_object (&prompter
);
176 g_clear_error (&local_error
);
180 credentials_prompter_lookup_source_details (ESource
*source
,
181 ECredentialsPrompter
*prompter
,
182 GAsyncReadyCallback callback
,
187 g_return_if_fail (E_IS_SOURCE (source
));
188 g_return_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter
));
190 task
= g_task_new (source
, prompter
->priv
->cancellable
, callback
, user_data
);
191 g_task_set_source_tag (task
, credentials_prompter_lookup_source_details_thread
);
192 g_task_set_task_data (task
, e_weak_ref_new (prompter
), (GDestroyNotify
) e_weak_ref_free
);
194 g_task_run_in_thread (task
, credentials_prompter_lookup_source_details_thread
);
196 g_object_unref (task
);
200 credentials_prompter_lookup_source_details_finish (ESource
*source
,
201 GAsyncResult
*result
,
202 ECredentialsPrompter
**out_prompter
, /* will be referenced, if not NULL */
203 LookupSourceDetailsData
**out_data
,
206 LookupSourceDetailsData
*data
;
208 g_return_val_if_fail (E_IS_SOURCE (source
), FALSE
);
209 g_return_val_if_fail (out_prompter
!= NULL
, FALSE
);
210 g_return_val_if_fail (out_data
!= NULL
, FALSE
);
211 g_return_val_if_fail (g_task_is_valid (result
, source
), FALSE
);
213 g_return_val_if_fail (
214 g_async_result_is_tagged (
215 result
, credentials_prompter_lookup_source_details_thread
), FALSE
);
217 data
= g_task_propagate_pointer (G_TASK (result
), error
);
222 *out_prompter
= g_weak_ref_get (g_task_get_task_data (G_TASK (result
)));
228 credentials_prompter_invoke_authenticate_cb (GObject
*source_object
,
229 GAsyncResult
*result
,
232 GError
*error
= NULL
;
234 if (!e_source_invoke_authenticate_finish (E_SOURCE (source_object
), result
, &error
) &&
235 !g_error_matches (error
, G_IO_ERROR
, G_IO_ERROR_CANCELLED
)) {
236 g_debug ("%s: Failed to invoke authenticate: %s", G_STRFUNC
, error
? error
->message
: "Unknown error");
239 g_clear_error (&error
);
242 typedef struct _CredentialsPromptData
{
245 ECredentialsPrompterPromptFlags flags
;
246 GTask
*complete_task
;
247 GSimpleAsyncResult
*async_result
;
248 } CredentialsPromptData
;
251 credentials_prompt_data_free (gpointer ptr
)
253 CredentialsPromptData
*data
= ptr
;
256 if (data
->async_result
) {
257 g_simple_async_result_set_error (data
->async_result
,
258 G_IO_ERROR
, G_IO_ERROR_CANCELLED
, "%s", _("Credentials prompt was cancelled"));
259 g_simple_async_result_complete_in_idle (data
->async_result
);
260 g_clear_object (&data
->async_result
);
263 g_clear_object (&data
->source
);
264 g_free (data
->error_text
);
269 typedef struct _CredentialsResultData
{
271 ENamedParameters
*credentials
;
272 } CredentialsResultData
;
275 credentials_result_data_free (gpointer ptr
)
277 CredentialsResultData
*data
= ptr
;
280 g_clear_object (&data
->source
);
281 e_named_parameters_free (data
->credentials
);
288 credentials_prompter_maybe_process_next_prompt (ECredentialsPrompter
*prompter
)
290 g_return_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter
));
292 g_rec_mutex_lock (&prompter
->priv
->queue_lock
);
294 /* Already processing one */
295 if (prompter
->priv
->processing_prompt
) {
296 g_rec_mutex_unlock (&prompter
->priv
->queue_lock
);
300 if (prompter
->priv
->queue
) {
301 ProcessPromptData
*ppd
= prompter
->priv
->queue
->data
;
303 g_warn_if_fail (ppd
!= NULL
);
305 prompter
->priv
->queue
= g_slist_remove (prompter
->priv
->queue
, ppd
);
306 prompter
->priv
->processing_prompt
= ppd
;
308 e_credentials_prompter_impl_prompt (ppd
->prompter_impl
, ppd
, ppd
->auth_source
,
309 ppd
->cred_source
, ppd
->error_text
, ppd
->credentials
);
312 g_rec_mutex_unlock (&prompter
->priv
->queue_lock
);
316 credentials_prompter_process_next_prompt_idle_cb (gpointer user_data
)
318 ECredentialsPrompter
*prompter
= user_data
;
320 if (g_source_is_destroyed (g_main_current_source ()))
323 g_return_val_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter
), FALSE
);
325 g_rec_mutex_lock (&prompter
->priv
->queue_lock
);
327 if (g_source_get_id (g_main_current_source ()) == prompter
->priv
->schedule_idle_id
) {
328 prompter
->priv
->schedule_idle_id
= 0;
330 credentials_prompter_maybe_process_next_prompt (prompter
);
333 g_rec_mutex_unlock (&prompter
->priv
->queue_lock
);
339 credentials_prompter_schedule_process_next_prompt (ECredentialsPrompter
*prompter
)
341 g_return_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter
));
343 g_rec_mutex_lock (&prompter
->priv
->queue_lock
);
345 /* Already processing one */
346 if (prompter
->priv
->processing_prompt
||
347 prompter
->priv
->schedule_idle_id
) {
348 g_rec_mutex_unlock (&prompter
->priv
->queue_lock
);
352 prompter
->priv
->schedule_idle_id
= g_idle_add_full (G_PRIORITY_HIGH_IDLE
,
353 credentials_prompter_process_next_prompt_idle_cb
,
356 g_rec_mutex_unlock (&prompter
->priv
->queue_lock
);
360 credentials_prompter_connection_status_changed_cb (ESource
*source
,
362 ECredentialsPrompter
*prompter
)
364 g_return_if_fail (E_IS_SOURCE (source
));
365 g_return_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter
));
367 /* Do not cancel the prompt when the source is still waiting for the credentials. */
368 if (e_source_get_connection_status (source
) == E_SOURCE_CONNECTION_STATUS_AWAITING_CREDENTIALS
)
371 g_rec_mutex_lock (&prompter
->priv
->queue_lock
);
373 if (prompter
->priv
->processing_prompt
&&
374 e_source_equal (prompter
->priv
->processing_prompt
->auth_source
, source
)) {
375 e_credentials_prompter_impl_cancel_prompt (prompter
->priv
->processing_prompt
->prompter_impl
, prompter
->priv
->processing_prompt
);
379 for (link
= prompter
->priv
->queue
; link
; link
= g_slist_next (link
)) {
380 ProcessPromptData
*ppd
= link
->data
;
382 g_warn_if_fail (ppd
!= NULL
);
384 if (ppd
&& e_source_equal (ppd
->auth_source
, source
)) {
385 if (ppd
->connection_status
!= e_source_get_connection_status (source
)) {
386 prompter
->priv
->queue
= g_slist_remove (prompter
->priv
->queue
, ppd
);
387 process_prompt_data_free (ppd
);
394 g_rec_mutex_unlock (&prompter
->priv
->queue_lock
);
398 e_credentials_prompter_eval_remember_password (ESource
*source
)
400 gboolean remember_password
= FALSE
;
402 if (e_source_has_extension (source
, E_SOURCE_EXTENSION_AUTHENTICATION
))
403 remember_password
= e_source_authentication_get_remember_password (
404 e_source_get_extension (source
, E_SOURCE_EXTENSION_AUTHENTICATION
));
406 return remember_password
;
410 e_credentials_prompter_manage_impl_prompt (ECredentialsPrompter
*prompter
,
411 ECredentialsPrompterImpl
*prompter_impl
,
412 ESource
*auth_source
,
413 ESource
*cred_source
,
414 const gchar
*error_text
,
415 const ENamedParameters
*credentials
,
416 gboolean allow_source_save
,
417 GSimpleAsyncResult
*async_result
)
420 gboolean success
= TRUE
;
422 g_return_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter
));
423 g_return_if_fail (E_IS_CREDENTIALS_PROMPTER_IMPL (prompter_impl
));
424 g_return_if_fail (E_IS_SOURCE (auth_source
));
425 g_return_if_fail (E_IS_SOURCE (cred_source
));
426 g_return_if_fail (credentials
!= NULL
);
428 g_rec_mutex_lock (&prompter
->priv
->queue_lock
);
430 for (link
= prompter
->priv
->queue
; link
; link
= g_slist_next (link
)) {
431 ProcessPromptData
*ppd
= link
->data
;
433 g_warn_if_fail (ppd
!= NULL
);
435 if (ppd
&& e_source_equal (ppd
->auth_source
, auth_source
)) {
440 if (link
!= NULL
|| (prompter
->priv
->processing_prompt
&&
441 e_source_equal (prompter
->priv
->processing_prompt
->auth_source
, auth_source
))) {
442 /* have queued or already asking for credentials for this source */
445 ProcessPromptData
*ppd
;
447 ppd
= g_new0 (ProcessPromptData
, 1);
448 ppd
->prompter
= e_weak_ref_new (prompter
);
449 ppd
->prompter_impl
= g_object_ref (prompter_impl
);
450 ppd
->auth_source
= g_object_ref (auth_source
);
451 ppd
->cred_source
= g_object_ref (cred_source
);
452 ppd
->connection_status
= e_source_get_connection_status (ppd
->auth_source
);
453 ppd
->remember_password
= e_credentials_prompter_eval_remember_password (ppd
->cred_source
);
454 ppd
->error_text
= g_strdup (error_text
);
455 ppd
->credentials
= e_named_parameters_new_clone (credentials
);
456 ppd
->allow_source_save
= allow_source_save
;
457 ppd
->async_result
= async_result
? g_object_ref (async_result
) : NULL
;
459 /* If the prompter doesn't auto-prompt, then it should not auto-close the prompt as well. */
460 if (e_credentials_prompter_get_auto_prompt (prompter
)) {
461 ppd
->notify_handler_id
= g_signal_connect (ppd
->auth_source
, "notify::connection-status",
462 G_CALLBACK (credentials_prompter_connection_status_changed_cb
), prompter
);
464 ppd
->notify_handler_id
= 0;
467 prompter
->priv
->queue
= g_slist_append (prompter
->priv
->queue
, ppd
);
469 credentials_prompter_schedule_process_next_prompt (prompter
);
472 g_rec_mutex_unlock (&prompter
->priv
->queue_lock
);
474 if (!success
&& async_result
) {
475 e_credentials_prompter_complete_prompt_call (prompter
, async_result
, auth_source
, NULL
, NULL
);
480 credentials_prompter_store_credentials_cb (GObject
*source_object
,
481 GAsyncResult
*result
,
484 GError
*error
= NULL
;
486 if (!e_source_credentials_provider_store_finish (E_SOURCE_CREDENTIALS_PROVIDER (source_object
), result
, &error
) &&
487 !g_error_matches (error
, G_IO_ERROR
, G_IO_ERROR_CANCELLED
)) {
488 g_warning ("%s: Failed to store source credentials: %s", G_STRFUNC
, error
? error
->message
: "Unknown error");
491 g_clear_error (&error
);
495 credentials_prompter_source_write_cb (GObject
*source_object
,
496 GAsyncResult
*result
,
499 GError
*error
= NULL
;
501 if (!e_source_write_finish (E_SOURCE (source_object
), result
, &error
) &&
502 !g_error_matches (error
, G_IO_ERROR
, G_IO_ERROR_CANCELLED
)) {
503 g_warning ("%s: Failed to write source changes: %s", G_STRFUNC
, error
? error
->message
: "Unknown error");
506 g_clear_error (&error
);
510 e_credentials_prompter_prompt_finish_for_source (ECredentialsPrompter
*prompter
,
511 ProcessPromptData
*ppd
,
512 const ENamedParameters
*credentials
)
514 gboolean changed
= FALSE
;
516 g_return_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter
));
517 g_return_if_fail (ppd
!= NULL
);
522 if (e_source_has_extension (ppd
->cred_source
, E_SOURCE_EXTENSION_AUTHENTICATION
)) {
523 ESourceAuthentication
*auth_extension
= e_source_get_extension (ppd
->cred_source
, E_SOURCE_EXTENSION_AUTHENTICATION
);
525 if (e_source_credentials_provider_can_store (e_credentials_prompter_get_provider (prompter
), ppd
->cred_source
)) {
526 e_source_credentials_provider_store (e_credentials_prompter_get_provider (prompter
), ppd
->cred_source
, credentials
,
527 e_source_authentication_get_remember_password (auth_extension
),
528 prompter
->priv
->cancellable
,
529 credentials_prompter_store_credentials_cb
, NULL
);
532 if (e_source_get_writable (ppd
->cred_source
)) {
533 const gchar
*username
;
535 username
= e_named_parameters_get (credentials
, E_SOURCE_CREDENTIAL_USERNAME
);
536 if (username
&& *username
&&
537 g_strcmp0 (username
, e_source_authentication_get_user (auth_extension
)) != 0) {
538 e_source_authentication_set_user (auth_extension
, username
);
544 if (ppd
->allow_source_save
&& e_source_get_writable (ppd
->cred_source
) &&
545 (changed
|| (ppd
->remember_password
? 1 : 0) != (e_credentials_prompter_eval_remember_password (ppd
->cred_source
) ? 1 : 0))) {
546 e_source_write (ppd
->cred_source
, prompter
->priv
->cancellable
,
547 credentials_prompter_source_write_cb
, NULL
);
550 if (ppd
->async_result
) {
551 ECredentialsPrompter
*ppd_prompter
;
553 ppd_prompter
= g_weak_ref_get (ppd
->prompter
);
555 e_credentials_prompter_complete_prompt_call (ppd_prompter
, ppd
->async_result
, ppd
->auth_source
, credentials
, NULL
);
556 g_clear_object (&ppd_prompter
);
558 /* To not be completed multiple times */
559 g_clear_object (&ppd
->async_result
);
562 e_source_invoke_authenticate (ppd
->auth_source
, credentials
, prompter
->priv
->cancellable
,
563 credentials_prompter_invoke_authenticate_cb
, NULL
);
568 credentials_prompter_prompt_finished_cb (ECredentialsPrompterImpl
*prompter_impl
,
570 const ENamedParameters
*credentials
,
571 ECredentialsPrompter
*prompter
)
573 g_return_if_fail (E_IS_CREDENTIALS_PROMPTER_IMPL (prompter_impl
));
574 g_return_if_fail (prompt_id
!= NULL
);
575 g_return_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter
));
577 g_rec_mutex_lock (&prompter
->priv
->queue_lock
);
579 if (prompt_id
== prompter
->priv
->processing_prompt
) {
580 ProcessPromptData
*ppd
= prompter
->priv
->processing_prompt
;
581 GSList
*link
, *to_remove
= NULL
;
583 prompter
->priv
->processing_prompt
= NULL
;
585 e_credentials_prompter_prompt_finish_for_source (prompter
, ppd
, credentials
);
587 /* Finish also any other pending prompts for the same credentials source
588 as was finished this one. This can be relevant to collection sources. */
589 for (link
= prompter
->priv
->queue
; link
; link
= g_slist_next (link
)) {
590 ProcessPromptData
*sub_ppd
= link
->data
;
592 if (sub_ppd
&& sub_ppd
->cred_source
&& e_source_equal (sub_ppd
->cred_source
, ppd
->cred_source
)) {
593 to_remove
= g_slist_prepend (to_remove
, sub_ppd
);
597 for (link
= to_remove
; link
; link
= g_slist_next (link
)) {
598 ProcessPromptData
*sub_ppd
= link
->data
;
601 prompter
->priv
->queue
= g_slist_remove (prompter
->priv
->queue
, sub_ppd
);
602 e_credentials_prompter_prompt_finish_for_source (prompter
, sub_ppd
, credentials
);
606 g_slist_free_full (to_remove
, process_prompt_data_free
);
607 process_prompt_data_free (ppd
);
609 credentials_prompter_schedule_process_next_prompt (prompter
);
611 g_warning ("%s: Unknown prompt_id %p", G_STRFUNC
, prompt_id
);
614 g_rec_mutex_unlock (&prompter
->priv
->queue_lock
);
618 credentials_prompter_prompt_with_source_details (ECredentialsPrompter
*prompter
,
619 LookupSourceDetailsData
*data
,
620 const gchar
*error_text
,
621 ECredentialsPrompterPromptFlags flags
,
622 GSimpleAsyncResult
*async_result
)
624 ECredentialsPrompterImpl
*prompter_impl
= NULL
;
625 gchar
*method
= NULL
;
626 gboolean success
= TRUE
;
628 g_return_val_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter
), FALSE
);
629 g_return_val_if_fail (data
!= NULL
, FALSE
);
631 if (e_source_has_extension (data
->cred_source
, E_SOURCE_EXTENSION_AUTHENTICATION
)) {
632 ESourceAuthentication
*authentication
= e_source_get_extension (data
->cred_source
, E_SOURCE_EXTENSION_AUTHENTICATION
);
634 method
= e_source_authentication_dup_method (authentication
);
637 g_mutex_lock (&prompter
->priv
->prompters_lock
);
639 prompter_impl
= g_hash_table_lookup (prompter
->priv
->prompters
, method
? method
: "");
640 if (!prompter_impl
&& method
&& *method
)
641 prompter_impl
= g_hash_table_lookup (prompter
->priv
->prompters
, "");
644 g_object_ref (prompter_impl
);
646 g_mutex_unlock (&prompter
->priv
->prompters_lock
);
649 ENamedParameters
*credentials
;
651 credentials
= e_named_parameters_new ();
652 if (data
->credentials
)
653 e_named_parameters_assign (credentials
, data
->credentials
);
655 if (async_result
&& data
->credentials
&& (flags
& E_CREDENTIALS_PROMPTER_PROMPT_FLAG_ALLOW_STORED_CREDENTIALS
) != 0) {
656 e_credentials_prompter_complete_prompt_call (prompter
, async_result
, data
->auth_source
, credentials
, NULL
);
657 } else if (!e_source_credentials_provider_can_prompt (prompter
->priv
->provider
, data
->auth_source
)) {
658 /* This source cannot be asked for credentials, thus end with a 'not supported' error. */
661 error
= g_error_new (G_IO_ERROR
, G_IO_ERROR_NOT_SUPPORTED
,
662 _("Source “%s” doesn’t support prompt for credentials"),
663 e_source_get_display_name (data
->cred_source
));
666 e_credentials_prompter_complete_prompt_call (prompter
, async_result
, data
->auth_source
, NULL
, error
);
668 g_clear_error (&error
);
670 e_credentials_prompter_manage_impl_prompt (prompter
, prompter_impl
,
671 data
->auth_source
, data
->cred_source
, error_text
, credentials
,
672 !async_result
|| (flags
& E_CREDENTIALS_PROMPTER_PROMPT_FLAG_ALLOW_SOURCE_SAVE
) != 0,
676 e_named_parameters_free (credentials
);
678 /* Shoud not happen, because the password prompter is added as the default prompter. */
679 g_warning ("%s: No prompter impl found for an authentication method '%s'", G_STRFUNC
, method
? method
: "");
683 g_clear_object (&prompter_impl
);
690 credentials_prompter_lookup_source_details_before_prompt_cb (GObject
*source_object
,
691 GAsyncResult
*result
,
694 CredentialsPromptData
*prompt_data
= user_data
;
695 ECredentialsPrompter
*prompter
= NULL
;
696 LookupSourceDetailsData
*data
= NULL
;
697 GError
*error
= NULL
;
699 g_return_if_fail (prompt_data
!= NULL
);
700 g_return_if_fail (E_IS_SOURCE (source_object
));
702 if (!credentials_prompter_lookup_source_details_finish (E_SOURCE (source_object
), result
, &prompter
, &data
, &error
)) {
703 g_clear_error (&error
);
704 credentials_prompt_data_free (prompt_data
);
708 if (credentials_prompter_prompt_with_source_details (prompter
, data
, prompt_data
->error_text
,
709 prompt_data
->flags
, prompt_data
->async_result
)) {
710 /* To not finish the async_result multiple times */
711 g_clear_object (&prompt_data
->async_result
);
714 g_clear_object (&prompter
);
716 credentials_prompt_data_free (prompt_data
);
717 lookup_source_details_data_free (data
);
721 credentials_prompter_lookup_source_details_cb (GObject
*source_object
,
722 GAsyncResult
*result
,
725 LookupSourceDetailsData
*data
= NULL
;
726 ECredentialsPrompter
*prompter
= NULL
;
728 GError
*error
= NULL
;
730 g_return_if_fail (E_IS_SOURCE (source_object
));
732 source
= E_SOURCE (source_object
);
734 if (!credentials_prompter_lookup_source_details_finish (source
, result
, &prompter
, &data
, &error
)) {
735 g_clear_error (&error
);
739 g_return_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter
));
740 g_return_if_fail (data
!= NULL
);
742 if (data
->credentials
) {
743 e_source_invoke_authenticate (E_SOURCE (data
->auth_source
), data
->credentials
, prompter
->priv
->cancellable
, credentials_prompter_invoke_authenticate_cb
, NULL
);
745 credentials_prompter_prompt_with_source_details (prompter
, data
, NULL
, 0, NULL
);
748 lookup_source_details_data_free (data
);
749 g_clear_object (&prompter
);
753 credentials_prompter_credentials_required_cb (ESourceRegistry
*registry
,
755 ESourceCredentialsReason reason
,
756 const gchar
*certificate_pem
,
757 GTlsCertificateFlags certificate_errors
,
758 const GError
*op_error
,
759 ECredentialsPrompter
*prompter
)
761 ESource
*cred_source
;
763 g_return_if_fail (E_IS_SOURCE_REGISTRY (registry
));
764 g_return_if_fail (E_IS_SOURCE (source
));
765 g_return_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter
));
767 /* Only these two reasons are meant to be used to prompt the user for credentials. */
768 if (reason
!= E_SOURCE_CREDENTIALS_REASON_REQUIRED
&&
769 reason
!= E_SOURCE_CREDENTIALS_REASON_REJECTED
) {
773 cred_source
= e_source_credentials_provider_ref_credentials_source (e_credentials_prompter_get_provider (prompter
), source
);
775 /* Global auto-prompt or the source's auto-prompt is disabled. */
776 if (!e_credentials_prompter_get_auto_prompt (prompter
) ||
777 (e_credentials_prompter_get_auto_prompt_disabled_for (prompter
, source
) &&
778 (!cred_source
|| e_credentials_prompter_get_auto_prompt_disabled_for (prompter
, cred_source
)))) {
779 g_clear_object (&cred_source
);
783 g_clear_object (&cred_source
);
785 /* This is a re-prompt, but the source cannot be prompted for credentials. */
786 if (reason
== E_SOURCE_CREDENTIALS_REASON_REJECTED
&&
787 !e_source_credentials_provider_can_prompt (prompter
->priv
->provider
, source
)) {
791 if (reason
== E_SOURCE_CREDENTIALS_REASON_REQUIRED
) {
792 credentials_prompter_lookup_source_details (source
, prompter
,
793 credentials_prompter_lookup_source_details_cb
, NULL
);
797 e_credentials_prompter_prompt (prompter
, source
, op_error
? op_error
->message
: NULL
, 0, NULL
, NULL
);
801 credentials_prompter_get_dialog_parent_accumulator (GSignalInvocationHint
*ihint
,
803 const GValue
*handler_return
,
806 if (handler_return
&& g_value_get_object (handler_return
) != NULL
) {
807 g_value_set_object (return_accu
, g_value_get_object (handler_return
));
815 credentials_prompter_set_registry (ECredentialsPrompter
*prompter
,
816 ESourceRegistry
*registry
)
818 g_return_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter
));
819 g_return_if_fail (E_IS_SOURCE_REGISTRY (registry
));
820 g_return_if_fail (prompter
->priv
->registry
== NULL
);
822 prompter
->priv
->registry
= g_object_ref (registry
);
823 prompter
->priv
->provider
= e_source_credentials_provider_new (prompter
->priv
->registry
);
825 g_signal_connect (prompter
->priv
->registry
, "credentials-required",
826 G_CALLBACK (credentials_prompter_credentials_required_cb
), prompter
);
830 credentials_prompter_set_property (GObject
*object
,
835 switch (property_id
) {
837 credentials_prompter_set_registry (
838 E_CREDENTIALS_PROMPTER (object
),
839 g_value_get_object (value
));
842 case PROP_AUTO_PROMPT
:
843 e_credentials_prompter_set_auto_prompt (
844 E_CREDENTIALS_PROMPTER (object
),
845 g_value_get_boolean (value
));
849 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
853 credentials_prompter_get_property (GObject
*object
,
858 switch (property_id
) {
860 g_value_set_object (value
,
861 e_credentials_prompter_get_registry (
862 E_CREDENTIALS_PROMPTER (object
)));
866 g_value_set_object (value
,
867 e_credentials_prompter_get_provider (
868 E_CREDENTIALS_PROMPTER (object
)));
871 case PROP_AUTO_PROMPT
:
872 g_value_set_boolean (value
,
873 e_credentials_prompter_get_auto_prompt (
874 E_CREDENTIALS_PROMPTER (object
)));
878 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
882 credentials_prompter_constructed (GObject
*object
)
884 /* Chain up to parent's method. */
885 G_OBJECT_CLASS (e_credentials_prompter_parent_class
)->constructed (object
);
887 e_extensible_load_extensions (E_EXTENSIBLE (object
));
891 credentials_prompter_dispose (GObject
*object
)
893 ECredentialsPrompter
*prompter
= E_CREDENTIALS_PROMPTER (object
);
897 if (prompter
->priv
->cancellable
) {
898 g_cancellable_cancel (prompter
->priv
->cancellable
);
899 g_clear_object (&prompter
->priv
->cancellable
);
902 if (prompter
->priv
->registry
) {
903 g_signal_handlers_disconnect_by_data (prompter
->priv
->registry
, prompter
);
904 g_clear_object (&prompter
->priv
->registry
);
907 g_rec_mutex_lock (&prompter
->priv
->queue_lock
);
909 if (prompter
->priv
->schedule_idle_id
) {
910 g_source_remove (prompter
->priv
->schedule_idle_id
);
911 prompter
->priv
->schedule_idle_id
= 0;
914 g_rec_mutex_unlock (&prompter
->priv
->queue_lock
);
916 g_clear_object (&prompter
->priv
->provider
);
918 g_mutex_lock (&prompter
->priv
->prompters_lock
);
920 g_hash_table_iter_init (&iter
, prompter
->priv
->prompters
);
921 while (g_hash_table_iter_next (&iter
, &key
, &value
)) {
922 ECredentialsPrompterImpl
*prompter_impl
= value
;
924 g_signal_handlers_disconnect_by_func (prompter_impl
, credentials_prompter_prompt_finished_cb
, prompter
);
927 g_hash_table_remove_all (prompter
->priv
->prompters
);
928 g_hash_table_remove_all (prompter
->priv
->known_prompters
);
929 g_mutex_unlock (&prompter
->priv
->prompters_lock
);
931 /* Chain up to parent's method. */
932 G_OBJECT_CLASS (e_credentials_prompter_parent_class
)->dispose (object
);
936 credentials_prompter_finalize (GObject
*object
)
938 ECredentialsPrompter
*prompter
= E_CREDENTIALS_PROMPTER (object
);
940 g_hash_table_destroy (prompter
->priv
->prompters
);
941 g_hash_table_destroy (prompter
->priv
->known_prompters
);
942 g_mutex_clear (&prompter
->priv
->prompters_lock
);
944 g_hash_table_destroy (prompter
->priv
->disabled_auto_prompt
);
945 g_mutex_clear (&prompter
->priv
->disabled_auto_prompt_lock
);
947 g_rec_mutex_clear (&prompter
->priv
->queue_lock
);
949 /* Chain up to parent's method. */
950 G_OBJECT_CLASS (e_credentials_prompter_parent_class
)->finalize (object
);
954 e_credentials_prompter_class_init (ECredentialsPrompterClass
*class)
956 GObjectClass
*object_class
;
958 g_type_class_add_private (class, sizeof (ECredentialsPrompterPrivate
));
960 object_class
= G_OBJECT_CLASS (class);
961 object_class
->set_property
= credentials_prompter_set_property
;
962 object_class
->get_property
= credentials_prompter_get_property
;
963 object_class
->constructed
= credentials_prompter_constructed
;
964 object_class
->dispose
= credentials_prompter_dispose
;
965 object_class
->finalize
= credentials_prompter_finalize
;
968 * ECredentialsPrompter:auto-prompt:
970 * Whether the #ECredentialsPrompter can response to credential
971 * requests automatically.
975 g_object_class_install_property (
978 g_param_spec_boolean (
981 "Whether can response to credential requests automatically",
985 G_PARAM_STATIC_STRINGS
));
988 * ECredentialsPrompter:registry:
990 * The #ESourceRegistry object, to whose credential requests the prompter listens.
994 g_object_class_install_property (
997 g_param_spec_object (
1000 "An ESourceRegistry",
1001 E_TYPE_SOURCE_REGISTRY
,
1003 G_PARAM_CONSTRUCT_ONLY
|
1004 G_PARAM_STATIC_STRINGS
));
1007 * ECredentialsPrompter:provider:
1009 * The #ESourceCredentialsProvider object, which the prompter uses.
1013 g_object_class_install_property (
1016 g_param_spec_object (
1019 "An ESourceCredentialsProvider",
1020 E_TYPE_SOURCE_CREDENTIALS_PROVIDER
,
1022 G_PARAM_STATIC_STRINGS
));
1025 * ECredentialsPrompter::get-dialog-parent:
1026 * @prompter: the #ECredentialsPrompter which emitted the signal
1028 * Emitted when a new dialog will be shown, to get the right parent
1029 * window for it. If the result of the call is %NULL, then it tries
1030 * to get the window from the default GtkApplication.
1032 * Returns: (transfer none): a #GtkWindow, to be used as a dialog parent,
1037 signals
[GET_DIALOG_PARENT
] = g_signal_new (
1038 "get-dialog-parent",
1039 G_OBJECT_CLASS_TYPE (object_class
),
1041 G_STRUCT_OFFSET (ECredentialsPrompterClass
, get_dialog_parent
),
1042 credentials_prompter_get_dialog_parent_accumulator
, NULL
, NULL
,
1043 GTK_TYPE_WINDOW
, 0, G_TYPE_NONE
);
1045 /* Ensure built-in credential providers implementation types */
1046 g_type_ensure (E_TYPE_CREDENTIALS_PROMPTER_IMPL_PASSWORD
);
1047 g_type_ensure (E_TYPE_CREDENTIALS_PROMPTER_IMPL_OAUTH2
);
1051 e_credentials_prompter_init (ECredentialsPrompter
*prompter
)
1053 prompter
->priv
= G_TYPE_INSTANCE_GET_PRIVATE (prompter
, E_TYPE_CREDENTIALS_PROMPTER
, ECredentialsPrompterPrivate
);
1055 prompter
->priv
->auto_prompt
= TRUE
;
1056 prompter
->priv
->provider
= NULL
;
1057 prompter
->priv
->cancellable
= g_cancellable_new ();
1059 g_mutex_init (&prompter
->priv
->prompters_lock
);
1060 prompter
->priv
->prompters
= g_hash_table_new_full (camel_strcase_hash
, camel_strcase_equal
, g_free
, g_object_unref
);
1061 prompter
->priv
->known_prompters
= g_hash_table_new (g_direct_hash
, g_direct_equal
);
1063 g_mutex_init (&prompter
->priv
->disabled_auto_prompt_lock
);
1064 prompter
->priv
->disabled_auto_prompt
= g_hash_table_new_full (g_str_hash
, g_str_equal
, g_free
, NULL
);
1066 g_rec_mutex_init (&prompter
->priv
->queue_lock
);
1070 * e_credentials_prompter_new:
1071 * @registry: an #ESourceRegistry to have the prompter listen to
1073 * Creates a new #ECredentialsPrompter, which listens for credential requests
1076 * Returns: (transfer full): a new #ECredentialsPrompter
1080 ECredentialsPrompter
*
1081 e_credentials_prompter_new (ESourceRegistry
*registry
)
1083 return g_object_new (E_TYPE_CREDENTIALS_PROMPTER
,
1084 "registry", registry
,
1089 * e_credentials_prompter_get_registry:
1090 * @prompter: an #ECredentialsPrompter
1092 * Returns an #ESourceRegistry, to which the @prompter listens.
1094 * Returns: (transfer none): an #ESourceRegistry, to which the @prompter listens.
1099 e_credentials_prompter_get_registry (ECredentialsPrompter
*prompter
)
1101 g_return_val_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter
), NULL
);
1103 return prompter
->priv
->registry
;
1107 * e_credentials_prompter_get_provider:
1108 * @prompter: an #ECredentialsPrompter
1110 * Returns an #ESourceCredentialsProvider, which the @prompter uses.
1112 * Returns: (transfer none): an #ESourceCredentialsProvider, which the @prompter uses.
1116 ESourceCredentialsProvider
*
1117 e_credentials_prompter_get_provider (ECredentialsPrompter
*prompter
)
1119 g_return_val_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter
), NULL
);
1120 g_return_val_if_fail (prompter
->priv
->provider
!= NULL
, NULL
);
1122 return prompter
->priv
->provider
;
1126 * e_credentials_prompter_get_auto_prompt:
1127 * @prompter: an #ECredentialsPrompter
1129 * Returns, whether can respond to credential prompts automatically.
1130 * Default value is %TRUE.
1132 * This property does not influence direct calls of e_credentials_prompter_prompt().
1134 * Returns: Whether can respond to credential prompts automatically.
1139 e_credentials_prompter_get_auto_prompt (ECredentialsPrompter
*prompter
)
1141 g_return_val_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter
), FALSE
);
1143 return prompter
->priv
->auto_prompt
;
1147 * e_credentials_prompter_set_auto_prompt:
1148 * @prompter: an #ECredentialsPrompter
1149 * @auto_prompt: new value of the auto-prompt property
1151 * Sets whether can respond to credential prompts automatically. That means that
1152 * whenever any ESource will ask for credentials, it'll try to provide them.
1154 * Use e_credentials_prompter_set_auto_prompt_disabled_for() to influence
1155 * auto-prompt per an #ESource.
1157 * This property does not influence direct calls of e_credentials_prompter_prompt().
1162 e_credentials_prompter_set_auto_prompt (ECredentialsPrompter
*prompter
,
1163 gboolean auto_prompt
)
1165 g_return_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter
));
1167 if ((prompter
->priv
->auto_prompt
? 1 : 0) == (auto_prompt
? 1 : 0))
1170 prompter
->priv
->auto_prompt
= auto_prompt
;
1172 g_object_notify (G_OBJECT (prompter
), "auto-prompt");
1176 * e_credentials_prompter_set_auto_prompt_disabled_for:
1177 * @prompter: an #ECredentialsPrompter
1178 * @source: an #ESource
1179 * @is_disabled: whether the auto-prompt should be disabled for this @source
1181 * Sets whether the auto-prompt should be disabled for the given @source.
1182 * All sources can be auto-prompted by default. This is a complementary
1183 * value for the ECredentialsPrompter::auto-prompt property.
1185 * This value does not influence direct calls of e_credentials_prompter_prompt().
1190 e_credentials_prompter_set_auto_prompt_disabled_for (ECredentialsPrompter
*prompter
,
1192 gboolean is_disabled
)
1194 g_return_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter
));
1195 g_return_if_fail (E_IS_SOURCE (source
));
1196 g_return_if_fail (e_source_get_uid (source
) != NULL
);
1198 g_mutex_lock (&prompter
->priv
->disabled_auto_prompt_lock
);
1201 g_hash_table_insert (prompter
->priv
->disabled_auto_prompt
, g_strdup (e_source_get_uid (source
)), GINT_TO_POINTER (1));
1203 g_hash_table_remove (prompter
->priv
->disabled_auto_prompt
, e_source_get_uid (source
));
1205 g_mutex_unlock (&prompter
->priv
->disabled_auto_prompt_lock
);
1209 * e_credentials_prompter_get_auto_prompt_disabled_for:
1210 * @prompter: an #ECredentialsPrompter
1211 * @source: an #ESource
1213 * Returns whether the auto-prompt is disabled for the given @source.
1214 * All sources can be auto-prompted by default. This is a complementary
1215 * value for the ECredentialsPrompter::auto-prompt property.
1217 * This value does not influence direct calls of e_credentials_prompter_prompt().
1219 * Returns: Whether the auto-prompt is disabled for the given @source
1224 e_credentials_prompter_get_auto_prompt_disabled_for (ECredentialsPrompter
*prompter
,
1227 gboolean is_disabled
;
1229 g_return_val_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter
), TRUE
);
1230 g_return_val_if_fail (E_IS_SOURCE (source
), TRUE
);
1231 g_return_val_if_fail (e_source_get_uid (source
) != NULL
, TRUE
);
1233 g_mutex_lock (&prompter
->priv
->disabled_auto_prompt_lock
);
1235 is_disabled
= g_hash_table_contains (prompter
->priv
->disabled_auto_prompt
, e_source_get_uid (source
));
1237 g_mutex_unlock (&prompter
->priv
->disabled_auto_prompt_lock
);
1243 credentials_prompter_guess_dialog_parent (ECredentialsPrompter
*prompter
)
1247 app
= g_application_get_default ();
1251 if (GTK_IS_APPLICATION (app
))
1252 return gtk_application_get_active_window (GTK_APPLICATION (app
));
1258 * e_credentials_prompter_get_dialog_parent:
1259 * @prompter: an #ECredentialsPrompter
1261 * Returns a #GtkWindow, which should be used as a dialog parent. This is determined
1262 * by an ECredentialsPrompter::get-dialog-parent signal emission. If there is no callback
1263 * registered or the current callbacks don't have any suitable window, then there's
1264 * chosen the last active window from the default GApplication, if any available.
1266 * Returns: (transfer none): a #GtkWindow, to be used as a dialog parent, or %NULL.
1271 e_credentials_prompter_get_dialog_parent (ECredentialsPrompter
*prompter
)
1273 GtkWindow
*parent
= NULL
;
1275 g_return_val_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter
), NULL
);
1277 g_signal_emit (prompter
, signals
[GET_DIALOG_PARENT
], 0, &parent
);
1280 parent
= credentials_prompter_guess_dialog_parent (prompter
);
1286 * e_credentials_prompter_register_impl:
1287 * @prompter: an #ECredentialsPrompter
1288 * @authentication_method: (allow-none): an authentication method to registr @prompter_impl for; or %NULL
1289 * @prompter_impl: an #ECredentialsPrompterImpl
1291 * Registers a prompter implementation for a given authentication method. If there is
1292 * registered a prompter for the same @authentication_method, then the function does
1293 * nothing, otherwise it adds its own reference on the @prompter_impl, and uses it
1294 * for that authentication method. One @prompter_impl can be registered for multiple
1295 * authentication methods.
1297 * A special value %NULL can be used for the @authentication_method, which means
1298 * a default credentials prompter, that is to be used when there is no prompter
1299 * registered for the exact authentication method.
1301 * Returns: %TRUE on success, %FALSE on failure or when there was another prompter
1302 * implementation registered for the given authentication method.
1307 e_credentials_prompter_register_impl (ECredentialsPrompter
*prompter
,
1308 const gchar
*authentication_method
,
1309 ECredentialsPrompterImpl
*prompter_impl
)
1311 guint known_prompters
;
1313 g_return_val_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter
), FALSE
);
1314 g_return_val_if_fail (E_IS_CREDENTIALS_PROMPTER_IMPL (prompter_impl
), FALSE
);
1316 if (!authentication_method
)
1317 authentication_method
= "";
1319 g_mutex_lock (&prompter
->priv
->prompters_lock
);
1321 if (g_hash_table_lookup (prompter
->priv
->prompters
, authentication_method
) != NULL
) {
1322 g_mutex_unlock (&prompter
->priv
->prompters_lock
);
1326 g_hash_table_insert (prompter
->priv
->prompters
, g_strdup (authentication_method
), g_object_ref (prompter_impl
));
1328 known_prompters
= GPOINTER_TO_UINT (g_hash_table_lookup (prompter
->priv
->known_prompters
, prompter_impl
));
1329 if (!known_prompters
) {
1330 g_signal_connect (prompter_impl
, "prompt-finished", G_CALLBACK (credentials_prompter_prompt_finished_cb
), prompter
);
1332 g_hash_table_insert (prompter
->priv
->known_prompters
, prompter_impl
, GUINT_TO_POINTER (known_prompters
+ 1));
1334 g_mutex_unlock (&prompter
->priv
->prompters_lock
);
1340 * e_credentials_prompter_unregister_impl:
1341 * @prompter: an #ECredentialsPrompter
1342 * @authentication_method: (allow-none): an authentication method to registr @prompter_impl for; or %NULL
1343 * @prompter_impl: an #ECredentialsPrompterImpl
1345 * Unregisters previously registered @prompter_impl for the given @autnetication_method with
1346 * e_credentials_prompter_register_impl(). Function does nothing, if no such authentication
1347 * method is registered or if it has set a different prompter implementation.
1352 e_credentials_prompter_unregister_impl (ECredentialsPrompter
*prompter
,
1353 const gchar
*authentication_method
,
1354 ECredentialsPrompterImpl
*prompter_impl
)
1356 ECredentialsPrompterImpl
*current_prompter_impl
;
1358 g_return_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter
));
1360 if (!authentication_method
)
1361 authentication_method
= "";
1363 g_mutex_lock (&prompter
->priv
->prompters_lock
);
1365 current_prompter_impl
= g_hash_table_lookup (prompter
->priv
->prompters
, authentication_method
);
1366 if (current_prompter_impl
== prompter_impl
) {
1367 guint known_prompters
;
1369 known_prompters
= GPOINTER_TO_UINT (g_hash_table_lookup (prompter
->priv
->known_prompters
, prompter_impl
));
1370 if (known_prompters
== 1) {
1371 g_signal_handlers_disconnect_by_func (prompter_impl
, credentials_prompter_prompt_finished_cb
, prompter
);
1372 g_hash_table_remove (prompter
->priv
->known_prompters
, prompter_impl
);
1375 g_hash_table_insert (prompter
->priv
->known_prompters
, prompter_impl
, GUINT_TO_POINTER (known_prompters
+ 1));
1378 g_hash_table_remove (prompter
->priv
->prompters
, authentication_method
);
1381 g_mutex_unlock (&prompter
->priv
->prompters_lock
);
1385 credentials_prompter_get_last_credentials_required_arguments_cb (GObject
*source_object
,
1386 GAsyncResult
*result
,
1389 ECredentialsPrompter
*prompter
= user_data
;
1391 ESourceCredentialsReason reason
= E_SOURCE_CREDENTIALS_REASON_UNKNOWN
;
1392 gchar
*certificate_pem
= NULL
;
1393 GTlsCertificateFlags certificate_errors
= 0;
1394 GError
*op_error
= NULL
;
1395 GError
*error
= NULL
;
1397 g_return_if_fail (E_IS_SOURCE (source_object
));
1399 source
= E_SOURCE (source_object
);
1401 if (!e_source_get_last_credentials_required_arguments_finish (source
, result
,
1402 &reason
, &certificate_pem
, &certificate_errors
, &op_error
, &error
)) {
1403 if (!g_error_matches (error
, G_IO_ERROR
, G_IO_ERROR_CANCELLED
)) {
1404 g_warning ("%s: Failed to get last credential values: %s", G_STRFUNC
, error
? error
->message
: "Unknown error");
1407 g_clear_error (&error
);
1411 /* Can check only now, when know the operation was not cancelled and the prompter freed. */
1412 g_return_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter
));
1414 /* Check once again, as this was called asynchronously and anything could change meanwhile. */
1415 if (e_source_get_connection_status (source
) == E_SOURCE_CONNECTION_STATUS_AWAITING_CREDENTIALS
) {
1416 credentials_prompter_credentials_required_cb (prompter
->priv
->registry
,
1417 source
, reason
, certificate_pem
, certificate_errors
, op_error
, prompter
);
1420 g_free (certificate_pem
);
1421 g_clear_error (&op_error
);
1425 * e_credentials_prompter_process_awaiting_credentials:
1426 * @prompter: an #ECredentialsPrompter
1428 * Process all enabled sources with connection state #E_SOURCE_CONNECTION_STATUS_AWAITING_CREDENTIALS,
1429 * like if they just asked for its credentials for the first time.
1434 e_credentials_prompter_process_awaiting_credentials (ECredentialsPrompter
*prompter
)
1436 GList
*sources
, *link
;
1438 g_return_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter
));
1440 sources
= e_source_registry_list_enabled (prompter
->priv
->registry
, NULL
);
1441 for (link
= sources
; link
; link
= g_list_next (link
)) {
1442 ESource
*source
= link
->data
;
1447 if (e_source_get_connection_status (source
) == E_SOURCE_CONNECTION_STATUS_AWAITING_CREDENTIALS
) {
1448 /* Check what failed the last time */
1449 e_credentials_prompter_process_source (prompter
, source
);
1453 g_list_free_full (sources
, g_object_unref
);
1457 * e_credentials_prompter_process_source:
1458 * @prompter: an #ECredentialsPrompter
1459 * @source: an #ESource
1461 * Continues a credential prompt for @source. Returns, whether anything wil be done.
1462 * The %FALSE either means that the @source<!-- -->'s connection status is not
1463 * the %E_SOURCE_CONNECTION_STATUS_AWAITING_CREDENTIALS.
1465 * Returns: Whether continues with the credentials prompt.
1470 e_credentials_prompter_process_source (ECredentialsPrompter
*prompter
,
1473 g_return_val_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter
), FALSE
);
1474 g_return_val_if_fail (E_IS_SOURCE (source
), FALSE
);
1476 if (e_source_get_connection_status (source
) != E_SOURCE_CONNECTION_STATUS_AWAITING_CREDENTIALS
)
1479 e_source_get_last_credentials_required_arguments (source
, prompter
->priv
->cancellable
,
1480 credentials_prompter_get_last_credentials_required_arguments_cb
, prompter
);
1486 * e_credentials_prompter_prompt:
1487 * @prompter: an #ECredentialsPrompter
1488 * @source: an #ESource, which prompt the credentials for
1489 * @error_text: (allow-none): Additional error text to show to a user, or %NULL
1490 * @flags: a bit-or of #ECredentialsPrompterPromptFlags
1491 * @callback: (allow-none): a callback to call when the credentials are ready, or %NULL
1492 * @user_data: user data passed into @callback
1494 * Asks the @prompter to prompt for credentials, which are returned
1495 * to the caller through @callback, when available.The @flags are ignored,
1496 * when the @callback is %NULL; the credentials are passed to the @source
1497 * with e_source_invoke_authenticate() directly, in this case.
1498 * Call e_credentials_prompter_prompt_finish() in @callback to get to
1499 * the provided credentials.
1504 e_credentials_prompter_prompt (ECredentialsPrompter
*prompter
,
1506 const gchar
*error_text
,
1507 ECredentialsPrompterPromptFlags flags
,
1508 GAsyncReadyCallback callback
,
1511 CredentialsPromptData
*prompt_data
;
1513 g_return_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter
));
1514 g_return_if_fail (E_IS_SOURCE (source
));
1516 prompt_data
= g_new0 (CredentialsPromptData
, 1);
1517 prompt_data
->source
= g_object_ref (source
);
1518 prompt_data
->error_text
= g_strdup (error_text
);
1519 prompt_data
->flags
= flags
;
1520 prompt_data
->async_result
= callback
? g_simple_async_result_new (G_OBJECT (prompter
),
1521 callback
, user_data
, e_credentials_prompter_prompt
) : NULL
;
1523 /* Just it can be shown in the UI as a prefilled value and the right source (collection) is used. */
1524 credentials_prompter_lookup_source_details (source
, prompter
,
1525 credentials_prompter_lookup_source_details_before_prompt_cb
, prompt_data
);
1529 * e_credentials_prompter_prompt_finish:
1530 * @prompter: an #ECredentialsPrompter
1531 * @result: a #GAsyncResult
1532 * @out_source: (transfer full): (allow-none): optionally set to an #ESource, on which the prompt was started; can be %NULL
1533 * @out_credentials: (transfer full): set to an #ENamedParameters with provied credentials
1534 * @error: return location for a #GError, or %NULL
1536 * Finishes a credentials prompt previously started with e_credentials_prompter_prompt().
1537 * The @out_source will have set a referenced #ESource, for which the prompt
1538 * was started. Unref it, when no longer needed. Similarly the @out_credentials
1539 * will have set a newly allocated #ENamedParameters structure with provided credentials,
1540 * which should be freed with e_named_credentials_free() when no longer needed.
1541 * Both output arguments will be set to %NULL on error and %FALSE will be returned.
1543 * Returns: %TRUE on success, %FALSE otherwise.
1548 e_credentials_prompter_prompt_finish (ECredentialsPrompter
*prompter
,
1549 GAsyncResult
*result
,
1550 ESource
**out_source
,
1551 ENamedParameters
**out_credentials
,
1554 CredentialsResultData
*data
;
1556 g_return_val_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter
), FALSE
);
1557 g_return_val_if_fail (g_simple_async_result_get_source_tag (G_SIMPLE_ASYNC_RESULT (result
))
1558 == e_credentials_prompter_prompt
, FALSE
);
1559 g_return_val_if_fail (out_credentials
, FALSE
);
1563 *out_credentials
= NULL
;
1565 if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result
), error
))
1568 data
= g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result
));
1569 g_return_val_if_fail (data
!= NULL
, FALSE
);
1571 if (data
->credentials
) {
1573 *out_source
= g_object_ref (data
->source
);
1574 *out_credentials
= e_named_parameters_new_clone (data
->credentials
);
1576 g_set_error_literal (error
, G_IO_ERROR
, G_IO_ERROR_CANCELLED
, _("Credentials prompt was cancelled"));
1585 * e_credentials_prompter_complete_prompt_call:
1586 * @prompter: an #ECredentialsPrompter
1587 * @async_result: a #GSimpleAsyncResult
1588 * @source: an #ESource, on which the prompt was started
1589 * @credentials: (allow-none): credentials, as provided by a user, on %NULL, when the prompt was cancelled
1590 * @error: (allow-none): a resulting #GError, or %NULL
1592 * Completes an ongoing credentials prompt on idle, by finishing the @async_result.
1593 * This function is meant to be used by an #ECredentialsPrompterImpl implementation.
1594 * To actually finish the credentials prompt previously started with
1595 * e_credentials_prompter_prompt(), the e_credentials_prompter_prompt_finish() should
1596 * be called from the provided callback.
1598 * Using %NULL @credentials will result in a G_IO_ERROR_CANCELLED error, if
1599 * no other @error is provided.
1604 e_credentials_prompter_complete_prompt_call (ECredentialsPrompter
*prompter
,
1605 GSimpleAsyncResult
*async_result
,
1607 const ENamedParameters
*credentials
,
1608 const GError
*error
)
1610 g_return_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter
));
1611 g_return_if_fail (G_IS_SIMPLE_ASYNC_RESULT (async_result
));
1612 g_return_if_fail (g_simple_async_result_get_source_tag (async_result
) == e_credentials_prompter_prompt
);
1613 g_return_if_fail (source
== NULL
|| E_IS_SOURCE (source
));
1615 g_return_if_fail (E_IS_SOURCE (source
));
1618 g_simple_async_result_set_from_error (async_result
, error
);
1619 } else if (!credentials
) {
1620 g_simple_async_result_set_error (async_result
, G_IO_ERROR
, G_IO_ERROR_CANCELLED
, _("Credentials prompt was cancelled"));
1622 CredentialsResultData
*result
;
1624 result
= g_new0 (CredentialsResultData
, 1);
1625 result
->source
= g_object_ref (source
);
1626 result
->credentials
= e_named_parameters_new_clone (credentials
);
1628 g_simple_async_result_set_op_res_gpointer (async_result
, result
, credentials_result_data_free
);
1631 g_simple_async_result_complete_in_idle (async_result
);
1635 credentials_prompter_prompt_sync (ECredentialsPrompter
*prompter
,
1638 ECredentialsPrompterPromptFlags
*flags
,
1639 const gchar
*error_text
,
1640 ENamedParameters
**out_credentials
,
1641 GCancellable
*cancellable
,
1644 gboolean res
= FALSE
;
1645 ESourceCredentialsProvider
*credentials_provider
;
1646 ENamedParameters
*credentials
= NULL
;
1648 g_return_val_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter
), FALSE
);
1649 g_return_val_if_fail (E_IS_SOURCE (source
), FALSE
);
1650 g_return_val_if_fail (flags
!= NULL
, FALSE
);
1651 g_return_val_if_fail (out_credentials
!= NULL
, FALSE
);
1653 if (g_cancellable_set_error_if_cancelled (cancellable
, error
))
1656 credentials_provider
= e_credentials_prompter_get_provider (prompter
);
1659 ESource
*cred_source
;
1660 GError
*local_error
= NULL
;
1662 cred_source
= e_source_credentials_provider_ref_credentials_source (credentials_provider
, source
);
1664 if (e_source_credentials_provider_lookup_sync (credentials_provider
, cred_source
? cred_source
: source
,
1665 cancellable
, &credentials
, &local_error
)) {
1667 } else if (!g_cancellable_is_cancelled (cancellable
)) {
1668 /* To prompt for the password directly */
1670 g_clear_error (&local_error
);
1672 g_propagate_error (error
, local_error
);
1675 g_clear_object (&cred_source
);
1679 EAsyncClosure
*closure
;
1680 GAsyncResult
*result
;
1682 *flags
= (*flags
) & (~E_CREDENTIALS_PROMPTER_PROMPT_FLAG_ALLOW_STORED_CREDENTIALS
);
1684 closure
= e_async_closure_new ();
1686 e_credentials_prompter_prompt (prompter
, source
, error_text
, *flags
,
1687 e_async_closure_callback
, closure
);
1689 result
= e_async_closure_wait (closure
);
1691 if (e_credentials_prompter_prompt_finish (prompter
, result
, NULL
, &credentials
, error
)) {
1695 e_async_closure_free (closure
);
1698 if (res
&& credentials
)
1699 *out_credentials
= e_named_parameters_new_clone (credentials
);
1701 e_named_parameters_free (credentials
);
1707 * e_credentials_prompter_loop_prompt_sync:
1708 * @prompter: an #ECredentialsPrompter
1709 * @source: an #ESource to be prompted credentials for
1710 * @flags: a bit-or of #ECredentialsPrompterPromptFlags initial flags
1711 * @func: (scope call): an #ECredentialsPrompterLoopPromptFunc user function to call to check provided credentials
1712 * @user_data: user data to pass to @func
1713 * @cancellable: (allow-none): an optional #GCancellable, or %NULL
1714 * @error: (allow-none): a #GError, to store any errors to, or %NULL
1716 * Runs a credentials prompt loop for @source, as long as the @func doesn't
1717 * indicate that the provided credentials can be used to successfully
1718 * authenticate against @source<!-- -->'s server, or that the @func
1719 * returns %FALSE. The loop is also teminated when a used cancels
1720 * the credentials prompt or the @cancellable is cancelled, though
1721 * not sooner than the credentials prompt dialog is closed.
1723 * Note: The function doesn't return until the loop is terminated, either
1724 * successfully or unsuccessfully. The function can be called from any
1725 * thread, though a dedicated thread is preferred.
1727 * Returns: %TRUE, when the credentials were provided sucessfully and they
1728 * can be used to authenticate the @source; %FALSE otherwise.
1733 e_credentials_prompter_loop_prompt_sync (ECredentialsPrompter
*prompter
,
1735 ECredentialsPrompterPromptFlags flags
,
1736 ECredentialsPrompterLoopPromptFunc func
,
1738 GCancellable
*cancellable
,
1741 gboolean is_retry
, authenticated
;
1742 ENamedParameters
*credentials
= NULL
;
1744 g_return_val_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter
), FALSE
);
1745 g_return_val_if_fail (E_IS_SOURCE (source
), FALSE
);
1746 g_return_val_if_fail (func
!= NULL
, FALSE
);
1749 authenticated
= FALSE
;
1751 while (!authenticated
&& !g_cancellable_is_cancelled (cancellable
)) {
1752 GError
*local_error
= NULL
;
1754 e_named_parameters_free (credentials
);
1757 if (!credentials_prompter_prompt_sync (prompter
, source
, is_retry
, &flags
, NULL
,
1758 &credentials
, cancellable
, error
))
1761 if (g_cancellable_set_error_if_cancelled (cancellable
, error
))
1764 g_clear_error (&local_error
);
1766 if (!func (prompter
, source
, credentials
, &authenticated
, user_data
, cancellable
, &local_error
)) {
1768 g_propagate_error (error
, local_error
);
1775 e_named_parameters_free (credentials
);
1777 return authenticated
;