[evolution-data-server] ESource: Add functions for password management.



commit 1d1e69c853543d6129760782480ed48f631cef57
Author: Matthew Barnes <mbarnes redhat com>
Date:   Tue Feb 11 18:39:14 2014 -0500

    ESource: Add functions for password management.
    
    Replaces the EAuthenticationSession password functions.
    
    Makes password management more accessible.  There's been cases where I
    wanted to access the keyring from clients or just outside of the normal
    authenication workflow, and had to copy the schema for EDS passwords.
    
    All that's needed from the ESource is its UID, so these functions can be
    called on unsubmitted "scratch" sources as well as registered sources.
    
    This will make it possible to accept a password during account creation
    and preemptively store it in the keyring to avoid a system modal dialog
    when first connecting.
    
    New functions:
    
       e_source_store_password_sync()
       e_source_store_password()
       e_source_store_password_finish()
       e_source_lookup_password_sync()
       e_source_lookup_password()
       e_source_lookup_password_finish()
       e_source_delete_password_sync()
       e_source_delete_password()
       e_source_delete_password_finish()

 docs/reference/eds/eds-sections.txt    |   14 +-
 libebackend/e-authentication-session.c |  205 ++++++++------
 libebackend/e-authentication-session.h |   42 ++--
 libedataserver/e-source.c              |  483 ++++++++++++++++++++++++++++++++
 libedataserver/e-source.h              |   38 +++
 5 files changed, 665 insertions(+), 117 deletions(-)
---
diff --git a/docs/reference/eds/eds-sections.txt b/docs/reference/eds/eds-sections.txt
index f97d9da..4d07c72 100644
--- a/docs/reference/eds/eds-sections.txt
+++ b/docs/reference/eds/eds-sections.txt
@@ -58,6 +58,9 @@ e_authentication_session_set_prompt_description
 e_authentication_session_execute_sync
 e_authentication_session_execute
 e_authentication_session_execute_finish
+<SUBSECTION Deprecated>
+E_AUTHENTICATION_SESSION_KEYRING_ERROR
+e_authentication_session_new
 e_authentication_session_store_password_sync
 e_authentication_session_store_password
 e_authentication_session_store_password_finish
@@ -67,8 +70,6 @@ e_authentication_session_lookup_password_finish
 e_authentication_session_delete_password_sync
 e_authentication_session_delete_password
 e_authentication_session_delete_password_finish
-E_AUTHENTICATION_SESSION_KEYRING_ERROR
-e_authentication_session_new
 <SUBSECTION Standard>
 EAuthenticationSessionPrivate
 E_AUTHENTICATION_SESSION
@@ -2880,6 +2881,15 @@ e_source_remote_delete_finish
 e_source_get_oauth2_access_token_sync
 e_source_get_oauth2_access_token
 e_source_get_oauth2_access_token_finish
+e_source_store_password_sync
+e_source_store_password
+e_source_store_password_finish
+e_source_lookup_password_sync
+e_source_lookup_password
+e_source_lookup_password_finish
+e_source_delete_password_sync
+e_source_delete_password
+e_source_delete_password_finish
 <SUBSECTION Standard>
 ESourcePrivate
 E_IS_SOURCE
diff --git a/libebackend/e-authentication-session.c b/libebackend/e-authentication-session.c
index 6397c5f..9dfb46f 100644
--- a/libebackend/e-authentication-session.c
+++ b/libebackend/e-authentication-session.c
@@ -69,9 +69,6 @@
 /* Wait forever for a system prompt. */
 #define SYSTEM_PROMPT_TIMEOUT (-1)
 
