4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) version 3.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with the program; if not, see <http://www.gnu.org/licenses/>
18 * Copyright (C) 2011 Red Hat, Inc. (www.redhat.com)
26 #include <glib/gi18n-lib.h>
28 #include <libsoup/soup.h>
30 #include <libedataserver/e-client.h>
31 #include "libedataserver/e-client-private.h"
32 #include <libebook/e-book-client.h>
33 #include <libecal/e-cal-client.h>
35 #include "e-passwords.h"
36 #include "e-client-utils.h"
41 * Proxy function for e_book_client_utils_new() and e_cal_client_utils_new().
46 e_client_utils_new (ESource *source,
47 EClientSourceType source_type,
52 g_return_val_if_fail (source != NULL, NULL);
53 g_return_val_if_fail (E_IS_SOURCE (source), NULL);
55 switch (source_type) {
56 case E_CLIENT_SOURCE_TYPE_CONTACTS:
57 res = E_CLIENT (e_book_client_new (source, error));
59 case E_CLIENT_SOURCE_TYPE_EVENTS:
60 res = E_CLIENT (e_cal_client_new (source, E_CAL_CLIENT_SOURCE_TYPE_EVENTS, error));
62 case E_CLIENT_SOURCE_TYPE_MEMOS:
63 res = E_CLIENT (e_cal_client_new (source, E_CAL_CLIENT_SOURCE_TYPE_MEMOS, error));
65 case E_CLIENT_SOURCE_TYPE_TASKS:
66 res = E_CLIENT (e_cal_client_new (source, E_CAL_CLIENT_SOURCE_TYPE_TASKS, error));
69 g_return_val_if_reached (NULL);
77 * e_client_utils_new_from_uri:
79 * Proxy function for e_book_client_utils_new_from_uri() and e_cal_client_utils_new_from_uri().
84 e_client_utils_new_from_uri (const gchar *uri,
85 EClientSourceType source_type,
90 g_return_val_if_fail (uri != NULL, NULL);
92 switch (source_type) {
93 case E_CLIENT_SOURCE_TYPE_CONTACTS:
94 res = E_CLIENT (e_book_client_new_from_uri (uri, error));
96 case E_CLIENT_SOURCE_TYPE_EVENTS:
97 res = E_CLIENT (e_cal_client_new_from_uri (uri, E_CAL_CLIENT_SOURCE_TYPE_EVENTS, error));
99 case E_CLIENT_SOURCE_TYPE_MEMOS:
100 res = E_CLIENT (e_cal_client_new_from_uri (uri, E_CAL_CLIENT_SOURCE_TYPE_MEMOS, error));
102 case E_CLIENT_SOURCE_TYPE_TASKS:
103 res = E_CLIENT (e_cal_client_new_from_uri (uri, E_CAL_CLIENT_SOURCE_TYPE_TASKS, error));
106 g_return_val_if_reached (NULL);
114 * e_client_utils_new_system:
116 * Proxy function for e_book_client_utils_new_system() and e_cal_client_utils_new_system().
121 e_client_utils_new_system (EClientSourceType source_type,
126 switch (source_type) {
127 case E_CLIENT_SOURCE_TYPE_CONTACTS:
128 res = E_CLIENT (e_book_client_new_system (error));
130 case E_CLIENT_SOURCE_TYPE_EVENTS:
131 res = E_CLIENT (e_cal_client_new_system (E_CAL_CLIENT_SOURCE_TYPE_EVENTS, error));
133 case E_CLIENT_SOURCE_TYPE_MEMOS:
134 res = E_CLIENT (e_cal_client_new_system (E_CAL_CLIENT_SOURCE_TYPE_MEMOS, error));
136 case E_CLIENT_SOURCE_TYPE_TASKS:
137 res = E_CLIENT (e_cal_client_new_system (E_CAL_CLIENT_SOURCE_TYPE_TASKS, error));
140 g_return_val_if_reached (NULL);
148 * e_client_utils_new_default:
150 * Proxy function for e_book_client_utils_new_default() and e_cal_client_utils_new_default().
155 e_client_utils_new_default (EClientSourceType source_type,
160 switch (source_type) {
161 case E_CLIENT_SOURCE_TYPE_CONTACTS:
162 res = E_CLIENT (e_book_client_new_default (error));
164 case E_CLIENT_SOURCE_TYPE_EVENTS:
165 res = E_CLIENT (e_cal_client_new_default (E_CAL_CLIENT_SOURCE_TYPE_EVENTS, error));
167 case E_CLIENT_SOURCE_TYPE_MEMOS:
168 res = E_CLIENT (e_cal_client_new_default (E_CAL_CLIENT_SOURCE_TYPE_MEMOS, error));
170 case E_CLIENT_SOURCE_TYPE_TASKS:
171 res = E_CLIENT (e_cal_client_new_default (E_CAL_CLIENT_SOURCE_TYPE_TASKS, error));
174 g_return_val_if_reached (NULL);
182 * e_client_utils_set_default:
184 * Proxy function for e_book_client_utils_set_default() and e_book_client_utils_set_default().
189 e_client_utils_set_default (EClient *client,
190 EClientSourceType source_type,
193 gboolean res = FALSE;
195 g_return_val_if_fail (client != NULL, FALSE);
196 g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
198 switch (source_type) {
199 case E_CLIENT_SOURCE_TYPE_CONTACTS:
200 g_return_val_if_fail (E_IS_BOOK_CLIENT (client), FALSE);
201 res = e_book_client_set_default (E_BOOK_CLIENT (client), error);
203 case E_CLIENT_SOURCE_TYPE_EVENTS:
204 case E_CLIENT_SOURCE_TYPE_MEMOS:
205 case E_CLIENT_SOURCE_TYPE_TASKS:
206 g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
207 res = e_cal_client_set_default (E_CAL_CLIENT (client), error);
210 g_return_val_if_reached (FALSE);
218 * e_client_utils_set_default_source:
220 * Proxy function for e_book_client_utils_set_default_source() and e_cal_client_utils_set_default_source().
225 e_client_utils_set_default_source (ESource *source,
226 EClientSourceType source_type,
229 gboolean res = FALSE;
231 g_return_val_if_fail (source != NULL, FALSE);
232 g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
234 switch (source_type) {
235 case E_CLIENT_SOURCE_TYPE_CONTACTS:
236 res = e_book_client_set_default_source (source, error);
238 case E_CLIENT_SOURCE_TYPE_EVENTS:
239 res = e_cal_client_set_default_source (source, E_CAL_CLIENT_SOURCE_TYPE_EVENTS, error);
241 case E_CLIENT_SOURCE_TYPE_MEMOS:
242 res = e_cal_client_set_default_source (source, E_CAL_CLIENT_SOURCE_TYPE_MEMOS, error);
244 case E_CLIENT_SOURCE_TYPE_TASKS:
245 res = e_cal_client_set_default_source (source, E_CAL_CLIENT_SOURCE_TYPE_TASKS, error);
248 g_return_val_if_reached (FALSE);
256 * e_client_utils_get_sources:
258 * Proxy function for e_book_client_utils_get_sources() and e_cal_client_utils_get_sources().
263 e_client_utils_get_sources (ESourceList **sources,
264 EClientSourceType source_type,
267 gboolean res = FALSE;
269 g_return_val_if_fail (sources != NULL, FALSE);
271 switch (source_type) {
272 case E_CLIENT_SOURCE_TYPE_CONTACTS:
273 res = e_book_client_get_sources (sources, error);
275 case E_CLIENT_SOURCE_TYPE_EVENTS:
276 res = e_cal_client_get_sources (sources, E_CAL_CLIENT_SOURCE_TYPE_EVENTS, error);
278 case E_CLIENT_SOURCE_TYPE_MEMOS:
279 res = e_cal_client_get_sources (sources, E_CAL_CLIENT_SOURCE_TYPE_MEMOS, error);
281 case E_CLIENT_SOURCE_TYPE_TASKS:
282 res = e_cal_client_get_sources (sources, E_CAL_CLIENT_SOURCE_TYPE_TASKS, error);
285 g_return_val_if_reached (FALSE);
292 typedef struct _EClientUtilsAsyncOpData
294 EClientUtilsAuthenticateHandler auth_handler;
295 gpointer auth_handler_user_data;
296 GAsyncReadyCallback async_cb;
297 gpointer async_cb_user_data;
298 GCancellable *cancellable;
301 ECredentials *used_credentials;
302 gboolean open_finished;
303 GError *opened_cb_error;
305 gboolean only_if_exists;
306 guint pending_properties_count;
307 } EClientUtilsAsyncOpData;
310 free_client_utils_async_op_data (EClientUtilsAsyncOpData *async_data)
312 g_return_if_fail (async_data != NULL);
313 g_return_if_fail (async_data->cancellable != NULL);
314 g_return_if_fail (async_data->client != NULL);
316 if (async_data->retry_open_id)
317 g_source_remove (async_data->retry_open_id);
319 g_signal_handlers_disconnect_matched (async_data->cancellable, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, async_data);
320 g_signal_handlers_disconnect_matched (async_data->client, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, async_data);
322 if (async_data->used_credentials)
323 e_credentials_free (async_data->used_credentials);
324 if (async_data->opened_cb_error)
325 g_error_free (async_data->opened_cb_error);
326 g_object_unref (async_data->cancellable);
327 g_object_unref (async_data->client);
328 g_object_unref (async_data->source);
333 complete_async_op_in_idle_cb (gpointer user_data)
335 GSimpleAsyncResult *simple = user_data;
338 g_return_val_if_fail (simple != NULL, FALSE);
340 run_main_depth = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (simple), "run-main-depth"));
341 if (run_main_depth < 1)
344 /* do not receive in higher level than was initially run */
345 if (g_main_depth () > run_main_depth) {
349 g_simple_async_result_complete (simple);
350 g_object_unref (simple);
355 #define return_async_error_if_fail(expr, async_cb, async_cb_user_data, src, source_tag) G_STMT_START { \
356 if (G_LIKELY ((expr))) { } else { \
359 error = g_error_new (E_CLIENT_ERROR, E_CLIENT_ERROR_INVALID_ARG, \
360 "%s: assertion '%s' failed", G_STRFUNC, #expr); \
362 return_async_error (error, async_cb, async_cb_user_data, src, source_tag); \
363 g_error_free (error); \
369 return_async_error (const GError *error,
370 GAsyncReadyCallback async_cb,
371 gpointer async_cb_user_data,
375 GSimpleAsyncResult *simple;
377 g_return_if_fail (error != NULL);
378 g_return_if_fail (source_tag != NULL);
380 simple = g_simple_async_result_new (G_OBJECT (source), async_cb, async_cb_user_data, source_tag);
381 g_simple_async_result_set_from_error (simple, error);
383 g_object_set_data (G_OBJECT (simple), "run-main-depth", GINT_TO_POINTER (g_main_depth ()));
384 g_idle_add (complete_async_op_in_idle_cb, simple);
388 client_utils_get_backend_property_cb (GObject *source_object,
389 GAsyncResult *result,
392 EClient *client = E_CLIENT (source_object);
393 EClientUtilsAsyncOpData *async_data = user_data;
394 GSimpleAsyncResult *simple;
396 g_return_if_fail (async_data != NULL);
397 g_return_if_fail (async_data->client != NULL);
398 g_return_if_fail (async_data->client == client);
401 gchar *prop_value = NULL;
403 if (e_client_get_backend_property_finish (client, result, &prop_value, NULL))
406 async_data->pending_properties_count--;
407 if (async_data->pending_properties_count)
411 /* keep the initial auth_handler connected directly, thus it will be able
412 * to answer any later authentication requests, for reconnection, for example
414 if (async_data->auth_handler)
415 g_signal_connect (async_data->client, "authenticate", G_CALLBACK (async_data->auth_handler), async_data->auth_handler_user_data);
417 simple = g_simple_async_result_new (G_OBJECT (async_data->source), async_data->async_cb, async_data->async_cb_user_data, e_client_utils_open_new);
418 g_simple_async_result_set_op_res_gpointer (simple, g_object_ref (async_data->client), g_object_unref);
420 g_object_set_data (G_OBJECT (simple), "run-main-depth", GINT_TO_POINTER (g_main_depth ()));
421 g_idle_add (complete_async_op_in_idle_cb, simple);
423 free_client_utils_async_op_data (async_data);
427 client_utils_capabilities_retrieved_cb (GObject *source_object,
428 GAsyncResult *result,
431 EClient *client = E_CLIENT (source_object);
432 EClientUtilsAsyncOpData *async_data = user_data;
433 gchar *capabilities = NULL;
436 g_return_if_fail (async_data != NULL);
437 g_return_if_fail (async_data->client != NULL);
438 g_return_if_fail (async_data->client == client);
440 caps_res = e_client_retrieve_capabilities_finish (client, result, &capabilities, NULL);
441 g_free (capabilities);
444 async_data->pending_properties_count = 1;
446 /* precache backend properties */
447 if (E_IS_CAL_CLIENT (client)) {
448 async_data->pending_properties_count += 3;
450 e_client_get_backend_property (async_data->client, CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS, async_data->cancellable, client_utils_get_backend_property_cb, async_data);
451 e_client_get_backend_property (async_data->client, CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS, async_data->cancellable, client_utils_get_backend_property_cb, async_data);
452 e_client_get_backend_property (async_data->client, CAL_BACKEND_PROPERTY_DEFAULT_OBJECT, async_data->cancellable, client_utils_get_backend_property_cb, async_data);
453 } else if (E_IS_BOOK_CLIENT (client)) {
454 async_data->pending_properties_count += 3;
456 e_client_get_backend_property (async_data->client, BOOK_BACKEND_PROPERTY_REQUIRED_FIELDS, async_data->cancellable, client_utils_get_backend_property_cb, async_data);
457 e_client_get_backend_property (async_data->client, BOOK_BACKEND_PROPERTY_SUPPORTED_FIELDS, async_data->cancellable, client_utils_get_backend_property_cb, async_data);
458 e_client_get_backend_property (async_data->client, BOOK_BACKEND_PROPERTY_SUPPORTED_AUTH_METHODS, async_data->cancellable, client_utils_get_backend_property_cb, async_data);
460 g_warn_if_reached ();
461 client_utils_get_backend_property_cb (source_object, NULL, async_data);
465 e_client_get_backend_property (async_data->client, CLIENT_BACKEND_PROPERTY_CACHE_DIR, async_data->cancellable, client_utils_get_backend_property_cb, async_data);
467 client_utils_get_backend_property_cb (source_object, NULL, async_data);
472 client_utils_open_new_done (EClientUtilsAsyncOpData *async_data)
474 g_return_if_fail (async_data != NULL);
475 g_return_if_fail (async_data->client != NULL);
477 /* retrieve capabilities just to have them cached on #EClient for later use */
478 e_client_retrieve_capabilities (async_data->client, async_data->cancellable, client_utils_capabilities_retrieved_cb, async_data);
481 static gboolean client_utils_retry_open_timeout_cb (gpointer user_data);
484 finish_or_retry_open (EClientUtilsAsyncOpData *async_data,
487 g_return_if_fail (async_data != NULL);
489 if (async_data->auth_handler && error && g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_AUTHENTICATION_FAILED)) {
490 if (async_data->used_credentials) {
491 const gchar *prompt_key;
493 prompt_key = e_credentials_peek (async_data->used_credentials, E_CREDENTIALS_KEY_PROMPT_KEY);
495 /* make sure the old password is forgotten when authentication failed */
497 e_passwords_forget_password (NULL, prompt_key);
499 e_credentials_set (async_data->used_credentials, E_CREDENTIALS_KEY_PROMPT_REASON, error->message);
502 e_client_process_authentication (async_data->client, async_data->used_credentials);
503 } else if (error && g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_BUSY)) {
504 /* postpone for 1/2 of a second, backend is busy now */
505 async_data->open_finished = FALSE;
506 async_data->retry_open_id = g_timeout_add (500, client_utils_retry_open_timeout_cb, async_data);
508 return_async_error (error, async_data->async_cb, async_data->async_cb_user_data, async_data->source, e_client_utils_open_new);
509 free_client_utils_async_op_data (async_data);
511 client_utils_open_new_done (async_data);
516 client_utils_opened_cb (EClient *client,
518 EClientUtilsAsyncOpData *async_data)
520 g_return_if_fail (client != NULL);
521 g_return_if_fail (async_data != NULL);
522 g_return_if_fail (client == async_data->client);
524 g_signal_handlers_disconnect_by_func (client, G_CALLBACK (client_utils_opened_cb), async_data);
526 if (!async_data->open_finished) {
527 /* there can happen that the "opened" signal is received
528 * before the e_client_open () is finished, thus keep detailed
529 * error for later use, if any */
531 async_data->opened_cb_error = g_error_copy (error);
533 finish_or_retry_open (async_data, error);
538 client_utils_open_new_async_cb (GObject *source_object,
539 GAsyncResult *result,
542 EClientUtilsAsyncOpData *async_data = user_data;
543 GError *error = NULL;
545 g_return_if_fail (source_object != NULL);
546 g_return_if_fail (result != NULL);
547 g_return_if_fail (async_data != NULL);
548 g_return_if_fail (async_data->async_cb != NULL);
549 g_return_if_fail (async_data->client == E_CLIENT (source_object));
551 async_data->open_finished = TRUE;
553 if (!e_client_open_finish (E_CLIENT (source_object), result, &error)
554 || g_cancellable_set_error_if_cancelled (async_data->cancellable, &error)) {
555 finish_or_retry_open (async_data, error);
556 g_error_free (error);
560 if (async_data->opened_cb_error) {
561 finish_or_retry_open (async_data, async_data->opened_cb_error);
565 if (e_client_is_opened (async_data->client)) {
566 client_utils_open_new_done (async_data);
570 /* wait for 'opened' signal, which is received in client_utils_opened_cb */
574 client_utils_retry_open_timeout_cb (gpointer user_data)
576 EClientUtilsAsyncOpData *async_data = user_data;
578 g_return_val_if_fail (async_data != NULL, FALSE);
580 g_signal_handlers_disconnect_matched (async_data->cancellable, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, async_data);
582 e_client_open (async_data->client, async_data->only_if_exists, async_data->cancellable, client_utils_open_new_async_cb, async_data);
584 async_data->retry_open_id = 0;
590 client_utils_open_new_auth_cb (EClient *client,
591 ECredentials *credentials,
594 EClientUtilsAsyncOpData *async_data = user_data;
597 g_return_val_if_fail (client != NULL, FALSE);
598 g_return_val_if_fail (async_data != NULL, FALSE);
599 g_return_val_if_fail (async_data->auth_handler != NULL, FALSE);
601 if (async_data->used_credentials) {
602 const gchar *reason = e_credentials_peek (async_data->used_credentials, E_CREDENTIALS_KEY_PROMPT_REASON);
605 e_credentials_set (credentials, E_CREDENTIALS_KEY_PROMPT_TEXT, NULL);
606 e_credentials_set (credentials, E_CREDENTIALS_KEY_PROMPT_REASON, reason);
610 handled = async_data->auth_handler (client, credentials, async_data->auth_handler_user_data);
612 if (handled && credentials) {
613 if (async_data->used_credentials) {
614 gchar *prompt_flags_str;
615 guint prompt_flags = 0;
617 e_credentials_free (async_data->used_credentials);
619 prompt_flags_str = e_credentials_get (credentials, E_CREDENTIALS_KEY_PROMPT_FLAGS);
620 if (prompt_flags_str) {
621 prompt_flags = e_credentials_util_string_to_prompt_flags (prompt_flags_str);
622 g_free (prompt_flags_str);
624 prompt_flags = E_CREDENTIALS_PROMPT_FLAG_REMEMBER_FOREVER
625 | E_CREDENTIALS_PROMPT_FLAG_SECRET
626 | E_CREDENTIALS_PROMPT_FLAG_ONLINE;
629 prompt_flags |= E_CREDENTIALS_PROMPT_FLAG_REPROMPT;
631 prompt_flags_str = e_credentials_util_prompt_flags_to_string (prompt_flags);
632 e_credentials_set (credentials, E_CREDENTIALS_KEY_PROMPT_FLAGS, prompt_flags_str);
633 g_free (prompt_flags_str);
636 async_data->used_credentials = e_credentials_new_clone (credentials);
643 * e_client_utils_open_new:
644 * @source: an #ESource to be opened
645 * @source_type: an #EClientSourceType of the @source
646 * @only_if_exists: if %TRUE, fail if this client doesn't already exist, otherwise create it first
647 * @cancellable: a #GCancellable; can be %NULL
648 * @auth_handler: authentication handler, to be used; the e_client_utils_authenticate_handler() is usually sufficient
649 * @auth_handler_user_data: user data for @auth_handler function
650 * @async_cb: callback to call when a result is ready
651 * @async_cb_user_data: user data for the @async_cb
653 * Begins asynchronous opening of a new #EClient corresponding
654 * to the @source of type @source_type. The resulting #EClient
655 * is fully opened and authenticated client, ready to be used.
656 * The opened client has also fetched capabilities.
657 * This call is finished by e_client_utils_open_new_finish()
658 * from the @async_cb.
660 * Note: the @auth_handler, and its @auth_handler_user_data,
661 * should be valid through whole live of returned #EClient.
666 e_client_utils_open_new (ESource *source,
667 EClientSourceType source_type,
668 gboolean only_if_exists,
669 GCancellable *cancellable,
670 EClientUtilsAuthenticateHandler auth_handler,
671 gpointer auth_handler_user_data,
672 GAsyncReadyCallback async_cb,
673 gpointer async_cb_user_data)
676 GError *error = NULL;
677 EClientUtilsAsyncOpData *async_data;
679 g_return_if_fail (async_cb != NULL);
680 return_async_error_if_fail (source != NULL, async_cb, async_cb_user_data, source, e_client_utils_open_new);
681 return_async_error_if_fail (E_IS_SOURCE (source), async_cb, async_cb_user_data, source, e_client_utils_open_new);
683 client = e_client_utils_new (source, source_type, &error);
685 return_async_error (error, async_cb, async_cb_user_data, source, e_client_utils_open_new);
686 g_error_free (error);
690 async_data = g_new0 (EClientUtilsAsyncOpData, 1);
691 async_data->auth_handler = auth_handler;
692 async_data->auth_handler_user_data = auth_handler_user_data;
693 async_data->async_cb = async_cb;
694 async_data->async_cb_user_data = async_cb_user_data;
695 async_data->source = g_object_ref (source);
696 async_data->client = client;
697 async_data->open_finished = FALSE;
698 async_data->only_if_exists = only_if_exists;
699 async_data->retry_open_id = 0;
702 async_data->cancellable = g_object_ref (cancellable);
704 async_data->cancellable = g_cancellable_new ();
707 g_signal_connect (client, "authenticate", G_CALLBACK (client_utils_open_new_auth_cb), async_data);
709 /* wait till backend notifies about its opened state */
710 g_signal_connect (client, "opened", G_CALLBACK (client_utils_opened_cb), async_data);
712 e_client_open (async_data->client, async_data->only_if_exists, async_data->cancellable, client_utils_open_new_async_cb, async_data);
716 * e_client_utils_open_new_finish:
717 * @source: an #ESource on which the e_client_utils_open_new() was invoked
718 * @result: a #GAsyncResult
719 * @client: (out): Return value for an #EClient
720 * @error: (out): a #GError to set an error, if any
722 * Finishes previous call of e_client_utils_open_new() and
723 * sets @client to a fully opened and authenticated #EClient.
724 * This @client, if not NULL, should be freed with g_object_unref().
726 * Returns: %TRUE if successful, %FALSE otherwise.
731 e_client_utils_open_new_finish (ESource *source,
732 GAsyncResult *result,
736 GSimpleAsyncResult *simple;
738 g_return_val_if_fail (source != NULL, FALSE);
739 g_return_val_if_fail (result != NULL, FALSE);
740 g_return_val_if_fail (client != NULL, FALSE);
741 g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (source), e_client_utils_open_new), FALSE);
744 simple = G_SIMPLE_ASYNC_RESULT (result);
746 if (g_simple_async_result_propagate_error (simple, error))
749 *client = g_object_ref (g_simple_async_result_get_op_res_gpointer (simple));
751 return *client != NULL;
754 /* free returned pointer with g_free() */
756 get_prompt_key (EClient *client,
757 const gchar *user_name)
762 g_return_val_if_fail (client != NULL, NULL);
764 suri = soup_uri_new (e_client_get_uri (client));
765 g_return_val_if_fail (suri != NULL, NULL);
767 soup_uri_set_user (suri, user_name);
768 soup_uri_set_password (suri, NULL);
769 soup_uri_set_fragment (suri, NULL);
771 uri_str = soup_uri_to_string (suri, FALSE);
772 soup_uri_free (suri);
778 * e_client_utils_authenticate_handler:
780 * This function is suitable as a handler for EClient::authenticate signal.
781 * It takes care of all the password prompt and such and returns TRUE if
782 * credentials (password) were provided. Thus just connect it to that signal
783 * and it'll take care of everything else.
785 * gtk_window_parent is user_data passed into the callback. It can be a pointer
786 * to GtkWindow, used as a parent for a pasword prompt dialog.
791 e_client_utils_authenticate_handler (EClient *client,
792 ECredentials *credentials,
793 gpointer gtk_window_parent)
796 gboolean is_book, is_cal, res, remember_password = FALSE;
799 g_return_val_if_fail (client != NULL, FALSE);
800 g_return_val_if_fail (credentials != NULL, FALSE);
802 is_book = E_IS_BOOK_CLIENT (client);
803 is_cal = !is_book && E_IS_CAL_CLIENT (client);
804 g_return_val_if_fail (is_book || is_cal, FALSE);
806 source = e_client_get_source (client);
807 g_return_val_if_fail (source != NULL, FALSE);
809 if (!e_credentials_has_key (credentials, E_CREDENTIALS_KEY_USERNAME)) {
810 const gchar *username;
812 username = e_source_get_property (source, "username");
816 auth = e_source_get_property (source, "auth");
817 if (g_strcmp0 (auth, "ldap/simple-binddn") == 0)
818 username = e_source_get_property (source, "binddn");
820 username = e_source_get_property (source, "email_addr");
826 e_credentials_set (credentials, E_CREDENTIALS_KEY_USERNAME, username);
828 /* no username set on the source - deny authentication request until
829 * username will be also enterable with e-passwords */
830 if (!e_credentials_has_key (credentials, E_CREDENTIALS_KEY_USERNAME))
834 if (!e_credentials_has_key (credentials, E_CREDENTIALS_KEY_PROMPT_KEY)) {
835 gchar *prompt_key = get_prompt_key (client, e_credentials_peek (credentials, E_CREDENTIALS_KEY_USERNAME));
837 e_credentials_set (credentials, E_CREDENTIALS_KEY_PROMPT_KEY, prompt_key);
842 if (!e_credentials_has_key (credentials, E_CREDENTIALS_KEY_PROMPT_TEXT)) {
843 gchar *prompt, *reason;
844 gchar *username_markup, *source_name_markup;
846 reason = e_credentials_get (credentials, E_CREDENTIALS_KEY_PROMPT_REASON);
847 username_markup = g_markup_printf_escaped ("<b>%s</b>", e_credentials_peek (credentials, E_CREDENTIALS_KEY_USERNAME));
848 source_name_markup = g_markup_printf_escaped ("<b>%s</b>", e_source_peek_name (source));
851 switch (e_cal_client_get_source_type (E_CAL_CLIENT (client))) {
853 g_warn_if_reached ();
854 case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
855 if (reason && *reason)
856 prompt = g_strdup_printf (_("Enter password for calendar %s (user %s)\nReason: %s"), source_name_markup, username_markup, reason);
858 prompt = g_strdup_printf (_("Enter password for calendar %s (user %s)"), source_name_markup, username_markup);
860 case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
861 if (reason && *reason)
862 prompt = g_strdup_printf (_("Enter password for task list %s (user %s)\nReason: %s"), source_name_markup, username_markup, reason);
864 prompt = g_strdup_printf (_("Enter password for task list %s (user %s)"), source_name_markup, username_markup);
866 case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
867 if (reason && *reason)
868 prompt = g_strdup_printf (_("Enter password for memo list %s (user %s)\nReason: %s"), source_name_markup, username_markup, reason);
870 prompt = g_strdup_printf (_("Enter password for memo list %s (user %s)"), source_name_markup, username_markup);
874 if (reason && *reason)
875 prompt = g_strdup_printf (_("Enter password for address book %s (user %s)\nReason: %s"), source_name_markup, username_markup, reason);
877 prompt = g_strdup_printf (_("Enter password for address book %s (user %s)"), source_name_markup, username_markup);
880 g_warn_if_reached ();
883 e_credentials_set (credentials, E_CREDENTIALS_KEY_PROMPT_TEXT, prompt);
885 g_free (username_markup);
886 g_free (source_name_markup);
891 prop = e_source_get_property (source, "remember_password");
892 remember_password = !prop || g_strcmp0 (prop, "true") == 0;
894 res = e_credentials_authenticate_helper (credentials, gtk_window_parent, &remember_password);
897 e_source_set_property (source, "remember_password", remember_password ? "true" : "false");
899 e_credentials_clear_peek (credentials);
905 * e_client_utils_forget_password:
906 * @client: An #EClient
908 * Forgets stored password for the given @client.
913 e_client_utils_forget_password (EClient *client)
918 g_return_if_fail (client != NULL);
919 g_return_if_fail (E_IS_CLIENT (client));
921 source = e_client_get_source (client);
922 g_return_if_fail (source != NULL);
924 prompt_key = get_prompt_key (client, e_source_get_property (source, "username"));
926 e_passwords_forget_password (NULL, prompt_key);
932 * e_credentials_authenticate_helper:
934 * Asks for a password based on the provided credentials information.
935 * Credentials should have set following keys:
936 * E_CREDENTIALS_KEY_USERNAME
937 * E_CREDENTIALS_KEY_PROMPT_KEY
938 * E_CREDENTIALS_KEY_PROMPT_TEXT
939 * all other keys are optional. If also E_CREDENTIALS_KEY_PASSWORD key is provided,
940 * then it implies a reprompt.
942 * When this returns TRUE, then the structure contains E_CREDENTIALS_KEY_PASSWORD set
943 * as entered by a user.
948 e_credentials_authenticate_helper (ECredentials *credentials,
950 gboolean *remember_password)
952 gboolean res, fake_remember_password = FALSE;
954 gchar *password = NULL;
955 const gchar *title, *prompt_key;
957 g_return_val_if_fail (credentials != NULL, FALSE);
958 g_return_val_if_fail (e_credentials_has_key (credentials, E_CREDENTIALS_KEY_USERNAME), FALSE);
959 g_return_val_if_fail (e_credentials_has_key (credentials, E_CREDENTIALS_KEY_PROMPT_KEY), FALSE);
960 g_return_val_if_fail (e_credentials_has_key (credentials, E_CREDENTIALS_KEY_PROMPT_TEXT), FALSE);
962 if (e_credentials_has_key (credentials, E_CREDENTIALS_KEY_PROMPT_FLAGS)) {
963 prompt_flags = e_credentials_util_string_to_prompt_flags (e_credentials_peek (credentials, E_CREDENTIALS_KEY_PROMPT_FLAGS));
965 prompt_flags = E_CREDENTIALS_PROMPT_FLAG_REMEMBER_FOREVER
966 | E_CREDENTIALS_PROMPT_FLAG_SECRET
967 | E_CREDENTIALS_PROMPT_FLAG_ONLINE;
970 if (!remember_password) {
971 prompt_flags |= E_CREDENTIALS_PROMPT_FLAG_DISABLE_REMEMBER;
972 remember_password = &fake_remember_password;
975 if (e_credentials_has_key (credentials, E_CREDENTIALS_KEY_PASSWORD))
976 prompt_flags |= E_CREDENTIALS_PROMPT_FLAG_REPROMPT;
978 if (e_credentials_has_key (credentials, E_CREDENTIALS_KEY_PROMPT_TITLE))
979 title = e_credentials_peek (credentials, E_CREDENTIALS_KEY_PROMPT_TITLE);
980 else if (prompt_flags & E_CREDENTIALS_PROMPT_FLAG_PASSPHRASE)
981 title = _("Enter Passphrase");
983 title = _("Enter Password");
985 prompt_key = e_credentials_peek (credentials, E_CREDENTIALS_KEY_PROMPT_KEY);
987 if (!(prompt_flags & E_CREDENTIALS_PROMPT_FLAG_REPROMPT))
988 password = e_passwords_get_password (NULL, prompt_key);
991 password = e_passwords_ask_password (title, NULL, prompt_key,
992 e_credentials_peek (credentials, E_CREDENTIALS_KEY_PROMPT_TEXT),
993 prompt_flags, remember_password, parent);
995 res = password != NULL;
998 e_credentials_set (credentials, E_CREDENTIALS_KEY_PASSWORD, password);
1000 e_credentials_util_safe_free_string (password);
1001 e_credentials_clear_peek (credentials);
1007 * e_credentials_forget_password:
1008 * @credentials: an #ECredentials
1010 * Forgets stored password for given @credentials, which should contain
1011 * E_CREDENTIALS_KEY_PROMPT_KEY.
1016 e_credentials_forget_password (const ECredentials *credentials)
1020 g_return_if_fail (credentials != NULL);
1021 g_return_if_fail (e_credentials_has_key (credentials, E_CREDENTIALS_KEY_PROMPT_KEY));
1023 prompt_key = e_credentials_get (credentials, E_CREDENTIALS_KEY_PROMPT_KEY);
1025 e_passwords_forget_password (NULL, prompt_key);
1027 g_free (prompt_key);