-#define KEYRING_ITEM_ATTRIBUTE_NAME    "e-source-uid"
-#define KEYRING_ITEM_DISPLAY_FORMAT    "Evolution Data Source %s"
-
 typedef struct _AsyncContext AsyncContext;
 
 struct _EAuthenticationSessionPrivate {
@@ -102,16 +99,6 @@ enum {
        PROP_SOURCE_UID
 };
 
-static SecretSchema schema = {
-       "org.gnome.Evolution.Data.Source",
-       SECRET_SCHEMA_DONT_MATCH_NAME,
-       {
-               { KEYRING_ITEM_ATTRIBUTE_NAME,
-                 SECRET_SCHEMA_ATTRIBUTE_STRING },
-               { NULL, 0 }
-       }
-};
-
 /* Forward Declarations */
 static void    authentication_session_msg
                                        (EAuthenticationSession *session,
@@ -402,15 +389,15 @@ authentication_session_execute_sync (EAuthenticationSession *session,
        EAuthenticationSessionResult session_result;
        ESourceAuthenticationResult auth_result;
        ESourceRegistryServer *server;
-       ESource *source;
+       ESource *source = NULL;
        GcrPrompt *prompt;
        GString *password_string;
-       gboolean allow_auth_prompt;
        const gchar *label;
        const gchar *source_uid;
        const gchar *prompt_password;
        gchar *stored_password = NULL;
        gboolean success;
+       gboolean allow_auth_prompt = TRUE;
        gboolean remember_password = TRUE;
        GError *local_error = NULL;
 
@@ -434,6 +421,10 @@ authentication_session_execute_sync (EAuthenticationSession *session,
        source_uid = e_authentication_session_get_source_uid (session);
        authenticator = e_authentication_session_get_authenticator (session);
 
+       /* This will return NULL if the authenticating data source
+        * has not yet been submitted to the D-Bus registry service. */
+       source = e_source_registry_server_ref_source (server, source_uid);
+
        if (e_source_authenticator_get_without_password (authenticator)) {
                password_string = g_string_new ("");
 
@@ -460,12 +451,28 @@ authentication_session_execute_sync (EAuthenticationSession *session,
                /* if an empty password fails, then ask a user for it */
        }
 
-       success = e_authentication_session_lookup_password_sync (
-               session, cancellable, &stored_password, error);
+       if (source != NULL) {
+               ESourceExtension *extension;
+               const gchar *extension_name;
 
-       if (!success) {
-               session_result = E_AUTHENTICATION_SESSION_ERROR;
-               goto exit;
+               success = e_source_lookup_password_sync (
+                       source, cancellable, &stored_password, error);
+
+               if (!success) {
+                       session_result = E_AUTHENTICATION_SESSION_ERROR;
+                       goto exit;
+               }
+
+               extension_name = E_SOURCE_EXTENSION_AUTHENTICATION;
+               extension = e_source_get_extension (source, extension_name);
+
+               allow_auth_prompt =
+                       e_server_side_source_get_allow_auth_prompt (
+                       E_SERVER_SIDE_SOURCE (source));
+
+               remember_password =
+                       e_source_authentication_get_remember_password (
+                       E_SOURCE_AUTHENTICATION (extension));
        }
 
        auth_result = E_SOURCE_AUTHENTICATION_REJECTED;
@@ -502,34 +509,14 @@ authentication_session_execute_sync (EAuthenticationSession *session,
         * Failure here does not affect the outcome of this operation,
         * but leave a breadcrumb as evidence that something went wrong. */
 
-       e_authentication_session_delete_password_sync (
-               session, cancellable, &local_error);
-
-       if (local_error != NULL) {
-               g_warning ("%s: %s", G_STRFUNC, local_error->message);
-               g_clear_error (&local_error);
-       }
-
-       /* This will return NULL if the authenticating data source
-        * has not yet been submitted to the D-Bus registry service. */
-       source = e_source_registry_server_ref_source (server, source_uid);
        if (source != NULL) {
-               ESourceExtension *extension;
-               const gchar *extension_name;
+               e_source_delete_password_sync (
+                       source, cancellable, &local_error);
 
-               allow_auth_prompt =
-                       e_server_side_source_get_allow_auth_prompt (
-                       E_SERVER_SIDE_SOURCE (source));
-
-               extension_name = E_SOURCE_EXTENSION_AUTHENTICATION;
-               extension = e_source_get_extension (source, extension_name);
-               remember_password =
-                       e_source_authentication_get_remember_password (
-                       E_SOURCE_AUTHENTICATION (extension));
-
-               g_object_unref (source);
-       } else {
-               allow_auth_prompt = TRUE;
+               if (local_error != NULL) {
+                       g_warning ("%s: %s", G_STRFUNC, local_error->message);
+                       g_clear_error (&local_error);
+               }
        }
 
        /* Check if we're allowed to interrupt the user for a password.
@@ -589,7 +576,6 @@ try_again:
                goto close_prompt;
        }
 
-       source = e_source_registry_server_ref_source (server, source_uid);
        if (source != NULL) {
                ESourceExtension *extension;
                const gchar *extension_name;
@@ -600,8 +586,6 @@ try_again:
                e_source_authentication_set_remember_password (
                        E_SOURCE_AUTHENTICATION (extension),
                        gcr_prompt_get_choice_chosen (prompt));
-
-               g_object_unref (source);
        }
 
        /* Attempt authentication with the provided password. */
@@ -654,9 +638,17 @@ try_again:
 
                g_object_unref (prompt);
 
-               e_authentication_session_store_password_sync (
-                       session, password_copy, permanently,
-                       cancellable, &local_error);
+               /* Create a phony "scratch" source if necessary. */
+               if (source == NULL) {
+                       source = e_source_new_with_uid (
+                               source_uid, NULL, &local_error);
+               }
+
+               if (source != NULL) {
+                       e_source_store_password_sync (
+                               source, password_copy, permanently,
+                               cancellable, &local_error);
+               }
 
                if (local_error != NULL) {
                        g_warning ("%s: %s", G_STRFUNC, local_error->message);
@@ -715,6 +707,8 @@ exit:
                        g_warn_if_reached ();
        }
 
+       g_clear_object (&source);
+
        return session_result;
 }
 
@@ -1359,6 +1353,8 @@ authentication_session_store_password_thread (GSimpleAsyncResult *simple,
  * Returns: %TRUE on success, %FALSE on error
  *
  * Since: 3.6
+ *
+ * Deprecated: 3.12: Use e_source_store_password_sync() instead.
  **/
 gboolean
 e_authentication_session_store_password_sync (EAuthenticationSession *session,
@@ -1367,31 +1363,31 @@ e_authentication_session_store_password_sync (EAuthenticationSession *session,
                                               GCancellable *cancellable,
                                               GError **error)
 {
-       gboolean result;
-       const gchar *collection;
+       ESourceRegistryServer *server;
+       ESource *source;
        const gchar *uid;
-       gchar *display_name;
+       gboolean success = FALSE;
 
        g_return_val_if_fail (E_IS_AUTHENTICATION_SESSION (session), FALSE);
-       g_return_val_if_fail (password != NULL, FALSE);
-
-       if (permanently)
-               collection = SECRET_COLLECTION_DEFAULT;
-       else
-               collection = SECRET_COLLECTION_SESSION;
 
+       server = e_authentication_session_get_server (session);
        uid = e_authentication_session_get_source_uid (session);
-       display_name = g_strdup_printf (KEYRING_ITEM_DISPLAY_FORMAT, uid);
 
-       result = secret_password_store_sync (
-               &schema, collection, display_name,
-               password, cancellable, error,
-               KEYRING_ITEM_ATTRIBUTE_NAME, uid,
-               NULL);
+       /* Try to use the registered ESource instance,
+        * otherwise create a phony "scratch" source. */
 
-       g_free (display_name);
+       source = e_source_registry_server_ref_source (server, uid);
 
-       return result;
+       if (source == NULL)
+               source = e_source_new_with_uid (uid, NULL, error);
+
+       if (source != NULL) {
+               success = e_source_store_password_sync (
+                       source, password, permanently, cancellable, error);
+               g_object_unref (source);
+       }
+
+       return success;
 }
 
 /**
@@ -1414,6 +1410,8 @@ e_authentication_session_store_password_sync (EAuthenticationSession *session,
  * of the operation.
  *
  * Since: 3.6
+ *
+ * Deprecated: 3.12: Use e_source_store_password() instead.
  **/
 void
 e_authentication_session_store_password (EAuthenticationSession *session,
@@ -1462,6 +1460,8 @@ e_authentication_session_store_password (EAuthenticationSession *session,
  * Returns: %TRUE on success, %FALSE on error
  *
  * Since: 3.6
+ *
+ * Deprecated: 3.12: Use e_source_store_password_finish() instead.
  **/
 gboolean
 e_authentication_session_store_password_finish (EAuthenticationSession *session,
@@ -1519,6 +1519,8 @@ authentication_session_lookup_password_thread (GSimpleAsyncResult *simple,
  * Returns: %TRUE on success, %FALSE on error
  *
  * Since: 3.6
+ *
+ * Deprecated: 3.12: Use e_source_lookup_password_sync() instead.
  **/
 gboolean
 e_authentication_session_lookup_password_sync (EAuthenticationSession *session,
@@ -1526,27 +1528,28 @@ e_authentication_session_lookup_password_sync (EAuthenticationSession *session,
                                                gchar **password,
                                                GError **error)
 {
+       ESourceRegistryServer *server;
+       ESource *source;
        const gchar *uid;
-       gchar *temp = NULL;
-       gboolean success = TRUE;
-       GError *local_error = NULL;
+       gboolean success = FALSE;
 
        g_return_val_if_fail (E_IS_AUTHENTICATION_SESSION (session), FALSE);
 
+       server = e_authentication_session_get_server (session);
        uid = e_authentication_session_get_source_uid (session);
 
-       temp = secret_password_lookup_sync (
-               &schema, cancellable, &local_error,
-               KEYRING_ITEM_ATTRIBUTE_NAME, uid, NULL);
+       /* Try to use the registered ESource instance,
+        * otherwise create a phony "scratch" source. */
 
-       if (local_error != NULL) {
-               g_warn_if_fail (temp == NULL);
-               g_propagate_error (error, local_error);
-               success = FALSE;
-       } else if (password != NULL) {
-               *password = temp;  /* takes ownership */
-       } else {
-               secret_password_free (temp);
+       source = e_source_registry_server_ref_source (server, uid);
+
+       if (source == NULL)
+               source = e_source_new_with_uid (uid, NULL, error);
+
+       if (source != NULL) {
+               success = e_source_lookup_password_sync (
+                       source, cancellable, password, error);
+               g_object_unref (source);
        }
 
        return success;
@@ -1568,6 +1571,8 @@ e_authentication_session_lookup_password_sync (EAuthenticationSession *session,
  * result of the operation.
  *
  * Since: 3.6
+ *
+ * Deprecated: 3.12: Use e_source_lookup_password() instead.
  **/
 void
 e_authentication_session_lookup_password (EAuthenticationSession *session,
@@ -1618,6 +1623,8 @@ e_authentication_session_lookup_password (EAuthenticationSession *session,
  * Returns: %TRUE on success, %FALSE on error
  *
  * Since: 3.6
+ *
+ * Deprecated: 3.12: Use e_source_lookup_password_finish() instead.
  **/
 gboolean
 e_authentication_session_lookup_password_finish (EAuthenticationSession *session,
@@ -1679,30 +1686,36 @@ authentication_session_delete_password_thread (GSimpleAsyncResult *simple,
  * Returns: %TRUE on success, %FALSE on error
  *
  * Since: 3.6
+ *
+ * Deprecated: 3.12: Use e_source_delete_password_sync() instead.
  **/
 gboolean
 e_authentication_session_delete_password_sync (EAuthenticationSession *session,
                                                GCancellable *cancellable,
                                                GError **error)
 {
+       ESourceRegistryServer *server;
+       ESource *source;
        const gchar *uid;
-       gboolean success = TRUE;
-       GError *local_error = NULL;
+       gboolean success = FALSE;
 
        g_return_val_if_fail (E_IS_AUTHENTICATION_SESSION (session), FALSE);
 
+       server = e_authentication_session_get_server (session);
        uid = e_authentication_session_get_source_uid (session);
 
-       /* The return value indicates whether any passwords were removed,
-        * not whether the operation completed successfully.  So we have
-        * check the GError directly. */
-       secret_password_clear_sync (
-               &schema, cancellable, &local_error,
-               KEYRING_ITEM_ATTRIBUTE_NAME, uid, NULL);
+       /* Try to use the registered ESource instance,
+        * otherwise create a phony "scratch" source. */
 
-       if (local_error != NULL) {
-               g_propagate_error (error, local_error);
-               success = FALSE;
+       source = e_source_registry_server_ref_source (server, uid);
+
+       if (source == NULL)
+               source = e_source_new_with_uid (uid, NULL, error);
+
+       if (source != NULL) {
+               success = e_source_delete_password_sync (
+                       source, cancellable, error);
+               g_object_unref (source);
        }
 
        return success;
@@ -1724,6 +1737,8 @@ e_authentication_session_delete_password_sync (EAuthenticationSession *session,
  * of the operation.
  *
  * Since: 3.6
+ *
+ * Deprecated: 3.12: Use e_source_delete_password() instead.
  **/
 void
 e_authentication_session_delete_password (EAuthenticationSession *session,
@@ -1766,6 +1781,8 @@ e_authentication_session_delete_password (EAuthenticationSession *session,
  * Returns: %TRUE on success, %FALSE on error
  *
  * Since: 3.6
+ *
+ * Deprecated: 3.12: Use e_source_delete_password_finish() instead.
  **/
 gboolean
 e_authentication_session_delete_password_finish (EAuthenticationSession *session,
diff --git a/libebackend/e-authentication-session.h b/libebackend/e-authentication-session.h
index 52fae6e..6f51e1d 100644
--- a/libebackend/e-authentication-session.h
+++ b/libebackend/e-authentication-session.h
@@ -155,6 +155,27 @@ EAuthenticationSessionResult
                                        (EAuthenticationSession *session,
                                         GAsyncResult *result,
                                         GError **error);
+
+#ifndef EDS_DISABLE_DEPRECATED
+/**
+ * E_AUTHENTICATION_SESSION_KEYRING_ERROR:
+ *
+ * Error domain for password storage and retrieval.
+ *
+ * No longer used.
+ *
+ * Since: 3.6
+ *
+ * Deprecated: 3.8: The #SECRET_ERROR domain is now used instead.
+ **/
+#define E_AUTHENTICATION_SESSION_KEYRING_ERROR \
+       (e_authentication_session_error_quark ())
+
+EAuthenticationSession *
+               e_authentication_session_new
+                                       (struct _ESourceRegistryServer *server,
+                                        ESourceAuthenticator *authenticator,
+                                        const gchar *source_uid);
 gboolean       e_authentication_session_store_password_sync
                                        (EAuthenticationSession *session,
                                         const gchar *password,
@@ -203,27 +224,6 @@ gboolean   e_authentication_session_delete_password_finish
                                        (EAuthenticationSession *session,
                                         GAsyncResult *result,
                                         GError **error);
-
-#ifndef EDS_DISABLE_DEPRECATED
-/**
- * E_AUTHENTICATION_SESSION_KEYRING_ERROR:
- *
- * Error domain for password storage and retrieval.
- *
- * No longer used.
- *
- * Since: 3.6
- *
- * Deprecated: 3.8: The #SECRET_ERROR domain is now used instead.
- **/
-#define E_AUTHENTICATION_SESSION_KEYRING_ERROR \
-       (e_authentication_session_error_quark ())
-
-EAuthenticationSession *
-               e_authentication_session_new
-                                       (struct _ESourceRegistryServer *server,
-                                        ESourceAuthenticator *authenticator,
-                                        const gchar *source_uid);
 #endif /* EDS_DISABLE_DEPRECATED */
 
 G_END_DECLS
diff --git a/libedataserver/e-source.c b/libedataserver/e-source.c
index 0463e57..824dc72 100644
--- a/libedataserver/e-source.c
+++ b/libedataserver/e-source.c
@@ -71,6 +71,8 @@
 #include <string.h>
 #include <glib/gi18n-lib.h>
 
+#include <libsecret/secret.h>
+
 /* Private D-Bus classes. */
 #include <e-dbus-source.h>
 
@@ -112,6 +114,9 @@
 
 #define PRIMARY_GROUP_NAME     "Data Source"
 
+#define KEYRING_ITEM_ATTRIBUTE_NAME    "e-source-uid"
+#define KEYRING_ITEM_DISPLAY_FORMAT    "Evolution Data Source '%s'"
+
 typedef struct _AsyncContext AsyncContext;
 typedef struct _RemoveContext RemoveContext;
 
@@ -143,6 +148,8 @@ struct _AsyncContext {
        ESource *scratch_source;
        gchar *access_token;
        gint expires_in;
+       gchar *password;
+       gboolean permanently;
 };
 
 /* Used in e_source_remove_sync() */
@@ -170,6 +177,16 @@ enum {
        LAST_SIGNAL
 };
 
+static SecretSchema password_schema = {
+       "org.gnome.Evolution.Data.Source",
+       SECRET_SCHEMA_DONT_MATCH_NAME,
+       {
+               { KEYRING_ITEM_ATTRIBUTE_NAME,
+                 SECRET_SCHEMA_ATTRIBUTE_STRING },
+               { NULL, 0 }
+       }
+};
+
 static guint signals[LAST_SIGNAL];
 
 /* Forward Declarations */
@@ -200,6 +217,7 @@ async_context_free (AsyncContext *async_context)
                g_object_unref (async_context->scratch_source);
 
        g_free (async_context->access_token);
+       g_free (async_context->password);
 
        g_slice_free (AsyncContext, async_context);
 }
@@ -3421,3 +3439,468 @@ e_source_get_oauth2_access_token_finish (ESource *source,
                source, result, out_access_token, out_expires_in, error);
 }
 
+/**
+ * e_source_store_password_sync:
+ * @source: an #ESource
+ * @password: the password to store
+ * @permanently: store permanently or just for the session
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Stores a password for @source.  This operation does not rely on the
+ * registry service and therefore works for any #ESource -- registered
+ * or "scratch".
+ *
+ * If @permanently is %TRUE, the password is stored in the default keyring.
+ * Otherwise the password is stored in the memory-only session keyring.  If
+ * an error occurs, the function sets @error and returns %FALSE.
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 3.12
+ **/
+gboolean
+e_source_store_password_sync (ESource *source,
+                              const gchar *password,
+                              gboolean permanently,
+                              GCancellable *cancellable,
+                              GError **error)
+{
+       gboolean success;
+       const gchar *collection;
+       const gchar *uid;
+       gchar *label;
+
+       g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+       g_return_val_if_fail (password != NULL, FALSE);
+
+       if (permanently)
+               collection = SECRET_COLLECTION_DEFAULT;
+       else
+               collection = SECRET_COLLECTION_SESSION;
+
+       uid = e_source_get_uid (source);
+       label = g_strdup_printf (KEYRING_ITEM_DISPLAY_FORMAT, uid);
+
+       success = secret_password_store_sync (
+               &password_schema,
+               collection, label, password,
+               cancellable, error,
+               KEYRING_ITEM_ATTRIBUTE_NAME, uid,
+               NULL);
+
+       g_free (label);
+
+       return success;
+}
+
+/* Helper for e_source_store_password() */
+static void
+source_store_password_thread (GTask *task,
+                              gpointer source_object,
+                              gpointer task_data,
+                              GCancellable *cancellable)
+{
+       gboolean success;
+       AsyncContext *async_context;
+       GError *local_error = NULL;
+
+       async_context = (AsyncContext *) task_data;
+
+       success = e_source_store_password_sync (
+               E_SOURCE (source_object),
+               async_context->password,
+               async_context->permanently,
+               cancellable, &local_error);
+
+       if (local_error != NULL) {
+               g_task_return_error (task, local_error);
+       } else {
+               g_task_return_boolean (task, success);
+       }
+}
+
+/**
+ * e_source_store_password:
+ * @source: an #ESource
+ * @password: the password to store
+ * @permanently: store permanently or just for the session
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously stores a password for @source.  This operation does
+ * not rely on the registry service and therefore works for any #ESource
+ * -- registered or "scratch".
+ *
+ * If @permanently is %TRUE, the password is stored in the default keyring.
+ * Otherwise the password is stored in the memory-only session keyring.  If
+ * an error occurs, the function sets @error and returns %FALSE.
+ *
+ * When the operation is finished, @callback will be called.  You can then
+ * call e_source_store_password_finish() to get the result of the operation.
+ *
+ * Since: 3.12
+ **/
+void
+e_source_store_password (ESource *source,
+                         const gchar *password,
+                         gboolean permanently,
+                         GCancellable *cancellable,
+                         GAsyncReadyCallback callback,
+                         gpointer user_data)
+{
+       GTask *task;
+       AsyncContext *async_context;
+
+       g_return_if_fail (E_IS_SOURCE (source));
+       g_return_if_fail (password != NULL);
+
+       async_context = g_slice_new0 (AsyncContext);
+       async_context->password = g_strdup (password);
+       async_context->permanently = permanently;
+
+       task = g_task_new (source, cancellable, callback, user_data);
+       g_task_set_source_tag (task, e_source_store_password);
+
+       g_task_set_task_data (
+               task, async_context,
+               (GDestroyNotify) async_context_free);
+
+       g_task_run_in_thread (task, source_store_password_thread);
+
+       g_object_unref (task);
+}
+
+/**
+ * e_source_store_password_finish:
+ * @source: an #ESource
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with e_source_store_password().
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 3.12
+ **/
+gboolean
+e_source_store_password_finish (ESource *source,
+                                GAsyncResult *result,
+                                GError **error)
+{
+       g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+       g_return_val_if_fail (g_task_is_valid (result, source), FALSE);
+
+       g_return_val_if_fail (
+               g_async_result_is_tagged (
+               result, e_source_store_password), FALSE);
+
+       return g_task_propagate_boolean (G_TASK (result), error);
+}
+
+/**
+ * e_source_lookup_password_sync:
+ * @source: an #ESource
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @out_password: return location for the password, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Looks up a password for @source.  Both the default and session keyrings
+ * are queried.  This operation does not rely on the registry service and
+ * therefore works for any #ESource -- registered or "scratch".
+ *
+ * Note the boolean return value indicates whether the lookup operation
+ * itself completed successfully, not whether a password was found.  If
+ * no password was found, the function will set @out_password to %NULL
+ * but still return %TRUE.  If an error occurs, the function sets @error
+ * and returns %FALSE.
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 3.12
+ **/
+gboolean
+e_source_lookup_password_sync (ESource *source,
+                               GCancellable *cancellable,
+                               gchar **out_password,
+                               GError **error)
+{
+       const gchar *uid;
+       gchar *temp = NULL;
+       gboolean success = TRUE;
+       GError *local_error = NULL;
+
+       g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+
+       uid = e_source_get_uid (source);
+
+       temp = secret_password_lookup_sync (
+               &password_schema,
+               cancellable, &local_error,
+               KEYRING_ITEM_ATTRIBUTE_NAME, uid,
+               NULL);
+
+       if (local_error != NULL) {
+               g_warn_if_fail (temp == NULL);
+               g_propagate_error (error, local_error);
+               success = FALSE;
+       } else if (out_password != NULL) {
+               *out_password = temp;  /* takes ownership */
+       } else {
+               secret_password_free (temp);
+       }
+
+       return success;
+}
+
+/* Helper for e_source_lookup_password() */
+static void
+source_lookup_password_thread (GTask *task,
+                               gpointer source_object,
+                               gpointer task_data,
+                               GCancellable *cancellable)
+{
+       gboolean success;
+       AsyncContext *async_context;
+       GError *local_error = NULL;
+
+       async_context = (AsyncContext *) task_data;
+
+       success = e_source_lookup_password_sync (
+               E_SOURCE (source_object),
+               cancellable,
+               &async_context->password,
+               &local_error);
+
+       if (local_error != NULL) {
+               g_task_return_error (task, local_error);
+       } else {
+               g_task_return_boolean (task, success);
+       }
+}
+
+/**
+ * e_source_lookup_password:
+ * @source: an #ESource
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously looks up a password for @source.  Both the default and
+ * session keyrings are queried.  This operation does not rely on the
+ * registry service and therefore works for any #ESource -- registered
+ * or "scratch".
+ *
+ * When the operation is finished, @callback will be called.  You can then
+ * call e_source_lookup_password_finish() to get the result of the operation.
+ *
+ * Since: 3.12
+ **/
+void
+e_source_lookup_password (ESource *source,
+                          GCancellable *cancellable,
+                          GAsyncReadyCallback callback,
+                          gpointer user_data)
+{
+       GTask *task;
+       AsyncContext *async_context;
+
+       g_return_if_fail (E_IS_SOURCE (source));
+
+       async_context = g_slice_new0 (AsyncContext);
+
+       task = g_task_new (source, cancellable, callback, user_data);
+       g_task_set_source_tag (task, e_source_lookup_password);
+
+       g_task_set_task_data (
+               task, async_context,
+               (GDestroyNotify) async_context_free);
+
+       g_task_run_in_thread (task, source_lookup_password_thread);
+
+       g_object_unref (task);
+}
+
+/**
+ * e_source_lookup_password_finish:
+ * @source: an #ESource
+ * @result: a #GAsyncResult
+ * @out_password: return location for the password, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with e_source_lookup_password().
+ *
+ * Note the boolean return value indicates whether the lookup operation
+ * itself completed successfully, not whether a password was found.  If
+ * no password was found, the function will set @out_password to %NULL
+ * but still return %TRUE.  If an error occurs, the function sets @error
+ * and returns %FALSE.
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 3.12
+ **/
+gboolean
+e_source_lookup_password_finish (ESource *source,
+                                 GAsyncResult *result,
+                                 gchar **out_password,
+                                 GError **error)
+{
+       AsyncContext *async_context;
+
+       g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+       g_return_val_if_fail (g_task_is_valid (result, source), FALSE);
+
+       g_return_val_if_fail (
+               g_async_result_is_tagged (
+               result, e_source_lookup_password), FALSE);
+
+       async_context = g_task_get_task_data (G_TASK (result));
+
+       if (!g_task_had_error (G_TASK (result))) {
+               if (out_password != NULL) {
+                       *out_password = async_context->password;
+                       async_context->password = NULL;
+               }
+       }
+
+       return g_task_propagate_boolean (G_TASK (result), error);
+}
+
+/**
+ * e_source_delete_password_sync:
+ * @source: an #ESource
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Deletes the password for @source from either the default keyring or
+ * session keyring.  This operation does not rely on the registry service
+ * and therefore works for any #ESource -- registered or "scratch".
+ *
+ * Note the boolean return value indicates whether the delete operation
+ * itself completed successfully, not whether a password was found and
+ * deleted.  If no password was found, the function will still return
+ * %TRUE.  If an error occurs, the function sets @error and returns %FALSE.
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 3.12
+ **/
+gboolean
+e_source_delete_password_sync (ESource *source,
+                               GCancellable *cancellable,
+                               GError **error)
+{
+       const gchar *uid;
+       gboolean success = TRUE;
+       GError *local_error = NULL;
+
+       g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+
+       uid = e_source_get_uid (source);
+
+       /* The return value indicates whether any passwords were removed,
+        * not whether the operation completed successfully.  So we have
+        * to check the GError directly. */
+       secret_password_clear_sync (
+               &password_schema,
+               cancellable, &local_error,
+               KEYRING_ITEM_ATTRIBUTE_NAME, uid,
+               NULL);
+
+       if (local_error != NULL) {
+               g_propagate_error (error, local_error);
+               success = FALSE;
+       }
+
+       return success;
+}
+
+/* Helper for e_source_delete_password() */
+static void
+source_delete_password_thread (GTask *task,
+                               gpointer source_object,
+                               gpointer task_data,
+                               GCancellable *cancellable)
+{
+       gboolean success;
+       GError *local_error = NULL;
+
+       success = e_source_delete_password_sync (
+               E_SOURCE (source_object),
+               cancellable, &local_error);
+
+       if (local_error != NULL) {
+               g_task_return_error (task, local_error);
+       } else {
+               g_task_return_boolean (task, success);
+       }
+}
+
+/**
+ * e_source_delete_password:
+ * @source: an #ESource
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously deletes the password for @source from either the default
+ * keyring or session keyring.  This operation does not rely on the registry
+ * service and therefore works for any #ESource -- registered or "scratch".
+ *
+ * When the operation is finished, @callback will be called.  You can then
+ * call e_source_delete_password_finish() to get the result of the operation.
+ *
+ * Since: 3.12
+ **/
+void
+e_source_delete_password (ESource *source,
+                          GCancellable *cancellable,
+                          GAsyncReadyCallback callback,
+                          gpointer user_data)
+{
+       GTask *task;
+
+       g_return_if_fail (E_IS_SOURCE (source));
+
+       task = g_task_new (source, cancellable, callback, user_data);
+       g_task_set_source_tag (task, e_source_delete_password);
+
+       g_task_run_in_thread (task, source_delete_password_thread);
+
+       g_object_unref (task);
+}
+
+/**
+ * e_source_delete_password_finish:
+ * @source: an #ESource
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with e_source_delete_password().
+ *
+ * Note the boolean return value indicates whether the delete operation
+ * itself completed successfully, not whether a password was found and
+ * deleted.  If no password was found, the function will still return
+ * %TRUE.  If an error occurs, the function sets @error and returns %FALSE.
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 3.12
+ **/
+gboolean
+e_source_delete_password_finish (ESource *source,
+                                 GAsyncResult *result,
+                                 GError **error)
+{
+       g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+       g_return_val_if_fail (g_task_is_valid (result, source), FALSE);
+
+       g_return_val_if_fail (
+               g_async_result_is_tagged (
+               result, e_source_delete_password), FALSE);
+
+       return g_task_propagate_boolean (G_TASK (result), error);
+}
+
diff --git a/libedataserver/e-source.h b/libedataserver/e-source.h
index 1491759..821e600 100644
--- a/libedataserver/e-source.h
+++ b/libedataserver/e-source.h
@@ -244,6 +244,44 @@ gboolean   e_source_get_oauth2_access_token_finish
                                                 gint *out_expires_in,
                                                 GError **error);
 
+/* Password Management */
+gboolean       e_source_store_password_sync    (ESource *source,
+                                                const gchar *password,
+                                                gboolean permanently,
+                                                GCancellable *cancellable,
+                                                GError **error);
+void           e_source_store_password         (ESource *source,
+                                                const gchar *password,
+                                                gboolean permanently,
+                                                GCancellable *cancellable,
+                                                GAsyncReadyCallback callback,
+                                                gpointer user_data);
+gboolean       e_source_store_password_finish  (ESource *source,
+                                                GAsyncResult *result,
+                                                GError **error);
+gboolean       e_source_lookup_password_sync   (ESource *source,
+                                                GCancellable *cancellable,
+                                                gchar **out_password,
+                                                GError **error);
+void           e_source_lookup_password        (ESource *source,
+                                                GCancellable *cancellable,
+                                                GAsyncReadyCallback callback,
+                                                gpointer user_data);
+gboolean       e_source_lookup_password_finish (ESource *source,
+                                                GAsyncResult *result,
+                                                gchar **out_password,
+                                                GError **error);
+gboolean       e_source_delete_password_sync   (ESource *source,
+                                                GCancellable *cancellable,
+                                                GError **error);
+void           e_source_delete_password        (ESource *source,
+                                                GCancellable *cancellable,
+                                                GAsyncReadyCallback callback,
+                                                gpointer user_data);
+gboolean       e_source_delete_password_finish (ESource *source,
+                                                GAsyncResult *result,
+                                                GError **error);
+
 G_END_DECLS
 
 #endif /* E_SOURCE_H */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]