[gcr] gcr: Rework how prompter works by introducing GcrPrompt interface
- From: Stefan Walter <stefw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gcr] gcr: Rework how prompter works by introducing GcrPrompt interface
- Date: Mon, 19 Dec 2011 07:34:38 +0000 (UTC)
commit b548891251edd0bf2afc9651c36ac3c7d1248e00
Author: Stef Walter <stefw collabora co uk>
Date: Mon Nov 21 08:46:47 2011 +0100
gcr: Rework how prompter works by introducing GcrPrompt interface
* GcrSystemPrompt is an implementation of GcrPrompt which
calls to GcrSystemPrompter
* GcrSystemPrompter creates GcrPrompt objects on its side
which do the actual prompting.
Makefile.decl | 4 +-
gcr/Makefile.am | 10 +-
gcr/gcr-base.h | 1 +
gcr/gcr-base.symbols | 86 ++--
gcr/gcr-dbus-constants.h | 30 +-
gcr/gcr-mock-prompter.c | 556 +++++++++------
gcr/gcr-mock-prompter.h | 4 +-
gcr/gcr-prompt-dialog.c | 808 +++++++++++++++++++++
gcr/gcr-prompt-dialog.h | 61 ++
gcr/gcr-prompt.c | 441 ++++++++++++
gcr/gcr-prompt.h | 152 ++++
gcr/gcr-prompter-tool.c | 595 +---------------
gcr/gcr-secret-exchange.c | 24 +-
gcr/gcr-system-prompt.c | 1333 ++++++++++++++++-------------------
gcr/gcr-system-prompt.h | 76 +--
gcr/gcr-system-prompter.c | 1390 ++++++++++++++----------------------
gcr/gcr-system-prompter.h | 63 +--
gcr/gcr.h | 1 +
gcr/gcr.symbols | 1 +
gcr/org.gnome.keyring.Prompt.xml | 36 -
gcr/org.gnome.keyring.Prompter.xml | 29 +-
gcr/tests/frob-system-prompt.c | 10 +-
gcr/tests/test-system-prompt.c | 227 +++++--
po/POTFILES.in | 2 +
24 files changed, 3243 insertions(+), 2697 deletions(-)
---
diff --git a/Makefile.decl b/Makefile.decl
index f399af3..4eaaa42 100644
--- a/Makefile.decl
+++ b/Makefile.decl
@@ -1,5 +1,7 @@
NULL =
+TEST_ARGS =
+
TEST_SUPPRESSIONS = $(top_builddir)/build/valgrind-suppressions
perform-memcheck: $(TEST_PROGS)
@@ -10,7 +12,7 @@ perform-memcheck: $(TEST_PROGS)
--suppressions=$(TEST_SUPPRESSIONS) \
--leak-check=full --show-reachable=yes --num-callers=16 \
--quiet --error-exitcode=3 \
- $(builddir)/$$test || exit 3; \
+ $(builddir)/$$test $(TEST_ARGS) || exit 3; \
done
coverage:
diff --git a/gcr/Makefile.am b/gcr/Makefile.am
index 631b62d..be40c75 100644
--- a/gcr/Makefile.am
+++ b/gcr/Makefile.am
@@ -30,6 +30,7 @@ HEADER_BASE_FILES = \
gcr-mock-prompter.h \
gcr-parser.h \
gcr-pkcs11-certificate.h \
+ gcr-prompt.h \
gcr-secret-exchange.h \
gcr-simple-certificate.h \
gcr-system-prompt.h \
@@ -54,6 +55,7 @@ HEADER_UI_FILES = \
gcr-key-widget.h \
gcr-import-button.h \
gcr-list-selector.h \
+ gcr-prompt-dialog.h \
gcr-renderer.h \
gcr-secure-entry-buffer.h \
gcr-simple-collection.h \
@@ -134,6 +136,7 @@ libgcr_base_ GCR_MAJOR@_la_SOURCES = \
gcr-parser.c gcr-parser.h \
gcr-pkcs11-certificate.c gcr-pkcs11-certificate.h \
gcr-pkcs11-importer.c gcr-pkcs11-importer.h \
+ gcr-prompt.c gcr-prompt.h \
gcr-record.c gcr-record.h \
gcr-secret-exchange.c gcr-secret-exchange.h \
gcr-simple-certificate.c gcr-simple-certificate.h \
@@ -175,6 +178,7 @@ libgcr_ GCR_MAJOR@_la_SOURCES = \
gcr-menu-button.c gcr-menu-button.h \
gcr-pkcs11-import-interaction.c gcr-pkcs11-import-interaction.h \
gcr-pkcs11-import-dialog.c gcr-pkcs11-import-dialog.h \
+ gcr-prompt-dialog.c gcr-prompt-dialog.h \
gcr-record.c gcr-record.h \
gcr-renderer.c gcr-renderer.h \
gcr-secure-entry-buffer.c gcr-secure-entry-buffer.h \
@@ -261,10 +265,10 @@ DBUS_XML_DEFINITIONS = \
org.gnome.keyring.Prompt.xml
gcr-dbus-generated.c: $(DBUS_XML_DEFINITIONS)
- $(AM_V_GEN) gdbus-codegen --interface-prefix org.gnome.keyring. \
- --generate-c-code gcr-dbus-generated --c-namespace Gcr \
+ $(AM_V_GEN) gdbus-codegen --interface-prefix org.gnome.keyring.internal. \
+ --generate-c-code gcr-dbus-generated --c-namespace GcrDBus \
$(DBUS_XML_DEFINITIONS)
- $(AM_V_GEN) sed -i -e 's/gcr_/_gcr_/g' gcr-dbus-generated.[ch]
+ $(AM_V_GEN) sed -i -e 's/gcr_dbus/_gcr_dbus/g' gcr-dbus-generated.[ch]
gcr-dbus-generated.h: gcr-dbus-generated.c
diff --git a/gcr/gcr-base.h b/gcr/gcr-base.h
index ff34ddc..873b2de 100644
--- a/gcr/gcr-base.h
+++ b/gcr/gcr-base.h
@@ -46,6 +46,7 @@
#include "gcr-mock-prompter.h"
#include "gcr-parser.h"
#include "gcr-pkcs11-certificate.h"
+#include "gcr-prompt.h"
#include "gcr-secret-exchange.h"
#include "gcr-simple-certificate.h"
#include "gcr-simple-collection.h"
diff --git a/gcr/gcr-base.symbols b/gcr/gcr-base.symbols
index 9256194..4a0e1ad 100644
--- a/gcr/gcr-base.symbols
+++ b/gcr/gcr-base.symbols
@@ -104,8 +104,12 @@ gcr_mock_prompter_expect_confirm_cancel
gcr_mock_prompter_expect_confirm_ok
gcr_mock_prompter_expect_password_cancel
gcr_mock_prompter_expect_password_ok
-gcr_mock_prompter_get_type
-gcr_mock_prompter_new
+gcr_mock_prompter_get_delay_msec
+gcr_mock_prompter_is_expecting
+gcr_mock_prompter_is_prompting
+gcr_mock_prompter_set_delay_msec
+gcr_mock_prompter_start
+gcr_mock_prompter_stop
gcr_parsed_get_attributes
gcr_parsed_get_data
gcr_parsed_get_description
@@ -148,6 +152,33 @@ gcr_pkcs11_initialize_finish
gcr_pkcs11_set_modules
gcr_pkcs11_set_trust_lookup_uris
gcr_pkcs11_set_trust_store_uri
+gcr_prompt_confirm
+gcr_prompt_confirm_async
+gcr_prompt_confirm_finish
+gcr_prompt_confirm_run
+gcr_prompt_get_caller_window
+gcr_prompt_get_choice_chosen
+gcr_prompt_get_choice_label
+gcr_prompt_get_description
+gcr_prompt_get_message
+gcr_prompt_get_password_new
+gcr_prompt_get_password_strength
+gcr_prompt_get_title
+gcr_prompt_get_type
+gcr_prompt_get_warning
+gcr_prompt_password
+gcr_prompt_password_async
+gcr_prompt_password_finish
+gcr_prompt_password_run
+gcr_prompt_reply_get_type
+gcr_prompt_set_caller_window
+gcr_prompt_set_choice_chosen
+gcr_prompt_set_choice_label
+gcr_prompt_set_description
+gcr_prompt_set_message
+gcr_prompt_set_password_new
+gcr_prompt_set_title
+gcr_prompt_set_warning
gcr_secret_exchange_begin
gcr_secret_exchange_get_protocol
gcr_secret_exchange_get_secret
@@ -163,59 +194,26 @@ gcr_simple_collection_contains
gcr_simple_collection_get_type
gcr_simple_collection_new
gcr_simple_collection_remove
-gcr_system_prompt_close
-gcr_system_prompt_confirm
-gcr_system_prompt_confirm_async
-gcr_system_prompt_confirm_finish
-gcr_system_prompter_get_caller_window
-gcr_system_prompter_get_choice_chosen
-gcr_system_prompter_get_choice_label
-gcr_system_prompter_get_description
-gcr_system_prompter_get_message
-gcr_system_prompter_get_password_new
-gcr_system_prompter_get_password_strength
-gcr_system_prompter_get_title
+gcr_system_prompter_get_mode
+gcr_system_prompter_get_prompt_type
gcr_system_prompter_get_type
-gcr_system_prompter_get_warning
+gcr_system_prompter_mode_get_type
gcr_system_prompter_new
gcr_system_prompter_register
-gcr_system_prompter_respond_cancelled
-gcr_system_prompter_respond_confirmed
-gcr_system_prompter_respond_with_password
+gcr_system_prompter_unregister
+gcr_system_prompt_close
+gcr_system_prompt_close_async
+gcr_system_prompt_close_finish
gcr_system_prompt_error_get_domain
gcr_system_prompt_error_get_type
-gcr_system_prompter_set_choice_chosen
-gcr_system_prompter_set_password_strength
-gcr_system_prompter_set_warning
-gcr_system_prompter_unregister
-gcr_system_prompt_get_caller_window
-gcr_system_prompt_get_choice_chosen
-gcr_system_prompt_get_choice_label
-gcr_system_prompt_get_description
-gcr_system_prompt_get_message
-gcr_system_prompt_get_password_new
-gcr_system_prompt_get_password_strength
-gcr_system_prompt_get_secret_exchange
-gcr_system_prompt_get_title
gcr_system_prompt_get_type
-gcr_system_prompt_get_warning
+gcr_system_prompt_get_secret_exchange
gcr_system_prompt_open
gcr_system_prompt_open_async
gcr_system_prompt_open_finish
gcr_system_prompt_open_for_prompter
gcr_system_prompt_open_for_prompter_async
-gcr_system_prompt_password
-gcr_system_prompt_password_async
-gcr_system_prompt_password_finish
-gcr_system_prompt_set_caller_window
-gcr_system_prompt_set_choice_chosen
-gcr_system_prompt_set_choice_label
-gcr_system_prompt_set_description
-gcr_system_prompt_set_message
-gcr_system_prompt_set_password_new
-gcr_system_prompt_set_secret_exchange
-gcr_system_prompt_set_title
-gcr_system_prompt_set_warning
+gcr_system_prompt_response_get_type
gcr_trust_add_pinned_certificate
gcr_trust_add_pinned_certificate_async
gcr_trust_add_pinned_certificate_finish
diff --git a/gcr/gcr-dbus-constants.h b/gcr/gcr-dbus-constants.h
index ac3787f..ebfc4b8 100644
--- a/gcr/gcr-dbus-constants.h
+++ b/gcr/gcr-dbus-constants.h
@@ -32,32 +32,28 @@ G_BEGIN_DECLS
#define GCR_DBUS_PROMPTER_MOCK_BUS_NAME "org.gnome.keyring.MockPrompter"
#define GCR_DBUS_PROMPTER_OBJECT_PATH "/org/gnome/keyring/Prompter"
+#define GCR_DBUS_PROMPT_OBJECT_PREFIX "/org/gnome/keyring/internal/Prompt"
-#define GCR_DBUS_PROMPTER_INTERFACE "org.gnome.keyring.Prompter"
+#define GCR_DBUS_PROMPTER_INTERFACE "org.gnome.keyring.internal.Prompter"
#define GCR_DBUS_PROMPTER_METHOD_BEGIN "BeginPrompting"
-#define GCR_DBUS_PROMPTER_METHOD_FINISH "FinishPrompting"
+#define GCR_DBUS_PROMPTER_METHOD_STOP "StopPrompting"
+#define GCR_DBUS_PROMPTER_METHOD_PERFORM "PerformPrompt"
-#define GCR_DBUS_PROMPTER_SIGNAL_READY "PrompterReady"
-
-#define GCR_DBUS_PROMPT_INTERFACE "org.gnome.keyring.Prompter.Prompt"
+#define GCR_DBUS_CALLBACK_INTERFACE "org.gnome.keyring.internal.Prompter.Callback"
#define GCR_DBUS_PROMPT_ERROR_IN_PROGRESS "org.gnome.keyring.Prompter.InProgress"
-#define GCR_DBUS_PROMPT_ERROR_NOT_HAPPENING "org.gnome.keyring.Prompter.NotHappening"
#define GCR_DBUS_PROMPT_ERROR_FAILED "org.gnome.keyring.Prompter.Failed"
-#define GCR_DBUS_PROMPT_PROPERTY_TITLE "Title"
-#define GCR_DBUS_PROMPT_PROPERTY_MESSAGE "Message"
-#define GCR_DBUS_PROMPT_PROPERTY_DESCRIPTION "Description"
-#define GCR_DBUS_PROMPT_PROPERTY_WARNING "Warning"
-#define GCR_DBUS_PROMPT_PROPERTY_CHOICE_LABEL "ChoiceLabel"
-#define GCR_DBUS_PROMPT_PROPERTY_CHOICE_CHOSEN "ChoiceChosen"
-#define GCR_DBUS_PROMPT_PROPERTY_PASSWORD_NEW "PasswordNew"
-#define GCR_DBUS_PROMPT_PROPERTY_PASSWORD_STRENGTH "PasswordStrength"
-#define GCR_DBUS_PROMPT_PROPERTY_CALLER_WINDOW "CallerWindow"
+#define GCR_DBUS_CALLBACK_METHOD_READY "PromptReady"
+#define GCR_DBUS_CALLBACK_METHOD_DONE "PromptDone"
+
+#define GCR_DBUS_PROMPT_TYPE_NONE ""
+#define GCR_DBUS_PROMPT_TYPE_PASSWORD "password"
+#define GCR_DBUS_PROMPT_TYPE_CONFIRM "confirm"
-#define GCR_DBUS_PROMPT_METHOD_PASSWORD "RequestPassword"
-#define GCR_DBUS_PROMPT_METHOD_CONFIRM "RequestConfirm"
+#define GCR_DBUS_PROMPT_REPLY_YES "yes"
+#define GCR_DBUS_PROMPT_REPLY_NO "no"
G_END_DECLS
diff --git a/gcr/gcr-mock-prompter.c b/gcr/gcr-mock-prompter.c
index 836ef35..fc0b6a6 100644
--- a/gcr/gcr-mock-prompter.c
+++ b/gcr/gcr-mock-prompter.c
@@ -24,6 +24,7 @@
#include "config.h"
#include "gcr-mock-prompter.h"
+#include "gcr-prompt.h"
#include "egg/egg-error.h"
@@ -52,45 +53,47 @@
*/
-GType gcr_mock_prompter_get_type (void) G_GNUC_CONST;
-#define GCR_TYPE_MOCK_PROMPTER (gcr_mock_prompter_get_type ())
-#define GCR_MOCK_PROMPTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_MOCK_PROMPTER, GcrMockPrompter))
-#define GCR_IS_MOCK_PROMPTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_MOCK_PROMPTER))
-#define GCR_IS_MOCK_PROMPTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_MOCK_PROMPTER))
-#define GCR_MOCK_PROMPTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_MOCK_PROMPTER, GcrMockPromptClass))
-#define GCR_MOCK_PROMPTER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_MOCK_PROMPTER, GcrMockPromptClass))
+GType _gcr_mock_prompt_get_type (void) G_GNUC_CONST;
+#define GCR_TYPE_MOCK_PROMPT (_gcr_mock_prompt_get_type ())
+#define GCR_MOCK_PROMPT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_MOCK_PROMPT, GcrMockPrompt))
+#define GCR_IS_MOCK_PROMPT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_MOCK_PROMPT))
+#define GCR_IS_MOCK_PROMPT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_MOCK_PROMPT))
+#define GCR_MOCK_PROMPT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_MOCK_PROMPT, GcrMockPromptClass))
+#define GCR_MOCK_PROMPT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_MOCK_PROMPT, GcrMockPromptClass))
-typedef struct _GcrMockPrompter GcrMockPrompter;
-typedef struct _GcrMockPrompterClass GcrMockPrompterClass;
-typedef struct _GcrMockPrompterPrivate GcrMockPrompterPrivate;
+typedef struct _GcrMockPrompt GcrMockPrompt;
+typedef struct _GcrMockPromptClass GcrMockPromptClass;
+typedef struct _GcrMockPromptPrivate GcrMockPromptPrivate;
enum {
PROP_0,
- PROP_CONNECTION,
- PROP_SHOWING,
- PROP_DELAY_MSEC
+
+ PROP_TITLE,
+ PROP_MESSAGE,
+ PROP_DESCRIPTION,
+ PROP_WARNING,
+ PROP_PASSWORD_NEW,
+ PROP_PASSWORD_STRENGTH,
+ PROP_CHOICE_LABEL,
+ PROP_CHOICE_CHOSEN,
+ PROP_CALLER_WINDOW
};
-struct _GcrMockPrompter {
- GcrSystemPrompter parent;
- GDBusConnection *connection;
- GQueue *responses;
- gboolean showing;
- guint delay_msec;
+struct _GcrMockPrompt {
+ GObject parent;
+ GHashTable *properties;
guint delay_source;
+ gboolean disposed;
};
-struct _GcrMockPrompterClass {
- GcrSystemPrompterClass parent_class;
+struct _GcrMockPromptClass {
+ GObjectClass parent_class;
};
typedef struct {
gboolean proceed;
gchar *password;
GList *properties;
-
- /* Used while responding */
- GcrMockPrompter *prompter;
} MockResponse;
typedef struct {
@@ -99,15 +102,23 @@ typedef struct {
GCond *start_cond;
GThread *thread;
+ guint delay_msec;
+ GQueue responses;
+
/* Owned by the prompter thread*/
- GcrMockPrompter *prompter;
+ GcrSystemPrompter *prompter;
const gchar *bus_name;
GMainLoop *loop;
} ThreadData;
+static gint prompts_a_prompting = 0;
static ThreadData *running = NULL;
-G_DEFINE_TYPE (GcrMockPrompter, gcr_mock_prompter, GCR_TYPE_SYSTEM_PROMPTER);
+static void gcr_mock_prompt_iface (GcrPromptIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GcrMockPrompt, _gcr_mock_prompt, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (GCR_TYPE_PROMPT, gcr_mock_prompt_iface);
+);
static void
mock_property_free (gpointer data)
@@ -121,32 +132,100 @@ static void
mock_response_free (gpointer data)
{
MockResponse *response = data;
+
+ if (response == NULL)
+ return;
+
g_free (response->password);
g_list_free_full (response->properties, mock_property_free);
- g_clear_object (&response->prompter);
g_free (response);
}
static void
-gcr_mock_prompter_init (GcrMockPrompter *self)
+blank_string_property (GHashTable *properties,
+ const gchar *property)
+{
+ GParameter *param;
+
+ param = g_new0 (GParameter, 1);
+ param->name = property;
+ g_value_init (¶m->value, G_TYPE_STRING);
+ g_value_set_string (¶m->value, "");
+ g_hash_table_insert (properties, (gpointer)param->name, param);
+}
+
+
+static void
+blank_boolean_property (GHashTable *properties,
+ const gchar *property)
+{
+ GParameter *param;
+
+ param = g_new0 (GParameter, 1);
+ param->name = property;
+ g_value_init (¶m->value, G_TYPE_BOOLEAN);
+ g_value_set_boolean (¶m->value, FALSE);
+ g_hash_table_insert (properties, (gpointer)param->name, param);
+}
+
+static void
+blank_int_property (GHashTable *properties,
+ const gchar *property)
+{
+ GParameter *param;
+
+ param = g_new0 (GParameter, 1);
+ param->name = property;
+ g_value_init (¶m->value, G_TYPE_INT);
+ g_value_set_int (¶m->value, 0);
+ g_hash_table_insert (properties, (gpointer)param->name, param);
+}
+
+static void
+_gcr_mock_prompt_init (GcrMockPrompt *self)
{
- self->responses = g_queue_new ();
+ g_atomic_int_add (&prompts_a_prompting, 1);
+
+ self->properties = g_hash_table_new_full (g_str_hash, g_str_equal,
+ NULL, mock_property_free);
+
+ blank_string_property (self->properties, "title");
+ blank_string_property (self->properties, "message");
+ blank_string_property (self->properties, "description");
+ blank_string_property (self->properties, "warning");
+ blank_string_property (self->properties, "choice-label");
+ blank_string_property (self->properties, "caller-window");
+
+ blank_boolean_property (self->properties, "choice-chosen");
+ blank_boolean_property (self->properties, "password-new");
+
+ blank_int_property (self->properties, "password-strength");
}
static void
-gcr_mock_prompter_set_property (GObject *obj,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
+_gcr_mock_prompt_set_property (GObject *obj,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
{
- GcrMockPrompter *self = GCR_MOCK_PROMPTER (obj);
+ GcrMockPrompt *self = GCR_MOCK_PROMPT (obj);
+ GParameter *param;
switch (prop_id) {
- case PROP_CONNECTION:
- self->connection = g_value_get_object (value);
- break;
- case PROP_DELAY_MSEC:
- self->delay_msec = g_value_get_uint (value);
+ case PROP_TITLE:
+ case PROP_MESSAGE:
+ case PROP_DESCRIPTION:
+ case PROP_WARNING:
+ case PROP_PASSWORD_NEW:
+ case PROP_CHOICE_LABEL:
+ case PROP_CHOICE_CHOSEN:
+ case PROP_CALLER_WINDOW:
+ param = g_new0 (GParameter, 1);
+ param->name = pspec->name;
+ g_value_init (¶m->value, pspec->value_type);
+ g_value_copy (value, ¶m->value);
+ g_hash_table_replace (self->properties, (gpointer)param->name, param);
+ g_object_notify (G_OBJECT (self), param->name);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
@@ -155,22 +234,27 @@ gcr_mock_prompter_set_property (GObject *obj,
}
static void
-gcr_mock_prompter_get_property (GObject *obj,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
+_gcr_mock_prompt_get_property (GObject *obj,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
{
- GcrMockPrompter *self = GCR_MOCK_PROMPTER (obj);
+ GcrMockPrompt *self = GCR_MOCK_PROMPT (obj);
+ GParameter *param;
switch (prop_id) {
- case PROP_CONNECTION:
- g_value_set_object (value, self->connection);
- break;
- case PROP_SHOWING:
- g_value_set_boolean (value, self->showing);
- break;
- case PROP_DELAY_MSEC:
- g_value_set_uint (value, self->delay_msec);
+ case PROP_TITLE:
+ case PROP_MESSAGE:
+ case PROP_DESCRIPTION:
+ case PROP_WARNING:
+ case PROP_PASSWORD_NEW:
+ case PROP_PASSWORD_STRENGTH:
+ case PROP_CHOICE_LABEL:
+ case PROP_CHOICE_CHOSEN:
+ case PROP_CALLER_WINDOW:
+ param = g_hash_table_lookup (self->properties, pspec->name);
+ g_return_if_fail (param != NULL);
+ g_value_copy (¶m->value, value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
@@ -180,37 +264,31 @@ gcr_mock_prompter_get_property (GObject *obj,
static void
-gcr_mock_prompter_dispose (GObject *obj)
+_gcr_mock_prompt_dispose (GObject *obj)
{
- GcrMockPrompter *self = GCR_MOCK_PROMPTER (obj);
- MockResponse *response;
+ GcrMockPrompt *self = GCR_MOCK_PROMPT (obj);
if (self->delay_source) {
g_source_remove (self->delay_source);
self->delay_source = 0;
}
- if (self->connection) {
- gcr_system_prompter_unregister (GCR_SYSTEM_PROMPTER (self), self->connection);
- g_object_remove_weak_pointer (G_OBJECT (self->connection),
- (gpointer *)&self->connection);
- self->connection = NULL;
+ if (!self->disposed) {
+ g_atomic_int_add (&prompts_a_prompting, -1);
+ self->disposed = TRUE;
}
- while ((response = g_queue_pop_head (self->responses)))
- mock_response_free (response);
-
- G_OBJECT_CLASS (gcr_mock_prompter_parent_class)->dispose (obj);
+ G_OBJECT_CLASS (_gcr_mock_prompt_parent_class)->dispose (obj);
}
static void
-gcr_mock_prompter_finalize (GObject *obj)
+_gcr_mock_prompt_finalize (GObject *obj)
{
- GcrMockPrompter *self = GCR_MOCK_PROMPTER (obj);
+ GcrMockPrompt *self = GCR_MOCK_PROMPT (obj);
- g_queue_free (self->responses);
+ g_hash_table_destroy(self->properties);
- G_OBJECT_CLASS (gcr_mock_prompter_parent_class)->finalize (obj);
+ G_OBJECT_CLASS (_gcr_mock_prompt_parent_class)->finalize (obj);
}
static gboolean
@@ -254,9 +332,10 @@ value_equal (const GValue *a, const GValue *b)
}
static void
-prompter_set_properties (GcrMockPrompter *self,
- GList *properties)
+prompt_set_or_check_properties (GcrMockPrompt *self,
+ GList *properties)
{
+ GValue value = G_VALUE_INIT;
GObjectClass *object_class;
GParameter *param;
GParamSpec *spec;
@@ -269,189 +348,212 @@ prompter_set_properties (GcrMockPrompter *self,
spec = g_object_class_find_property (object_class, param->name);
g_assert (spec != NULL);
- /* A writable property, set it */
- if ((spec->flags & G_PARAM_WRITABLE)) {
+ /* For these we set the value */
+ if (g_str_equal (param->name, "choice-chosen")) {
g_object_set_property (G_OBJECT (self), param->name, ¶m->value);
- /* Other properties get checked */
+ /* For others we check that the value is correct */
} else {
- GValue value = G_VALUE_INIT;
-
- g_value_init (&value, spec->value_type);
+ g_value_init (&value, G_VALUE_TYPE (¶m->value));
g_object_get_property (G_OBJECT (self), param->name, &value);
if (!value_equal (&value, ¶m->value)) {
gchar *expected = g_strdup_value_contents (¶m->value);
gchar *actual = g_strdup_value_contents (&value);
-
g_critical ("expected prompt property '%s' to be %s, but it "
"is instead %s", param->name, expected, actual);
-
g_free (expected);
g_free (actual);
}
-
g_value_unset (&value);
}
}
}
static void
-gcr_mock_prompter_open (GcrSystemPrompter *prompter)
-{
- GcrMockPrompter *self = GCR_MOCK_PROMPTER (prompter);
- self->showing = TRUE;
-}
-
-static void
-gcr_mock_prompter_close (GcrSystemPrompter *prompter)
+_gcr_mock_prompt_class_init (GcrMockPromptClass *klass)
{
- GcrMockPrompter *self = GCR_MOCK_PROMPTER (prompter);
-
- if (self->delay_source != 0) {
- g_source_remove (self->delay_source);
- self->delay_source = 0;
- }
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
- self->showing = FALSE;
+ gobject_class->get_property = _gcr_mock_prompt_get_property;
+ gobject_class->set_property = _gcr_mock_prompt_set_property;
+ gobject_class->dispose = _gcr_mock_prompt_dispose;
+ gobject_class->finalize = _gcr_mock_prompt_finalize;
+
+ g_object_class_override_property (gobject_class, PROP_TITLE, "title");
+ g_object_class_override_property (gobject_class, PROP_MESSAGE, "message");
+ g_object_class_override_property (gobject_class, PROP_DESCRIPTION, "description");
+ g_object_class_override_property (gobject_class, PROP_WARNING, "warning");
+ g_object_class_override_property (gobject_class, PROP_CALLER_WINDOW, "caller-window");
+ g_object_class_override_property (gobject_class, PROP_CHOICE_LABEL, "choice-label");
+ g_object_class_override_property (gobject_class, PROP_CHOICE_CHOSEN, "choice-chosen");
+ g_object_class_override_property (gobject_class, PROP_PASSWORD_NEW, "password-new");
+ g_object_class_override_property (gobject_class, PROP_PASSWORD_STRENGTH, "password-strength");
}
static gboolean
-on_timeout_prompt_confirm (gpointer data)
+on_timeout_complete_response (gpointer data)
{
- MockResponse *response = data;
- GcrSystemPrompter *prompter = GCR_SYSTEM_PROMPTER (response->prompter);
-
- response->prompter->delay_source = 0;
-
- if (!response->proceed)
- gcr_system_prompter_respond_cancelled (prompter);
- else
- gcr_system_prompter_respond_confirmed (prompter);
-
+ GSimpleAsyncResult *res = data;
+ g_simple_async_result_complete_in_idle (res);
return FALSE;
}
-static gboolean
-gcr_mock_prompter_prompt_confirm (GcrSystemPrompter *prompter)
+static void
+gcr_mock_prompt_confirm_async (GcrPrompt *prompt,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
- GcrMockPrompter *self = GCR_MOCK_PROMPTER (prompter);
- MockResponse *response = g_queue_pop_head (self->responses);
+ GcrMockPrompt *self = GCR_MOCK_PROMPT (prompt);
+ GSimpleAsyncResult *res;
+ MockResponse *response;
+ guint delay_msec;
+
+ g_mutex_lock (running->mutex);
+ delay_msec = running->delay_msec;
+ response = g_queue_pop_head (&running->responses);
+ g_mutex_unlock (running->mutex);
+
+ res = g_simple_async_result_new (G_OBJECT (prompt), callback, user_data,
+ gcr_mock_prompt_confirm_async);
if (response == NULL) {
- g_critical ("confirmation prompt requested, but not expected");
- return FALSE;
+ g_critical ("password prompt requested, but not expected");
+ g_simple_async_result_set_op_res_gboolean (res, FALSE);
} else if (response->password) {
g_critical ("confirmation prompt requested, but password prompt expected");
- mock_response_free (response);
- return FALSE;
+ g_simple_async_result_set_op_res_gboolean (res, FALSE);
+
+ } else {
+ prompt_set_or_check_properties (self, response->properties);
+ g_simple_async_result_set_op_res_gboolean (res, response->proceed);
}
- prompter_set_properties (self, response->properties);
- response->prompter = g_object_ref (prompter);
+ mock_response_free (response);
- if (self->delay_msec > 0) {
+ if (delay_msec > 0) {
g_assert (!self->delay_source);
- self->delay_source = g_timeout_add_full (G_PRIORITY_DEFAULT, self->delay_msec,
- on_timeout_prompt_confirm,
- response, mock_response_free);
+ self->delay_source = g_timeout_add_full (G_PRIORITY_DEFAULT, delay_msec,
+ on_timeout_complete_response,
+ g_object_ref (res), g_object_unref);
} else {
- on_timeout_prompt_confirm (response);
- mock_response_free (response);
+ on_timeout_complete_response (res);
}
- return TRUE;
+ g_object_unref (res);
}
-static gboolean
-on_timeout_prompt_password (gpointer data)
+static GcrPromptReply
+gcr_mock_prompt_confirm_finish (GcrPrompt *prompt,
+ GAsyncResult *result,
+ GError **error)
{
- MockResponse *response = data;
- GcrSystemPrompter *prompter = GCR_SYSTEM_PROMPTER (response->prompter);
-
- response->prompter->delay_source = 0;
+ g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (prompt),
+ gcr_mock_prompt_confirm_async), GCR_PROMPT_REPLY_CANCEL);
- if (!response->proceed)
- gcr_system_prompter_respond_cancelled (prompter);
- else
- gcr_system_prompter_respond_with_password (prompter, response->password);
+ return g_simple_async_result_get_op_res_gboolean (G_SIMPLE_ASYNC_RESULT (result)) ?
+ GCR_PROMPT_REPLY_OK : GCR_PROMPT_REPLY_CANCEL;
+}
- return FALSE;
+static void
+ensure_password_strength (GcrMockPrompt *self,
+ const gchar *password)
+{
+ GParameter *param;
+ gint strength;
+
+ strength = strlen (password) > 0 ? 1 : 0;
+ param = g_new0 (GParameter, 1);
+ param->name = "password-strength";
+ g_value_init (¶m->value, G_TYPE_INT);
+ g_value_set_int (¶m->value, strength);
+ g_hash_table_replace (self->properties, (gpointer)param->name, param);
+ g_object_notify (G_OBJECT (self), param->name);
}
-static gboolean
-gcr_mock_prompter_prompt_password (GcrSystemPrompter *prompter)
+static void
+gcr_mock_prompt_password_async (GcrPrompt *prompt,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
- GcrMockPrompter *self = GCR_MOCK_PROMPTER (prompter);
- MockResponse *response = g_queue_pop_head (self->responses);
+ GcrMockPrompt *self = GCR_MOCK_PROMPT (prompt);
+ GSimpleAsyncResult *res;
+ MockResponse *response;
+ guint delay_msec;
+
+ g_mutex_lock (running->mutex);
+ delay_msec = running->delay_msec;
+ response = g_queue_pop_head (&running->responses);
+ g_mutex_unlock (running->mutex);
+
+ res = g_simple_async_result_new (G_OBJECT (prompt), callback, user_data,
+ gcr_mock_prompt_password_async);
if (response == NULL) {
g_critical ("password prompt requested, but not expected");
- return FALSE;
+ g_simple_async_result_set_op_res_gpointer (res, NULL, NULL);
} else if (!response->password) {
g_critical ("password prompt requested, but confirmation prompt expected");
- mock_response_free (response);
- return FALSE;
+ g_simple_async_result_set_op_res_gpointer (res, NULL, NULL);
+
+ } else if (!response->proceed) {
+ prompt_set_or_check_properties (self, response->properties);
+ g_simple_async_result_set_op_res_gpointer (res, NULL, NULL);
+ } else {
+ ensure_password_strength (self, response->password);
+ prompt_set_or_check_properties (self, response->properties);
+ g_simple_async_result_set_op_res_gpointer (res, response->password, g_free);
+ response->password = NULL;
}
- prompter_set_properties (self, response->properties);
- response->prompter = g_object_ref (prompter);
+ mock_response_free (response);
- if (self->delay_msec > 0) {
+ if (delay_msec > 0) {
g_assert (!self->delay_source);
- self->delay_source = g_timeout_add_full (G_PRIORITY_DEFAULT, self->delay_msec,
- on_timeout_prompt_password,
- response, mock_response_free);
+ self->delay_source = g_timeout_add_full (G_PRIORITY_DEFAULT, delay_msec,
+ on_timeout_complete_response,
+ g_object_ref (res), g_object_unref);
} else {
- on_timeout_prompt_password (response);
- mock_response_free (response);
+ on_timeout_complete_response (res);
}
- return TRUE;
+ g_object_unref (res);
}
-static void
-gcr_mock_prompter_class_init (GcrMockPrompterClass *klass)
-{
- GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
- GcrSystemPrompterClass *prompter_class = GCR_SYSTEM_PROMPTER_CLASS (klass);
-
- gobject_class->get_property = gcr_mock_prompter_get_property;
- gobject_class->set_property = gcr_mock_prompter_set_property;
- gobject_class->dispose = gcr_mock_prompter_dispose;
- gobject_class->finalize = gcr_mock_prompter_finalize;
- prompter_class->open = gcr_mock_prompter_open;
- prompter_class->close = gcr_mock_prompter_close;
- prompter_class->prompt_password= gcr_mock_prompter_prompt_password;
- prompter_class->prompt_confirm = gcr_mock_prompter_prompt_confirm;
+static const gchar *
+gcr_mock_prompt_password_finish (GcrPrompt *prompt,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (prompt),
+ gcr_mock_prompt_password_async), NULL);
- g_object_class_install_property (gobject_class, PROP_CONNECTION,
- g_param_spec_object ("connection", "Connection", "DBus connection",
- G_TYPE_DBUS_CONNECTION, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ return g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
- g_object_class_install_property (gobject_class, PROP_SHOWING,
- g_param_spec_boolean ("showing", "Showing", "Whether showing a prompt",
- FALSE, G_PARAM_READABLE));
+}
- g_object_class_install_property (gobject_class, PROP_DELAY_MSEC,
- g_param_spec_uint ("delay-msec", "Delay msec", "Prompt delay in milliseconds",
- 0, G_MAXUINT, 0, G_PARAM_READWRITE));
+static void
+gcr_mock_prompt_iface (GcrPromptIface *iface)
+{
+ iface->prompt_confirm_async = gcr_mock_prompt_confirm_async;
+ iface->prompt_confirm_finish = gcr_mock_prompt_confirm_finish;
+ iface->prompt_password_async = gcr_mock_prompt_password_async;
+ iface->prompt_password_finish = gcr_mock_prompt_password_finish;
}
static GList *
-build_properties (GcrMockPrompter *self,
+build_properties (GObjectClass *object_class,
const gchar *first_property,
va_list var_args)
{
- GObjectClass *object_class;
GList *result = NULL;
const gchar *name;
- object_class = G_OBJECT_GET_CLASS (self);
-
name = first_property;
while (name) {
GValue value = G_VALUE_INIT;
@@ -461,14 +563,12 @@ build_properties (GcrMockPrompter *self,
spec = g_object_class_find_property (object_class, name);
if (spec == NULL) {
- g_warning ("%s object class has no property named '%s'",
- G_OBJECT_TYPE_NAME (self), name);
+ g_warning ("prompt object class has no property named '%s'", name);
break;
}
if ((spec->flags & G_PARAM_CONSTRUCT_ONLY) && !(spec->flags & G_PARAM_READABLE)) {
- g_warning ("%s property '%s' can't be set after construction",
- G_OBJECT_TYPE_NAME (self), name);
+ g_warning ("prompt property '%s' can't be set after construction", name);
break;
}
@@ -492,16 +592,9 @@ build_properties (GcrMockPrompter *self,
}
gboolean
-gcr_mock_prompter_get_showing (void)
+gcr_mock_prompter_is_prompting (void)
{
- gboolean showing = FALSE;
-
- g_assert (running != NULL);
- g_mutex_lock (running->mutex);
- g_object_get (running->prompter, "showing", &showing, NULL);
- g_mutex_unlock (running->mutex);
-
- return showing;
+ return g_atomic_int_get (&prompts_a_prompting) > 0;
}
guint
@@ -511,7 +604,7 @@ gcr_mock_prompter_get_delay_msec (void)
g_assert (running != NULL);
g_mutex_lock (running->mutex);
- g_object_get (running->prompter, "delay-msec", &delay_msec, NULL);
+ delay_msec = running->delay_msec;
g_mutex_unlock (running->mutex);
return delay_msec;
@@ -522,7 +615,7 @@ gcr_mock_prompter_set_delay_msec (guint delay_msec)
{
g_assert (running != NULL);
g_mutex_lock (running->mutex);
- g_object_set (running->prompter, "delay-msec", delay_msec, NULL);
+ running->delay_msec = delay_msec;
g_mutex_unlock (running->mutex);
}
@@ -531,6 +624,7 @@ gcr_mock_prompter_expect_confirm_ok (const gchar *first_property_name,
...)
{
MockResponse *response;
+ gpointer klass;
va_list var_args;
g_assert (running != NULL);
@@ -541,11 +635,14 @@ gcr_mock_prompter_expect_confirm_ok (const gchar *first_property_name,
response->password = NULL;
response->proceed = TRUE;
+ klass = g_type_class_ref (gcr_system_prompter_get_prompt_type (running->prompter));
+
va_start (var_args, first_property_name);
- response->properties = build_properties (running->prompter, first_property_name, var_args);
+ response->properties = build_properties (G_OBJECT_CLASS (klass), first_property_name, var_args);
va_end (var_args);
- g_queue_push_tail (running->prompter->responses, response);
+ g_type_class_unref (klass);
+ g_queue_push_tail (&running->responses, response);
g_mutex_unlock (running->mutex);
}
@@ -562,7 +659,7 @@ gcr_mock_prompter_expect_confirm_cancel (void)
response->password = NULL;
response->proceed = FALSE;
- g_queue_push_tail (running->prompter->responses, response);
+ g_queue_push_tail (&running->responses, response);
g_mutex_unlock (running->mutex);
}
@@ -573,6 +670,7 @@ gcr_mock_prompter_expect_password_ok (const gchar *password,
...)
{
MockResponse *response;
+ gpointer klass;
va_list var_args;
g_assert (running != NULL);
@@ -584,11 +682,14 @@ gcr_mock_prompter_expect_password_ok (const gchar *password,
response->password = g_strdup (password);
response->proceed = TRUE;
+ klass = g_type_class_ref (gcr_system_prompter_get_prompt_type (running->prompter));
+
va_start (var_args, first_property_name);
- response->properties = build_properties (running->prompter, first_property_name, var_args);
+ response->properties = build_properties (G_OBJECT_CLASS (klass), first_property_name, var_args);
va_end (var_args);
- g_queue_push_tail (running->prompter->responses, response);
+ g_type_class_unref (klass);
+ g_queue_push_tail (&running->responses, response);
g_mutex_unlock (running->mutex);
}
@@ -606,9 +707,33 @@ gcr_mock_prompter_expect_password_cancel (void)
response->password = g_strdup ("");
response->proceed = FALSE;
- g_queue_push_tail (running->prompter->responses, response);
+ g_queue_push_tail (&running->responses, response);
+
+ g_mutex_unlock (running->mutex);
+}
+
+gboolean
+gcr_mock_prompter_is_expecting (void)
+{
+ gboolean expecting;
+
+ g_assert (running != NULL);
+
+ g_mutex_lock (running->mutex);
+
+ expecting = !g_queue_is_empty (&running->responses);
g_mutex_unlock (running->mutex);
+
+ return expecting;
+}
+
+static gboolean
+on_idle_signal_cond (gpointer user_data)
+{
+ GCond *cond = user_data;
+ g_cond_signal (cond);
+ return FALSE; /* Don't run again */
}
static gpointer
@@ -618,13 +743,15 @@ mock_prompter_thread (gpointer data)
GDBusConnection *connection;
GMainContext *context;
GError *error = NULL;
+ GSource *idle;
gchar *address;
g_mutex_lock (thread_data->mutex);
context = g_main_context_new ();
g_main_context_push_thread_default (context);
- thread_data->prompter = g_object_new (GCR_TYPE_MOCK_PROMPTER, NULL);
+ thread_data->prompter = gcr_system_prompter_new (GCR_SYSTEM_PROMPTER_SINGLE,
+ GCR_TYPE_MOCK_PROMPT);
address = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SESSION, NULL, &error);
if (error == NULL) {
@@ -636,6 +763,9 @@ mock_prompter_thread (gpointer data)
gcr_system_prompter_register (GCR_SYSTEM_PROMPTER (thread_data->prompter),
connection);
thread_data->bus_name = g_dbus_connection_get_unique_name (connection);
+ } else {
+ g_critical ("couldn't create connection: %s", error->message);
+ g_error_free (error);
}
g_free (address);
@@ -648,21 +778,35 @@ mock_prompter_thread (gpointer data)
}
thread_data->loop = g_main_loop_new (context, FALSE);
- g_cond_signal (thread_data->start_cond);
g_mutex_unlock (thread_data->mutex);
+ idle = g_idle_source_new ();
+ g_source_set_callback (idle, on_idle_signal_cond, thread_data->start_cond, NULL);
+ g_source_attach (idle, context);
+ g_source_unref (idle);
+
g_main_loop_run (thread_data->loop);
g_mutex_lock (thread_data->mutex);
g_main_context_pop_thread_default (context);
- g_main_context_unref (context);
- if (connection) {
- gcr_system_prompter_unregister (GCR_SYSTEM_PROMPTER (thread_data->prompter),
- connection);
- g_object_unref (connection);
+ gcr_system_prompter_unregister (thread_data->prompter, TRUE);
+ g_object_unref (thread_data->prompter);
+ thread_data->prompter = NULL;
+
+ if (!g_dbus_connection_flush_sync (connection, NULL, &error)) {
+ g_critical ("connection flush failed: %s", error->message);
+ g_error_free (error);
}
+ g_object_unref (connection);
+
+ while (g_main_context_iteration (context, FALSE));
+
+ g_main_context_unref (context);
+ g_main_loop_unref (thread_data->loop);
+ thread_data->loop = NULL;
+
g_mutex_unlock (thread_data->mutex);
return thread_data;
}
@@ -677,6 +821,7 @@ gcr_mock_prompter_start (void)
running = g_new0 (ThreadData, 1);
running->mutex = g_mutex_new ();
running->start_cond = g_cond_new ();
+ g_queue_init (&running->responses);
g_mutex_lock (running->mutex);
running->thread = g_thread_create (mock_prompter_thread, running, TRUE, &error);
@@ -707,6 +852,9 @@ gcr_mock_prompter_stop (void)
check = g_thread_join (running->thread);
g_assert (check == running);
+ g_queue_foreach (&running->responses, (GFunc)mock_response_free, NULL);
+ g_queue_clear (&running->responses);
+
g_cond_free (running->start_cond);
g_mutex_free (running->mutex);
g_free (running);
diff --git a/gcr/gcr-mock-prompter.h b/gcr/gcr-mock-prompter.h
index f2068ec..3542250 100644
--- a/gcr/gcr-mock-prompter.h
+++ b/gcr/gcr-mock-prompter.h
@@ -38,7 +38,7 @@ const gchar * gcr_mock_prompter_start (void);
void gcr_mock_prompter_stop (void);
-gboolean gcr_mock_prompter_get_showing (void);
+gboolean gcr_mock_prompter_is_prompting (void);
guint gcr_mock_prompter_get_delay_msec (void);
@@ -55,6 +55,8 @@ void gcr_mock_prompter_expect_password_ok (const gchar *p
void gcr_mock_prompter_expect_password_cancel (void);
+gboolean gcr_mock_prompter_is_expecting (void);
+
G_END_DECLS
#endif /* __GCR_MOCK_PROMPTER_H__ */
diff --git a/gcr/gcr-prompt-dialog.c b/gcr/gcr-prompt-dialog.c
new file mode 100644
index 0000000..3a053b1
--- /dev/null
+++ b/gcr/gcr-prompt-dialog.c
@@ -0,0 +1,808 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2011 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Author: Stef Walter <stef thewalter net>
+ */
+
+#include "config.h"
+
+#define DEBUG_FLAG GCR_DEBUG_PROMPT
+#include "gcr-debug.h"
+#include "gcr-prompt.h"
+#include "gcr-prompt-dialog.h"
+#include "gcr-secure-entry-buffer.h"
+
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+#include <glib/gi18n.h>
+
+#define LOG_ERRORS 1
+#define GRAB_KEYBOARD 1
+
+typedef enum {
+ PROMPT_NONE,
+ PROMPT_CONFIRMING,
+ PROMPT_PASSWORDING
+} PromptMode;
+
+enum {
+ PROP_0,
+ PROP_TITLE,
+ PROP_MESSAGE,
+ PROP_DESCRIPTION,
+ PROP_WARNING,
+ PROP_CHOICE_LABEL,
+ PROP_CHOICE_CHOSEN,
+ PROP_PASSWORD_NEW,
+ PROP_PASSWORD_STRENGTH,
+ PROP_CALLER_WINDOW,
+
+ PROP_PASSWORD_VISIBLE,
+ PROP_CONFIRM_VISIBLE,
+ PROP_WARNING_VISIBLE,
+ PROP_CHOICE_VISIBLE,
+};
+
+struct _GcrPromptDialogPrivate {
+ gchar *title;
+ gchar *message;
+ gchar *description;
+ gchar *warning;
+ gchar *choice_label;
+ gboolean choice_chosen;
+ gboolean password_new;
+ guint password_strength;
+ gchar *caller_window;
+
+ GSimpleAsyncResult *async_result;
+ GcrPromptReply last_reply;
+ GtkWidget *spinner;
+ GtkWidget *image;
+ GtkEntryBuffer *password_buffer;
+ GtkEntryBuffer *confirm_buffer;
+ PromptMode mode;
+ GdkDevice *grabbed_device;
+ gulong grab_broken_id;
+};
+
+static void gcr_prompt_dialog_prompt_iface (GcrPromptIface *iface);
+
+static gboolean ungrab_keyboard (GtkWidget *win,
+ GdkEvent *event,
+ gpointer unused);
+
+G_DEFINE_TYPE_WITH_CODE (GcrPromptDialog, gcr_prompt_dialog, GTK_TYPE_DIALOG,
+ G_IMPLEMENT_INTERFACE (GCR_TYPE_PROMPT, gcr_prompt_dialog_prompt_iface);
+);
+
+static void
+update_transient_for (GcrPromptDialog *self)
+{
+ GdkDisplay *display;
+ GdkWindow *transient_for;
+ GdkWindow *window;
+ gint64 handle;
+ gchar *end;
+
+ if (self->pv->caller_window == NULL || g_str_equal (self->pv->caller_window, "")) {
+ gtk_window_set_modal (GTK_WINDOW (self), FALSE);
+ return;
+ }
+
+ window = gtk_widget_get_window (GTK_WIDGET (self));
+ if (window == NULL)
+ return;
+
+ handle = g_ascii_strtoll (self->pv->caller_window, &end, 10);
+ if (!end || *end != '\0') {
+ g_warning ("couldn't parse caller-window property: %s", self->pv->caller_window);
+ return;
+ }
+
+ display = gtk_widget_get_display (GTK_WIDGET (self));
+ transient_for = gdk_x11_window_foreign_new_for_display (display, (Window)handle);
+ if (transient_for == NULL) {
+ g_warning ("caller-window property doesn't represent a window on current display: %s",
+ self->pv->caller_window);
+ } else {
+ gdk_window_set_transient_for (window, transient_for);
+ g_object_unref (transient_for);
+ }
+
+ gtk_window_set_modal (GTK_WINDOW (self), TRUE);
+}
+
+static void
+gcr_prompt_dialog_init (GcrPromptDialog *self)
+{
+ self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_PROMPT_DIALOG,
+ GcrPromptDialogPrivate);
+}
+
+static void
+gcr_prompt_dialog_set_property (GObject *obj,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GcrPromptDialog *self = GCR_PROMPT_DIALOG (obj);
+
+ switch (prop_id) {
+ case PROP_TITLE:
+ g_free (self->pv->title);
+ self->pv->title = g_value_dup_string (value);
+ g_object_notify (obj, "title");
+ break;
+ case PROP_MESSAGE:
+ g_free (self->pv->message);
+ self->pv->message = g_value_dup_string (value);
+ g_object_notify (obj, "message");
+ break;
+ case PROP_DESCRIPTION:
+ g_free (self->pv->description);
+ self->pv->description = g_value_dup_string (value);
+ g_object_notify (obj, "description");
+ break;
+ case PROP_WARNING:
+ g_free (self->pv->warning);
+ self->pv->warning = g_value_dup_string (value);
+ g_object_notify (obj, "warning");
+ break;
+ case PROP_CHOICE_LABEL:
+ g_free (self->pv->choice_label);
+ self->pv->choice_label = g_value_dup_string (value);
+ g_object_notify (obj, "choice-label");
+ break;
+ case PROP_PASSWORD_NEW:
+ self->pv->password_new = g_value_get_boolean (value);
+ break;
+ case PROP_CALLER_WINDOW:
+ g_free (self->pv->caller_window);
+ self->pv->caller_window = g_value_dup_string (value);
+ update_transient_for (self);
+ g_object_notify (obj, "caller-window");
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gcr_prompt_dialog_get_property (GObject *obj,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GcrPromptDialog *self = GCR_PROMPT_DIALOG (obj);
+
+ switch (prop_id) {
+ case PROP_TITLE:
+ g_value_set_string (value, self->pv->title);
+ break;
+ case PROP_MESSAGE:
+ g_value_set_string (value, self->pv->message);
+ break;
+ case PROP_DESCRIPTION:
+ g_value_set_string (value, self->pv->description);
+ break;
+ case PROP_WARNING:
+ g_value_set_string (value, self->pv->warning);
+ break;
+ case PROP_CHOICE_LABEL:
+ g_value_set_string (value, self->pv->choice_label);
+ break;
+ case PROP_CHOICE_CHOSEN:
+ g_value_set_boolean (value, self->pv->choice_chosen);
+ break;
+ case PROP_PASSWORD_NEW:
+ g_value_set_boolean (value, self->pv->password_new);
+ break;
+ case PROP_PASSWORD_STRENGTH:
+ g_value_set_uint (value, self->pv->password_strength);
+ break;
+ case PROP_CALLER_WINDOW:
+ g_value_set_string (value, self->pv->caller_window);
+ break;
+ case PROP_PASSWORD_VISIBLE:
+ g_value_set_boolean (value, self->pv->mode == PROMPT_PASSWORDING);
+ break;
+ case PROP_CONFIRM_VISIBLE:
+ g_value_set_boolean (value, self->pv->password_new &&
+ self->pv->mode == PROMPT_PASSWORDING);
+ break;
+ case PROP_WARNING_VISIBLE:
+ g_value_set_boolean (value, self->pv->warning && self->pv->warning[0]);
+ break;
+ case PROP_CHOICE_VISIBLE:
+ g_value_set_boolean (value, self->pv->choice_label && self->pv->choice_label[0]);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+
+static void
+on_password_changed (GtkEditable *editable,
+ gpointer user_data)
+{
+ int upper, lower, digit, misc;
+ const char *password;
+ gdouble pwstrength;
+ int length, i;
+
+ password = gtk_entry_get_text (GTK_ENTRY (editable));
+
+ /*
+ * This code is based on the Master Password dialog in Firefox
+ * (pref-masterpass.js)
+ * Original code triple-licensed under the MPL, GPL, and LGPL
+ * so is license-compatible with this file
+ */
+
+ length = strlen (password);
+ upper = 0;
+ lower = 0;
+ digit = 0;
+ misc = 0;
+
+ for ( i = 0; i < length ; i++) {
+ if (g_ascii_isdigit (password[i]))
+ digit++;
+ else if (g_ascii_islower (password[i]))
+ lower++;
+ else if (g_ascii_isupper (password[i]))
+ upper++;
+ else
+ misc++;
+ }
+
+ if (length > 5)
+ length = 5;
+ if (digit > 3)
+ digit = 3;
+ if (upper > 3)
+ upper = 3;
+ if (misc > 3)
+ misc = 3;
+
+ pwstrength = ((length * 0.1) - 0.2) +
+ (digit * 0.1) +
+ (misc * 0.15) +
+ (upper * 0.1);
+
+ if (pwstrength < 0.0)
+ pwstrength = 0.0;
+ if (pwstrength > 1.0)
+ pwstrength = 1.0;
+
+ gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (user_data), pwstrength);
+}
+
+
+static const gchar*
+grab_status_message (GdkGrabStatus status)
+{
+ switch (status) {
+ case GDK_GRAB_SUCCESS:
+ g_return_val_if_reached ("");
+ break;
+ case GDK_GRAB_ALREADY_GRABBED:
+ return "already grabbed";
+ case GDK_GRAB_INVALID_TIME:
+ return "invalid time";
+ case GDK_GRAB_NOT_VIEWABLE:
+ return "not viewable";
+ case GDK_GRAB_FROZEN:
+ return "frozen";
+ default:
+ g_message ("unknown grab status: %d", (int)status);
+ return "unknown";
+ }
+}
+
+static gboolean
+on_grab_broken (GtkWidget *widget,
+ GdkEventGrabBroken * event)
+{
+ ungrab_keyboard (widget, (GdkEvent *)event, NULL);
+ return TRUE;
+}
+
+static gboolean
+grab_keyboard (GtkWidget *widget,
+ GdkEvent *event,
+ gpointer user_data)
+{
+ GcrPromptDialog *self = GCR_PROMPT_DIALOG (user_data);
+ GdkGrabStatus status;
+ guint32 at;
+ GdkDevice *device = NULL;
+ GdkDeviceManager *manager;
+ GdkDisplay *display;
+ GList *devices, *l;
+
+ if (self->pv->grabbed_device || !GRAB_KEYBOARD)
+ return FALSE;
+
+ display = gtk_widget_get_display (widget);
+ manager = gdk_display_get_device_manager (display);
+ devices = gdk_device_manager_list_devices (manager, GDK_DEVICE_TYPE_MASTER);
+ for (l = devices; l; l = g_list_next (l)) {
+ device = l->data;
+ if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
+ break;
+ }
+ g_list_free (devices);
+
+ if (!device) {
+ g_message ("couldn't find device to grab");
+ return FALSE;
+ }
+
+ at = event ? gdk_event_get_time (event) : GDK_CURRENT_TIME;
+ status = gdk_device_grab (device, gtk_widget_get_window (widget),
+ GDK_OWNERSHIP_APPLICATION, TRUE,
+ GDK_KEY_PRESS | GDK_KEY_RELEASE, NULL, at);
+ if (status == GDK_GRAB_SUCCESS) {
+ self->pv->grab_broken_id = g_signal_connect (widget, "grab-broken-event",
+ G_CALLBACK (on_grab_broken), NULL);
+ gtk_device_grab_add (widget, device, TRUE);
+ self->pv->grabbed_device = device;
+ } else {
+ g_message ("could not grab keyboard: %s", grab_status_message (status));
+ }
+
+ /* Always return false, so event is handled elsewhere */
+ return FALSE;
+}
+
+static gboolean
+ungrab_keyboard (GtkWidget *widget,
+ GdkEvent *event,
+ gpointer user_data)
+{
+ guint32 at = event ? gdk_event_get_time (event) : GDK_CURRENT_TIME;
+ GcrPromptDialog *self = GCR_PROMPT_DIALOG (user_data);
+
+ if (self->pv->grabbed_device) {
+ g_signal_handler_disconnect (widget, self->pv->grab_broken_id);
+ gdk_device_ungrab (self->pv->grabbed_device, at);
+ gtk_device_grab_remove (widget, self->pv->grabbed_device);
+ self->pv->grabbed_device = NULL;
+ self->pv->grab_broken_id = 0;
+ }
+
+ /* Always return false, so event is handled elsewhere */
+ return FALSE;
+}
+
+static gboolean
+window_state_changed (GtkWidget *win, GdkEventWindowState *event, gpointer data)
+{
+ GdkWindowState state = gdk_window_get_state (gtk_widget_get_window (win));
+
+ if (state & GDK_WINDOW_STATE_WITHDRAWN ||
+ state & GDK_WINDOW_STATE_ICONIFIED ||
+ state & GDK_WINDOW_STATE_FULLSCREEN ||
+ state & GDK_WINDOW_STATE_MAXIMIZED)
+ ungrab_keyboard (win, (GdkEvent*)event, data);
+ else
+ grab_keyboard (win, (GdkEvent*)event, data);
+
+ return FALSE;
+}
+
+static void
+gcr_prompt_dialog_constructed (GObject *obj)
+{
+ GcrPromptDialog *self = GCR_PROMPT_DIALOG (obj);
+ GtkDialog *dialog;
+ PangoAttrList *attrs;
+ GtkWidget *widget;
+ GtkWidget *entry;
+ GtkWidget *content;
+ GtkGrid *grid;
+
+ G_OBJECT_CLASS (gcr_prompt_dialog_parent_class)->constructed (obj);
+
+ dialog = GTK_DIALOG (self);
+ gtk_dialog_add_buttons (dialog,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ _("Continue"), GTK_RESPONSE_OK,
+ NULL);
+
+ content = gtk_dialog_get_content_area (dialog);
+
+ grid = GTK_GRID (gtk_grid_new ());
+ gtk_container_set_border_width (GTK_CONTAINER (grid), 6);
+ gtk_widget_set_hexpand (GTK_WIDGET (grid), TRUE);
+ gtk_grid_set_column_spacing (grid, 12);
+ gtk_grid_set_row_spacing (grid, 6);
+
+ /* The prompt image */
+ self->pv->image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_AUTHENTICATION,
+ GTK_ICON_SIZE_DIALOG);
+ gtk_widget_set_valign (self->pv->image, GTK_ALIGN_START);
+ gtk_grid_attach (grid, self->pv->image, -1, 0, 1, 4);
+ gtk_widget_show (self->pv->image);
+
+ /* The prompt spinner */
+ self->pv->spinner = gtk_spinner_new ();
+ gtk_widget_set_valign (self->pv->image, GTK_ALIGN_START);
+ gtk_grid_attach (grid, self->pv->spinner, -2, -1, 1, 4);
+ gtk_widget_show (self->pv->spinner);
+
+ /* The message label */
+ widget = gtk_label_new ("");
+ attrs = pango_attr_list_new ();
+ pango_attr_list_insert (attrs, pango_attr_weight_new (PANGO_WEIGHT_BOLD));
+ pango_attr_list_insert (attrs, pango_attr_scale_new (PANGO_SCALE_LARGE));
+ gtk_label_set_attributes (GTK_LABEL (widget), attrs);
+ pango_attr_list_unref (attrs);
+ gtk_widget_set_halign (widget, GTK_ALIGN_START);
+ gtk_widget_set_hexpand (widget, TRUE);
+ gtk_widget_set_margin_bottom (widget, 8);
+ g_object_bind_property (self, "message", widget, "label", G_BINDING_DEFAULT);
+ gtk_grid_attach (grid, widget, 0, 0, 2, 1);
+ gtk_widget_show (widget);
+
+ /* The description label */
+ widget = gtk_label_new ("");
+ gtk_widget_set_halign (widget, GTK_ALIGN_START);
+ gtk_widget_set_hexpand (widget, TRUE);
+ gtk_widget_set_margin_bottom (widget, 4);
+ g_object_bind_property (self, "description", widget, "label", G_BINDING_DEFAULT);
+ gtk_grid_attach (grid, widget, 0, 1, 2, 1);
+ gtk_widget_show (widget);
+
+ /* The password label */
+ widget = gtk_label_new (_("Password:"));
+ gtk_widget_set_halign (widget, GTK_ALIGN_START);
+ g_object_bind_property (self, "password-visible", widget, "visible", G_BINDING_DEFAULT);
+ gtk_grid_attach (grid, widget, 0, 2, 1, 1);
+
+ /* The password entry */
+ self->pv->password_buffer = gcr_secure_entry_buffer_new ();
+ entry = gtk_entry_new_with_buffer (self->pv->password_buffer);
+ gtk_entry_set_visibility (GTK_ENTRY (entry), FALSE);
+ gtk_widget_set_hexpand (widget, TRUE);
+ g_object_bind_property (self, "password-visible", entry, "visible", G_BINDING_DEFAULT);
+ gtk_grid_attach (grid, entry, 1, 2, 1, 1);
+
+ /* The confirm label */
+ widget = gtk_label_new (_("Confirm:"));
+ gtk_widget_set_halign (widget, GTK_ALIGN_START);
+ g_object_bind_property (self, "confirm-visible", widget, "visible", G_BINDING_DEFAULT);
+ gtk_grid_attach (grid, widget, 0, 3, 1, 1);
+
+ /* The confirm entry */
+ self->pv->confirm_buffer = gcr_secure_entry_buffer_new ();
+ widget = gtk_entry_new_with_buffer (self->pv->password_buffer);
+ gtk_widget_set_hexpand (widget, TRUE);
+ gtk_entry_set_visibility (GTK_ENTRY (widget), FALSE);
+ g_object_bind_property (self, "confirm-visible", widget, "visible", G_BINDING_DEFAULT);
+ gtk_grid_attach (grid, widget, 1, 3, 1, 1);
+
+ /* The quality progress bar */
+ widget = gtk_progress_bar_new ();
+ gtk_widget_set_hexpand (widget, TRUE);
+ g_object_bind_property (self, "confirm-visible", widget, "visible", G_BINDING_DEFAULT);
+ gtk_grid_attach (grid, widget, 1, 4, 1, 1);
+ g_signal_connect (entry, "changed", G_CALLBACK (on_password_changed), widget);
+
+ /* The warning */
+ widget = gtk_label_new ("");
+ attrs = pango_attr_list_new ();
+ pango_attr_list_insert (attrs, pango_attr_style_new (PANGO_STYLE_ITALIC));
+ gtk_label_set_attributes (GTK_LABEL (widget), attrs);
+ pango_attr_list_unref (attrs);
+ g_object_bind_property (self, "warning", widget, "label", G_BINDING_DEFAULT);
+ g_object_bind_property (self, "warning-visible", widget, "visible", G_BINDING_DEFAULT);
+ gtk_grid_attach (grid, widget, 0, 5, 2, 1);
+ gtk_widget_show (widget);
+
+ /* The checkbox */
+ widget = gtk_check_button_new ();
+ g_object_bind_property (self, "choice-label", widget, "label", G_BINDING_DEFAULT);
+ g_object_bind_property (self, "choice-visible", widget, "visible", G_BINDING_DEFAULT);
+ g_object_bind_property (self, "choice-chosen", widget, "active", G_BINDING_BIDIRECTIONAL);
+ gtk_grid_attach (grid, widget, 0, 6, 2, 1);
+
+ gtk_container_add (GTK_CONTAINER (content), GTK_WIDGET (grid));
+ gtk_widget_show (GTK_WIDGET (grid));
+
+ g_signal_connect (self, "map-event", G_CALLBACK (grab_keyboard), self);
+ g_signal_connect (self, "unmap-event", G_CALLBACK (ungrab_keyboard), self);
+ g_signal_connect (self, "window-state-event", G_CALLBACK (window_state_changed), self);
+
+}
+
+static gboolean
+handle_password_response (GcrPromptDialog *self)
+{
+ const gchar *password;
+ const gchar *confirm;
+ const gchar *env;
+ gint strength;
+
+ password = gtk_entry_buffer_get_text (self->pv->password_buffer);
+
+ /* Is it a new password? */
+ if (self->pv->password_new) {
+ confirm = gtk_entry_buffer_get_text (self->pv->confirm_buffer);
+
+ /* Do the passwords match? */
+ if (!g_str_equal (password, confirm)) {
+ gcr_prompt_set_warning (GCR_PROMPT (self), _("Passwords do not match."));
+ return FALSE;
+ }
+
+ /* Don't allow blank passwords if in paranoid mode */
+ env = g_getenv ("GNOME_KEYRING_PARANOID");
+ if (env && *env) {
+ gcr_prompt_set_warning (GCR_PROMPT (self), _("Password cannot be blank"));
+ return FALSE;
+ }
+ }
+
+ if (g_str_equal (password, ""))
+ strength = 0;
+ else
+ strength = 1;
+
+ self->pv->password_strength = strength;
+ g_object_notify (G_OBJECT (self), "password-strength");
+ return TRUE;
+}
+
+static void
+gcr_prompt_dialog_response (GtkDialog *dialog,
+ gint response_id)
+{
+ GcrPromptDialog *self = GCR_PROMPT_DIALOG (dialog);
+ GSimpleAsyncResult *res;
+
+ g_return_if_fail (self->pv->mode != PROMPT_NONE);
+ g_return_if_fail (self->pv->async_result != NULL);
+
+ switch (response_id) {
+ case GTK_RESPONSE_OK:
+
+ switch (self->pv->mode) {
+ case PROMPT_PASSWORDING:
+ if (!handle_password_response (self))
+ return;
+ break;
+ default:
+ break;
+ }
+ self->pv->last_reply = GCR_PROMPT_REPLY_OK;
+ break;
+
+ default:
+ self->pv->last_reply = GCR_PROMPT_REPLY_CANCEL;
+ break;
+ }
+
+ gtk_widget_set_sensitive (GTK_WIDGET (self), FALSE);
+ gtk_widget_hide (GTK_WIDGET (self->pv->image));
+ gtk_widget_show (GTK_WIDGET (self->pv->spinner));
+ self->pv->mode = PROMPT_NONE;
+
+ res = self->pv->async_result;
+ self->pv->async_result = NULL;
+
+ g_simple_async_result_complete (res);
+ g_object_unref (res);
+}
+
+static void
+gcr_prompt_dialog_dispose (GObject *obj)
+{
+ GcrPromptDialog *self = GCR_PROMPT_DIALOG (obj);
+
+ if (self->pv->async_result)
+ gcr_prompt_dialog_response (GTK_DIALOG (self), GTK_RESPONSE_DELETE_EVENT);
+ g_assert (self->pv->async_result == NULL);
+
+ ungrab_keyboard (GTK_WIDGET (self), NULL, self);
+ g_assert (self->pv->grabbed_device == NULL);
+
+ G_OBJECT_CLASS (gcr_prompt_dialog_parent_class)->dispose (obj);
+}
+
+static void
+gcr_prompt_dialog_finalize (GObject *obj)
+{
+ GcrPromptDialog *self = GCR_PROMPT_DIALOG (obj);
+
+ g_free (self->pv->title);
+ g_free (self->pv->message);
+ g_free (self->pv->description);
+ g_free (self->pv->warning);
+ g_free (self->pv->choice_label);
+ g_free (self->pv->caller_window);
+
+ g_object_unref (self->pv->password_buffer);
+ g_object_unref (self->pv->confirm_buffer);
+
+ G_OBJECT_CLASS (gcr_prompt_dialog_parent_class)->finalize (obj);
+}
+
+static void
+gcr_prompt_dialog_class_init (GcrPromptDialogClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GtkDialogClass *dialog_class = GTK_DIALOG_CLASS (klass);
+
+ gobject_class->constructed = gcr_prompt_dialog_constructed;
+ gobject_class->get_property = gcr_prompt_dialog_get_property;
+ gobject_class->set_property = gcr_prompt_dialog_set_property;
+ gobject_class->dispose = gcr_prompt_dialog_dispose;
+ gobject_class->finalize = gcr_prompt_dialog_finalize;
+
+ dialog_class->response = gcr_prompt_dialog_response;
+
+ g_type_class_add_private (gobject_class, sizeof (GcrPromptDialogPrivate));
+
+ g_object_class_override_property (gobject_class, PROP_TITLE, "title");
+
+ g_object_class_override_property (gobject_class, PROP_MESSAGE, "message");
+
+ g_object_class_override_property (gobject_class, PROP_DESCRIPTION, "description");
+
+ g_object_class_override_property (gobject_class, PROP_WARNING, "warning");
+
+ g_object_class_override_property (gobject_class, PROP_PASSWORD_NEW, "password-new");
+
+ g_object_class_override_property (gobject_class, PROP_PASSWORD_STRENGTH, "password-strength");
+
+ g_object_class_override_property (gobject_class, PROP_CHOICE_LABEL, "choice-label");
+
+ g_object_class_override_property (gobject_class, PROP_CHOICE_CHOSEN, "choice-chosen");
+
+ g_object_class_override_property (gobject_class, PROP_CALLER_WINDOW, "caller-window");
+
+ g_object_class_install_property (gobject_class, PROP_PASSWORD_VISIBLE,
+ g_param_spec_boolean ("password-visible", "Password visible", "Password field is visible",
+ FALSE, G_PARAM_READABLE));
+
+ g_object_class_install_property (gobject_class, PROP_CONFIRM_VISIBLE,
+ g_param_spec_boolean ("confirm-visible", "Confirm visible", "Confirm field is visible",
+ FALSE, G_PARAM_READABLE));
+
+ g_object_class_install_property (gobject_class, PROP_WARNING_VISIBLE,
+ g_param_spec_boolean ("warning-visible", "Warning visible", "Warning is visible",
+ FALSE, G_PARAM_READABLE));
+
+ g_object_class_install_property (gobject_class, PROP_CHOICE_VISIBLE,
+ g_param_spec_boolean ("choice-visible", "Choice visible", "Choice is visible",
+ FALSE, G_PARAM_READABLE));
+}
+
+static void
+gcr_prompt_dialog_password_async (GcrPrompt *prompt,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GcrPromptDialog *self = GCR_PROMPT_DIALOG (prompt);
+ GObject *obj;
+
+ if (self->pv->async_result != NULL) {
+ g_warning ("this prompt is already prompting");
+ return;
+ }
+
+ self->pv->mode = PROMPT_PASSWORDING;
+ self->pv->async_result = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
+ gcr_prompt_dialog_password_async);
+
+ gtk_image_set_from_stock (GTK_IMAGE (self->pv->image),
+ GTK_STOCK_DIALOG_AUTHENTICATION,
+ GTK_ICON_SIZE_DIALOG);
+ gtk_widget_set_sensitive (GTK_WIDGET (self), TRUE);
+ gtk_widget_show (self->pv->image);
+ gtk_widget_hide (self->pv->spinner);
+
+ obj = G_OBJECT (self);
+ g_object_notify (obj, "password-visible");
+ g_object_notify (obj, "confirm-visible");
+ g_object_notify (obj, "warning-visible");
+ g_object_notify (obj, "choice-visible");
+}
+
+static const gchar *
+gcr_prompt_dialog_password_finish (GcrPrompt *prompt,
+ GAsyncResult *result,
+ GError **error)
+{
+ GcrPromptDialog *self = GCR_PROMPT_DIALOG (prompt);
+
+ g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (prompt),
+ gcr_prompt_dialog_password_async), NULL);
+
+ if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+ return NULL;
+
+ if (self->pv->last_reply == GCR_PROMPT_REPLY_OK)
+ return gtk_entry_buffer_get_text (self->pv->password_buffer);
+ return NULL;
+}
+
+static void
+gcr_prompt_dialog_confirm_async (GcrPrompt *prompt,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GcrPromptDialog *self = GCR_PROMPT_DIALOG (prompt);
+ GObject *obj;
+
+ if (self->pv->async_result != NULL) {
+ g_warning ("this prompt is already prompting");
+ return;
+ }
+
+ self->pv->mode = PROMPT_CONFIRMING;
+ self->pv->async_result = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
+ gcr_prompt_dialog_password_async);
+
+ gtk_image_set_from_stock (GTK_IMAGE (self->pv->image),
+ GTK_STOCK_DIALOG_QUESTION,
+ GTK_ICON_SIZE_DIALOG);
+ gtk_widget_set_sensitive (GTK_WIDGET (self), TRUE);
+ gtk_widget_show (self->pv->image);
+ gtk_widget_hide (self->pv->spinner);
+
+ obj = G_OBJECT (self);
+ g_object_notify (obj, "password-visible");
+ g_object_notify (obj, "confirm-visible");
+ g_object_notify (obj, "warning-visible");
+ g_object_notify (obj, "choice-visible");
+}
+
+static GcrPromptReply
+gcr_prompt_dialog_confirm_finish (GcrPrompt *prompt,
+ GAsyncResult *result,
+ GError **error)
+{
+ GcrPromptDialog *self = GCR_PROMPT_DIALOG (prompt);
+
+ g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (prompt),
+ gcr_prompt_dialog_confirm_async), GCR_PROMPT_REPLY_CANCEL);
+
+ if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+ return GCR_PROMPT_REPLY_CANCEL;
+
+ return self->pv->last_reply;
+}
+
+static void
+gcr_prompt_dialog_prompt_iface (GcrPromptIface *iface)
+{
+ iface->prompt_password_async = gcr_prompt_dialog_password_async;
+ iface->prompt_password_finish = gcr_prompt_dialog_password_finish;
+ iface->prompt_confirm_async = gcr_prompt_dialog_confirm_async;
+ iface->prompt_confirm_finish = gcr_prompt_dialog_confirm_finish;
+}
diff --git a/gcr/gcr-prompt-dialog.h b/gcr/gcr-prompt-dialog.h
new file mode 100644
index 0000000..7f04e59
--- /dev/null
+++ b/gcr/gcr-prompt-dialog.h
@@ -0,0 +1,61 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2011 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Author: Stef Walter <stef thewalter net>
+ */
+
+#if !defined (__GCR_INSIDE_HEADER__) && !defined (GCR_COMPILATION)
+#error "Only <gcr/gcr.h> or <gcr/gcr-base.h> can be included directly."
+#endif
+
+#ifndef __GCR_PROMPT_DIALOG_H__
+#define __GCR_PROMPT_DIALOG_H__
+
+#include <gtk/gtk.h>
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GCR_TYPE_PROMPT_DIALOG (gcr_prompt_dialog_get_type ())
+#define GCR_PROMPT_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_PROMPT_DIALOG, GcrPromptDialog))
+#define GCR_PROMPT_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_PROMPT_DIALOG, GcrPromptDialogClass))
+#define GCR_IS_PROMPT_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_PROMPT_DIALOG))
+#define GCR_IS_PROMPT_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_PROMPT_DIALOG))
+#define GCR_PROMPT_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_PROMPT_DIALOG, GcrPromptDialogClass))
+
+typedef struct _GcrPromptDialog GcrPromptDialog;
+typedef struct _GcrPromptDialogClass GcrPromptDialogClass;
+typedef struct _GcrPromptDialogPrivate GcrPromptDialogPrivate;
+
+struct _GcrPromptDialog {
+ GtkDialog parent;
+ GcrPromptDialogPrivate *pv;
+};
+
+struct _GcrPromptDialogClass {
+ GtkDialogClass parent;
+};
+
+GType gcr_prompt_dialog_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GCR_PROMPT_DIALOG_H__ */
diff --git a/gcr/gcr-prompt.c b/gcr/gcr-prompt.c
new file mode 100644
index 0000000..7fa4c12
--- /dev/null
+++ b/gcr/gcr-prompt.c
@@ -0,0 +1,441 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2011 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Author: Stef Walter <stef thewalter net>
+ */
+
+#include "config.h"
+
+#include "gcr-prompt.h"
+
+typedef struct {
+ GAsyncResult *result;
+ GMainLoop *loop;
+ GMainContext *context;
+} RunClosure;
+
+typedef GcrPromptIface GcrPromptInterface;
+
+static void gcr_prompt_default_init (GcrPromptIface *iface);
+
+G_DEFINE_INTERFACE (GcrPrompt, gcr_prompt, G_TYPE_OBJECT);
+
+static void
+gcr_prompt_default_init (GcrPromptIface *iface)
+{
+ static gsize initialized = 0;
+
+ if (g_once_init_enter (&initialized)) {
+
+ g_object_interface_install_property (iface,
+ g_param_spec_string ("title", "Title", "Prompt title",
+ NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_interface_install_property (iface,
+ g_param_spec_string ("message", "Message", "Prompt message",
+ NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_interface_install_property (iface,
+ g_param_spec_string ("description", "Description", "Prompt description",
+ NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_interface_install_property (iface,
+ g_param_spec_string ("warning", "Warning", "Prompt warning",
+ NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_interface_install_property (iface,
+ g_param_spec_boolean ("password-new", "Password new", "Whether prompting for a new password",
+ FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_interface_install_property (iface,
+ g_param_spec_int ("password-strength", "Password strength", "String of new password",
+ 0, G_MAXINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+ g_object_interface_install_property (iface,
+ g_param_spec_string ("choice-label", "Choice label", "Label for prompt choice",
+ NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_interface_install_property (iface,
+ g_param_spec_boolean ("choice-chosen", "Choice chosen", "Whether prompt choice is chosen",
+ FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_interface_install_property (iface,
+ g_param_spec_string ("caller-window", "Caller window", "Window ID of application window requesting prompt",
+ NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_once_init_leave (&initialized, 1);
+ }
+}
+
+static void
+run_closure_end (gpointer data)
+{
+ RunClosure *closure = data;
+ g_clear_object (&closure->result);
+ g_main_loop_unref (closure->loop);
+ if (closure->context != NULL) {
+ g_main_context_pop_thread_default (closure->context);
+ g_main_context_unref (closure->context);
+ }
+ g_free (closure);
+}
+
+static RunClosure *
+run_closure_begin (GMainContext *context)
+{
+ RunClosure *closure = g_new0 (RunClosure, 1);
+ closure->loop = g_main_loop_new (context ? context : g_main_context_get_thread_default (), FALSE);
+ closure->result = NULL;
+
+ /* We assume ownership of context reference */
+ closure->context = context;
+ if (closure->context != NULL)
+ g_main_context_push_thread_default (closure->context);
+
+ return closure;
+}
+
+static void
+on_run_complete (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ RunClosure *closure = user_data;
+ g_return_if_fail (closure->result == NULL);
+ closure->result = g_object_ref (result);
+ g_main_loop_quit (closure->loop);
+}
+
+gchar *
+gcr_prompt_get_title (GcrPrompt *prompt)
+{
+ gchar *title = NULL;
+ g_object_get (prompt, "title", &title, NULL);
+ return title;
+}
+
+void
+gcr_prompt_set_title (GcrPrompt *prompt,
+ const gchar *title)
+{
+ g_return_if_fail (GCR_IS_PROMPT (prompt));
+ g_object_set (prompt, "title", title, NULL);
+}
+
+gchar *
+gcr_prompt_get_message (GcrPrompt *prompt)
+{
+ gchar *message = NULL;
+ g_object_get (prompt, "message", &message, NULL);
+ return message;
+}
+
+void
+gcr_prompt_set_message (GcrPrompt *prompt,
+ const gchar *message)
+{
+ g_return_if_fail (GCR_IS_PROMPT (prompt));
+ g_object_set (prompt, "message", message, NULL);
+}
+
+gchar *
+gcr_prompt_get_description (GcrPrompt *prompt)
+{
+ gchar *description = NULL;
+ g_object_get (prompt, "description", &description, NULL);
+ return description;
+}
+
+void
+gcr_prompt_set_description (GcrPrompt *prompt,
+ const gchar *description)
+{
+ g_return_if_fail (GCR_IS_PROMPT (prompt));
+ g_object_set (prompt, "description", description, NULL);
+}
+
+gchar *
+gcr_prompt_get_warning (GcrPrompt *prompt)
+{
+ gchar *warning = NULL;
+ g_object_get (prompt, "warning", &warning, NULL);
+ return warning;
+}
+
+void
+gcr_prompt_set_warning (GcrPrompt *prompt,
+ const gchar *warning)
+{
+ g_return_if_fail (GCR_IS_PROMPT (prompt));
+ g_object_set (prompt, "warning", warning, NULL);
+}
+
+gchar *
+gcr_prompt_get_choice_label (GcrPrompt *prompt)
+{
+ gchar *choice_label = NULL;
+ g_object_get (prompt, "choice-label", &choice_label, NULL);
+ return choice_label;
+}
+
+void
+gcr_prompt_set_choice_label (GcrPrompt *prompt,
+ const gchar *choice_label)
+{
+ g_return_if_fail (GCR_IS_PROMPT (prompt));
+ g_object_set (prompt, "choice-label", choice_label, NULL);
+}
+
+gboolean
+gcr_prompt_get_choice_chosen (GcrPrompt *prompt)
+{
+ gboolean choice_chosen;
+ g_object_get (prompt, "choice-chosen", &choice_chosen, NULL);
+ return choice_chosen;
+}
+
+void
+gcr_prompt_set_choice_chosen (GcrPrompt *prompt,
+ gboolean chosen)
+{
+ g_return_if_fail (GCR_IS_PROMPT (prompt));
+ g_object_set (prompt, "choice-chosen", chosen, NULL);
+}
+
+gboolean
+gcr_prompt_get_password_new (GcrPrompt *prompt)
+{
+ gboolean password_new;
+ g_object_get (prompt, "password-new", &password_new, NULL);
+ return password_new;
+}
+
+void
+gcr_prompt_set_password_new (GcrPrompt *prompt,
+ gboolean new_password)
+{
+ g_return_if_fail (GCR_IS_PROMPT (prompt));
+ g_object_set (prompt, "password-new", new_password, NULL);
+}
+
+gint
+gcr_prompt_get_password_strength (GcrPrompt *prompt)
+{
+ gboolean password_strength;
+ g_object_get (prompt, "password-strength", &password_strength, NULL);
+ return password_strength;
+}
+
+gchar *
+gcr_prompt_get_caller_window (GcrPrompt *prompt)
+{
+ gchar *caller_window = NULL;
+ g_object_get (prompt, "caller-window", &caller_window, NULL);
+ return caller_window;
+}
+
+void
+gcr_prompt_set_caller_window (GcrPrompt *prompt,
+ const gchar *window_id)
+{
+ g_return_if_fail (GCR_IS_PROMPT (prompt));
+ g_object_set (prompt, "caller-window", window_id, NULL);
+}
+
+void
+gcr_prompt_password_async (GcrPrompt *prompt,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GcrPromptIface *iface;
+
+ g_return_if_fail (GCR_IS_PROMPT (prompt));
+ g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+
+ iface = GCR_PROMPT_GET_INTERFACE (prompt);
+ g_return_if_fail (iface->prompt_password_async);
+
+ (iface->prompt_password_async) (prompt, cancellable, callback, user_data);
+}
+
+const gchar *
+gcr_prompt_password_finish (GcrPrompt *prompt,
+ GAsyncResult *result,
+ GError **error)
+{
+ GcrPromptIface *iface;
+
+ g_return_val_if_fail (GCR_IS_PROMPT (prompt), NULL);
+ g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ iface = GCR_PROMPT_GET_INTERFACE (prompt);
+ g_return_val_if_fail (iface->prompt_password_async, NULL);
+
+ return (iface->prompt_password_finish) (prompt, result, error);
+}
+
+const gchar *
+gcr_prompt_password (GcrPrompt *prompt,
+ GCancellable *cancellable,
+ GError **error)
+{
+ RunClosure *closure;
+ const gchar *reply;
+
+ g_return_val_if_fail (GCR_IS_PROMPT (prompt), NULL);
+ g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ closure = run_closure_begin (g_main_context_new ());
+
+ gcr_prompt_password_async (prompt, cancellable, on_run_complete, closure);
+
+ g_main_loop_run (closure->loop);
+
+ reply = gcr_prompt_password_finish (prompt, closure->result, error);
+ run_closure_end (closure);
+
+ return reply;
+}
+
+const gchar *
+gcr_prompt_password_run (GcrPrompt *prompt,
+ GCancellable *cancellable,
+ GError **error)
+{
+ RunClosure *closure;
+ const gchar *reply;
+
+ g_return_val_if_fail (GCR_IS_PROMPT (prompt), NULL);
+ g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ closure = run_closure_begin (NULL);
+
+ gcr_prompt_password_async (prompt, cancellable, on_run_complete, closure);
+
+ g_main_loop_run (closure->loop);
+
+ reply = gcr_prompt_password_finish (prompt, closure->result, error);
+ run_closure_end (closure);
+
+ return reply;
+}
+
+void
+gcr_prompt_confirm_async (GcrPrompt *prompt,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GcrPromptIface *iface;
+
+ g_return_if_fail (GCR_IS_PROMPT (prompt));
+ g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+
+ iface = GCR_PROMPT_GET_INTERFACE (prompt);
+ g_return_if_fail (iface->prompt_confirm_async);
+
+ (iface->prompt_confirm_async) (prompt, cancellable, callback, user_data);
+}
+
+GcrPromptReply
+gcr_prompt_confirm_finish (GcrPrompt *prompt,
+ GAsyncResult *result,
+ GError **error)
+{
+ GcrPromptIface *iface;
+
+ g_return_val_if_fail (GCR_IS_PROMPT (prompt), GCR_PROMPT_REPLY_CANCEL);
+ g_return_val_if_fail (G_IS_ASYNC_RESULT (result), GCR_PROMPT_REPLY_CANCEL);
+ g_return_val_if_fail (error == NULL || *error == NULL, GCR_PROMPT_REPLY_CANCEL);
+
+ iface = GCR_PROMPT_GET_INTERFACE (prompt);
+ g_return_val_if_fail (iface->prompt_confirm_async, GCR_PROMPT_REPLY_CANCEL);
+
+ return (iface->prompt_confirm_finish) (prompt, result, error);
+}
+
+GcrPromptReply
+gcr_prompt_confirm (GcrPrompt *prompt,
+ GCancellable *cancellable,
+ GError **error)
+{
+ RunClosure *closure;
+ GcrPromptReply reply;
+
+ g_return_val_if_fail (GCR_IS_PROMPT (prompt), GCR_PROMPT_REPLY_CANCEL);
+ g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), GCR_PROMPT_REPLY_CANCEL);
+ g_return_val_if_fail (error == NULL || *error == NULL, GCR_PROMPT_REPLY_CANCEL);
+
+ closure = run_closure_begin (g_main_context_new ());
+
+ gcr_prompt_confirm_async (prompt, cancellable, on_run_complete, closure);
+
+ g_main_loop_run (closure->loop);
+
+ reply = gcr_prompt_confirm_finish (prompt, closure->result, error);
+ run_closure_end (closure);
+
+ return reply;
+}
+
+/**
+ * gcr_system_prompt_confirm:
+ * @self: a prompt
+ * @cancellable: optional cancellation object
+ * @error: location to place error on failure
+ *
+ * Prompts for confirmation asking a cancel/continue style question.
+ * Set the various properties on the prompt to represent the question
+ * correctly.
+ *
+ * This method will block until the a response is returned from the prompter.
+ * and %TRUE or %FALSE will be returned based on the response. The return value
+ * will also be %FALSE if an error occurs. Check the @error argument to tell
+ * the difference.
+ *
+ * Returns: whether the prompt was confirmed or not
+ */
+GcrPromptReply
+gcr_prompt_confirm_run (GcrPrompt *prompt,
+ GCancellable *cancellable,
+ GError **error)
+{
+ RunClosure *closure;
+ GcrPromptReply reply;
+
+ g_return_val_if_fail (GCR_IS_PROMPT (prompt), GCR_PROMPT_REPLY_CANCEL);
+ g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), GCR_PROMPT_REPLY_CANCEL);
+ g_return_val_if_fail (error == NULL || *error == NULL, GCR_PROMPT_REPLY_CANCEL);
+
+ closure = run_closure_begin (NULL);
+
+ gcr_prompt_confirm_async (prompt, cancellable, on_run_complete, closure);
+
+ g_main_loop_run (closure->loop);
+
+ reply = gcr_prompt_confirm_finish (prompt, closure->result, error);
+ run_closure_end (closure);
+
+ return reply;
+}
diff --git a/gcr/gcr-prompt.h b/gcr/gcr-prompt.h
new file mode 100644
index 0000000..a115704
--- /dev/null
+++ b/gcr/gcr-prompt.h
@@ -0,0 +1,152 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2011 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Author: Stef Walter <stef thewalter net>
+ */
+
+#if !defined (__GCR_INSIDE_HEADER__) && !defined (GCR_COMPILATION)
+#error "Only <gcr/gcr.h> or <gcr/gcr-base.h> can be included directly."
+#endif
+
+#ifndef __GCR_PROMPT_H__
+#define __GCR_PROMPT_H__
+
+#include "gcr-types.h"
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+typedef enum {
+ GCR_PROMPT_REPLY_CANCEL = 0,
+ GCR_PROMPT_REPLY_OK = 1,
+} GcrPromptReply;
+
+#define GCR_TYPE_PROMPT (gcr_prompt_get_type ())
+#define GCR_PROMPT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_PROMPT, GcrPrompt))
+#define GCR_IS_PROMPT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_PROMPT))
+#define GCR_PROMPT_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GCR_TYPE_PROMPT, GcrPromptIface))
+
+typedef struct _GcrPrompt GcrPrompt;
+typedef struct _GcrPromptIface GcrPromptIface;
+
+struct _GcrPromptIface {
+ GTypeInterface parent_class;
+
+ void (* prompt_password_async) (GcrPrompt *prompt,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+ const gchar * (* prompt_password_finish) (GcrPrompt *prompt,
+ GAsyncResult *result,
+ GError **error);
+
+ void (* prompt_confirm_async) (GcrPrompt *prompt,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+ GcrPromptReply (* prompt_confirm_finish) (GcrPrompt *prompt,
+ GAsyncResult *result,
+ GError **error);
+};
+
+GType gcr_prompt_get_type (void);
+
+gchar * gcr_prompt_get_title (GcrPrompt *prompt);
+
+void gcr_prompt_set_title (GcrPrompt *prompt,
+ const gchar *title);
+
+gchar * gcr_prompt_get_message (GcrPrompt *prompt);
+
+void gcr_prompt_set_message (GcrPrompt *prompt,
+ const gchar *message);
+
+gchar * gcr_prompt_get_description (GcrPrompt *prompt);
+
+void gcr_prompt_set_description (GcrPrompt *prompt,
+ const gchar *description);
+
+gchar * gcr_prompt_get_warning (GcrPrompt *prompt);
+
+void gcr_prompt_set_warning (GcrPrompt *prompt,
+ const gchar *warning);
+
+gchar * gcr_prompt_get_choice_label (GcrPrompt *prompt);
+
+void gcr_prompt_set_choice_label (GcrPrompt *prompt,
+ const gchar *warning);
+
+gboolean gcr_prompt_get_choice_chosen (GcrPrompt *prompt);
+
+void gcr_prompt_set_choice_chosen (GcrPrompt *prompt,
+ gboolean chosen);
+
+gboolean gcr_prompt_get_password_new (GcrPrompt *prompt);
+
+void gcr_prompt_set_password_new (GcrPrompt *prompt,
+ gboolean new_password);
+
+gint gcr_prompt_get_password_strength (GcrPrompt *prompt);
+
+gchar * gcr_prompt_get_caller_window (GcrPrompt *prompt);
+
+void gcr_prompt_set_caller_window (GcrPrompt *prompt,
+ const gchar *window_id);
+
+void gcr_prompt_password_async (GcrPrompt *prompt,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+const gchar * gcr_prompt_password_finish (GcrPrompt *prompt,
+ GAsyncResult *result,
+ GError **error);
+
+const gchar * gcr_prompt_password (GcrPrompt *prompt,
+ GCancellable *cancellable,
+ GError **error);
+
+const gchar * gcr_prompt_password_run (GcrPrompt *prompt,
+ GCancellable *cancellable,
+ GError **error);
+
+void gcr_prompt_confirm_async (GcrPrompt *prompt,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+GcrPromptReply gcr_prompt_confirm_finish (GcrPrompt *prompt,
+ GAsyncResult *result,
+ GError **error);
+
+GcrPromptReply gcr_prompt_confirm (GcrPrompt *prompt,
+ GCancellable *cancellable,
+ GError **error);
+
+GcrPromptReply gcr_prompt_confirm_run (GcrPrompt *prompt,
+ GCancellable *cancellable,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* __GCR_PROMPT_H__ */
diff --git a/gcr/gcr-prompter-tool.c b/gcr/gcr-prompter-tool.c
index 86ca293..089dc65 100644
--- a/gcr/gcr-prompter-tool.c
+++ b/gcr/gcr-prompter-tool.c
@@ -38,51 +38,13 @@
#include <stdlib.h>
#include <string.h>
-#define LOG_ERRORS 1
-#define GRAB_KEYBOARD 1
#define QUIT_TIMEOUT 10
static GcrSystemPrompter *the_prompter = NULL;
-GType gcr_prompter_dialog_get_type (void) G_GNUC_CONST;
-#define GCR_TYPE_PROMPTER_DIALOG (gcr_prompter_dialog_get_type ())
-#define GCR_PROMPTER_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_PROMPTER_DIALOG, GcrPrompterDialog))
-#define GCR_IS_PROMPTER_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_PROMPTER_DIALOG))
-
-typedef enum {
- PROMPT_NONE,
- PROMPT_CONFIRMING,
- PROMPT_PASSWORDING
-} PromptMode;
-
-enum {
- PROP_0,
- PROP_PASSWORD_VISIBLE,
- PROP_CONFIRM_VISIBLE,
- PROP_WARNING_VISIBLE,
- PROP_CHOICE_VISIBLE,
-};
-
-typedef struct {
- GtkDialog parent;
- GtkWidget *spinner;
- GtkWidget *image;
- GtkEntryBuffer *password_buffer;
- GtkEntryBuffer *confirm_buffer;
- PromptMode mode;
- GdkDevice *grabbed_device;
- gulong grab_broken_id;
- guint quit_timeout;
-} GcrPrompterDialog;
-
-typedef struct {
- GtkDialogClass parent;
-} GcrPrompterDialogClass;
-
-G_DEFINE_TYPE (GcrPrompterDialog, gcr_prompter_dialog, GTK_TYPE_DIALOG);
-
+#if 0
static gboolean
-on_timeout_quit ()
+on_timeout_quit (gpointer unused)
{
gtk_main_quit ();
return FALSE; /* Don't run again */
@@ -105,555 +67,13 @@ stop_timeout (GcrPrompterDialog *self)
g_source_remove (self->quit_timeout);
self->quit_timeout = 0;
}
-
-static void
-on_open_prompt (GcrSystemPrompter *prompter,
- gpointer user_data)
-{
- GcrPrompterDialog *self = GCR_PROMPTER_DIALOG (user_data);
- gtk_widget_show (GTK_WIDGET (self));
- stop_timeout (self);
-}
-
-static void
-on_close_prompt (GcrSystemPrompter *prompter,
- gpointer user_data)
-{
- GcrPrompterDialog *self = GCR_PROMPTER_DIALOG (user_data);
- gtk_widget_hide (GTK_WIDGET (self));
- start_timeout (self);
-}
-
-static gboolean
-on_prompt_confirm (GcrSystemPrompter *prompter,
- gpointer user_data)
-{
- GcrPrompterDialog *self = GCR_PROMPTER_DIALOG (user_data);
- GObject *obj;
-
- g_return_val_if_fail (self->mode == PROMPT_NONE, FALSE);
-
- self->mode = PROMPT_CONFIRMING;
- gtk_image_set_from_stock (GTK_IMAGE (self->image),
- GTK_STOCK_DIALOG_QUESTION,
- GTK_ICON_SIZE_DIALOG);
- gtk_widget_set_sensitive (GTK_WIDGET (self), TRUE);
- gtk_widget_show (self->image);
- gtk_widget_hide (self->spinner);
-
- obj = G_OBJECT (self);
- g_object_notify (obj, "password-visible");
- g_object_notify (obj, "confirm-visible");
- g_object_notify (obj, "warning-visible");
- g_object_notify (obj, "choice-visible");
-
- return TRUE;
-}
-
-static gboolean
-on_prompt_password (GcrSystemPrompter *prompter,
- gpointer user_data)
-{
- GcrPrompterDialog *self = GCR_PROMPTER_DIALOG (user_data);
- GObject *obj;
-
- g_return_val_if_fail (self->mode == PROMPT_NONE, FALSE);
-
- self->mode = PROMPT_PASSWORDING;
- gtk_image_set_from_stock (GTK_IMAGE (self->image),
- GTK_STOCK_DIALOG_AUTHENTICATION,
- GTK_ICON_SIZE_DIALOG);
- gtk_widget_set_sensitive (GTK_WIDGET (self), TRUE);
- gtk_widget_show (self->image);
- gtk_widget_hide (self->spinner);
-
- obj = G_OBJECT (self);
- g_object_notify (obj, "password-visible");
- g_object_notify (obj, "confirm-visible");
- g_object_notify (obj, "warning-visible");
- g_object_notify (obj, "choice-visible");
-
- return TRUE;
-}
-
-static void
-on_responded (GcrSystemPrompter *prompter,
- gpointer user_data)
-{
- GcrPrompterDialog *self = GCR_PROMPTER_DIALOG (user_data);
- gtk_widget_set_sensitive (GTK_WIDGET (self), FALSE);
- gtk_widget_hide (GTK_WIDGET (self->image));
- gtk_widget_show (GTK_WIDGET (self->spinner));
- self->mode = PROMPT_NONE;
-}
-
-static const gchar *
-grab_status_message (GdkGrabStatus status)
-{
- switch (status) {
- case GDK_GRAB_SUCCESS:
- g_return_val_if_reached ("");
- case GDK_GRAB_ALREADY_GRABBED:
- return "already grabbed";
- case GDK_GRAB_INVALID_TIME:
- return "invalid time";
- case GDK_GRAB_NOT_VIEWABLE:
- return "not viewable";
- case GDK_GRAB_FROZEN:
- return "frozen";
- default:
- g_message ("unknown grab status: %d", (int)status);
- return "unknown";
- }
-}
-
-static gboolean
-on_grab_broken (GtkWidget *widget,
- GdkEventGrabBroken *event,
- gpointer user_data)
-{
- GcrPrompterDialog *self = GCR_PROMPTER_DIALOG (user_data);
- if (self->grabbed_device && event->keyboard)
- self->grabbed_device = NULL;
- return TRUE;
-}
-
-static gboolean
-grab_keyboard (GtkWidget *widget,
- GdkEvent *event,
- gpointer user_data)
-{
- GcrPrompterDialog *self = GCR_PROMPTER_DIALOG (user_data);
- GdkGrabStatus status;
- guint32 at;
-
- GdkDevice *device = NULL;
- GdkDeviceManager *manager;
- GdkDisplay *display;
- GList *devices, *l;
-
- if (self->grabbed_device || !GRAB_KEYBOARD)
- return FALSE;
-
- display = gtk_widget_get_display (widget);
- manager = gdk_display_get_device_manager (display);
- devices = gdk_device_manager_list_devices (manager, GDK_DEVICE_TYPE_MASTER);
- for (l = devices; l; l = g_list_next (l)) {
- device = l->data;
- if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
- break;
- }
- g_list_free (devices);
-
- if (!device) {
- g_message ("couldn't find device to grab");
- return FALSE;
- }
-
- at = event ? gdk_event_get_time (event) : GDK_CURRENT_TIME;
- status = gdk_device_grab (device, gtk_widget_get_window (widget),
- GDK_OWNERSHIP_WINDOW, TRUE,
- GDK_KEY_PRESS | GDK_KEY_RELEASE, NULL, at);
- if (status == GDK_GRAB_SUCCESS) {
- self->grab_broken_id = g_signal_connect (widget, "grab-broken-event",
- G_CALLBACK (on_grab_broken), self);
- gtk_device_grab_add (widget, device, TRUE);
- self->grabbed_device = device;
- } else {
- g_message ("could not grab keyboard: %s", grab_status_message (status));
- }
-
- /* Always return false, so event is handled elsewhere */
- return FALSE;
-}
-
-
-static gboolean
-ungrab_keyboard (GtkWidget *widget,
- GdkEvent *event,
- gpointer user_data)
-{
- guint32 at = event ? gdk_event_get_time (event) : GDK_CURRENT_TIME;
- GcrPrompterDialog *self = GCR_PROMPTER_DIALOG (user_data);
-
- if (self->grabbed_device) {
- g_signal_handler_disconnect (widget, self->grab_broken_id);
- gdk_device_ungrab (self->grabbed_device, at);
- gtk_device_grab_remove (widget, self->grabbed_device);
- self->grabbed_device = NULL;
- self->grab_broken_id = 0;
- }
-
- /* Always return false, so event is handled elsewhere */
- return FALSE;
-}
-
-static gboolean
-window_state_changed (GtkWidget *widget,
- GdkEventWindowState *event,
- gpointer user_data)
-{
- GdkWindowState state = gdk_window_get_state (gtk_widget_get_window (widget));
-
- if (state & GDK_WINDOW_STATE_WITHDRAWN ||
- state & GDK_WINDOW_STATE_ICONIFIED ||
- state & GDK_WINDOW_STATE_FULLSCREEN ||
- state & GDK_WINDOW_STATE_MAXIMIZED)
- ungrab_keyboard (widget, (GdkEvent*)event, user_data);
- else
- grab_keyboard (widget, (GdkEvent*)event, user_data);
-
- return FALSE;
-}
-
-static void
-on_password_changed (GtkEditable *editable,
- gpointer user_data)
-{
- int upper, lower, digit, misc;
- const char *password;
- gdouble pwstrength;
- int length, i;
-
- password = gtk_entry_get_text (GTK_ENTRY (editable));
-
- /*
- * This code is based on the Master Password dialog in Firefox
- * (pref-masterpass.js)
- * Original code triple-licensed under the MPL, GPL, and LGPL
- * so is license-compatible with this file
- */
-
- length = strlen (password);
- upper = 0;
- lower = 0;
- digit = 0;
- misc = 0;
-
- for ( i = 0; i < length ; i++) {
- if (g_ascii_isdigit (password[i]))
- digit++;
- else if (g_ascii_islower (password[i]))
- lower++;
- else if (g_ascii_isupper (password[i]))
- upper++;
- else
- misc++;
- }
-
- if (length > 5)
- length = 5;
- if (digit > 3)
- digit = 3;
- if (upper > 3)
- upper = 3;
- if (misc > 3)
- misc = 3;
-
- pwstrength = ((length * 0.1) - 0.2) +
- (digit * 0.1) +
- (misc * 0.15) +
- (upper * 0.1);
-
- if (pwstrength < 0.0)
- pwstrength = 0.0;
- if (pwstrength > 1.0)
- pwstrength = 1.0;
-
- gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (user_data), pwstrength);
-}
-
-static void
-handle_password_response (GcrPrompterDialog *self)
-{
- const gchar *password;
- const gchar *confirm;
- const gchar *env;
- gint strength;
-
- password = gtk_entry_buffer_get_text (self->password_buffer);
-
- /* Is it a new password? */
- if (gcr_system_prompter_get_password_new (the_prompter)) {
- confirm = gtk_entry_buffer_get_text (self->confirm_buffer);
-
- /* Do the passwords match? */
- if (!g_str_equal (password, confirm)) {
- gcr_system_prompter_set_warning (the_prompter, _("Passwords do not match."));
- return;
- }
-
- /* Don't allow blank passwords if in paranoid mode */
- env = g_getenv ("GNOME_KEYRING_PARANOID");
- if (env && *env) {
- gcr_system_prompter_set_warning (the_prompter, _("Password cannot be blank"));
- return;
- }
- }
-
- if (g_str_equal (password, ""))
- strength = 0;
- else
- strength = 1;
- gcr_system_prompter_set_password_strength (the_prompter, strength);
-
- gcr_system_prompter_respond_with_password (the_prompter, password);
-}
-
-static void
-gcr_prompter_dialog_realize (GtkWidget *widget)
-{
- gboolean modal = FALSE;
- const gchar *value;
- gulong caller_window_id;
- GdkWindow *caller_window;
- GdkWindow *self_window;
- GdkDisplay *display;
- gchar *end;
-
- GTK_WIDGET_CLASS (gcr_prompter_dialog_parent_class)->realize (widget);
-
- value= gcr_system_prompter_get_caller_window (the_prompter);
- if (value) {
- caller_window_id = strtoul (value, &end, 10);
- if (caller_window_id && end && end[0] == '\0') {
- display = gtk_widget_get_display (widget);
- caller_window = gdk_x11_window_foreign_new_for_display (display, caller_window_id);
- if (caller_window) {
- self_window = gtk_widget_get_window (widget);
- gdk_window_set_transient_for (self_window, caller_window);
- g_object_unref (caller_window);
- modal = TRUE;
- }
- }
- }
-
- gtk_window_set_modal (GTK_WINDOW (widget), modal);
-}
-
-static void
-gcr_prompter_dialog_response (GtkDialog *dialog,
- gint response_id)
-{
- GcrPrompterDialog *self = GCR_PROMPTER_DIALOG (dialog);
-
- if (response_id != GTK_RESPONSE_OK)
- gcr_system_prompter_respond_cancelled (the_prompter);
-
- else if (self->mode == PROMPT_PASSWORDING)
- handle_password_response (self);
-
- else if (self->mode == PROMPT_CONFIRMING)
- gcr_system_prompter_respond_confirmed (the_prompter);
-
- else
- g_return_if_reached ();
-}
-
-static void
-gcr_prompter_dialog_init (GcrPrompterDialog *self)
-{
- PangoAttrList *attrs;
- GtkDialog *dialog;
- GtkWidget *widget;
- GtkWidget *entry;
- GtkWidget *content;
- GtkGrid *grid;
-
- g_assert (GCR_IS_SYSTEM_PROMPTER (the_prompter));
-
- g_signal_connect (the_prompter, "open", G_CALLBACK (on_open_prompt), self);
- g_signal_connect (the_prompter, "prompt-password", G_CALLBACK (on_prompt_password), self);
- g_signal_connect (the_prompter, "prompt-confirm", G_CALLBACK (on_prompt_confirm), self);
- g_signal_connect (the_prompter, "responded", G_CALLBACK (on_responded), self);
- g_signal_connect (the_prompter, "close", G_CALLBACK (on_close_prompt), self);
-
- dialog = GTK_DIALOG (self);
- gtk_dialog_add_buttons (dialog,
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
- _("Continue"), GTK_RESPONSE_OK,
- NULL);
-
- content = gtk_dialog_get_content_area (dialog);
-
- grid = GTK_GRID (gtk_grid_new ());
- gtk_container_set_border_width (GTK_CONTAINER (grid), 6);
- gtk_widget_set_hexpand (GTK_WIDGET (grid), TRUE);
- gtk_grid_set_column_spacing (grid, 12);
- gtk_grid_set_row_spacing (grid, 6);
-
- /* The prompt image */
- self->image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_AUTHENTICATION,
- GTK_ICON_SIZE_DIALOG);
- gtk_widget_set_valign (self->image, GTK_ALIGN_START);
- gtk_grid_attach (grid, self->image, -1, 0, 1, 4);
- gtk_widget_show (self->image);
-
- /* The prompt spinner */
- self->spinner = gtk_spinner_new ();
- gtk_widget_set_valign (self->image, GTK_ALIGN_START);
- gtk_grid_attach (grid, self->spinner, -2, -1, 1, 4);
- gtk_widget_show (self->spinner);
-
- /* The message label */
- widget = gtk_label_new ("");
- attrs = pango_attr_list_new ();
- pango_attr_list_insert (attrs, pango_attr_weight_new (PANGO_WEIGHT_BOLD));
- pango_attr_list_insert (attrs, pango_attr_scale_new (PANGO_SCALE_LARGE));
- gtk_label_set_attributes (GTK_LABEL (widget), attrs);
- pango_attr_list_unref (attrs);
- gtk_widget_set_halign (widget, GTK_ALIGN_START);
- gtk_widget_set_hexpand (widget, TRUE);
- gtk_widget_set_margin_bottom (widget, 8);
- g_object_bind_property (the_prompter, "message", widget, "label", G_BINDING_DEFAULT);
- gtk_grid_attach (grid, widget, 0, 0, 2, 1);
- gtk_widget_show (widget);
-
- /* The description label */
- widget = gtk_label_new ("");
- gtk_widget_set_halign (widget, GTK_ALIGN_START);
- gtk_widget_set_hexpand (widget, TRUE);
- gtk_widget_set_margin_bottom (widget, 4);
- g_object_bind_property (the_prompter, "description", widget, "label", G_BINDING_DEFAULT);
- gtk_grid_attach (grid, widget, 0, 1, 2, 1);
- gtk_widget_show (widget);
-
- /* The password label */
- widget = gtk_label_new (_("Password:"));
- gtk_widget_set_halign (widget, GTK_ALIGN_START);
- g_object_bind_property (self, "password-visible", widget, "visible", G_BINDING_DEFAULT);
- gtk_grid_attach (grid, widget, 0, 2, 1, 1);
-
- /* The password entry */
- self->password_buffer = gcr_secure_entry_buffer_new ();
- entry = gtk_entry_new_with_buffer (self->password_buffer);
- gtk_entry_set_visibility (GTK_ENTRY (entry), FALSE);
- gtk_widget_set_hexpand (widget, TRUE);
- g_object_bind_property (self, "password-visible", entry, "visible", G_BINDING_DEFAULT);
- gtk_grid_attach (grid, entry, 1, 2, 1, 1);
-
- /* The confirm label */
- widget = gtk_label_new (_("Confirm:"));
- gtk_widget_set_halign (widget, GTK_ALIGN_START);
- g_object_bind_property (self, "confirm-visible", widget, "visible", G_BINDING_DEFAULT);
- gtk_grid_attach (grid, widget, 0, 3, 1, 1);
-
- /* The confirm entry */
- self->confirm_buffer = gcr_secure_entry_buffer_new ();
- widget = gtk_entry_new_with_buffer (self->password_buffer);
- gtk_widget_set_hexpand (widget, TRUE);
- gtk_entry_set_visibility (GTK_ENTRY (widget), FALSE);
- g_object_bind_property (self, "confirm-visible", widget, "visible", G_BINDING_DEFAULT);
- gtk_grid_attach (grid, widget, 1, 3, 1, 1);
-
- /* The quality progress bar */
- widget = gtk_progress_bar_new ();
- gtk_widget_set_hexpand (widget, TRUE);
- g_object_bind_property (self, "confirm-visible", widget, "visible", G_BINDING_DEFAULT);
- gtk_grid_attach (grid, widget, 1, 4, 1, 1);
- g_signal_connect (entry, "changed", G_CALLBACK (on_password_changed), widget);
-
- /* The warning */
- widget = gtk_label_new ("");
- attrs = pango_attr_list_new ();
- pango_attr_list_insert (attrs, pango_attr_style_new (PANGO_STYLE_ITALIC));
- gtk_label_set_attributes (GTK_LABEL (widget), attrs);
- pango_attr_list_unref (attrs);
- g_object_bind_property (the_prompter, "warning", widget, "label", G_BINDING_DEFAULT);
- g_object_bind_property (self, "warning-visible", widget, "visible", G_BINDING_DEFAULT);
- gtk_grid_attach (grid, widget, 0, 5, 2, 1);
- gtk_widget_show (widget);
-
- /* The checkbox */
- widget = gtk_check_button_new ();
- g_object_bind_property (the_prompter, "choice-label", widget, "label", G_BINDING_DEFAULT);
- g_object_bind_property (self, "choice-visible", widget, "visible", G_BINDING_DEFAULT);
- g_object_bind_property (the_prompter, "choice-chosen", widget, "active", G_BINDING_BIDIRECTIONAL);
- gtk_grid_attach (grid, widget, 0, 6, 2, 1);
-
- gtk_container_add (GTK_CONTAINER (content), GTK_WIDGET (grid));
- gtk_widget_show (GTK_WIDGET (grid));
-
- g_signal_connect (self, "map-event", G_CALLBACK (grab_keyboard), self);
- g_signal_connect (self, "unmap-event", G_CALLBACK (ungrab_keyboard), self);
- g_signal_connect (self, "window-state-event", G_CALLBACK (window_state_changed), self);
-}
-
-static void
-gcr_prompter_dialog_get_property (GObject *obj,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- GcrPrompterDialog *self = GCR_PROMPTER_DIALOG (obj);
- const gchar *string;
-
- switch (prop_id)
- {
- case PROP_PASSWORD_VISIBLE:
- g_value_set_boolean (value, self->mode == PROMPT_PASSWORDING);
- break;
- case PROP_CONFIRM_VISIBLE:
- g_value_set_boolean (value, gcr_system_prompter_get_password_new (the_prompter) &&
- self->mode == PROMPT_PASSWORDING);
- break;
- case PROP_WARNING_VISIBLE:
- string = gcr_system_prompter_get_warning (the_prompter);
- g_value_set_boolean (value, string && string[0]);
- break;
- case PROP_CHOICE_VISIBLE:
- string = gcr_system_prompter_get_choice_label (the_prompter);
- g_value_set_boolean (value, string && string[0]);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
- break;
- }
-}
-
-static void
-gcr_prompter_dialog_finalize (GObject *obj)
-{
- G_OBJECT_GET_CLASS (gcr_prompter_dialog_parent_class)->finalize (obj);
-}
-
-static void
-gcr_prompter_dialog_class_init (GcrPrompterDialogClass *klass)
-{
- GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
- GtkDialogClass *dialog_class = GTK_DIALOG_CLASS (klass);
- GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
-
- widget_class->realize = gcr_prompter_dialog_realize;
-
- gobject_class->finalize = gcr_prompter_dialog_finalize;
- gobject_class->get_property = gcr_prompter_dialog_get_property;
-
- dialog_class->response = gcr_prompter_dialog_response;
-
- g_object_class_install_property (gobject_class, PROP_PASSWORD_VISIBLE,
- g_param_spec_boolean ("password-visible", "", "",
- FALSE, G_PARAM_READABLE));
-
- g_object_class_install_property (gobject_class, PROP_CONFIRM_VISIBLE,
- g_param_spec_boolean ("confirm-visible", "", "",
- FALSE, G_PARAM_READABLE));
-
- g_object_class_install_property (gobject_class, PROP_WARNING_VISIBLE,
- g_param_spec_boolean ("warning-visible", "", "",
- FALSE, G_PARAM_READABLE));
-
- g_object_class_install_property (gobject_class, PROP_CHOICE_VISIBLE,
- g_param_spec_boolean ("choice-visible", "", "",
- FALSE, G_PARAM_READABLE));
-}
+#endif
static void
on_bus_acquired (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
- gcr_system_prompter_register (the_prompter, connection);
}
static void
@@ -661,7 +81,7 @@ on_name_acquired (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
-
+ gcr_system_prompter_register (the_prompter, connection);
}
static void
@@ -669,13 +89,13 @@ on_name_lost (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
+ gcr_system_prompter_unregister (the_prompter, FALSE);
gtk_main_quit ();
}
int
main (int argc, char *argv[])
{
- GtkDialog *dialog;
guint owner_id;
g_type_init ();
@@ -692,8 +112,8 @@ main (int argc, char *argv[])
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
#endif
- the_prompter = gcr_system_prompter_new ();
- dialog = g_object_new (GCR_TYPE_PROMPTER_DIALOG, NULL);
+ the_prompter = gcr_system_prompter_new (GCR_SYSTEM_PROMPTER_SINGLE,
+ GCR_TYPE_PROMPT_DIALOG);
owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
GCR_DBUS_PROMPTER_BUS_NAME,
G_BUS_NAME_OWNER_FLAGS_NONE,
@@ -707,7 +127,6 @@ main (int argc, char *argv[])
g_bus_unown_name (owner_id);
g_object_unref (the_prompter);
- gtk_widget_destroy (GTK_WIDGET (dialog));
return 0;
}
diff --git a/gcr/gcr-secret-exchange.c b/gcr/gcr-secret-exchange.c
index 43672f1..cb3941f 100644
--- a/gcr/gcr-secret-exchange.c
+++ b/gcr/gcr-secret-exchange.c
@@ -378,7 +378,10 @@ perform_decrypt (GcrSecretExchange *self,
* @exchange: the string received
*
* Receive a string from the other side of secret exchange. This string will
- * have been created by gcr_secret_exchange_begin() or gcr_secret_exchange_send()
+ * have been created by gcr_secret_exchange_begin() or gcr_secret_exchange_send().
+ *
+ * After this call completes successfully the value returned from
+ * gcr_secret_exchange_get_secret() will have changed.
*
* Returns: whether the string was successfully parsed and received
*/
@@ -387,9 +390,9 @@ gcr_secret_exchange_receive (GcrSecretExchange *self,
const gchar *exchange)
{
GcrSecretExchangeClass *klass;
+ gchar *secret = NULL;
+ gsize n_secret = 0;
GKeyFile *input;
- gchar *secret;
- gsize n_secret;
gboolean ret;
g_return_val_if_fail (GCR_IS_SECRET_EXCHANGE (self), FALSE);
@@ -422,16 +425,13 @@ gcr_secret_exchange_receive (GcrSecretExchange *self,
ret = FALSE;
}
- if (ret && g_key_file_has_key (input, GCR_SECRET_EXCHANGE_PROTOCOL_1, "secret", NULL)) {
+ if (ret && g_key_file_has_key (input, GCR_SECRET_EXCHANGE_PROTOCOL_1, "secret", NULL))
+ ret = perform_decrypt (self, input, (guchar **)&secret, &n_secret);
- /* Remember that this can return a NULL secret */
- if (!perform_decrypt (self, input, (guchar **)&secret, &n_secret)) {
- ret = FALSE;
- } else {
- egg_secure_free (self->pv->secret);
- self->pv->secret = secret;
- self->pv->n_secret = n_secret;
- }
+ if (ret) {
+ egg_secure_free (self->pv->secret);
+ self->pv->secret = secret;
+ self->pv->n_secret = n_secret;
}
g_key_file_free (input);
diff --git a/gcr/gcr-system-prompt.c b/gcr/gcr-system-prompt.c
index 165f3e3..fc6f6ba 100644
--- a/gcr/gcr-system-prompt.c
+++ b/gcr/gcr-system-prompt.c
@@ -29,11 +29,14 @@
#include "gcr-debug.h"
#include "gcr-internal.h"
#include "gcr-library.h"
+#include "gcr-prompt.h"
#include "gcr-secret-exchange.h"
#include "gcr-system-prompt.h"
#include "egg/egg-error.h"
+#include <glib/gi18n.h>
+
/**
* SECTION:gcr-system-prompt
* @title: GcrSystemPrompt
@@ -72,17 +75,24 @@ enum {
struct _GcrSystemPromptPrivate {
gchar *prompter_bus_name;
- GDBusConnection *connection;
GcrSecretExchange *exchange;
- GHashTable *properties_to_write;
- GHashTable *property_cache;
- GDBusProxy *prompt_proxy;
- gchar *prompt_path;
- gboolean exchanged;
- gboolean begun_prompting;
+ gboolean received;
+ GHashTable *properties;
+ GHashTable *dirty_properties;
gint timeout_seconds;
+
+ GDBusConnection *connection;
+ gboolean begun_prompting;
+ gboolean closed;
+ guint prompt_registered;
+ gchar *prompt_path;
+
+ GSimpleAsyncResult *pending;
+ gchar *last_response;
};
+static void gcr_system_prompt_prompt_iface (GcrPromptIface *iface);
+
static void gcr_system_prompt_initable_iface (GInitableIface *iface);
static void gcr_system_prompt_async_initable_iface (GAsyncInitableIface *iface);
@@ -91,10 +101,30 @@ static void perform_init_async (GcrSystemPrompt *self,
GSimpleAsyncResult *res);
G_DEFINE_TYPE_WITH_CODE (GcrSystemPrompt, gcr_system_prompt, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (GCR_TYPE_PROMPT, gcr_system_prompt_prompt_iface);
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, gcr_system_prompt_initable_iface);
G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, gcr_system_prompt_async_initable_iface);
);
+static gint unique_prompt_id = 0;
+
+typedef struct {
+ GSource *timeout;
+ GMainContext *context;
+ GCancellable *cancellable;
+ gboolean waiting;
+} CallClosure;
+
+static void
+call_closure_free (gpointer data)
+{
+ CallClosure *closure = data;
+ if (closure->timeout)
+ g_source_destroy (closure->timeout);
+ g_clear_object (&closure->cancellable);
+ g_free (data);
+}
+
static void
gcr_system_prompt_init (GcrSystemPrompt *self)
{
@@ -102,9 +132,94 @@ gcr_system_prompt_init (GcrSystemPrompt *self)
GcrSystemPromptPrivate);
self->pv->timeout_seconds = -1;
- self->pv->properties_to_write = g_hash_table_new (g_str_hash, g_str_equal);
- self->pv->property_cache = g_hash_table_new_full (g_str_hash, g_str_equal,
- NULL, (GDestroyNotify)g_variant_unref);
+ self->pv->properties = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+ NULL, (GDestroyNotify)g_variant_unref);
+ self->pv->dirty_properties = g_hash_table_new (g_direct_hash, g_direct_equal);
+}
+
+static const gchar *
+prompt_get_string_property (GcrSystemPrompt *self,
+ const gchar *property_name)
+{
+ GVariant *variant;
+ gconstpointer key;
+
+ g_return_val_if_fail (GCR_IS_SYSTEM_PROMPT (self), NULL);
+
+ key = g_intern_string (property_name);
+ variant = g_hash_table_lookup (self->pv->properties, key);
+ if (variant != NULL)
+ return g_variant_get_string (variant, NULL);
+
+ return NULL;
+}
+
+static void
+prompt_set_string_property (GcrSystemPrompt *self,
+ const gchar *property_name,
+ const gchar *value)
+{
+ GVariant *variant;
+ gpointer key;
+
+ g_return_if_fail (GCR_IS_SYSTEM_PROMPT (self));
+
+ key = (gpointer)g_intern_string (property_name);
+ variant = g_variant_ref_sink (g_variant_new_string (value ? value : ""));
+ g_hash_table_insert (self->pv->properties, key, variant);
+ g_hash_table_insert (self->pv->dirty_properties, key, key);
+ g_object_notify (G_OBJECT (self), property_name);
+}
+
+static gint
+prompt_get_int_property (GcrSystemPrompt *self,
+ const gchar *property_name)
+{
+ GVariant *variant;
+ gconstpointer key;
+
+ g_return_val_if_fail (GCR_IS_SYSTEM_PROMPT (self), 0);
+
+ key = g_intern_string (property_name);
+ variant = g_hash_table_lookup (self->pv->properties, key);
+ if (variant != NULL)
+ return g_variant_get_int32 (variant);
+
+ return 0;
+}
+
+static gboolean
+prompt_get_boolean_property (GcrSystemPrompt *self,
+ const gchar *property_name)
+{
+ GVariant *variant;
+ gconstpointer key;
+
+ g_return_val_if_fail (GCR_IS_SYSTEM_PROMPT (self), FALSE);
+
+ key = g_intern_string (property_name);
+ variant = g_hash_table_lookup (self->pv->properties, key);
+ if (variant != NULL)
+ return g_variant_get_boolean (variant);
+
+ return FALSE;
+}
+
+static void
+prompt_set_boolean_property (GcrSystemPrompt *self,
+ const gchar *property_name,
+ gboolean value)
+{
+ GVariant *variant;
+ gpointer key;
+
+ g_return_if_fail (GCR_IS_SYSTEM_PROMPT (self));
+
+ key = (gpointer)g_intern_string (property_name);
+ variant = g_variant_ref_sink (g_variant_new_boolean (value));
+ g_hash_table_insert (self->pv->properties, key, variant);
+ g_hash_table_insert (self->pv->dirty_properties, key, key);
+ g_object_notify (G_OBJECT (self), property_name);
}
static void
@@ -121,34 +236,39 @@ gcr_system_prompt_set_property (GObject *obj,
self->pv->prompter_bus_name = g_value_dup_string (value);
break;
case PROP_SECRET_EXCHANGE:
- gcr_system_prompt_set_secret_exchange (self, g_value_get_object (value));
+ if (self->pv->exchange) {
+ g_warning ("The secret exchange is already in use, and cannot be changed");
+ return;
+ }
+ self->pv->exchange = g_value_dup_object (value);
+ g_object_notify (G_OBJECT (self), "secret-exchange");
break;
case PROP_TIMEOUT_SECONDS:
self->pv->timeout_seconds = g_value_get_int (value);
break;
case PROP_TITLE:
- gcr_system_prompt_set_title (self, g_value_get_string (value));
+ prompt_set_string_property (self, "title", g_value_get_string (value));
break;
case PROP_MESSAGE:
- gcr_system_prompt_set_message (self, g_value_get_string (value));
+ prompt_set_string_property (self, "message", g_value_get_string (value));
break;
case PROP_DESCRIPTION:
- gcr_system_prompt_set_description (self, g_value_get_string (value));
+ prompt_set_string_property (self, "description", g_value_get_string (value));
break;
case PROP_WARNING:
- gcr_system_prompt_set_warning (self, g_value_get_string (value));
+ prompt_set_string_property (self, "warning", g_value_get_string (value));
break;
case PROP_PASSWORD_NEW:
- gcr_system_prompt_set_password_new (self, g_value_get_boolean (value));
+ prompt_set_boolean_property (self, "password-new", g_value_get_boolean (value));
break;
case PROP_CHOICE_LABEL:
- gcr_system_prompt_set_choice_label (self, g_value_get_string (value));
+ prompt_set_string_property (self, "choice-label", g_value_get_string (value));
break;
case PROP_CHOICE_CHOSEN:
- gcr_system_prompt_set_choice_chosen (self, g_value_get_boolean (value));
+ prompt_set_boolean_property (self, "choice-chosen", g_value_get_boolean (value));
break;
case PROP_CALLER_WINDOW:
- gcr_system_prompt_set_caller_window (self, g_value_get_string (value));
+ prompt_set_string_property (self, "caller-window", g_value_get_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
@@ -172,28 +292,31 @@ gcr_system_prompt_get_property (GObject *obj,
g_value_set_object (value, gcr_system_prompt_get_secret_exchange (self));
break;
case PROP_TITLE:
- g_value_set_string (value, gcr_system_prompt_get_title (self));
+ g_value_set_string (value, prompt_get_string_property (self, "title"));
+ break;
+ case PROP_MESSAGE:
+ g_value_set_string (value, prompt_get_string_property (self, "message"));
break;
case PROP_DESCRIPTION:
- g_value_set_string (value, gcr_system_prompt_get_description (self));
+ g_value_set_string (value, prompt_get_string_property (self, "description"));
break;
case PROP_WARNING:
- g_value_set_string (value, gcr_system_prompt_get_warning (self));
+ g_value_set_string (value, prompt_get_string_property (self, "warning"));
break;
case PROP_PASSWORD_NEW:
- g_value_set_boolean (value, gcr_system_prompt_get_password_new (self));
+ g_value_set_boolean (value, prompt_get_boolean_property (self, "password-new"));
break;
case PROP_PASSWORD_STRENGTH:
- g_value_set_int (value, gcr_system_prompt_get_password_strength (self));
+ g_value_set_int (value, prompt_get_int_property (self, "password-strength"));
break;
case PROP_CHOICE_LABEL:
- g_value_set_string (value, gcr_system_prompt_get_choice_label (self));
+ g_value_set_string (value, prompt_get_string_property (self, "choice-label"));
break;
case PROP_CHOICE_CHOSEN:
- g_value_set_boolean (value, gcr_system_prompt_get_choice_chosen (self));
+ g_value_set_boolean (value, prompt_get_boolean_property (self, "choice-chosen"));
break;
case PROP_CALLER_WINDOW:
- g_value_set_string (value, gcr_system_prompt_get_caller_window (self));
+ g_value_set_string (value, prompt_get_string_property (self, "caller-window"));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
@@ -205,9 +328,18 @@ static void
gcr_system_prompt_constructed (GObject *obj)
{
GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (obj);
+ gint seed;
G_OBJECT_CLASS (gcr_system_prompt_parent_class)->constructed (obj);
+#if GLIB_CHECK_VERSION (2,29,90)
+ seed = g_atomic_int_add (&unique_prompt_id, 1);
+#else
+ seed = g_atomic_int_exchange_and_add (&unique_prompt_id, 1);
+#endif
+
+ self->pv->prompt_path = g_strdup_printf ("%s/p%d", GCR_DBUS_PROMPT_OBJECT_PREFIX, seed);
+
if (self->pv->prompter_bus_name == NULL)
self->pv->prompter_bus_name = g_strdup (GCR_DBUS_PROMPTER_BUS_NAME);
}
@@ -219,30 +351,12 @@ gcr_system_prompt_dispose (GObject *obj)
g_clear_object (&self->pv->exchange);
- if (self->pv->prompt_path) {
- _gcr_debug ("closing prompt asynchronously: %s", self->pv->prompt_path);
+ _gcr_debug ("closing prompt asynchronously: %s", self->pv->prompt_path);
+ if (self->pv->connection)
+ gcr_system_prompt_close_async (self, NULL, NULL, NULL);
- g_dbus_connection_call (self->pv->connection,
- self->pv->prompter_bus_name,
- GCR_DBUS_PROMPTER_OBJECT_PATH,
- GCR_DBUS_PROMPTER_INTERFACE,
- GCR_DBUS_PROMPTER_METHOD_FINISH,
- g_variant_new ("(o)", self->pv->prompt_path),
- NULL, G_DBUS_CALL_FLAGS_NO_AUTO_START,
- -1, NULL, NULL, NULL);
- g_free (self->pv->prompt_path);
- self->pv->prompt_path = NULL;
- }
-
- g_hash_table_remove_all (self->pv->properties_to_write);
- g_hash_table_remove_all (self->pv->property_cache);
-
- if (self->pv->prompt_proxy) {
- g_object_unref (self->pv->prompt_proxy);
- self->pv->prompt_proxy = NULL;
- }
-
- g_clear_object (&self->pv->connection);
+ g_hash_table_remove_all (self->pv->properties);
+ g_hash_table_remove_all (self->pv->dirty_properties);
G_OBJECT_CLASS (gcr_system_prompt_parent_class)->dispose (obj);
}
@@ -253,8 +367,8 @@ gcr_system_prompt_finalize (GObject *obj)
GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (obj);
g_free (self->pv->prompter_bus_name);
- g_hash_table_destroy (self->pv->properties_to_write);
- g_hash_table_destroy (self->pv->property_cache);
+ g_hash_table_destroy (self->pv->properties);
+ g_hash_table_destroy (self->pv->dirty_properties);
G_OBJECT_CLASS (gcr_system_prompt_parent_class)->finalize (obj);
}
@@ -284,41 +398,15 @@ gcr_system_prompt_class_init (GcrSystemPromptClass *klass)
g_param_spec_object ("secret-exchange", "Secret exchange", "Secret exchange for passing passwords",
GCR_TYPE_SECRET_EXCHANGE, G_PARAM_READWRITE));
- g_object_class_install_property (gobject_class, PROP_TITLE,
- g_param_spec_string ("title", "Title", "Prompt title",
- NULL, G_PARAM_READWRITE));
-
- g_object_class_install_property (gobject_class, PROP_MESSAGE,
- g_param_spec_string ("message", "Message", "Prompt message",
- NULL, G_PARAM_READWRITE));
-
- g_object_class_install_property (gobject_class, PROP_DESCRIPTION,
- g_param_spec_string ("description", "Description", "Prompt description",
- NULL, G_PARAM_READWRITE));
-
- g_object_class_install_property (gobject_class, PROP_WARNING,
- g_param_spec_string ("warning", "Warning", "Prompt warning",
- NULL, G_PARAM_READWRITE));
-
- g_object_class_install_property (gobject_class, PROP_PASSWORD_NEW,
- g_param_spec_boolean ("password-new", "Password new", "Whether prompting for a new password",
- FALSE, G_PARAM_READWRITE));
-
- g_object_class_install_property (gobject_class, PROP_PASSWORD_STRENGTH,
- g_param_spec_int ("password-strength", "Password strength", "String of new password",
- 0, G_MAXINT, 0, G_PARAM_READABLE));
-
- g_object_class_install_property (gobject_class, PROP_CHOICE_LABEL,
- g_param_spec_string ("choice-label", "Choice label", "Label for prompt choice",
- NULL, G_PARAM_READWRITE));
-
- g_object_class_install_property (gobject_class, PROP_CHOICE_CHOSEN,
- g_param_spec_boolean ("choice-chosen", "Choice chosen", "Whether prompt choice is chosen",
- FALSE, G_PARAM_READWRITE));
-
- g_object_class_install_property (gobject_class, PROP_CALLER_WINDOW,
- g_param_spec_string ("caller-window", "Caller window", "Window ID of application window requesting prompt",
- NULL, G_PARAM_READWRITE));
+ g_object_class_override_property (gobject_class, PROP_TITLE, "title");
+ g_object_class_override_property (gobject_class, PROP_MESSAGE, "message");
+ g_object_class_override_property (gobject_class, PROP_DESCRIPTION, "description");
+ g_object_class_override_property (gobject_class, PROP_WARNING, "warning");
+ g_object_class_override_property (gobject_class, PROP_PASSWORD_NEW, "password-new");
+ g_object_class_override_property (gobject_class, PROP_PASSWORD_STRENGTH, "password-strength");
+ g_object_class_override_property (gobject_class, PROP_CHOICE_LABEL, "choice-label");
+ g_object_class_override_property (gobject_class, PROP_CHOICE_CHOSEN, "choice-chosen");
+ g_object_class_override_property (gobject_class, PROP_CALLER_WINDOW, "caller-window");
}
/**
@@ -342,317 +430,168 @@ gcr_system_prompt_get_secret_exchange (GcrSystemPrompt *self)
return self->pv->exchange;
}
-void
-gcr_system_prompt_set_secret_exchange (GcrSystemPrompt *self,
- GcrSecretExchange *exchange)
-{
- g_return_if_fail (GCR_IS_SYSTEM_PROMPT (self));
- g_return_if_fail (GCR_IS_SECRET_EXCHANGE (exchange));
-
- if (self->pv->exchange) {
- g_warning ("The secret exchange is already in use, and cannot be changed");
- return;
- }
-
- self->pv->exchange = g_object_ref (exchange);
- g_object_notify (G_OBJECT (self), "secret-exchange");
-}
-
-static GVariant *
-lookup_property_in_caches (GcrSystemPrompt *self,
- const gchar *property_name)
-{
- GVariant *variant;
-
- variant = g_hash_table_lookup (self->pv->property_cache, property_name);
- if (variant == NULL && self->pv->prompt_proxy) {
- variant = g_dbus_proxy_get_cached_property (self->pv->prompt_proxy, property_name);
- if (variant != NULL)
- g_hash_table_insert (self->pv->property_cache,
- (gpointer)g_intern_string (property_name),
- variant);
- }
-
- return variant;
-}
-
-static const gchar *
-prompt_get_string_property (GcrSystemPrompt *self,
- const gchar *property_name)
-{
- GVariant *variant;
-
- g_return_val_if_fail (GCR_IS_SYSTEM_PROMPT (self), NULL);
-
- variant = lookup_property_in_caches (self, property_name);
- if (variant != NULL)
- return g_variant_get_string (variant, NULL);
-
- return NULL;
-}
-
static void
-prompt_set_string_property (GcrSystemPrompt *self,
- const gchar *property_name,
- const gchar *value)
+update_properties_from_iter (GcrSystemPrompt *self,
+ GVariantIter *iter)
{
+ GObject *obj = G_OBJECT (self);
GVariant *variant;
+ GVariant *value;
+ GVariant *already;
gpointer key;
-
- g_return_if_fail (GCR_IS_SYSTEM_PROMPT (self));
-
- key = (gpointer)g_intern_string (property_name);
- variant = g_variant_ref_sink (g_variant_new_string (value ? value : ""));
- g_hash_table_insert (self->pv->property_cache, key, variant);
- g_hash_table_insert (self->pv->properties_to_write, key, key);
-}
-
-static gboolean
-prompt_get_boolean_property (GcrSystemPrompt *self,
- const gchar *property_name)
-{
- GVariant *variant;
-
- g_return_val_if_fail (GCR_IS_SYSTEM_PROMPT (self), FALSE);
-
- variant = lookup_property_in_caches (self, property_name);
- if (variant != NULL)
- return g_variant_get_boolean (variant);
-
- return FALSE;
+ gchar *name;
+
+ g_object_freeze_notify (obj);
+ while (g_variant_iter_loop (iter, "{sv}", &name, &variant)) {
+ key = (gpointer)g_intern_string (name);
+ value = g_variant_get_variant (variant);
+ already = g_hash_table_lookup (self->pv->properties, key);
+ if (!already || !g_variant_equal (already, value)) {
+ g_hash_table_replace (self->pv->properties, key, g_variant_ref (value));
+ g_object_notify (obj, name);
+ }
+ }
+ g_object_thaw_notify (obj);
}
static void
-prompt_set_boolean_property (GcrSystemPrompt *self,
- const gchar *property_name,
- gboolean value)
-{
- GVariant *variant;
- gpointer key;
-
- g_return_if_fail (GCR_IS_SYSTEM_PROMPT (self));
-
- key = (gpointer)g_intern_string (property_name);
- variant = g_variant_ref_sink (g_variant_new_boolean (value));
- g_hash_table_insert (self->pv->property_cache, key, variant);
- g_hash_table_insert (self->pv->properties_to_write, key, key);
-}
-
-const gchar *
-gcr_system_prompt_get_title (GcrSystemPrompt *self)
-{
- return prompt_get_string_property (self, GCR_DBUS_PROMPT_PROPERTY_TITLE);
-}
-
-void
-gcr_system_prompt_set_title (GcrSystemPrompt *self,
- const gchar *title)
-{
- prompt_set_string_property (self, GCR_DBUS_PROMPT_PROPERTY_TITLE, title);
- g_object_notify (G_OBJECT (self), "title");
-}
-
-const gchar *
-gcr_system_prompt_get_message (GcrSystemPrompt *self)
-{
- return prompt_get_string_property (self, GCR_DBUS_PROMPT_PROPERTY_MESSAGE);
-}
-
-void
-gcr_system_prompt_set_message (GcrSystemPrompt *self,
- const gchar *message)
-{
- prompt_set_string_property (self, GCR_DBUS_PROMPT_PROPERTY_MESSAGE, message);
- g_object_notify (G_OBJECT (self), "message");
-}
-
-
-const gchar *
-gcr_system_prompt_get_description (GcrSystemPrompt *self)
-{
- return prompt_get_string_property (self, GCR_DBUS_PROMPT_PROPERTY_DESCRIPTION);
-}
-
-void
-gcr_system_prompt_set_description (GcrSystemPrompt *self,
- const gchar *description)
-{
- prompt_set_string_property (self, GCR_DBUS_PROMPT_PROPERTY_DESCRIPTION, description);
- g_object_notify (G_OBJECT (self), "description");
-}
-
-const gchar *
-gcr_system_prompt_get_warning (GcrSystemPrompt *self)
-{
- return prompt_get_string_property (self, GCR_DBUS_PROMPT_PROPERTY_WARNING);
-}
-
-void
-gcr_system_prompt_set_warning (GcrSystemPrompt *self,
- const gchar *warning)
-{
- prompt_set_string_property (self, GCR_DBUS_PROMPT_PROPERTY_WARNING, warning);
- g_object_notify (G_OBJECT (self), "warning");
-}
-
-gboolean
-gcr_system_prompt_get_password_new (GcrSystemPrompt *self)
-{
- return prompt_get_boolean_property (self, GCR_DBUS_PROMPT_PROPERTY_PASSWORD_NEW);
-}
-
-void
-gcr_system_prompt_set_password_new (GcrSystemPrompt *self,
- gboolean new_password)
+prompt_method_ready (GcrSystemPrompt *self,
+ GDBusMethodInvocation *invocation,
+ GVariant *parameters)
{
- prompt_set_boolean_property (self, GCR_DBUS_PROMPT_PROPERTY_PASSWORD_NEW, new_password);
- g_object_notify (G_OBJECT (self), "password-new");
-}
-
-gint
-gcr_system_prompt_get_password_strength (GcrSystemPrompt *self)
-{
- GVariant *variant;
+ GcrSecretExchange *exchange;
+ GSimpleAsyncResult *res;
+ GVariantIter *iter;
+ gchar *received;
- g_return_val_if_fail (GCR_IS_SYSTEM_PROMPT (self), 0);
+ g_return_if_fail (G_IS_SIMPLE_ASYNC_RESULT (self->pv->pending));
- variant = lookup_property_in_caches (self, GCR_DBUS_PROMPT_PROPERTY_PASSWORD_STRENGTH);
- if (variant != NULL)
- return g_variant_get_int32 (variant);
+ g_free (self->pv->last_response);
+ g_variant_get (parameters, "(sa{sv}s)",
+ &self->pv->last_response,
+ &iter, &received);
- return 0;
-}
+ g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
+ update_properties_from_iter (self, iter);
+ g_variant_iter_free (iter);
-const gchar *
-gcr_system_prompt_get_choice_label (GcrSystemPrompt *self)
-{
- return prompt_get_string_property (self, GCR_DBUS_PROMPT_PROPERTY_CHOICE_LABEL);
-}
+ exchange = gcr_system_prompt_get_secret_exchange (self);
+ if (gcr_secret_exchange_receive (exchange, received))
+ self->pv->received = TRUE;
+ else
+ g_warning ("received invalid secret exchange string");
+ g_free (received);
-void
-gcr_system_prompt_set_choice_label (GcrSystemPrompt *self,
- const gchar *label)
-{
- prompt_set_string_property (self, GCR_DBUS_PROMPT_PROPERTY_CHOICE_LABEL, label);
- g_object_notify (G_OBJECT (self), "choice-label");
+ res = g_object_ref (self->pv->pending);
+ g_clear_object (&self->pv->pending);
+ g_simple_async_result_set_op_res_gpointer (res, NULL, NULL);
+ g_simple_async_result_complete (res);
+ g_object_unref (res);
}
-gboolean
-gcr_system_prompt_get_choice_chosen (GcrSystemPrompt *self)
+static void
+prompt_method_done (GcrSystemPrompt *self,
+ GDBusMethodInvocation *invocation,
+ GVariant *parameters)
{
- return prompt_get_boolean_property (self, GCR_DBUS_PROMPT_PROPERTY_CHOICE_CHOSEN);
-}
+ GSimpleAsyncResult *res;
-void
-gcr_system_prompt_set_choice_chosen (GcrSystemPrompt *self,
- gboolean chosen)
-{
- prompt_set_boolean_property (self, GCR_DBUS_PROMPT_PROPERTY_CHOICE_CHOSEN, chosen);
- g_object_notify (G_OBJECT (self), "choice-chosen");
-}
+ g_return_if_fail (G_IS_SIMPLE_ASYNC_RESULT (self->pv->pending));
-const gchar *
-gcr_system_prompt_get_caller_window (GcrSystemPrompt *self)
-{
- return prompt_get_string_property (self, GCR_DBUS_PROMPT_PROPERTY_CALLER_WINDOW);
-}
+ g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
-void
-gcr_system_prompt_set_caller_window (GcrSystemPrompt *self,
- const gchar *window_id)
-{
- prompt_set_string_property (self, GCR_DBUS_PROMPT_PROPERTY_CALLER_WINDOW, window_id);
- g_object_notify (G_OBJECT (self), "caller-window");
+ res = g_object_ref (self->pv->pending);
+ g_clear_object (&self->pv->pending);
+ g_simple_async_result_set_op_res_gpointer (res, NULL, NULL);
+ g_simple_async_result_complete (res);
+ g_object_unref (res);
}
-static gboolean
-gcr_system_prompt_real_init (GInitable *initable,
- GCancellable *cancellable,
- GError **error)
+static void
+prompt_method_call (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
{
- GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (initable);
-
- /* 1. Connect to the session bus */
- if (!self->pv->connection) {
+ GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (user_data);
- self->pv->connection = g_bus_get_sync (G_BUS_TYPE_SESSION,
- cancellable, error);
- if (self->pv->connection == NULL) {
- _gcr_debug ("failed to connect to bus: %s",
- egg_error_result_message (error));
- return FALSE;
- }
+ g_return_if_fail (method_name != NULL);
- _gcr_debug ("connected to bus");
- }
+ if (g_str_equal (method_name, GCR_DBUS_CALLBACK_METHOD_READY)) {
+ prompt_method_ready (self, invocation, parameters);
- /* 2. Tell the prompter we want to begin prompting */
- if (!self->pv->prompt_path) {
- GVariant *ret;
-
- ret = g_dbus_connection_call_sync (self->pv->connection,
- self->pv->prompter_bus_name,
- GCR_DBUS_PROMPTER_OBJECT_PATH,
- GCR_DBUS_PROMPTER_INTERFACE,
- GCR_DBUS_PROMPTER_METHOD_BEGIN,
- g_variant_new ("()"),
- G_VARIANT_TYPE ("(o)"),
- G_DBUS_CALL_FLAGS_NONE,
- -1, cancellable, error);
- if (ret == NULL) {
- _gcr_debug ("failed to open prompt %s: %s", self->pv->prompter_bus_name,
- egg_error_result_message (error));
- return FALSE;
- }
+ } else if (g_str_equal (method_name, GCR_DBUS_CALLBACK_METHOD_DONE)) {
+ prompt_method_done (self, invocation, parameters);
- self->pv->begun_prompting = TRUE;
- g_assert (self->pv->prompt_path == NULL);
- g_variant_get (ret, "(o)", &self->pv->prompt_path);
- g_variant_unref (ret);
-
- _gcr_debug ("opened prompt %s: %s", self->pv->prompter_bus_name, self->pv->prompt_path);
- }
-
- /* 3. Create a dbus proxy */
- if (!self->pv->prompt_proxy) {
- self->pv->prompt_proxy = g_dbus_proxy_new_sync (self->pv->connection,
- G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
- _gcr_prompter_prompt_interface_info (),
- self->pv->prompter_bus_name,
- self->pv->prompt_path,
- GCR_DBUS_PROMPT_INTERFACE,
- cancellable, error);
- if (self->pv->prompt_proxy == NULL) {
- _gcr_debug ("failed to create prompt proxy: %s",
- egg_error_result_message (error));
- return FALSE;
- }
-
- g_dbus_proxy_set_default_timeout (self->pv->prompt_proxy, G_MAXINT);
- _gcr_debug ("created prompt proxy");
+ } else {
+ g_return_if_reached ();
}
+}
- return TRUE;
+static GVariant *
+prompt_get_property (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *property_name,
+ GError **error,
+ gpointer user_data)
+{
+ g_return_val_if_reached (NULL);
}
-static void
-gcr_system_prompt_initable_iface (GInitableIface *iface)
+static gboolean
+prompt_set_property (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *property_name,
+ GVariant *value,
+ GError **error,
+ gpointer user_data)
{
- iface->init = gcr_system_prompt_real_init;
+ g_return_val_if_reached (FALSE);
}
-typedef struct {
- GCancellable *cancellable;
- guint subscribe_sig;
-} InitClosure;
+
+static GDBusInterfaceVTable prompt_dbus_vtable = {
+ prompt_method_call,
+ prompt_get_property,
+ prompt_set_property,
+};
static void
-init_closure_free (gpointer data)
+register_prompt_object (GcrSystemPrompt *self,
+ GError **error)
{
- InitClosure *closure = data;
- g_clear_object (&closure->cancellable);
- g_free (closure);
+ GError *lerror = NULL;
+ guint id;
+
+ /*
+ * The unregister/reregister allows us to register this under a whatever
+ * GMainContext has been pushed as the thread default context.
+ */
+
+ if (self->pv->prompt_registered)
+ g_dbus_connection_unregister_object (self->pv->connection,
+ self->pv->prompt_registered);
+
+ id = g_dbus_connection_register_object (self->pv->connection,
+ self->pv->prompt_path,
+ _gcr_dbus_prompter_callback_interface_info (),
+ &prompt_dbus_vtable,
+ self, NULL, &lerror);
+ self->pv->prompt_registered = id;
+
+ if (lerror != NULL) {
+ g_warning ("error registering prompter %s", egg_error_message (lerror));
+ g_propagate_error (error, lerror);
+ }
}
static void
@@ -662,19 +601,29 @@ on_bus_connected (GObject *source,
{
GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (g_async_result_get_source_object (user_data));
+ CallClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
GError *error = NULL;
g_assert (self->pv->connection == NULL);
self->pv->connection = g_bus_get_finish (result, &error);
- if (error == NULL) {
- g_return_if_fail (self->pv->connection != NULL);
+ if (error != NULL) {
+ _gcr_debug ("failed to connect to bus: %s", egg_error_message (error));
+ } else {
+ g_return_if_fail (self->pv->connection != NULL);
_gcr_debug ("connected to bus");
- perform_init_async (self, res);
+ g_main_context_push_thread_default (closure->context);
+
+ register_prompt_object (self, &error);
+
+ g_main_context_pop_thread_default (closure->context);
+ }
+
+ if (error == NULL) {
+ perform_init_async (self, res);
} else {
- _gcr_debug ("failed to connect to bus: %s", egg_error_message (error));
g_simple_async_result_take_error (res, error);
g_simple_async_result_complete (res);
}
@@ -697,18 +646,16 @@ on_prompter_begin_prompting (GObject *source,
if (error == NULL) {
self->pv->begun_prompting = TRUE;
- g_assert (self->pv->prompt_path == NULL);
- g_variant_get (ret, "(o)", &self->pv->prompt_path);
g_variant_unref (ret);
- _gcr_debug ("opened prompt %s: %s",
+ _gcr_debug ("registered prompt %s: %s",
self->pv->prompter_bus_name, self->pv->prompt_path);
g_return_if_fail (self->pv->prompt_path != NULL);
perform_init_async (self, res);
} else {
- _gcr_debug ("failed to open prompt %s: %s",
+ _gcr_debug ("failed to register prompt %s: %s",
self->pv->prompter_bus_name, egg_error_message (error));
g_simple_async_result_take_error (res, error);
@@ -719,40 +666,35 @@ on_prompter_begin_prompting (GObject *source,
g_object_unref (res);
}
-static void
-on_prompt_proxy_new (GObject *source,
- GAsyncResult *result,
- gpointer user_data)
+static gboolean
+on_call_timeout (gpointer user_data)
{
GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+ CallClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (g_async_result_get_source_object (user_data));
- GError *error = NULL;
-
- g_assert (self->pv->prompt_proxy == NULL);
- self->pv->prompt_proxy = g_dbus_proxy_new_finish (result, &error);
- if (error == NULL) {
- _gcr_debug ("created prompt proxy");
-
- g_return_if_fail (self->pv->prompt_proxy != NULL);
- perform_init_async (self, res);
+ g_source_destroy (closure->timeout);
+ closure->timeout = NULL;
- } else {
- _gcr_debug ("failed to create prompt proxy: %s", egg_error_message (error));
+ /* Tell the prompter we're no longer interested */
+ gcr_system_prompt_close_async (self, NULL, NULL, NULL);
- g_simple_async_result_take_error (res, error);
- g_simple_async_result_complete (res);
- }
+ g_simple_async_result_set_error (res, GCR_SYSTEM_PROMPT_ERROR,
+ GCR_SYSTEM_PROMPT_IN_PROGRESS,
+ _("Another prompt is already in progress"));
+ g_simple_async_result_complete (res);
g_object_unref (self);
- g_object_unref (res);
+ return FALSE; /* Don't call this function again */
}
void
perform_init_async (GcrSystemPrompt *self,
GSimpleAsyncResult *res)
{
- InitClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
+ CallClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
+
+ g_main_context_push_thread_default (closure->context);
/* 1. Connect to the session bus */
if (!self->pv->connection) {
@@ -760,39 +702,38 @@ perform_init_async (GcrSystemPrompt *self,
g_bus_get (G_BUS_TYPE_SESSION, closure->cancellable,
on_bus_connected, g_object_ref (res));
- /* 2. Tell the prompter we want to begin prompting */
- } else if (!self->pv->prompt_path) {
- _gcr_debug ("opening prompt");
+ /* 2. Export our object, BeginPrompting on prompter */
+ } else if (!self->pv->begun_prompting) {
+ g_assert (self->pv->prompt_path != NULL);
+
g_dbus_connection_call (self->pv->connection,
self->pv->prompter_bus_name,
GCR_DBUS_PROMPTER_OBJECT_PATH,
GCR_DBUS_PROMPTER_INTERFACE,
GCR_DBUS_PROMPTER_METHOD_BEGIN,
- g_variant_new ("()"),
- G_VARIANT_TYPE ("(o)"),
+ g_variant_new ("(o)", self->pv->prompt_path),
+ G_VARIANT_TYPE ("()"),
G_DBUS_CALL_FLAGS_NONE,
-1, closure->cancellable,
on_prompter_begin_prompting,
g_object_ref (res));
- /* 3. Create a dbus proxy */
- } else if (!self->pv->prompt_proxy) {
- _gcr_debug ("creating prompt proxy");
- g_dbus_proxy_new (self->pv->connection,
- G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
- _gcr_prompter_prompt_interface_info (),
- self->pv->prompter_bus_name,
- self->pv->prompt_path,
- GCR_DBUS_PROMPT_INTERFACE,
- closure->cancellable,
- on_prompt_proxy_new,
- g_object_ref (res));
+ /* 3. Wait for iterate */
+ } else if (!self->pv->pending) {
+ self->pv->pending = g_object_ref (res);
+ if (self->pv->timeout_seconds > 0) {
+ g_assert (closure->timeout == NULL);
+ closure->timeout = g_timeout_source_new_seconds (self->pv->timeout_seconds);
+ g_source_set_callback (closure->timeout, on_call_timeout, res, NULL);
+ g_source_attach (closure->timeout, closure->context);
+ }
/* 4. All done */
} else {
- _gcr_debug ("successfully initialized prompt");
- g_simple_async_result_complete (res);
+ g_assert_not_reached ();
}
+
+ g_main_context_pop_thread_default (closure->context);
}
static void
@@ -804,14 +745,15 @@ gcr_system_prompt_real_init_async (GAsyncInitable *initable,
{
GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (initable);
GSimpleAsyncResult *res;
- InitClosure *closure;
+ CallClosure *closure;
res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
gcr_system_prompt_real_init_async);
-
- closure = g_new0 (InitClosure, 1);
- closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
- g_simple_async_result_set_op_res_gpointer (res, closure, init_closure_free);
+ closure = g_new0 (CallClosure, 1);
+ closure->context = g_main_context_get_thread_default ();
+ if (closure->context)
+ g_main_context_ref (closure->context);
+ g_simple_async_result_set_op_res_gpointer (res, closure, call_closure_free);
perform_init_async (self, res);
@@ -842,314 +784,253 @@ gcr_system_prompt_async_initable_iface (GAsyncInitableIface *iface)
iface->init_finish = gcr_system_prompt_real_init_finish;
}
-static GVariant *
-parameter_properties (GcrSystemPrompt *self)
+typedef struct {
+ GAsyncResult *result;
+ GMainContext *context;
+ GMainLoop *loop;
+} SyncClosure;
+
+static SyncClosure *
+sync_closure_new (void)
{
- GHashTableIter iter;
- GVariantBuilder builder;
- const gchar *property_name;
- GVariant *variant;
+ SyncClosure *closure;
- g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ssv)"));
-
- g_hash_table_iter_init (&iter, self->pv->properties_to_write);
- while (g_hash_table_iter_next (&iter, (gpointer *)&property_name, NULL)) {
- _gcr_debug ("sending prompt property: %s", property_name);
- variant = g_hash_table_lookup (self->pv->property_cache, property_name);
- if (variant == NULL)
- g_warning ("couldn't find prompt property to write: %s", property_name);
- else
- g_variant_builder_add (&builder, "(ssv)", GCR_DBUS_PROMPT_INTERFACE,
- property_name, variant);
- }
+ closure = g_new0 (SyncClosure, 1);
+
+ closure->context = g_main_context_new ();
+ closure->loop = g_main_loop_new (closure->context, FALSE);
- g_hash_table_remove_all (self->pv->properties_to_write);
- return g_variant_builder_end (&builder);
+ return closure;
}
static void
-return_properties (GcrSystemPrompt *self,
- GVariant *properties)
+sync_closure_free (gpointer data)
{
- GVariantIter *iter;
- GVariant *value;
- gchar *interface;
- gchar *property_name;
- gpointer key;
+ SyncClosure *closure = data;
- g_variant_get (properties, "a(ssv)", &iter);
- while (g_variant_iter_loop (iter, "(ssv)", &interface, &property_name, &value)) {
- _gcr_debug ("received prompt property: %s", property_name);
- key = (gpointer)g_intern_string (property_name);
- if (!g_hash_table_lookup (self->pv->properties_to_write, key)) {
- g_hash_table_insert (self->pv->property_cache,
- key, g_variant_ref (value));
- }
- }
- g_variant_iter_free (iter);
+ g_clear_object (&closure->result);
+ g_main_loop_unref (closure->loop);
+ g_main_context_unref (closure->context);
}
-static GVariant *
-parameters_for_password (GcrSystemPrompt *self)
+static void
+on_sync_result (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
{
- GcrSecretExchange *exchange;
- GVariant *properties;
- GVariant *params;
- gchar *input;
+ SyncClosure *closure = user_data;
+ closure->result = g_object_ref (result);
+ g_main_loop_quit (closure->loop);
+}
- exchange = gcr_system_prompt_get_secret_exchange (self);
+static gboolean
+gcr_system_prompt_real_init (GInitable *initable,
+ GCancellable *cancellable,
+ GError **error)
+{
+ SyncClosure *closure;
+ gboolean result;
- if (self->pv->exchanged) {
- _gcr_debug ("sending secret exchange");
- input = gcr_secret_exchange_send (exchange, NULL, 0);
- } else {
- _gcr_debug ("beginning secret exchange");
- input = gcr_secret_exchange_begin (exchange);
- }
- self->pv->exchanged = TRUE;
+ closure = sync_closure_new ();
+ g_main_context_push_thread_default (closure->context);
+
+ gcr_system_prompt_real_init_async (G_ASYNC_INITABLE (initable),
+ G_PRIORITY_DEFAULT, cancellable,
+ on_sync_result, closure);
+
+ g_main_loop_run (closure->loop);
- properties = parameter_properties (self);
- params = g_variant_new ("(@a(ssv)s)", properties, input);
- g_free (input);
+ result = gcr_system_prompt_real_init_finish (G_ASYNC_INITABLE (initable),
+ closure->result, error);
- return params;
+ g_main_context_pop_thread_default (closure->context);
+ sync_closure_free (closure);
+
+ return result;
}
-static const gchar *
-return_for_password (GcrSystemPrompt *self,
- GVariant *retval,
- GError **error)
+static void
+gcr_system_prompt_initable_iface (GInitableIface *iface)
{
- GcrSecretExchange *exchange;
- GVariant *properties;
- const gchar *ret = NULL;
- gchar *output;
+ iface->init = gcr_system_prompt_real_init;
+}
- exchange = gcr_system_prompt_get_secret_exchange (self);
- g_variant_get (retval, "(@a(ssv)s)", &properties, &output);
-
- return_properties (self, properties);
-
- if (output && output[0]) {
- if (!gcr_secret_exchange_receive (exchange, output)) {
- _gcr_debug ("received invalid secret exchange");
- g_set_error (error, GCR_SYSTEM_PROMPT_ERROR,
- GCR_SYSTEM_PROMPT_FAILED, "Invalid secret exchanged");
- } else {
- _gcr_debug ("received password in secret exchange");
- ret = gcr_secret_exchange_get_secret (exchange, NULL);
- }
- } else {
- _gcr_debug ("password prompt was cancelled");
- }
+static GVariantBuilder *
+build_dirty_properties (GcrSystemPrompt *self)
+{
+ GVariantBuilder *builder;
+ GHashTableIter iter;
+ GVariant *variant;
+ gpointer key;
+
+ builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
- g_variant_unref (properties);
- g_free (output);
+ g_hash_table_iter_init (&iter, self->pv->dirty_properties);
+ while (g_hash_table_iter_next (&iter, &key, NULL)) {
+ variant = g_hash_table_lookup (self->pv->properties, key);
+ g_variant_builder_add (builder, "{sv}", (const gchar *)key, variant);
+ }
- return ret;
+ g_hash_table_remove_all (self->pv->dirty_properties);
+ return builder;
}
static void
-on_prompt_requested_password (GObject *source,
- GAsyncResult *result,
- gpointer user_data)
+on_perform_prompt_complete (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
{
GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (g_async_result_get_source_object (user_data));
- const gchar *password;
+ CallClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
GError *error = NULL;
GVariant *retval;
- retval = g_dbus_proxy_call_finish (self->pv->prompt_proxy, result, &error);
-
- if (retval != NULL) {
- password = return_for_password (self, retval, &error);
- g_simple_async_result_set_op_res_gpointer (res, (gpointer)password, NULL);
- g_variant_unref (retval);
- }
-
+ retval = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error);
if (error != NULL) {
- _gcr_debug ("failed to prompt for password: %s", egg_error_message (error));
g_simple_async_result_take_error (res, error);
+ g_simple_async_result_complete_in_idle (res);
+ } else {
+ closure->waiting = TRUE;
}
- g_simple_async_result_complete (res);
+ if (retval)
+ g_variant_unref (retval);
+
g_object_unref (self);
g_object_unref (res);
}
-void
-gcr_system_prompt_password_async (GcrSystemPrompt *self,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
+static void
+perform_prompt_async (GcrSystemPrompt *self,
+ const gchar *type,
+ gpointer source_tag,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
GSimpleAsyncResult *res;
+ GcrSecretExchange *exchange;
+ GVariantBuilder *builder;
+ CallClosure *closure;
+ gchar *sent;
g_return_if_fail (GCR_IS_SYSTEM_PROMPT (self));
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
- res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
- gcr_system_prompt_password_async);
+ if (self->pv->pending != NULL) {
+ g_warning ("another operation is already pending on this prompt");
+ return;
+ }
_gcr_debug ("prompting for password");
- g_dbus_proxy_call (G_DBUS_PROXY (self->pv->prompt_proxy),
- GCR_DBUS_PROMPT_METHOD_PASSWORD,
- parameters_for_password (self),
- G_DBUS_CALL_FLAGS_NO_AUTO_START, -1, cancellable,
- on_prompt_requested_password, g_object_ref (res));
+ res = g_simple_async_result_new (G_OBJECT (self), callback, user_data, source_tag);
+ closure = g_new0 (CallClosure, 1);
+ closure->cancellable = cancellable ? g_object_ref (cancellable) : cancellable;
+ g_simple_async_result_set_op_res_gpointer (res, closure, call_closure_free);
- g_object_unref (res);
-}
+ exchange = gcr_system_prompt_get_secret_exchange (self);
+ if (self->pv->received)
+ sent = gcr_secret_exchange_send (exchange, NULL, 0);
+ else
+ sent = gcr_secret_exchange_begin (exchange);
-const gchar *
-gcr_system_prompt_password_finish (GcrSystemPrompt *self,
- GAsyncResult *result,
- GError **error)
-{
- GSimpleAsyncResult *res;
+ builder = build_dirty_properties (self);
- g_return_val_if_fail (GCR_IS_SYSTEM_PROMPT (self), FALSE);
- g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
- gcr_system_prompt_password_async), FALSE);
+ /* Reregister the prompt object in the current GMainContext */
+ register_prompt_object (self, NULL);
- res = G_SIMPLE_ASYNC_RESULT (result);
- if (g_simple_async_result_propagate_error (res, error))
- return FALSE;
+ g_dbus_connection_call (self->pv->connection,
+ self->pv->prompter_bus_name,
+ GCR_DBUS_PROMPTER_OBJECT_PATH,
+ GCR_DBUS_PROMPTER_INTERFACE,
+ GCR_DBUS_PROMPTER_METHOD_PERFORM,
+ g_variant_new ("(osa{sv}s)", self->pv->prompt_path,
+ type, builder, sent),
+ G_VARIANT_TYPE ("()"),
+ G_DBUS_CALL_FLAGS_NO_AUTO_START,
+ -1, cancellable,
+ on_perform_prompt_complete,
+ g_object_ref (res));
- return g_simple_async_result_get_op_res_gpointer (res);
+ self->pv->pending = res;
+ g_free (sent);
}
-const gchar *
-gcr_system_prompt_password (GcrSystemPrompt *self,
- GCancellable *cancellable,
- GError **error)
+static GcrSystemPromptResponse
+handle_last_response (GcrSystemPrompt *self)
{
- GVariant *retval;
- const gchar *ret = NULL;
-
- g_return_val_if_fail (GCR_IS_SYSTEM_PROMPT (self), NULL);
- g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
- g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+ GcrSystemPromptResponse response;
- if (!self->pv->prompt_proxy) {
- g_warning ("GcrSystemPrompt was not successfully opened");
- return NULL;
- }
+ g_return_val_if_fail (self->pv->last_response != NULL,
+ GCR_SYSTEM_PROMPT_CANCEL);
- _gcr_debug ("prompting for password");
+ if (g_str_equal (self->pv->last_response, GCR_DBUS_PROMPT_REPLY_YES)) {
+ response = GCR_SYSTEM_PROMPT_OK;
- retval = g_dbus_proxy_call_sync (self->pv->prompt_proxy,
- GCR_DBUS_PROMPT_METHOD_PASSWORD,
- parameters_for_password (self),
- G_DBUS_CALL_FLAGS_NO_AUTO_START, -1,
- cancellable, error);
+ } else if (g_str_equal (self->pv->last_response, GCR_DBUS_PROMPT_REPLY_NO)) {
+ response = GCR_SYSTEM_PROMPT_CANCEL;
- if (retval != NULL) {
- ret = return_for_password (self, retval, error);
- g_variant_unref (retval);
+ } else {
+ g_warning ("unknown response from prompter: %s", self->pv->last_response);
+ response = GCR_SYSTEM_PROMPT_CANCEL;
}
- return ret;
+ return response;
}
-static GVariant *
-parameters_for_confirm (GcrSystemPrompt *self)
+static void
+gcr_system_prompt_password_async (GcrPrompt *prompt,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
- GVariant *properties;
-
- properties = parameter_properties (self);
- return g_variant_new ("(@a(ssv))", properties);
+ GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (prompt);
+ perform_prompt_async (self, GCR_DBUS_PROMPT_TYPE_PASSWORD,
+ gcr_system_prompt_password_async,
+ cancellable, callback, user_data);
}
-static gboolean
-return_for_confirm (GcrSystemPrompt *self,
- GVariant *retval,
- GError **error)
+static const gchar *
+gcr_system_prompt_password_finish (GcrPrompt *prompt,
+ GAsyncResult *result,
+ GError **error)
{
- GVariant *properties;
- gboolean confirm = FALSE;
-
- g_variant_get (retval, "(@a(ssv)b)", &properties, &confirm);
+ GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (prompt);
+ GSimpleAsyncResult *res;
- return_properties (self, properties);
+ g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
+ gcr_system_prompt_password_async), FALSE);
- g_variant_unref (properties);
+ res = G_SIMPLE_ASYNC_RESULT (result);
+ if (g_simple_async_result_propagate_error (res, error))
+ return FALSE;
- if (confirm)
- _gcr_debug ("prompt confirmed");
- else
- _gcr_debug ("prompt was cancelled");
+ if (handle_last_response (self) == GCR_SYSTEM_PROMPT_OK)
+ return gcr_secret_exchange_get_secret (self->pv->exchange, NULL);
- return confirm;
+ return NULL;
}
static void
-on_prompt_requested_confirm (GObject *source,
- GAsyncResult *result,
- gpointer user_data)
-{
- GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
- GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (g_async_result_get_source_object (user_data));
- GError *error = NULL;
- GVariant *retval;
- gboolean ret;
-
- retval = g_dbus_proxy_call_finish (self->pv->prompt_proxy, result, &error);
-
- if (retval != NULL) {
- ret = return_for_confirm (self, retval, &error);
- g_simple_async_result_set_op_res_gboolean (res, ret);
- }
-
- if (error != NULL) {
- _gcr_debug ("failed to prompt for confirm: %s", egg_error_message (error));
- g_simple_async_result_take_error (res, error);
- }
-
- g_simple_async_result_complete (res);
- g_object_unref (self);
- g_object_unref (res);
-}
-
-/**
- * gcr_system_prompt_confirm_async:
- * @self: a prompt
- * @cancellable: optional cancellation object
- *
- * xxx
- */
-void
-gcr_system_prompt_confirm_async (GcrSystemPrompt *self,
+gcr_system_prompt_confirm_async (GcrPrompt *prompt,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
- GSimpleAsyncResult *res;
-
- g_return_if_fail (GCR_IS_SYSTEM_PROMPT (self));
- g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
-
- res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
- gcr_system_prompt_confirm_async);
-
- _gcr_debug ("prompting for confirm");
-
- g_dbus_proxy_call (G_DBUS_PROXY (self->pv->prompt_proxy),
- GCR_DBUS_PROMPT_METHOD_CONFIRM,
- parameters_for_confirm (self),
- G_DBUS_CALL_FLAGS_NO_AUTO_START, -1, cancellable,
- on_prompt_requested_confirm, g_object_ref (res));
-
- g_object_unref (res);
+ GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (prompt);
+ perform_prompt_async (self, GCR_DBUS_PROMPT_TYPE_CONFIRM,
+ gcr_system_prompt_confirm_async,
+ cancellable, callback, user_data);
}
-gboolean
-gcr_system_prompt_confirm_finish (GcrSystemPrompt *self,
+static GcrPromptReply
+gcr_system_prompt_confirm_finish (GcrPrompt *prompt,
GAsyncResult *result,
GError **error)
{
+ GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (prompt);
GSimpleAsyncResult *res;
g_return_val_if_fail (GCR_IS_SYSTEM_PROMPT (self), FALSE);
@@ -1160,57 +1041,16 @@ gcr_system_prompt_confirm_finish (GcrSystemPrompt *self,
if (g_simple_async_result_propagate_error (res, error))
return FALSE;
- return g_simple_async_result_get_op_res_gboolean (res);
+ return handle_last_response (self);
}
-/**
- * gcr_system_prompt_confirm:
- * @self: a prompt
- * @cancellable: optional cancellation object
- * @error: location to place error on failure
- *
- * Prompts for confirmation asking a cancel/continue style question.
- * Set the various properties on the prompt to represent the question
- * correctly.
- *
- * This method will block until the a response is returned from the prompter.
- * and %TRUE or %FALSE will be returned based on the response. The return value
- * will also be %FALSE if an error occurs. Check the @error argument to tell
- * the difference.
- *
- * Returns: whether the prompt was confirmed or not
- */
-gboolean
-gcr_system_prompt_confirm (GcrSystemPrompt *self,
- GCancellable *cancellable,
- GError **error)
+static void
+gcr_system_prompt_prompt_iface (GcrPromptIface *iface)
{
- GVariant *retval;
- gboolean ret = FALSE;
-
- g_return_val_if_fail (GCR_IS_SYSTEM_PROMPT (self), FALSE);
- g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
- g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
-
- if (!self->pv->prompt_proxy) {
- g_warning ("GcrSystemPrompt was not successfully opened");
- return FALSE;
- }
-
- _gcr_debug ("prompting for confirm");
-
- retval = g_dbus_proxy_call_sync (self->pv->prompt_proxy,
- GCR_DBUS_PROMPT_METHOD_CONFIRM,
- parameters_for_confirm (self),
- G_DBUS_CALL_FLAGS_NO_AUTO_START, -1,
- cancellable, error);
-
- if (retval != NULL) {
- ret = return_for_confirm (self, retval, error);
- g_variant_unref (retval);
- }
-
- return ret;
+ iface->prompt_password_async = gcr_system_prompt_password_async;
+ iface->prompt_password_finish = gcr_system_prompt_password_finish;
+ iface->prompt_confirm_async = gcr_system_prompt_confirm_async;
+ iface->prompt_confirm_finish = gcr_system_prompt_confirm_finish;
}
/**
@@ -1404,51 +1244,44 @@ gcr_system_prompt_close (GcrSystemPrompt *self,
GCancellable *cancellable,
GError **error)
{
- GVariant *retval;
+ SyncClosure *closure;
+ gboolean result;
- g_return_val_if_fail (GCR_IS_SYSTEM_PROMPT (self), FALSE);
- g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
- g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
- g_return_val_if_fail (self->pv->prompt_path != NULL, FALSE);
+ closure = sync_closure_new ();
+ g_main_context_push_thread_default (closure->context);
- _gcr_debug ("closing prompt");
+ gcr_system_prompt_close_async (self, cancellable,
+ on_sync_result, closure);
- retval = g_dbus_connection_call_sync (self->pv->connection,
- self->pv->prompter_bus_name,
- GCR_DBUS_PROMPTER_OBJECT_PATH,
- GCR_DBUS_PROMPTER_INTERFACE,
- GCR_DBUS_PROMPTER_METHOD_FINISH,
- g_variant_new ("(o)", self->pv->prompt_path),
- NULL, G_DBUS_CALL_FLAGS_NO_AUTO_START,
- -1, cancellable, error);
- if (retval == NULL) {
- _gcr_debug ("failed to close prompt: %s",
- egg_error_result_message (error));
- return FALSE;
- }
+ g_main_loop_run (closure->loop);
- g_variant_unref (retval);
- g_free (self->pv->prompt_path);
- self->pv->prompt_path = NULL;
- return TRUE;
+ result = gcr_system_prompt_close_finish (self, closure->result, error);
+
+ g_main_context_pop_thread_default (closure->context);
+ sync_closure_free (closure);
+
+ return result;
}
static void
-on_prompt_close_async (GObject *source,
- GAsyncResult *result,
- gpointer user_data)
+on_prompter_stop_prompting (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
{
GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
- GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (g_async_result_get_source_object (user_data));
GError *error = NULL;
+ GVariant *retval;
- if (!g_dbus_connection_call_finish (self->pv->connection, result, &error)) {
- _gcr_debug ("failed to close prompt: %s", egg_error_message (error));
- g_simple_async_result_take_error (res, error);
+ retval = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error);
+ if (error != NULL) {
+ _gcr_debug ("failed to stop prompting: %s", egg_error_message (error));
+ g_clear_error (&error);
}
+ if (retval)
+ g_variant_unref (retval);
+
g_simple_async_result_complete (res);
- g_object_unref (self);
g_object_unref (res);
}
@@ -1459,25 +1292,66 @@ gcr_system_prompt_close_async (GcrSystemPrompt *self,
gpointer user_data)
{
GSimpleAsyncResult *res;
+ CallClosure *closure;
+ gboolean called = FALSE;
g_return_if_fail (GCR_SYSTEM_PROMPT (self));
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+ g_return_if_fail (self->pv->connection != NULL);
g_return_if_fail (self->pv->prompt_path != NULL);
+ g_return_if_fail (self->pv->closed == FALSE);
- res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
+ _gcr_debug ("closing prompt");
+ self->pv->closed = TRUE;
+
+ if (self->pv->pending) {
+ res = g_object_ref (self->pv->pending);
+ g_clear_object (&self->pv->pending);
+ closure = g_simple_async_result_get_op_res_gpointer (res);
+ g_cancellable_cancel (closure->cancellable);
+ g_simple_async_result_complete_in_idle (res);
+ g_object_unref (res);
+ }
+
+ res = g_simple_async_result_new (NULL, callback, user_data,
gcr_system_prompt_close_async);
+ closure = g_new0 (CallClosure, 1);
+ closure->cancellable = cancellable ? g_object_ref (cancellable) : g_cancellable_new ();
+ closure->context = g_main_context_get_thread_default ();
+ if (closure->context != NULL)
+ g_main_context_ref (closure->context);
+ g_simple_async_result_set_op_res_gpointer (res, closure, call_closure_free);
+
+ if (self->pv->prompt_registered) {
+ g_dbus_connection_unregister_object (self->pv->connection,
+ self->pv->prompt_registered);
+ self->pv->prompt_registered = 0;
+ }
- _gcr_debug ("closing prompt");
+ if (self->pv->begun_prompting) {
+ if (self->pv->connection) {
+ g_dbus_connection_call (self->pv->connection,
+ self->pv->prompter_bus_name,
+ GCR_DBUS_PROMPTER_OBJECT_PATH,
+ GCR_DBUS_PROMPTER_INTERFACE,
+ GCR_DBUS_PROMPTER_METHOD_STOP,
+ g_variant_new ("(o)", self->pv->prompt_path),
+ G_VARIANT_TYPE ("()"),
+ G_DBUS_CALL_FLAGS_NO_AUTO_START,
+ -1, closure->cancellable,
+ on_prompter_stop_prompting,
+ g_object_ref (res));
+ called = TRUE;
+ }
+ }
- g_dbus_connection_call (self->pv->connection,
- self->pv->prompter_bus_name,
- GCR_DBUS_PROMPTER_OBJECT_PATH,
- GCR_DBUS_PROMPTER_INTERFACE,
- GCR_DBUS_PROMPTER_METHOD_FINISH,
- g_variant_new ("(o)", self->pv->prompt_path),
- NULL, G_DBUS_CALL_FLAGS_NO_AUTO_START,
- -1, NULL, on_prompt_close_async, g_object_ref (res));
+ g_free (self->pv->prompt_path);
+ self->pv->prompt_path = NULL;
+ g_clear_object (&self->pv->connection);
+
+ if (!called)
+ g_simple_async_result_complete_in_idle (res);
g_object_unref (res);
}
@@ -1489,10 +1363,10 @@ gcr_system_prompt_close_finish (GcrSystemPrompt *self,
g_return_val_if_fail (GCR_IS_SYSTEM_PROMPT (self), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
- g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
+ g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL,
gcr_system_prompt_close_async), FALSE);
- if (!g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+ if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
return FALSE;
return TRUE;
@@ -1500,7 +1374,6 @@ gcr_system_prompt_close_finish (GcrSystemPrompt *self,
static const GDBusErrorEntry SYSTEM_PROMPT_ERRORS[] = {
{ GCR_SYSTEM_PROMPT_IN_PROGRESS, GCR_DBUS_PROMPT_ERROR_IN_PROGRESS },
- { GCR_SYSTEM_PROMPT_NOT_HAPPENING, GCR_DBUS_PROMPT_ERROR_NOT_HAPPENING },
{ GCR_SYSTEM_PROMPT_FAILED, GCR_DBUS_PROMPT_ERROR_FAILED },
};
diff --git a/gcr/gcr-system-prompt.h b/gcr/gcr-system-prompt.h
index 3fe2b33..4bd154b 100644
--- a/gcr/gcr-system-prompt.h
+++ b/gcr/gcr-system-prompt.h
@@ -35,10 +35,13 @@
G_BEGIN_DECLS
+typedef enum {
+ GCR_SYSTEM_PROMPT_CANCEL = 0,
+ GCR_SYSTEM_PROMPT_OK = 1,
+} GcrSystemPromptResponse;
typedef enum {
GCR_SYSTEM_PROMPT_IN_PROGRESS = 1,
- GCR_SYSTEM_PROMPT_NOT_HAPPENING,
GCR_SYSTEM_PROMPT_FAILED,
GCR_SYSTEM_PROMPT_CLOSED
} GcrSystemPromptError;
@@ -73,51 +76,6 @@ GType gcr_system_prompt_get_type (void);
GcrSecretExchange * gcr_system_prompt_get_secret_exchange (GcrSystemPrompt *self);
-void gcr_system_prompt_set_secret_exchange (GcrSystemPrompt *self,
- GcrSecretExchange *exchange);
-
-const gchar * gcr_system_prompt_get_title (GcrSystemPrompt *self);
-
-void gcr_system_prompt_set_title (GcrSystemPrompt *self,
- const gchar *title);
-
-const gchar * gcr_system_prompt_get_message (GcrSystemPrompt *self);
-
-void gcr_system_prompt_set_message (GcrSystemPrompt *self,
- const gchar *message);
-
-const gchar * gcr_system_prompt_get_description (GcrSystemPrompt *self);
-
-void gcr_system_prompt_set_description (GcrSystemPrompt *self,
- const gchar *description);
-
-const gchar * gcr_system_prompt_get_warning (GcrSystemPrompt *self);
-
-void gcr_system_prompt_set_warning (GcrSystemPrompt *self,
- const gchar *warning);
-
-const gchar * gcr_system_prompt_get_choice_label (GcrSystemPrompt *self);
-
-void gcr_system_prompt_set_choice_label (GcrSystemPrompt *self,
- const gchar *warning);
-
-gboolean gcr_system_prompt_get_choice_chosen (GcrSystemPrompt *self);
-
-void gcr_system_prompt_set_choice_chosen (GcrSystemPrompt *self,
- gboolean chosen);
-
-gboolean gcr_system_prompt_get_password_new (GcrSystemPrompt *self);
-
-void gcr_system_prompt_set_password_new (GcrSystemPrompt *self,
- gboolean new_password);
-
-gint gcr_system_prompt_get_password_strength (GcrSystemPrompt *self);
-
-const gchar * gcr_system_prompt_get_caller_window (GcrSystemPrompt *self);
-
-void gcr_system_prompt_set_caller_window (GcrSystemPrompt *self,
- const gchar *window_id);
-
void gcr_system_prompt_open_async (gint timeout_seconds,
GCancellable *cancellable,
GAsyncReadyCallback callback,
@@ -142,32 +100,6 @@ GcrSystemPrompt * gcr_system_prompt_open (gint timeout_s
GCancellable *cancellable,
GError **error);
-void gcr_system_prompt_password_async (GcrSystemPrompt *self,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
-
-const gchar * gcr_system_prompt_password_finish (GcrSystemPrompt *self,
- GAsyncResult *result,
- GError **error);
-
-const gchar * gcr_system_prompt_password (GcrSystemPrompt *self,
- GCancellable *cancellable,
- GError **error);
-
-void gcr_system_prompt_confirm_async (GcrSystemPrompt *self,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
-
-gboolean gcr_system_prompt_confirm_finish (GcrSystemPrompt *self,
- GAsyncResult *result,
- GError **error);
-
-gboolean gcr_system_prompt_confirm (GcrSystemPrompt *self,
- GCancellable *cancellable,
- GError **error);
-
gboolean gcr_system_prompt_close (GcrSystemPrompt *self,
GCancellable *cancellable,
GError **error);
diff --git a/gcr/gcr-system-prompter.c b/gcr/gcr-system-prompter.c
index 3f8546b..278c41f 100644
--- a/gcr/gcr-system-prompter.c
+++ b/gcr/gcr-system-prompter.c
@@ -27,8 +27,10 @@
#include "gcr-dbus-generated.h"
#define DEBUG_FLAG GCR_DEBUG_PROMPT
#include "gcr-debug.h"
+#include "gcr-enum-types-base.h"
#include "gcr-internal.h"
#include "gcr-library.h"
+#include "gcr-prompt.h"
#include "gcr-secret-exchange.h"
#include "gcr-system-prompter.h"
#include "gcr-system-prompt.h"
@@ -59,415 +61,125 @@
enum {
PROP_0,
- PROP_TITLE,
- PROP_MESSAGE,
- PROP_DESCRIPTION,
- PROP_WARNING,
- PROP_PASSWORD_NEW,
- PROP_PASSWORD_STRENGTH,
- PROP_CHOICE_LABEL,
- PROP_CHOICE_CHOSEN,
- PROP_CALLER_WINDOW,
-};
-
-enum {
- OPEN,
- PROMPT_PASSWORD,
- PROMPT_CONFIRM,
- RESPONDED,
- CLOSE,
- LAST_SIGNAL
+ PROP_MODE,
+ PROP_PROMPT_TYPE
};
struct _GcrSystemPrompterPrivate {
+ GcrSystemPrompterMode mode;
+ GType prompt_type;
+
guint prompter_registered;
GDBusConnection *connection;
- /* Prompt state */
- gchar *prompt_path;
- guint prompt_registered;
- gchar *owner_name;
- guint owner_watching_id;
- GcrSecretExchange *exchange;
- GDBusMethodInvocation *invocation;
- gboolean opened;
-
- /* Properties */
- GHashTable *properties;
- GQueue *properties_changed;
+ GHashTable *pending; /* callback path (string) -> sender (string) */
+ GHashTable *active; /* callback path (string) -> active (ActivePrompt) */
};
-static gint signals[LAST_SIGNAL] = { 0, };
-
G_DEFINE_TYPE (GcrSystemPrompter, gcr_system_prompter, G_TYPE_OBJECT);
-static GVariant *
-build_changed_properties (GcrSystemPrompter *self)
-{
- const gchar *property_name;
- GVariantBuilder builder;
- GVariant *value;
-
- g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ssv)"));
-
- while ((property_name = g_queue_pop_head (self->pv->properties_changed))) {
- value = g_hash_table_lookup (self->pv->properties, property_name);
- g_variant_builder_add (&builder, "(ssv)", GCR_DBUS_PROMPT_INTERFACE, property_name, value);
- }
-
- return g_variant_builder_end (&builder);
-}
-
-static void
-prompt_emit_changed (GcrSystemPrompter *self,
- const gchar *dbus_property)
-{
- const gchar *object_property;
-
- g_assert (dbus_property);
-
- g_queue_push_tail (self->pv->properties_changed,
- (gpointer)g_intern_string (dbus_property));
-
- if (g_str_equal ("Title", dbus_property))
- object_property = "title";
- else if (g_str_equal ("Message", dbus_property))
- object_property = "message";
- else if (g_str_equal ("Warning", dbus_property))
- object_property = "warning";
- else if (g_str_equal ("Description", dbus_property))
- object_property = "description";
- else if (g_str_equal ("PasswordNew", dbus_property))
- object_property = "password-new";
- else if (g_str_equal ("PasswordStrength", dbus_property))
- object_property = "password-strength";
- else if (g_str_equal ("ChoiceLabel", dbus_property))
- object_property = "choice-label";
- else if (g_str_equal ("ChoiceChosen", dbus_property))
- object_property = "choice-chosen";
- else if (g_str_equal ("CallerWindow", dbus_property))
- object_property = "caller-window";
- else
- g_assert_not_reached ();
-
- g_object_notify (G_OBJECT (self), object_property);
-}
-
-static GVariant *
-prompt_get_property (GDBusConnection *connection,
- const gchar *sender,
- const gchar *object_path,
- const gchar *interface_name,
- const gchar *property_name,
- GError **error,
- gpointer user_data)
-{
- GcrSystemPrompter *self = GCR_SYSTEM_PROMPTER (user_data);
- GVariant *ret;
-
- g_return_val_if_fail (property_name != NULL, NULL);
-
- if (g_strcmp0 (self->pv->owner_name, sender) != 0) {
- g_error_new_literal (G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED,
- "This prompt is owned by another process.");
- return NULL;
- }
-
- ret = g_hash_table_lookup (self->pv->properties, property_name);
- g_return_val_if_fail (ret != NULL, NULL);
-
- return g_variant_ref (ret);
-}
-
-static gboolean
-prompt_set_property (GDBusConnection *connection,
- const gchar *sender,
- const gchar *object_path,
- const gchar *interface_name,
- const gchar *property_name,
- GVariant *value,
- GError **error,
- gpointer user_data)
-{
- GcrSystemPrompter *self = GCR_SYSTEM_PROMPTER (user_data);
-
- g_return_val_if_fail (property_name != NULL, FALSE);
-
- if (g_strcmp0 (self->pv->owner_name, sender) != 0) {
- g_error_new_literal (G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED,
- "This prompt is owned by another process.");
- return FALSE;
- }
-
- if (!g_hash_table_lookup (self->pv->properties, property_name))
- g_return_val_if_reached (FALSE);
-
- g_hash_table_insert (self->pv->properties,
- (gpointer)g_intern_string (property_name),
- g_variant_ref (value));
-
- prompt_emit_changed (self, property_name);
- return TRUE;
-}
-
-static void
-prompt_update_properties (GcrSystemPrompter *self,
- GVariant *properties)
-{
- GObject *obj = G_OBJECT (self);
- GVariantIter *iter;
- GVariant *variant;
- gchar *property_name;
- gchar *interface;
-
- g_object_freeze_notify (obj);
+typedef struct {
+ gint refs;
+ gchar *callback_path;
+ gchar *callback_name;
+ GcrSystemPrompter *prompter;
+ GCancellable *cancellable;
+ GcrPrompt *prompt;
+ gboolean ready;
+ guint notify_sig;
+ GHashTable *changed;
+ GcrSecretExchange *exchange;
+ gboolean received;
+} ActivePrompt;
- g_variant_get (properties, "a(ssv)", &iter);
- while (g_variant_iter_loop (iter, "(ssv)", &interface, &property_name, &variant)) {
- if (g_strcmp0 (interface, GCR_DBUS_PROMPT_INTERFACE) != 0)
- continue;
- if (g_hash_table_lookup (self->pv->properties, property_name)) {
- g_hash_table_insert (self->pv->properties,
- (gpointer)g_intern_string (property_name),
- g_variant_ref (variant));
- prompt_emit_changed (self, property_name);
- }
- }
+static void prompt_send_ready (ActivePrompt *active,
+ const gchar *response,
+ const gchar *secret);
- g_variant_iter_free (iter);
+static void prompt_possibly_ready (GcrSystemPrompter *self,
+ const gchar *callback);
- g_object_thaw_notify (obj);
-}
+static void prompt_stop_prompting (ActivePrompt *active,
+ gboolean send_done_message,
+ gboolean wait_for_reply);
-static void
-prompt_clear_property (GcrSystemPrompter *self,
- const gchar *property_name,
- GVariant *value)
+static ActivePrompt *
+active_prompt_ref (ActivePrompt *active)
{
- g_hash_table_insert (self->pv->properties,
- (gpointer)g_intern_string (property_name),
- g_variant_ref (value));
+ g_atomic_int_inc (&active->refs);
+ return active;
}
static void
-prompt_clear_properties (GcrSystemPrompter *self)
+on_prompt_notify (GObject *object,
+ GParamSpec *param,
+ gpointer user_data)
{
- GVariant *variant;
-
- variant = g_variant_ref_sink (g_variant_new_string (""));
- prompt_clear_property (self, GCR_DBUS_PROMPT_PROPERTY_TITLE, variant);
- prompt_clear_property (self, GCR_DBUS_PROMPT_PROPERTY_MESSAGE, variant);
- prompt_clear_property (self, GCR_DBUS_PROMPT_PROPERTY_WARNING, variant);
- prompt_clear_property (self, GCR_DBUS_PROMPT_PROPERTY_DESCRIPTION, variant);
- prompt_clear_property (self, GCR_DBUS_PROMPT_PROPERTY_CHOICE_LABEL, variant);
- prompt_clear_property (self, GCR_DBUS_PROMPT_PROPERTY_CALLER_WINDOW, variant);
- g_variant_unref (variant);
-
- variant = g_variant_ref_sink (g_variant_new_boolean (FALSE));
- prompt_clear_property (self, GCR_DBUS_PROMPT_PROPERTY_PASSWORD_NEW, variant);
- prompt_clear_property (self, GCR_DBUS_PROMPT_PROPERTY_CHOICE_CHOSEN, variant);
- g_variant_unref (variant);
-
- variant = g_variant_ref_sink (g_variant_new_int32 (0));
- prompt_clear_property (self, GCR_DBUS_PROMPT_PROPERTY_PASSWORD_STRENGTH, variant);
- g_variant_unref (variant);
-
- g_queue_clear (self->pv->properties_changed);
+ ActivePrompt *active = user_data;
+ gpointer key = (gpointer)g_intern_string (param->name);
+ g_hash_table_replace (active->changed, key, key);
}
static void
-prompt_method_request_password (GcrSystemPrompter *self,
- GDBusMethodInvocation *invocation,
- GVariant *properties,
- const gchar *exchange)
-{
- gboolean result;
-
- if (self->pv->invocation != NULL) {
- g_dbus_method_invocation_return_error_literal (invocation, GCR_SYSTEM_PROMPT_ERROR,
- GCR_SYSTEM_PROMPT_IN_PROGRESS,
- "The prompt is already requesting.");
- return;
- }
-
- if (!gcr_secret_exchange_receive (self->pv->exchange, exchange)) {
- g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR,
- G_DBUS_ERROR_INVALID_ARGS,
- "The exchange argument was invalid.");
- return;
- }
-
- prompt_update_properties (self, properties);
-
- if (!self->pv->opened) {
- self->pv->opened = TRUE;
- _gcr_debug ("prompter opening prompt");
- g_signal_emit (self, signals[OPEN], 0);
- }
-
- self->pv->invocation = invocation;
- g_signal_emit (self, signals[PROMPT_PASSWORD], 0, &result);
-
- if (!result) {
- g_return_if_fail (self->pv->invocation == invocation);
- self->pv->invocation = NULL;
- g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR,
- G_DBUS_ERROR_NOT_SUPPORTED,
- "Prompting for confirmation not supported.");
+active_prompt_unref (gpointer data)
+{
+ ActivePrompt *active = data;
+
+ if (g_atomic_int_dec_and_test (&active->refs)) {
+ g_free (active->callback_path);
+ g_free (active->callback_name);
+ g_object_unref (active->prompter);
+ g_object_unref (active->cancellable);
+ g_signal_handlers_disconnect_by_func (active->prompt, on_prompt_notify, active);
+ g_object_unref (active->prompt);
+ g_hash_table_destroy (active->changed);
+ if (active->exchange)
+ g_object_unref (active->exchange);
+ g_slice_free (ActivePrompt, active);
}
}
-static void
-prompt_method_request_confirm (GcrSystemPrompter *self,
- GDBusMethodInvocation *invocation,
- GVariant *properties)
+static GcrSecretExchange *
+active_prompt_get_secret_exchange (ActivePrompt *active)
{
- gboolean result;
-
- if (self->pv->invocation != NULL) {
- g_dbus_method_invocation_return_error_literal (invocation, GCR_SYSTEM_PROMPT_ERROR,
- GCR_SYSTEM_PROMPT_IN_PROGRESS,
- "The prompt is already requesting.");
- return;
- }
-
- prompt_update_properties (self, properties);
-
- if (!self->pv->opened) {
- self->pv->opened = TRUE;
- _gcr_debug ("prompter opening prompt");
- g_signal_emit (self, signals[OPEN], 0);
- }
-
- self->pv->invocation = invocation;
- g_signal_emit (self, signals[PROMPT_CONFIRM], 0, &result);
-
- if (!result) {
- g_return_if_fail (self->pv->invocation == invocation);
- self->pv->invocation = NULL;
- g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR,
- G_DBUS_ERROR_NOT_SUPPORTED,
- "Prompting for confirmation not supported.");
- }
+ if (active->exchange == NULL)
+ active->exchange = gcr_secret_exchange_new (NULL);
+ return active->exchange;
}
-static void
-prompt_method_call (GDBusConnection *connection,
- const gchar *sender,
- const gchar *object_path,
- const gchar *interface_name,
- const gchar *method_name,
- GVariant *parameters,
- GDBusMethodInvocation *invocation,
- gpointer user_data)
+static ActivePrompt *
+active_prompt_create (GcrSystemPrompter *self,
+ const gchar *callback)
{
- GcrSystemPrompter *self = GCR_SYSTEM_PROMPTER (user_data);
- GVariant *properties = NULL;
- gchar *string = NULL;
-
- g_return_if_fail (method_name != NULL);
+ ActivePrompt *active;
- if (g_strcmp0 (self->pv->owner_name, sender) != 0) {
- g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR,
- G_DBUS_ERROR_ACCESS_DENIED,
- "This prompt is owned by another process.");
+ active = g_slice_new0 (ActivePrompt);
+ if (!g_hash_table_lookup_extended (self->pv->pending, callback,
+ (gpointer *)&active->callback_path,
+ (gpointer *)&active->callback_name))
+ g_return_val_if_reached (NULL);
+ if (!g_hash_table_steal (self->pv->pending, callback))
+ g_return_val_if_reached (NULL);
- } else if (g_str_equal (method_name, "RequestPassword")) {
- g_variant_get (parameters, "(@a(ssv)s)", &properties, &string);
- prompt_method_request_password (self, invocation, properties, string);
+ active->refs = 1;
+ active->prompter = g_object_ref (self);
+ active->cancellable = g_cancellable_new ();
+ active->prompt = g_object_new (self->pv->prompt_type, NULL);
+ active->notify_sig = g_signal_connect (active->prompt, "notify", G_CALLBACK (on_prompt_notify), active);
+ active->changed = g_hash_table_new (g_direct_hash, g_direct_equal);
- } else if (g_str_equal (method_name, "RequestConfirm")) {
- g_variant_get (parameters, "(@a(ssv))", &properties);
- prompt_method_request_confirm (self, invocation, properties);
-
- } else {
- g_return_if_reached ();
- }
-
- if (properties)
- g_variant_unref (properties);
- g_free (string);
+ /* Insert us into the active hash table */
+ g_hash_table_replace (self->pv->active, active->callback_path, active);
+ return active;
}
-static GDBusInterfaceVTable prompt_dbus_vtable = {
- prompt_method_call,
- prompt_get_property,
- prompt_set_property,
-};
-
-static const gchar *
-begin_prompting (GcrSystemPrompter *self,
- GDBusConnection *connection)
-{
- GError *error = NULL;
-
- g_assert (self->pv->prompt_path == NULL);
-
- self->pv->prompt_path = g_strdup (GCR_DBUS_PROMPTER_OBJECT_PATH "/prompt0");
- _gcr_debug ("prompter registering prompt: %s", self->pv->prompt_path);
- self->pv->prompt_registered = g_dbus_connection_register_object (connection, self->pv->prompt_path,
- _gcr_prompter_prompt_interface_info (),
- &prompt_dbus_vtable, self, NULL, &error);
-
- if (error != NULL) {
- g_warning ("couldn't register prompt object: %s", error->message);
- g_clear_object (&error);
- }
-
- /* Setup the secret exchange */
- g_assert (self->pv->exchange == NULL);
- self->pv->exchange = gcr_secret_exchange_new (NULL);
-
- return self->pv->prompt_path;
-}
-
-static void
-finish_prompting (GcrSystemPrompter *self)
-{
- g_assert (self->pv->invocation == NULL);
-
- prompt_clear_properties (self);
-
- /* Tell the implementation to hide the display */
- if (self->pv->opened) {
- _gcr_debug ("prompter closing prompt");
- self->pv->opened = FALSE;
- g_signal_emit (self, signals[CLOSE], 0);
- }
-
- if (self->pv->owner_watching_id) {
- _gcr_debug ("prompter stopping watch of client: %s", self->pv->owner_name);
- g_bus_unwatch_name (self->pv->owner_watching_id);
- self->pv->owner_watching_id = 0;
- }
-
- g_free (self->pv->owner_name);
- self->pv->owner_name = NULL;
-
- if (self->pv->prompt_registered) {
- _gcr_debug ("prompter unregistering prompt: %s", self->pv->prompt_path);
- if (!g_dbus_connection_unregister_object (self->pv->connection,
- self->pv->prompt_registered))
- g_return_if_reached ();
- self->pv->prompt_registered = 0;
- }
-
- g_free (self->pv->prompt_path);
- self->pv->prompt_path = NULL;
-
- g_clear_object (&self->pv->exchange);
-}
-
-
static void
gcr_system_prompter_init (GcrSystemPrompter *self)
{
self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_SYSTEM_PROMPTER,
GcrSystemPrompterPrivate);
- self->pv->properties = g_hash_table_new_full (g_str_hash, g_str_equal, NULL,
- (GDestroyNotify)g_variant_unref);
- self->pv->properties_changed = g_queue_new ();
- prompt_clear_properties (self);
+ self->pv->pending = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+ self->pv->active = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, active_prompt_unref);
}
static void
@@ -479,11 +191,11 @@ gcr_system_prompter_set_property (GObject *obj,
GcrSystemPrompter *self = GCR_SYSTEM_PROMPTER (obj);
switch (prop_id) {
- case PROP_CHOICE_CHOSEN:
- gcr_system_prompter_set_choice_chosen (self, g_value_get_boolean (value));
+ case PROP_MODE:
+ self->pv->mode = g_value_get_enum (value);
break;
- case PROP_PASSWORD_STRENGTH:
- gcr_system_prompter_set_password_strength (self, g_value_get_int (value));
+ case PROP_PROMPT_TYPE:
+ self->pv->prompt_type = g_value_get_gtype (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
@@ -500,32 +212,11 @@ gcr_system_prompter_get_property (GObject *obj,
GcrSystemPrompter *self = GCR_SYSTEM_PROMPTER (obj);
switch (prop_id) {
- case PROP_TITLE:
- g_value_set_string (value, gcr_system_prompter_get_title (self));
- break;
- case PROP_MESSAGE:
- g_value_set_string (value, gcr_system_prompter_get_message (self));
- break;
- case PROP_DESCRIPTION:
- g_value_set_string (value, gcr_system_prompter_get_description (self));
- break;
- case PROP_WARNING:
- g_value_set_string (value, gcr_system_prompter_get_warning (self));
- break;
- case PROP_PASSWORD_NEW:
- g_value_set_boolean (value, gcr_system_prompter_get_password_new (self));
- break;
- case PROP_PASSWORD_STRENGTH:
- g_value_set_int (value, gcr_system_prompter_get_password_strength (self));
- break;
- case PROP_CHOICE_LABEL:
- g_value_set_string (value, gcr_system_prompter_get_choice_label (self));
+ case PROP_MODE:
+ g_value_set_enum (value, gcr_system_prompter_get_mode (self));
break;
- case PROP_CHOICE_CHOSEN:
- g_value_set_boolean (value, gcr_system_prompter_get_choice_chosen (self));
- break;
- case PROP_CALLER_WINDOW:
- g_value_set_string (value, gcr_system_prompter_get_caller_window (self));
+ case PROP_PROMPT_TYPE:
+ g_value_set_gtype (value, gcr_system_prompter_get_prompt_type (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
@@ -540,13 +231,11 @@ gcr_system_prompter_dispose (GObject *obj)
_gcr_debug ("disposing prompter");
- if (self->pv->invocation)
- gcr_system_prompter_respond_cancelled (self);
-
- finish_prompting (self);
-
if (self->pv->prompter_registered)
- gcr_system_prompter_unregister (self, self->pv->connection);
+ gcr_system_prompter_unregister (self, FALSE);
+
+ g_hash_table_remove_all (self->pv->active);
+ g_hash_table_remove_all (self->pv->pending);
G_OBJECT_CLASS (gcr_system_prompter_parent_class)->dispose (obj);
}
@@ -558,143 +247,249 @@ gcr_system_prompter_finalize (GObject *obj)
_gcr_debug ("finalizing prompter");
- g_hash_table_destroy (self->pv->properties);
- g_queue_free (self->pv->properties_changed);
+ g_assert (self->pv->connection == NULL);
+ g_assert (self->pv->prompter_registered == 0);
+
+ g_hash_table_destroy (self->pv->active);
+ g_hash_table_destroy (self->pv->pending);
G_OBJECT_CLASS (gcr_system_prompter_parent_class)->finalize (obj);
}
static void
-gcr_system_prompter_real_show_prompt (GcrSystemPrompter *self)
+gcr_system_prompter_class_init (GcrSystemPrompterClass *klass)
{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-}
-
-static gboolean
-gcr_system_prompter_real_prompt_confirm (GcrSystemPrompter *self)
-{
- return FALSE;
-}
+ gobject_class->get_property = gcr_system_prompter_get_property;
+ gobject_class->set_property = gcr_system_prompter_set_property;
+ gobject_class->dispose = gcr_system_prompter_dispose;
+ gobject_class->finalize = gcr_system_prompter_finalize;
-static gboolean
-gcr_system_prompter_real_prompt_password (GcrSystemPrompter *self)
-{
- return FALSE;
-}
+ g_type_class_add_private (gobject_class, sizeof (GcrSystemPrompterPrivate));
-static void
-gcr_system_prompter_real_hide_prompt (GcrSystemPrompter *self)
-{
+ g_object_class_install_property (gobject_class, PROP_MODE,
+ g_param_spec_enum ("mode", "Mode", "Prompting mode",
+ GCR_TYPE_SYSTEM_PROMPTER_MODE, GCR_SYSTEM_PROMPTER_SINGLE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class, PROP_PROMPT_TYPE,
+ g_param_spec_gtype ("prompt-type", "Prompt GType", "GObject type of prompts",
+ GCR_TYPE_PROMPT,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
}
-static void
-gcr_system_prompter_class_init (GcrSystemPrompterClass *klass)
+static GVariantBuilder *
+prompt_build_properties (GcrPrompt *prompt,
+ GHashTable *changed)
{
- GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GObject *obj = G_OBJECT (prompt);
+ GVariantBuilder *builder;
+ const gchar *property_name;
+ GParamSpec *pspec;
+ GHashTableIter iter;
+ const GVariantType *type;
+ GVariant *variant;
+ GValue value;
- gobject_class->get_property = gcr_system_prompter_get_property;
- gobject_class->set_property = gcr_system_prompter_set_property;
- gobject_class->dispose = gcr_system_prompter_dispose;
- gobject_class->finalize = gcr_system_prompter_finalize;
+ builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
+ g_hash_table_iter_init (&iter, changed);
+ while (g_hash_table_iter_next (&iter, (gpointer *)&property_name, NULL)) {
- klass->open = gcr_system_prompter_real_show_prompt;
- klass->prompt_password= gcr_system_prompter_real_prompt_password;
- klass->prompt_confirm = gcr_system_prompter_real_prompt_confirm;
- klass->close = gcr_system_prompter_real_hide_prompt;
+ /* Make sure this property is on the prompt interface */
+ pspec = g_object_interface_find_property (GCR_PROMPT_GET_INTERFACE (obj),
+ property_name);
+ if (pspec == NULL)
+ continue;
- g_type_class_add_private (gobject_class, sizeof (GcrSystemPrompterPrivate));
+ memset (&value, 0, sizeof (GValue));
+ g_value_init (&value, pspec->value_type);
+ g_object_get_property (obj, property_name, &value);
+
+ switch (pspec->value_type) {
+ case G_TYPE_STRING:
+ type = G_VARIANT_TYPE ("s");
+ break;
+ case G_TYPE_INT:
+ type = G_VARIANT_TYPE ("i");
+ break;
+ case G_TYPE_BOOLEAN:
+ type = G_VARIANT_TYPE ("b");
+ break;
+ default:
+ g_critical ("encountered unsupported property type on GcrPrompt: %s",
+ g_type_name (pspec->value_type));
+ continue;
+ }
- g_object_class_install_property (gobject_class, PROP_TITLE,
- g_param_spec_string ("title", "Title", "Prompt title",
- "", G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+ variant = g_dbus_gvalue_to_gvariant (&value, type);
+ g_variant_builder_add (builder, "{sv}", property_name,
+ g_variant_new_variant (variant));
+ g_value_unset (&value);
+ g_variant_unref (variant);
+ }
+ g_hash_table_remove_all (changed);
+ return builder;
+}
- g_object_class_install_property (gobject_class, PROP_MESSAGE,
- g_param_spec_string ("message", "Message", "Prompt message",
- "", G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+static void
+prompt_stop_prompting (ActivePrompt *active,
+ gboolean send_done_message,
+ gboolean wait_for_reply)
+{
+ GcrSystemPrompter *self = g_object_ref (active->prompter);
+ GVariant *retval;
+
+ if (!active->ready)
+ g_cancellable_cancel (active->cancellable);
+
+ if (send_done_message && wait_for_reply) {
+ retval = g_dbus_connection_call_sync (self->pv->connection,
+ active->callback_name,
+ active->callback_path,
+ GCR_DBUS_CALLBACK_INTERFACE,
+ GCR_DBUS_CALLBACK_METHOD_DONE,
+ g_variant_new ("()"),
+ G_VARIANT_TYPE ("()"),
+ G_DBUS_CALL_FLAGS_NO_AUTO_START,
+ -1, NULL, NULL);
+ if (retval)
+ g_variant_unref (retval);
+ } else if (send_done_message) {
+ g_dbus_connection_call (self->pv->connection,
+ active->callback_name,
+ active->callback_path,
+ GCR_DBUS_CALLBACK_INTERFACE,
+ GCR_DBUS_CALLBACK_METHOD_DONE,
+ g_variant_new ("()"),
+ G_VARIANT_TYPE ("()"),
+ G_DBUS_CALL_FLAGS_NO_AUTO_START,
+ -1, NULL, NULL, NULL);
+ }
- g_object_class_install_property (gobject_class, PROP_DESCRIPTION,
- g_param_spec_string ("description", "Description", "Prompt description",
- "", G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+ g_object_run_dispose (G_OBJECT (active->prompt));
+ if (!g_hash_table_remove (self->pv->active, active->callback_path))
+ g_assert_not_reached ();
- g_object_class_install_property (gobject_class, PROP_WARNING,
- g_param_spec_string ("warning", "Warning", "Prompt warning",
- "", G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+ g_object_unref (self);
+}
- g_object_class_install_property (gobject_class, PROP_PASSWORD_NEW,
- g_param_spec_boolean ("password-new", "Password new", "Whether is a new password",
- FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+static void
+on_prompt_ready_complete (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ ActivePrompt *active = user_data;
+ GcrSystemPrompter *self = g_object_ref (active->prompter);
+ GError *error = NULL;
+ GVariant *retval;
- g_object_class_install_property (gobject_class, PROP_PASSWORD_STRENGTH,
- g_param_spec_int ("password-strength", "Password strength", "Strength of password",
- 0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ active->ready = TRUE;
+ retval = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error);
- g_object_class_install_property (gobject_class, PROP_CHOICE_LABEL,
- g_param_spec_string ("choice-label", "Choice label", "Label for prompt choice",
- "", G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+ /* The ready call failed, */
+ if (error != NULL) {
+ if (g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD))
+ _gcr_debug ("prompt disappeared or does not exist: %s: %s",
+ active->callback_name, active->callback_path);
+ else
+ g_message ("received an error from the prompt callback: %s", error->message);
+ g_error_free (error);
+ prompt_stop_prompting (active, FALSE, FALSE);
- g_object_class_install_property (gobject_class, PROP_CHOICE_CHOSEN,
- g_param_spec_boolean ("choice-chosen", "Choice chosen", "Whether choice is chosen",
- FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ /* Another new prompt may be ready to go active? */
+ prompt_possibly_ready (self, NULL);
+ }
- g_object_class_install_property (gobject_class, PROP_CALLER_WINDOW,
- g_param_spec_string ("caller-window", "Caller window", "Window id of caller",
- "", G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+ if (retval != NULL)
+ g_variant_unref (retval);
- signals[OPEN] = g_signal_new ("open", GCR_TYPE_SYSTEM_PROMPTER, G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GcrSystemPrompterClass, open),
- NULL, NULL, NULL, G_TYPE_NONE, 0);
+ active_prompt_unref (active);
+ g_object_unref (self);
+}
- signals[PROMPT_PASSWORD] = g_signal_new ("prompt-password", GCR_TYPE_SYSTEM_PROMPTER, G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GcrSystemPrompterClass, prompt_password),
- g_signal_accumulator_true_handled, NULL, NULL,
- G_TYPE_BOOLEAN, 0);
+static void
+prompt_send_ready (ActivePrompt *active,
+ const gchar *response,
+ const gchar *secret)
+{
+ GcrSystemPrompter *self;
+ GVariantBuilder *builder;
+ GcrSecretExchange *exchange;
+ gchar *sent;
- signals[PROMPT_CONFIRM] = g_signal_new ("prompt-confirm", GCR_TYPE_SYSTEM_PROMPTER, G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GcrSystemPrompterClass, prompt_confirm),
- g_signal_accumulator_true_handled, NULL, NULL,
- G_TYPE_BOOLEAN, 0);
+ exchange = active_prompt_get_secret_exchange (active);
+ if (!active->received) {
+ g_return_if_fail (secret == NULL);
+ sent = gcr_secret_exchange_begin (exchange);
+ } else {
+ sent = gcr_secret_exchange_send (exchange, secret, -1);
+ }
+
+ self = active->prompter;
+ builder = prompt_build_properties (active->prompt, active->changed);
- signals[RESPONDED] = g_signal_new ("responded", GCR_TYPE_SYSTEM_PROMPTER, G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GcrSystemPrompterClass, responded),
- NULL, NULL, NULL, G_TYPE_NONE, 0);
+ g_dbus_connection_call (self->pv->connection,
+ active->callback_name,
+ active->callback_path,
+ GCR_DBUS_CALLBACK_INTERFACE,
+ GCR_DBUS_CALLBACK_METHOD_READY,
+ g_variant_new ("(sa{sv}s)", response, builder, sent),
+ G_VARIANT_TYPE ("()"),
+ G_DBUS_CALL_FLAGS_NO_AUTO_START,
+ -1, active->cancellable,
+ on_prompt_ready_complete,
+ active_prompt_ref (active));
- signals[CLOSE] = g_signal_new ("close", GCR_TYPE_SYSTEM_PROMPTER, G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GcrSystemPrompterClass, close),
- NULL, NULL, NULL, G_TYPE_NONE, 0);
+ g_variant_builder_unref (builder);
+ g_free (sent);
}
static void
-emit_prompter_ready (GcrSystemPrompter *self)
+prompt_possibly_ready (GcrSystemPrompter *self,
+ const gchar *callback)
{
- GError *error = NULL;
+ ActivePrompt *active;
+ GHashTableIter iter;
- /* Now let everyone else know, we're ready! */
- g_dbus_connection_emit_signal (self->pv->connection, NULL,
- GCR_DBUS_PROMPTER_OBJECT_PATH,
- GCR_DBUS_PROMPTER_INTERFACE,
- GCR_DBUS_PROMPTER_SIGNAL_READY,
- g_variant_new ("()"),
- &error);
+ if (callback == NULL) {
+ g_hash_table_iter_init (&iter, self->pv->pending);
+ if (!g_hash_table_iter_next (&iter, (gpointer *)&callback, NULL))
+ return;
+ g_assert (callback != NULL);
+ }
- if (error != NULL) {
- g_warning ("couldn't emit prompter ready signal: %s", egg_error_message (error));
- g_error_free (error);
+ active = g_hash_table_lookup (self->pv->active, callback);
+
+ /* Only one prompt at a time, and only one active */
+ if (active == NULL) {
+ if (self->pv->mode == GCR_SYSTEM_PROMPTER_SINGLE &&
+ g_hash_table_size (self->pv->active) > 0)
+ return;
+
+ active = active_prompt_create (self, callback);
}
+
+ prompt_send_ready (active, GCR_DBUS_PROMPT_REPLY_YES, NULL);
}
static void
-on_owner_vanished (GDBusConnection *connection,
- const gchar *name,
- gpointer user_data)
+prompt_update_properties (GcrPrompt *prompt,
+ GVariantIter *iter)
{
- GcrSystemPrompter *self = GCR_SYSTEM_PROMPTER (user_data);
-
- if (self->pv->invocation != NULL)
- gcr_system_prompter_respond_cancelled (self);
+ GObject *obj = G_OBJECT (prompt);
+ gchar *property_name;
+ GVariant *variant;
+ GValue value;
- finish_prompting (self);
- emit_prompter_ready (self);
+ g_object_freeze_notify (obj);
+ while (g_variant_iter_loop (iter, "{&sv}", &property_name, &variant)) {
+ memset (&value, 0, sizeof (GValue));
+ g_dbus_gvariant_to_gvalue (variant, &value);
+ g_object_set_property (obj, property_name, &value);
+ g_value_unset (&value);
+ }
+ g_object_thaw_notify (obj);
}
static GVariant *
@@ -724,70 +519,173 @@ prompter_set_property (GDBusConnection *connection,
static void
prompter_method_begin_prompting (GcrSystemPrompter *self,
- GDBusMethodInvocation *invocation)
+ GDBusMethodInvocation *invocation,
+ GVariant *parameters)
{
- GDBusConnection *connection;
- const gchar *path;
+ gchar *callback;
+ const gchar *sender;
+
+ g_variant_get (parameters, "(o)", &callback);
- if (self->pv->owner_name != NULL) {
- g_dbus_method_invocation_return_error_literal (invocation,
- GCR_SYSTEM_PROMPT_ERROR,
- GCR_SYSTEM_PROMPT_IN_PROGRESS,
- "There is already a prompt in progress");
+ if (g_hash_table_lookup (self->pv->pending, callback) ||
+ g_hash_table_lookup (self->pv->active, callback)) {
+ g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
+ "Already begun prompting for this prompt callback");
return;
}
- /* Setup the owner of the prompting */
- self->pv->owner_name = g_strdup (g_dbus_method_invocation_get_sender (invocation));
- g_return_if_fail (self->pv->owner_name != NULL);
-
- connection = g_dbus_method_invocation_get_connection (invocation);
- _gcr_debug ("prompter starting watch of dbus client: %s", self->pv->owner_name);
- self->pv->owner_watching_id = g_bus_watch_name_on_connection (connection,
- self->pv->owner_name,
- G_BUS_NAME_WATCHER_FLAGS_NONE,
- NULL, on_owner_vanished,
- self, NULL);
-
- /* And respond */
- path = begin_prompting (self, connection);
- g_dbus_method_invocation_return_value (invocation, g_variant_new ("(o)", path));
+ sender = g_dbus_method_invocation_get_sender (invocation);
+ g_hash_table_insert (self->pv->pending, g_strdup (callback), g_strdup (sender));
+
+ g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
+ prompt_possibly_ready (self, callback);
+ g_free (callback);
}
static void
-prompter_method_finish_prompting (GcrSystemPrompter *self,
- GDBusMethodInvocation *invocation,
- const gchar *prompt)
+on_prompt_password (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
{
- if (g_strcmp0 (prompt, self->pv->prompt_path) != 0) {
- _gcr_debug ("caller passed invalid prompt: %s != %s", prompt, self->pv->prompt_path);
- g_dbus_method_invocation_return_error_literal (invocation,
- G_DBUS_ERROR,
- G_DBUS_ERROR_INVALID_ARGS,
- "The prompt argument is not valid");
+ ActivePrompt *active = user_data;
+ const gchar *reply;
+ GError *error = NULL;
+ const gchar *response;
+
+ g_assert (active->ready == FALSE);
+
+ reply = gcr_prompt_password_finish (GCR_PROMPT (source), result, &error);
+ if (error != NULL) {
+ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ g_warning ("prompting failed: %s", error->message);
+ g_clear_error (&error);
+ }
+
+ if (reply == NULL)
+ response = "no";
+ else
+ response = "yes";
+
+ prompt_send_ready (active, response, reply);
+ active_prompt_unref (active);
+}
+
+static void
+on_prompt_confirm (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ ActivePrompt *active = user_data;
+ GcrPromptReply reply;
+ GError *error = NULL;
+ const gchar *response;
+
+ g_assert (active->ready == FALSE);
+
+ reply = gcr_prompt_confirm_finish (GCR_PROMPT (source), result, &error);
+ if (error != NULL) {
+ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ g_warning ("prompting failed: %s", error->message);
+ g_clear_error (&error);
+ }
+
+ switch (reply) {
+ case GCR_PROMPT_REPLY_OK:
+ response = GCR_DBUS_PROMPT_REPLY_YES;
+ break;
+ case GCR_PROMPT_REPLY_CANCEL:
+ response = GCR_DBUS_PROMPT_REPLY_NO;
+ break;
+ }
+
+ prompt_send_ready (active, response, NULL);
+ active_prompt_unref (active);
+}
+
+static void
+prompter_method_perform_prompt (GcrSystemPrompter *self,
+ GDBusMethodInvocation *invocation,
+ GVariant *parameters)
+{
+ GcrSecretExchange *exchange;
+ GError *error = NULL;
+ ActivePrompt *active;
+ const gchar *callback;
+ const gchar *type;
+ GVariantIter *iter;
+ const gchar *received;
+
+ g_variant_get (parameters, "(&o&sa{sv}&s)",
+ &callback, &type, &iter, &received);
+
+ active = g_hash_table_lookup (self->pv->active, callback);
+ if (active == NULL) {
+ error = g_error_new (G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
+ "Not begun prompting for this prompt callback");
+
+ } else if (!g_str_equal (active->callback_name, g_dbus_method_invocation_get_sender (invocation))) {
+ error = g_error_new (G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED,
+ "This prompt is not owned by this application");
+
+ } else if (!active->ready) {
+ error = g_error_new (G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
+ "Already performing a prompt for this prompt callback");
+ }
+
+ if (error != NULL) {
+ g_dbus_method_invocation_take_error (invocation, error);
+ g_variant_iter_free (iter);
return;
}
- if (self->pv->owner_name == NULL) {
- _gcr_debug ("prompting is not in progress");
- g_dbus_method_invocation_return_error_literal (invocation,
- GCR_SYSTEM_PROMPT_ERROR,
- GCR_SYSTEM_PROMPT_NOT_HAPPENING,
- "The prompt is not in progress");
+ g_assert (active != NULL);
+ prompt_update_properties (active->prompt, iter);
+ g_variant_iter_free (iter);
+
+ exchange = active_prompt_get_secret_exchange (active);
+ if (!gcr_secret_exchange_receive (exchange, received)) {
+ g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
+ "Invalid secret exchange received");
return;
}
- _gcr_debug ("finishing prompting owned by caller %s", self->pv->owner_name);
+ active->received = TRUE;
- /* Close a prompt that's prompting */
- if (self->pv->invocation != NULL)
- gcr_system_prompter_respond_cancelled (self);
+ if (g_strcmp0 (type, GCR_DBUS_PROMPT_TYPE_CONFIRM) == 0) {
+ active->ready = FALSE;
+ gcr_prompt_confirm_async (active->prompt, active->cancellable,
+ on_prompt_confirm, active_prompt_ref (active));
- finish_prompting (self);
+ } else if (g_strcmp0 (type, GCR_DBUS_PROMPT_TYPE_PASSWORD) == 0) {
+ active->ready = FALSE;
+ gcr_prompt_password_async (active->prompt, active->cancellable,
+ on_prompt_password, active_prompt_ref (active));
+
+ } else {
+ g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
+ "Invalid type argument");
+ return;
+ }
g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
+}
- emit_prompter_ready (self);
+static void
+prompter_method_stop_prompting (GcrSystemPrompter *self,
+ GDBusMethodInvocation *invocation,
+ GVariant *parameters)
+{
+ const gchar *callback;
+ ActivePrompt *active;
+
+ g_variant_get (parameters, "(&o)", &callback);
+
+ active = g_hash_table_lookup (self->pv->active, callback);
+ if (active != NULL)
+ prompt_stop_prompting (active, TRUE, FALSE);
+
+ g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
+ prompt_possibly_ready (self, NULL);
}
static void
@@ -801,22 +699,21 @@ prompter_method_call (GDBusConnection *connection,
gpointer user_data)
{
GcrSystemPrompter *self = GCR_SYSTEM_PROMPTER (user_data);
- gchar *path = NULL;
g_return_if_fail (method_name != NULL);
if (g_str_equal (method_name, GCR_DBUS_PROMPTER_METHOD_BEGIN)) {
- prompter_method_begin_prompting (self, invocation);
+ prompter_method_begin_prompting (self, invocation, parameters);
+
+ } else if (g_str_equal (method_name, GCR_DBUS_PROMPTER_METHOD_PERFORM)) {
+ prompter_method_perform_prompt (self, invocation, parameters);
- } else if (g_str_equal (method_name, GCR_DBUS_PROMPTER_METHOD_FINISH)) {
- g_variant_get (parameters, "(o)", &path);
- prompter_method_finish_prompting (self, invocation, path);
+ } else if (g_str_equal (method_name, GCR_DBUS_PROMPTER_METHOD_STOP)) {
+ prompter_method_stop_prompting (self, invocation, parameters);
} else {
g_return_if_reached ();
}
-
- g_free (path);
}
static GDBusInterfaceVTable prompter_dbus_vtable = {
@@ -838,16 +735,13 @@ gcr_system_prompter_register (GcrSystemPrompter *self,
_gcr_debug ("registering prompter");
- self->pv->connection = connection;
- g_object_add_weak_pointer (G_OBJECT (connection), (gpointer *)&self->pv->connection);
+ self->pv->connection = g_object_ref (connection);
self->pv->prompter_registered = g_dbus_connection_register_object (connection,
GCR_DBUS_PROMPTER_OBJECT_PATH,
- _gcr_prompter_interface_info (),
+ _gcr_dbus_prompter_interface_info (),
&prompter_dbus_vtable,
- g_object_ref (self),
- g_object_unref,
- &error);
+ self, NULL, &error);
if (error != NULL) {
g_warning ("error registering prompter %s", egg_error_message (error));
g_clear_error (&error);
@@ -856,339 +750,97 @@ gcr_system_prompter_register (GcrSystemPrompter *self,
void
gcr_system_prompter_unregister (GcrSystemPrompter *self,
- GDBusConnection *connection)
+ gboolean wait)
{
+ ActivePrompt *active;
+ GVariantBuilder builder;
+ const gchar *sender;
+ GVariant *retval;
+ GList *paths;
+ GList *l;
+
g_return_if_fail (GCR_IS_SYSTEM_PROMPTER (self));
- g_return_if_fail (G_DBUS_CONNECTION (connection));
g_return_if_fail (self->pv->prompter_registered != 0);
- g_return_if_fail (self->pv->connection == connection);
_gcr_debug ("unregistering prompter");
- if (self->pv->invocation)
- gcr_system_prompter_respond_cancelled (self);
+ paths = g_hash_table_get_keys (self->pv->active);
+ for (l = paths; l != NULL; l = g_list_next (l)) {
+ active = g_hash_table_lookup (self->pv->active, l->data);
+ prompt_stop_prompting (active, TRUE, wait);
+ }
+ g_assert (g_hash_table_size (self->pv->active) == 0);
+ g_list_free (paths);
+
+ paths = g_hash_table_get_keys (self->pv->pending);
+ for (l = paths; l != NULL; l = g_list_next (l)) {
+ sender = g_hash_table_lookup (self->pv->pending, l->data);
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
+
+ if (wait) {
+ retval = g_dbus_connection_call_sync (self->pv->connection,
+ sender, l->data,
+ GCR_DBUS_CALLBACK_INTERFACE,
+ GCR_DBUS_CALLBACK_METHOD_DONE,
+ g_variant_new ("()"),
+ G_VARIANT_TYPE ("()"),
+ G_DBUS_CALL_FLAGS_NO_AUTO_START,
+ -1, NULL, NULL);
+ if (retval)
+ g_variant_unref (retval);
+
+ } else {
+ g_dbus_connection_call (self->pv->connection,
+ sender, l->data,
+ GCR_DBUS_CALLBACK_INTERFACE,
+ GCR_DBUS_CALLBACK_METHOD_DONE,
+ g_variant_new ("()"),
+ G_VARIANT_TYPE ("()"),
+ G_DBUS_CALL_FLAGS_NO_AUTO_START,
+ -1, NULL, NULL, NULL);
+ }
- finish_prompting (self);
+ if (!g_hash_table_remove (self->pv->pending, l->data))
+ g_assert_not_reached ();
+ }
+ g_assert (g_hash_table_size (self->pv->pending) == 0);
+ g_list_free (paths);
- g_dbus_connection_unregister_object (connection, self->pv->prompter_registered);
+ if (!g_dbus_connection_unregister_object (self->pv->connection, self->pv->prompter_registered))
+ g_assert_not_reached ();
self->pv->prompter_registered = 0;
- g_object_remove_weak_pointer (G_OBJECT (connection), (gpointer *)&self->pv->connection);
- self->pv->connection = NULL;
-}
-
-const gchar *
-gcr_system_prompter_get_title (GcrSystemPrompter *self)
-{
- GVariant *variant;
-
- g_return_val_if_fail (GCR_IS_SYSTEM_PROMPTER (self), NULL);
-
- variant = g_hash_table_lookup (self->pv->properties, GCR_DBUS_PROMPT_PROPERTY_TITLE);
- g_return_val_if_fail (variant != NULL, NULL);
- return g_variant_get_string (variant, NULL);
-}
-
-const gchar *
-gcr_system_prompter_get_message (GcrSystemPrompter *self)
-{
- GVariant *variant;
-
- g_return_val_if_fail (GCR_IS_SYSTEM_PROMPTER (self), NULL);
-
- variant = g_hash_table_lookup (self->pv->properties, GCR_DBUS_PROMPT_PROPERTY_MESSAGE);
- g_return_val_if_fail (variant != NULL, NULL);
- return g_variant_get_string (variant, NULL);
-}
-
-const gchar *
-gcr_system_prompter_get_description (GcrSystemPrompter *self)
-{
- GVariant *variant;
-
- g_return_val_if_fail (GCR_IS_SYSTEM_PROMPTER (self), NULL);
-
- variant = g_hash_table_lookup (self->pv->properties, GCR_DBUS_PROMPT_PROPERTY_DESCRIPTION);
- g_return_val_if_fail (variant != NULL, NULL);
- return g_variant_get_string (variant, NULL);
-}
-
-const gchar *
-gcr_system_prompter_get_warning (GcrSystemPrompter *self)
-{
- GVariant *variant;
-
- g_return_val_if_fail (GCR_IS_SYSTEM_PROMPTER (self), NULL);
-
- variant = g_hash_table_lookup (self->pv->properties, GCR_DBUS_PROMPT_PROPERTY_WARNING);
- g_return_val_if_fail (variant != NULL, NULL);
- return g_variant_get_string (variant, NULL);
-}
-
-void
-gcr_system_prompter_set_warning (GcrSystemPrompter *self,
- const gchar *warning)
-{
- GVariant *variant;
-
- g_return_if_fail (GCR_IS_SYSTEM_PROMPTER (self));
-
- if (warning == NULL)
- warning = "";
-
- variant = g_variant_new_string (warning ? warning : "");
- g_hash_table_insert (self->pv->properties,
- (gpointer)GCR_DBUS_PROMPT_PROPERTY_WARNING,
- g_variant_ref_sink (variant));
-
- prompt_emit_changed (self, GCR_DBUS_PROMPT_PROPERTY_WARNING);
-}
-
-gboolean
-gcr_system_prompter_get_password_new (GcrSystemPrompter *self)
-{
- GVariant *variant;
-
- g_return_val_if_fail (GCR_IS_SYSTEM_PROMPTER (self), FALSE);
-
- variant = g_hash_table_lookup (self->pv->properties, GCR_DBUS_PROMPT_PROPERTY_PASSWORD_NEW);
- g_return_val_if_fail (variant != NULL, FALSE);
- return g_variant_get_boolean (variant);
-}
-
-gint
-gcr_system_prompter_get_password_strength (GcrSystemPrompter *self)
-{
- GVariant *variant;
-
- g_return_val_if_fail (GCR_IS_SYSTEM_PROMPTER (self), 0);
-
- variant = g_hash_table_lookup (self->pv->properties, GCR_DBUS_PROMPT_PROPERTY_PASSWORD_STRENGTH);
- g_return_val_if_fail (variant != NULL, 0);
- return g_variant_get_int32 (variant);
-}
-
-void
-gcr_system_prompter_set_password_strength (GcrSystemPrompter *self,
- gint strength)
-{
- GVariant *variant;
-
- g_return_if_fail (GCR_IS_SYSTEM_PROMPTER (self));
-
- variant = g_variant_new_int32 (strength);
- g_hash_table_insert (self->pv->properties,
- (gpointer) GCR_DBUS_PROMPT_PROPERTY_PASSWORD_STRENGTH,
- g_variant_ref_sink (variant));
-
- prompt_emit_changed (self, GCR_DBUS_PROMPT_PROPERTY_PASSWORD_STRENGTH);
-}
-
-const gchar *
-gcr_system_prompter_get_choice_label (GcrSystemPrompter *self)
-{
- GVariant *variant;
-
- g_return_val_if_fail (GCR_IS_SYSTEM_PROMPTER (self), NULL);
-
- variant = g_hash_table_lookup (self->pv->properties, GCR_DBUS_PROMPT_PROPERTY_CHOICE_LABEL);
- g_return_val_if_fail (variant != NULL, NULL);
- return g_variant_get_string (variant, NULL);
-}
-
-/**
- * gcr_system_prompter_get_choice_chosen:
- * @self: a prompter
- *
- * Used by prompter implementations to check if the choice offered by the
- * prompt should be checked or unchecked.
- *
- * Returns: whether the choice is chosen
- */
-gboolean
-gcr_system_prompter_get_choice_chosen (GcrSystemPrompter *self)
-{
- GVariant *variant;
-
- g_return_val_if_fail (GCR_IS_SYSTEM_PROMPTER (self), FALSE);
-
- variant = g_hash_table_lookup (self->pv->properties, GCR_DBUS_PROMPT_PROPERTY_CHOICE_CHOSEN);
- g_return_val_if_fail (variant != NULL, FALSE);
- return g_variant_get_boolean (variant);
-}
-
-/**
- * gcr_system_prompter_set_choice_chosen:
- * @self: a prompter
- * @chosen: the user's choice
- *
- * Used by prompter implementations to let the prompter know when the user
- * has checked or unchecked the choice offered by the prompt.
- */
-void
-gcr_system_prompter_set_choice_chosen (GcrSystemPrompter *self,
- gboolean chosen)
-{
- GVariant *variant;
-
- g_return_if_fail (GCR_IS_SYSTEM_PROMPTER (self));
-
- variant = g_variant_new_boolean (chosen);
- g_hash_table_insert (self->pv->properties,
- (gpointer)GCR_DBUS_PROMPT_PROPERTY_CHOICE_CHOSEN,
- g_variant_ref_sink (variant));
-
- prompt_emit_changed (self, GCR_DBUS_PROMPT_PROPERTY_CHOICE_CHOSEN);
+ g_clear_object (&self->pv->connection);
}
/**
- * gcr_system_prompter_get_caller_window:
- * @self: a prompter
- *
- * Get a string containing the callers window identifier. If the prompter
- * supports making its prompts transient for
- */
-const gchar *
-gcr_system_prompter_get_caller_window (GcrSystemPrompter *self)
-{
- GVariant *variant;
- const gchar *window;
-
- g_return_val_if_fail (GCR_IS_SYSTEM_PROMPTER (self), NULL);
-
- variant = g_hash_table_lookup (self->pv->properties, GCR_DBUS_PROMPT_PROPERTY_CALLER_WINDOW);
- g_return_val_if_fail (variant != NULL, NULL);
- window = g_variant_get_string (variant, NULL);
- if (!window || !window[0])
- return NULL;
- return window;
-}
-
-/**
- * gcr_system_prompter_respond_cancelled:
- * @self: a prompter
+ * gcr_system_prompter_new:
*
- * Used by prompter implementations to let the prompter know when the user
- * has cancelled the current prompt.
- */
-void
-gcr_system_prompter_respond_cancelled (GcrSystemPrompter *self)
-{
- GDBusMethodInvocation *invocation;
- const gchar *method;
- GVariant *properties;
-
- g_return_if_fail (GCR_IS_SYSTEM_PROMPTER (self));
- g_return_if_fail (self->pv->invocation != NULL);
-
- invocation = self->pv->invocation;
- self->pv->invocation = NULL;
-
- /* Don't send back any changed properties on cancel */
- properties = g_variant_new_array (G_VARIANT_TYPE ("(ssv)"), NULL, 0);
-
- _gcr_debug ("responding to with cancelled");
-
- method = g_dbus_method_invocation_get_method_name (invocation);
- if (method && g_str_equal (method, GCR_DBUS_PROMPT_METHOD_PASSWORD))
- g_dbus_method_invocation_return_value (invocation,
- g_variant_new ("(@a(ssv)s)",
- properties, ""));
-
- else if (method && g_str_equal (method, GCR_DBUS_PROMPT_METHOD_CONFIRM))
- g_dbus_method_invocation_return_value (invocation, g_variant_new ("(@a(ssv)b)",
- properties, FALSE));
-
- else
- g_return_if_reached ();
-
- g_signal_emit (self, signals[RESPONDED], 0);
-}
-
-/**
- * gcr_system_prompter_respond_confirmed:
- * @self: a prompter
- * @password: the password
+ * Create a new system prompter service. This prompter won't do anything unless
+ * you connect to its signals and show appropriate prompts.
*
- * Used by prompter implementations to let the prompter know when the user
- * has entered a password and clicked 'OK'.
+ * Returns: (transfer full): a new prompter service
*/
-void
-gcr_system_prompter_respond_with_password (GcrSystemPrompter *self,
- const gchar *password)
+GcrSystemPrompter *
+gcr_system_prompter_new (GcrSystemPrompterMode mode,
+ GType prompt_type)
{
- GDBusMethodInvocation *invocation;
- const gchar *method;
- GVariant *properties;
- gchar *exchange;
-
- g_return_if_fail (GCR_IS_SYSTEM_PROMPTER (self));
- g_return_if_fail (password != NULL);
- g_return_if_fail (self->pv->invocation != NULL);
-
- invocation = self->pv->invocation;
- self->pv->invocation = NULL;
-
- method = g_dbus_method_invocation_get_method_name (invocation);
- g_return_if_fail (method != NULL && g_str_equal (method, GCR_DBUS_PROMPT_METHOD_PASSWORD));
-
- /* Send back all the properties before we respond */
- properties = build_changed_properties (self);
-
- _gcr_debug ("responding to prompt with password");
-
- exchange = gcr_secret_exchange_send (self->pv->exchange, password, -1);
- g_dbus_method_invocation_return_value (invocation, g_variant_new ("(@a(ssv)s)",
- properties, exchange));
- g_free (exchange);
-
- g_signal_emit (self, signals[RESPONDED], 0);
+ return g_object_new (GCR_TYPE_SYSTEM_PROMPTER,
+ "mode", mode,
+ "prompt-type", prompt_type,
+ NULL);
}
-/**
- * gcr_system_prompter_respond_confirmed:
- * @self: a prompter
- *
- * Used by prompter implementations to let the prompter know when the user
- * has confirmed the request, ie: clicked 'OK'.
- */
-void
-gcr_system_prompter_respond_confirmed (GcrSystemPrompter *self)
+GcrSystemPrompterMode
+gcr_system_prompter_get_mode (GcrSystemPrompter *self)
{
- GDBusMethodInvocation *invocation;
- GVariant *properties;
- const gchar *method;
-
- g_return_if_fail (GCR_IS_SYSTEM_PROMPTER (self));
- g_return_if_fail (self->pv->invocation != NULL);
-
- invocation = self->pv->invocation;
- self->pv->invocation = NULL;
-
- /* Send back all the properties before we respond */
- properties = build_changed_properties (self);
-
- method = g_dbus_method_invocation_get_method_name (invocation);
- g_return_if_fail (method != NULL && g_str_equal (method, GCR_DBUS_PROMPT_METHOD_CONFIRM));
-
- _gcr_debug ("responding to prompt with confirm");
-
- g_dbus_method_invocation_return_value (invocation, g_variant_new ("(@a(ssv)b)",
- properties, TRUE));
-
- g_signal_emit (self, signals[RESPONDED], 0);
+ g_return_val_if_fail (GCR_IS_SYSTEM_PROMPTER (self), GCR_SYSTEM_PROMPTER_SINGLE);
+ return self->pv->mode;
}
-/**
- * gcr_system_prompter_new:
- *
- * Create a new system prompter service. This prompter won't do anything unless
- * you connect to its signals and show appropriate prompts.
- *
- * Returns: (transfer full): a new prompter service
- */
-GcrSystemPrompter *
-gcr_system_prompter_new (void)
+GType
+gcr_system_prompter_get_prompt_type (GcrSystemPrompter *self)
{
- return g_object_new (GCR_TYPE_SYSTEM_PROMPTER, NULL);
+ g_return_val_if_fail (GCR_IS_SYSTEM_PROMPTER (self), 0);
+ return self->pv->prompt_type;
}
diff --git a/gcr/gcr-system-prompter.h b/gcr/gcr-system-prompter.h
index b697473..8549924 100644
--- a/gcr/gcr-system-prompter.h
+++ b/gcr/gcr-system-prompter.h
@@ -28,12 +28,18 @@
#ifndef __GCR_SYSTEM_PROMPTER_H__
#define __GCR_SYSTEM_PROMPTER_H__
+#include "gcr-secret-exchange.h"
#include "gcr-types.h"
#include <glib-object.h>
G_BEGIN_DECLS
+typedef enum {
+ GCR_SYSTEM_PROMPTER_SINGLE,
+ GCR_SYSTEM_PROMPTER_MULTIPLE
+} GcrSystemPrompterMode;
+
#define GCR_TYPE_SYSTEM_PROMPTER (gcr_system_prompter_get_type ())
#define GCR_SYSTEM_PROMPTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_SYSTEM_PROMPTER, GcrSystemPrompter))
#define GCR_SYSTEM_PROMPTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_SYSTEM_PROMPTER, GcrSystemPrompterClass))
@@ -52,61 +58,26 @@ struct _GcrSystemPrompter {
struct _GcrSystemPrompterClass {
GObjectClass parent_class;
-
- void (*open) (GcrSystemPrompter *self);
-
- gboolean (*prompt_password) (GcrSystemPrompter *self);
-
- gboolean (*prompt_confirm) (GcrSystemPrompter *self);
-
- void (*responded) (GcrSystemPrompter *self);
-
- void (*close) (GcrSystemPrompter *self);
};
-GType gcr_system_prompter_get_type (void) G_GNUC_CONST;
-
-GcrSystemPrompter * gcr_system_prompter_new (void);
-
-void gcr_system_prompter_register (GcrSystemPrompter *self,
- GDBusConnection *connection);
-
-void gcr_system_prompter_unregister (GcrSystemPrompter *self,
- GDBusConnection *connection);
-
-const gchar * gcr_system_prompter_get_title (GcrSystemPrompter *self);
-
-const gchar * gcr_system_prompter_get_message (GcrSystemPrompter *self);
-
-const gchar * gcr_system_prompter_get_description (GcrSystemPrompter *self);
-
-const gchar * gcr_system_prompter_get_warning (GcrSystemPrompter *self);
+GType gcr_system_prompter_get_type (void) G_GNUC_CONST;
-void gcr_system_prompter_set_warning (GcrSystemPrompter *self,
- const gchar *warning);
+GcrSystemPrompter * gcr_system_prompter_new (GcrSystemPrompterMode mode,
+ GType prompt_type);
-gboolean gcr_system_prompter_get_password_new (GcrSystemPrompter *self);
+GcrSystemPrompterMode gcr_system_prompter_get_mode (GcrSystemPrompter *self);
-gint gcr_system_prompter_get_password_strength (GcrSystemPrompter *self);
+GType gcr_system_prompter_get_prompt_type (GcrSystemPrompter *self);
-void gcr_system_prompter_set_password_strength (GcrSystemPrompter *self,
- gint strength);
+gint gcr_system_prompter_get_showing (GcrSystemPrompter *self);
-const gchar * gcr_system_prompter_get_choice_label (GcrSystemPrompter *self);
+void gcr_system_prompter_stop_all (GcrSystemPrompter *self);
-gboolean gcr_system_prompter_get_choice_chosen (GcrSystemPrompter *self);
-
-void gcr_system_prompter_set_choice_chosen (GcrSystemPrompter *self,
- gboolean chosen);
-
-const gchar * gcr_system_prompter_get_caller_window (GcrSystemPrompter *self);
-
-void gcr_system_prompter_respond_cancelled (GcrSystemPrompter *self);
-
-void gcr_system_prompter_respond_with_password (GcrSystemPrompter *self,
- const gchar *password);
+void gcr_system_prompter_register (GcrSystemPrompter *self,
+ GDBusConnection *connection);
-void gcr_system_prompter_respond_confirmed (GcrSystemPrompter *self);
+void gcr_system_prompter_unregister (GcrSystemPrompter *self,
+ gboolean wait);
G_END_DECLS
diff --git a/gcr/gcr.h b/gcr/gcr.h
index 6c09364..a7c9f35 100644
--- a/gcr/gcr.h
+++ b/gcr/gcr.h
@@ -48,6 +48,7 @@
#include "gcr-key-widget.h"
#include "gcr-import-button.h"
#include "gcr-list-selector.h"
+#include "gcr-prompt-dialog.h"
#include "gcr-renderer.h"
#include "gcr-secure-entry-buffer.h"
#include "gcr-tree-selector.h"
diff --git a/gcr/gcr.symbols b/gcr/gcr.symbols
index 4119e4c..07128d0 100644
--- a/gcr/gcr.symbols
+++ b/gcr/gcr.symbols
@@ -63,6 +63,7 @@ gcr_list_selector_get_selected
gcr_list_selector_get_type
gcr_list_selector_new
gcr_list_selector_set_selected
+gcr_prompt_dialog_get_type
gcr_renderer_create
gcr_renderer_emit_data_changed
gcr_renderer_get_type
diff --git a/gcr/org.gnome.keyring.Prompt.xml b/gcr/org.gnome.keyring.Prompt.xml
index c29635b..1b76647 100644
--- a/gcr/org.gnome.keyring.Prompt.xml
+++ b/gcr/org.gnome.keyring.Prompt.xml
@@ -2,41 +2,5 @@
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
- <interface name="org.gnome.keyring.Prompter.Prompt">
- <property name="Title" type="s" access="readwrite"/>
- <property name="Message" type="s" access="readwrite"/>
-
- <property name="Description" type="s" access="readwrite"/>
-
- <property name="Warning" type="s" access="readwrite"/>
-
- <property name="PasswordNew" type="b" access="readwrite"/>
-
- <property name="PasswordStrength" type="i" access="read"/>
-
- <property name="ChoiceLabel" type="s" access="readwrite"/>
-
- <property name="ChoiceChosen" type="b" access="readwrite"/>
-
- <property name="CallerWindow" type="s" access="readwrite"/>
-
- <!--
- * In addition to PropertiesChanged, we send back changed
- * properties with the method response. To avoid race conditions
- -->
-
- <method name="RequestPassword">
- <arg name="properties" type="a(ssv)" direction="in"/>
- <arg name="input" type="s" direction="in"/>
- <arg name="changed" type="a(ssv)" direction="out"/>
- <arg name="output" type="s" direction="out"/>
- </method>
-
- <method name="RequestConfirm">
- <arg name="properties" type="a(ssv)" direction="in"/>
- <arg name="changed" type="a(ssv)" direction="out"/>
- <arg name="confirmed" type="b" direction="out"/>
- </method>
- </interface>
</node>
diff --git a/gcr/org.gnome.keyring.Prompter.xml b/gcr/org.gnome.keyring.Prompter.xml
index 8fdda02..189b0f6 100644
--- a/gcr/org.gnome.keyring.Prompter.xml
+++ b/gcr/org.gnome.keyring.Prompter.xml
@@ -1,15 +1,30 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
-<node name="/org/gnome/keyring/Prompter">
- <interface name="org.gnome.keyring.Prompter">
+<node>
+ <interface name="org.gnome.keyring.internal.Prompter">
<method name="BeginPrompting">
- <arg name="prompt" type="o" direction="out"/>
+ <arg name="callback" type="o" direction="in"/>
</method>
- <method name="FinishPrompting">
- <arg name="prompt" type="o" direction="in"/>
+ <method name="PerformPrompt">
+ <arg name="callback" type="o" direction="in"/>
+ <arg name="type" type="s" direction="in"/>
+ <arg name="properties" type="a{sv}" direction="in"/>
+ <arg name="exchange" type="s" direction="in"/>
+ </method>
+ <method name="StopPrompting">
+ <arg name="callback" type="o" direction="in"/>
+ </method>
+ </interface>
+
+ <!-- Called when ready to prompt or a prompt completes -->
+ <interface name="org.gnome.keyring.internal.Prompter.Callback">
+ <method name="PromptReady">
+ <arg name="reply" type="s" direction="in"/>
+ <arg name="properties" type="a{sv}" direction="in"/>
+ <arg name="exchange" type="s" direction="in"/>
+ </method>
+ <method name="PromptClose">
</method>
- <signal name="PrompterReady">
- </signal>
</interface>
</node>
diff --git a/gcr/tests/frob-system-prompt.c b/gcr/tests/frob-system-prompt.c
index ef01139..6834c56 100644
--- a/gcr/tests/frob-system-prompt.c
+++ b/gcr/tests/frob-system-prompt.c
@@ -49,15 +49,15 @@ on_prompt_clicked (GtkToolButton *button,
return;
}
- gcr_system_prompt_set_title (prompt, "This is the title");
- gcr_system_prompt_set_message (prompt, "This is the message");
- gcr_system_prompt_set_description (prompt, "This is the description");
+ gcr_prompt_set_title (GCR_PROMPT (prompt), "This is the title");
+ gcr_prompt_set_message (GCR_PROMPT (prompt), "This is the message");
+ gcr_prompt_set_description (GCR_PROMPT (prompt), "This is the description");
caller_id = g_strdup_printf ("%lu", (gulong)GDK_WINDOW_XID (gtk_widget_get_window (parent)));
- gcr_system_prompt_set_caller_window (prompt, caller_id);
+ gcr_prompt_set_caller_window (GCR_PROMPT (prompt), caller_id);
g_free (caller_id);
- password = gcr_system_prompt_password (prompt, NULL, &error);
+ password = gcr_prompt_password_run (GCR_PROMPT (prompt), NULL, &error);
if (error != NULL) {
g_warning ("couldn't prompt for password: %s", error->message);
g_error_free (error);
diff --git a/gcr/tests/test-system-prompt.c b/gcr/tests/test-system-prompt.c
index aec1ce6..bb6d841 100644
--- a/gcr/tests/test-system-prompt.c
+++ b/gcr/tests/test-system-prompt.c
@@ -48,6 +48,51 @@ teardown (Test *test,
}
static void
+test_open_prompt (Test *test,
+ gconstpointer unused)
+{
+ GcrSystemPrompt *prompt;
+ GError *error = NULL;
+ gboolean ret;
+ gchar *bus_name;
+
+ prompt = gcr_system_prompt_open_for_prompter (test->prompter_name, 0, NULL, &error);
+ g_assert_no_error (error);
+ g_assert (GCR_IS_SYSTEM_PROMPT (prompt));
+
+ g_object_get (prompt, "bus-name", &bus_name, NULL);
+ g_assert_cmpstr (bus_name, ==, test->prompter_name);
+
+ ret = gcr_system_prompt_close (prompt, NULL, &error);
+ g_assert_no_error (error);
+ g_assert (ret == TRUE);
+
+ g_free (bus_name);
+ g_object_unref (prompt);
+}
+
+static void
+test_open_failure (Test *test,
+ gconstpointer unused)
+{
+ GcrSystemPrompt *prompt;
+ GDBusConnection *connection;
+ GError *error = NULL;
+
+ connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
+ g_assert_no_error (error);
+
+ /* Try to open a prompt where no prompter is running */
+
+ prompt = gcr_system_prompt_open_for_prompter (g_dbus_connection_get_unique_name (connection),
+ 0, NULL, &error);
+ g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD);
+ g_assert (prompt == NULL);
+
+ g_object_unref (connection);
+}
+
+static void
test_prompt_password (Test *test,
gconstpointer unused)
{
@@ -61,12 +106,12 @@ test_prompt_password (Test *test,
g_assert_no_error (error);
g_assert (GCR_IS_SYSTEM_PROMPT (prompt));
- password = gcr_system_prompt_password (prompt, NULL, &error);
+ password = gcr_prompt_password_run (GCR_PROMPT (prompt), NULL, &error);
g_assert_no_error (error);
g_assert_cmpstr (password, ==, "booo");
g_object_unref (prompt);
- g_assert (!G_IS_OBJECT (prompt));
+ egg_assert_not_object (prompt);
}
static void
@@ -83,7 +128,7 @@ test_password_in_exchange (Test *test,
g_assert_no_error (error);
g_assert (GCR_IS_SYSTEM_PROMPT (prompt));
- gcr_system_prompt_password (prompt, NULL, &error);
+ gcr_prompt_password_run (GCR_PROMPT (prompt), NULL, &error);
g_assert_no_error (error);
g_object_get (prompt, "secret-exchange", &exchange, NULL);
@@ -92,7 +137,39 @@ test_password_in_exchange (Test *test,
g_object_unref (exchange);
g_object_unref (prompt);
- g_assert (!G_IS_OBJECT (prompt));
+ egg_assert_not_object (prompt);
+}
+
+static void
+test_password_custom_exchange (Test *test,
+ gconstpointer unused)
+{
+ GcrSystemPrompt *prompt;
+ GError *error = NULL;
+ GcrSecretExchange *exchange;
+ const gchar *password;
+
+ exchange = gcr_secret_exchange_new (NULL);
+ gcr_mock_prompter_expect_password_ok ("booo", NULL);
+
+ prompt = g_initable_new (GCR_TYPE_SYSTEM_PROMPT, NULL, &error,
+ "timeout-seconds", 0,
+ "bus-name", test->prompter_name,
+ "secret-exchange", exchange,
+ NULL);
+ g_assert_no_error (error);
+ g_assert (GCR_IS_SYSTEM_PROMPT (prompt));
+
+ password = gcr_prompt_password_run (GCR_PROMPT (prompt), NULL, &error);
+ g_assert_cmpstr (password, ==, "booo");
+ g_assert_no_error (error);
+
+ password = gcr_secret_exchange_get_secret (exchange, NULL);
+ g_assert_cmpstr (password, ==, "booo");
+
+ g_object_unref (exchange);
+ g_object_unref (prompt);
+ egg_assert_not_object (prompt);
}
static void
@@ -127,12 +204,12 @@ test_async_password (Test *test,
g_assert (GCR_IS_SYSTEM_PROMPT (prompt));
g_clear_object (&result);
- gcr_system_prompt_password_async (prompt, NULL,
- on_async_result, &result);
+ gcr_prompt_password_async (GCR_PROMPT (prompt), NULL,
+ on_async_result, &result);
g_assert (result == NULL);
egg_test_wait ();
- password = gcr_system_prompt_password_finish (prompt, result, &error);
+ password = gcr_prompt_password_finish (GCR_PROMPT (prompt), result, &error);
g_assert_no_error (error);
g_assert_cmpstr (password, ==, "booo");
g_clear_object (&result);
@@ -154,12 +231,12 @@ test_prompt_confirm (Test *test,
g_assert_no_error (error);
g_assert (GCR_IS_SYSTEM_PROMPT (prompt));
- ret = gcr_system_prompt_confirm (prompt, NULL, &error);
+ ret = gcr_prompt_confirm_run (GCR_PROMPT (prompt), NULL, &error);
g_assert_no_error (error);
g_assert (ret == TRUE);
g_object_unref (prompt);
- g_assert (!G_IS_OBJECT (prompt));
+ egg_assert_not_object (prompt);
}
static void
@@ -184,18 +261,18 @@ test_async_confirm (Test *test,
g_assert (GCR_IS_SYSTEM_PROMPT (prompt));
g_clear_object (&result);
- gcr_system_prompt_confirm_async (prompt, NULL,
- on_async_result, &result);
+ gcr_prompt_confirm_async (GCR_PROMPT (prompt), NULL,
+ on_async_result, &result);
g_assert (result == NULL);
egg_test_wait ();
- confirm = gcr_system_prompt_confirm_finish (prompt, result, &error);
+ confirm = gcr_prompt_confirm_finish (GCR_PROMPT (prompt), result, &error);
g_assert_no_error (error);
g_assert (confirm == TRUE);
g_clear_object (&result);
g_object_unref (prompt);
- g_assert (!G_IS_OBJECT (prompt));
+ egg_assert_not_object (prompt);
}
static void
@@ -212,12 +289,12 @@ test_cancel_password (Test *test,
g_assert_no_error (error);
g_assert (GCR_IS_SYSTEM_PROMPT (prompt));
- password = gcr_system_prompt_password (prompt, NULL, &error);
+ password = gcr_prompt_password_run (GCR_PROMPT (prompt), NULL, &error);
g_assert_no_error (error);
g_assert_cmpstr (password, ==, NULL);
g_object_unref (prompt);
- g_assert (!G_IS_OBJECT (prompt));
+ egg_assert_not_object (prompt);
}
static void
@@ -234,19 +311,20 @@ test_cancel_confirm (Test *test,
g_assert_no_error (error);
g_assert (GCR_IS_SYSTEM_PROMPT (prompt));
- ret = gcr_system_prompt_confirm (prompt, NULL, &error);
+ ret = gcr_prompt_confirm_run (GCR_PROMPT (prompt), NULL, &error);
g_assert_no_error (error);
g_assert (ret == FALSE);
g_object_unref (prompt);
- g_assert (!G_IS_OBJECT (prompt));
+ egg_assert_not_object (prompt);
}
static void
test_prompt_properties (Test *test,
gconstpointer unused)
{
- GcrSystemPrompt *prompt;
+ GcrSystemPrompt *sprompt;
+ GcrPrompt *prompt;
GError *error = NULL;
gboolean ret;
@@ -258,13 +336,14 @@ test_prompt_properties (Test *test,
"choice-label", "My Choice",
"choice-chosen", TRUE,
"password-new", TRUE,
- "password-strength", 2,
+ "password-strength", 0,
NULL);
- prompt = gcr_system_prompt_open_for_prompter (test->prompter_name, 0, NULL, &error);
+ sprompt = gcr_system_prompt_open_for_prompter (test->prompter_name, 0, NULL, &error);
g_assert_no_error (error);
- g_assert (GCR_IS_SYSTEM_PROMPT (prompt));
+ g_assert (GCR_IS_SYSTEM_PROMPT (sprompt));
+ prompt = GCR_PROMPT (sprompt);
g_object_set (prompt,
"title", "Other Title",
"choice-label", "Other Choice",
@@ -276,33 +355,60 @@ test_prompt_properties (Test *test,
"choice-chosen", TRUE,
NULL);
- g_assert_cmpstr (gcr_system_prompt_get_title (prompt), ==, "Other Title");
- g_assert_cmpstr (gcr_system_prompt_get_choice_label (prompt), ==, "Other Choice");
- g_assert_cmpstr (gcr_system_prompt_get_description (prompt), ==, "Other Description");
- g_assert_cmpstr (gcr_system_prompt_get_message (prompt), ==, "Other Message");
- g_assert_cmpstr (gcr_system_prompt_get_caller_window (prompt), ==, "01012");
- g_assert_cmpstr (gcr_system_prompt_get_warning (prompt), ==, "Other Warning");
- g_assert (gcr_system_prompt_get_password_new (prompt) == FALSE);
- g_assert (gcr_system_prompt_get_choice_chosen (prompt) == TRUE);
-
- gcr_system_prompt_set_title (prompt, "My Title");
- gcr_system_prompt_set_choice_label (prompt, "My Choice");
- gcr_system_prompt_set_description (prompt, "My Description");
- gcr_system_prompt_set_message (prompt, "My Message");
- gcr_system_prompt_set_caller_window (prompt, "01010");
- gcr_system_prompt_set_warning (prompt, "My Warning");
- gcr_system_prompt_set_password_new (prompt, TRUE);
- gcr_system_prompt_set_choice_chosen (prompt, FALSE);
-
- ret = gcr_system_prompt_confirm (prompt, NULL, &error);
+ g_assert_cmpstr (gcr_prompt_get_title (prompt), ==, "Other Title");
+ g_assert_cmpstr (gcr_prompt_get_choice_label (prompt), ==, "Other Choice");
+ g_assert_cmpstr (gcr_prompt_get_description (prompt), ==, "Other Description");
+ g_assert_cmpstr (gcr_prompt_get_message (prompt), ==, "Other Message");
+ g_assert_cmpstr (gcr_prompt_get_caller_window (prompt), ==, "01012");
+ g_assert_cmpstr (gcr_prompt_get_warning (prompt), ==, "Other Warning");
+ g_assert (gcr_prompt_get_password_new (prompt) == FALSE);
+ g_assert (gcr_prompt_get_choice_chosen (prompt) == TRUE);
+
+ gcr_prompt_set_title (prompt, "My Title");
+ gcr_prompt_set_choice_label (prompt, "My Choice");
+ gcr_prompt_set_description (prompt, "My Description");
+ gcr_prompt_set_message (prompt, "My Message");
+ gcr_prompt_set_caller_window (prompt, "01010");
+ gcr_prompt_set_warning (prompt, "My Warning");
+ gcr_prompt_set_password_new (prompt, TRUE);
+ gcr_prompt_set_choice_chosen (prompt, TRUE);
+
+ ret = gcr_prompt_confirm_run (prompt, NULL, &error);
g_assert_no_error (error);
g_assert (ret == TRUE);
- g_assert (gcr_system_prompt_get_choice_chosen (prompt) == TRUE);
- g_assert_cmpint (gcr_system_prompt_get_password_strength (prompt), ==, 2);
+ g_assert (gcr_prompt_get_choice_chosen (prompt) == TRUE);
+ g_assert_cmpint (gcr_prompt_get_password_strength (prompt), ==, 0);
g_object_unref (prompt);
- g_assert (!G_IS_OBJECT (prompt));
+ egg_assert_not_object (prompt);
+}
+
+static void
+test_prompt_properties_unset (Test *test,
+ gconstpointer unused)
+{
+ GcrSystemPrompt *sprompt;
+ GcrPrompt *prompt;
+ GError *error = NULL;
+
+ sprompt = gcr_system_prompt_open_for_prompter (test->prompter_name, 0, NULL, &error);
+ g_assert_no_error (error);
+ g_assert (GCR_IS_SYSTEM_PROMPT (sprompt));
+ prompt = GCR_PROMPT (sprompt);
+
+ g_assert_cmpstr (gcr_prompt_get_title (prompt), ==, NULL);
+ g_assert_cmpstr (gcr_prompt_get_choice_label (prompt), ==, NULL);
+ g_assert_cmpstr (gcr_prompt_get_description (prompt), ==, NULL);
+ g_assert_cmpstr (gcr_prompt_get_message (prompt), ==, NULL);
+ g_assert_cmpstr (gcr_prompt_get_caller_window (prompt), ==, NULL);
+ g_assert_cmpstr (gcr_prompt_get_warning (prompt), ==, NULL);
+ g_assert (gcr_prompt_get_password_new (prompt) == FALSE);
+ g_assert (gcr_prompt_get_choice_chosen (prompt) == FALSE);
+ g_assert_cmpint (gcr_prompt_get_password_strength (prompt), ==, 0);
+
+ g_object_unref (prompt);
+ egg_assert_not_object (prompt);
}
static void
@@ -312,39 +418,32 @@ test_prompt_close (Test *test,
GcrSystemPrompt *prompt;
GcrSystemPrompt *prompt2;
GError *error = NULL;
- gboolean showing;
gboolean ret;
gcr_mock_prompter_expect_confirm_ok (NULL);
- prompt = gcr_system_prompt_open_for_prompter (test->prompter_name, 0, NULL, &error);
+ prompt = gcr_system_prompt_open_for_prompter (test->prompter_name, 1, NULL, &error);
g_assert_no_error (error);
g_assert (GCR_IS_SYSTEM_PROMPT (prompt));
- prompt2 = gcr_system_prompt_open_for_prompter (test->prompter_name, 0, NULL, &error);
+ prompt2 = gcr_system_prompt_open_for_prompter (test->prompter_name, 1, NULL, &error);
g_assert_error (error, GCR_SYSTEM_PROMPT_ERROR, GCR_SYSTEM_PROMPT_IN_PROGRESS);
g_clear_error (&error);
g_assert (prompt2 == NULL);
- ret = gcr_system_prompt_confirm (prompt, NULL, &error);
+ ret = gcr_prompt_confirm_run (GCR_PROMPT (prompt), NULL, &error);
g_assert_no_error (error);
g_assert (ret == TRUE);
- prompt2 = gcr_system_prompt_open_for_prompter (test->prompter_name, 0, NULL, &error);
+ prompt2 = gcr_system_prompt_open_for_prompter (test->prompter_name, 1, NULL, &error);
g_assert_error (error, GCR_SYSTEM_PROMPT_ERROR, GCR_SYSTEM_PROMPT_IN_PROGRESS);
g_clear_error (&error);
g_assert (prompt2 == NULL);
- showing = gcr_mock_prompter_get_showing ();
- g_assert (showing == TRUE);
-
gcr_system_prompt_close (prompt, NULL, &error);
g_assert_no_error (error);
- showing = gcr_mock_prompter_get_showing ();
- g_assert (showing == FALSE);
-
- prompt2 = gcr_system_prompt_open_for_prompter (test->prompter_name, 0, NULL, &error);
+ prompt2 = gcr_system_prompt_open_for_prompter (test->prompter_name, 1, NULL, &error);
g_assert_no_error (error);
g_assert (GCR_IS_SYSTEM_PROMPT (prompt2));
@@ -352,12 +451,12 @@ test_prompt_close (Test *test,
g_assert (!G_IS_OBJECT (prompt));
g_object_unref (prompt2);
- g_assert (!G_IS_OBJECT (prompt2));
+ egg_assert_not_object (prompt);
}
static void
-test_finish_cancels (Test *test,
- gconstpointer unused)
+test_close_cancels (Test *test,
+ gconstpointer unused)
{
GcrSystemPrompt *prompt;
GError *error = NULL;
@@ -371,20 +470,20 @@ test_finish_cancels (Test *test,
g_assert_no_error (error);
g_assert (GCR_IS_SYSTEM_PROMPT (prompt));
- gcr_system_prompt_password_async (prompt, NULL, on_async_result, &result);
+ gcr_prompt_password_async (GCR_PROMPT (prompt), NULL, on_async_result, &result);
gcr_system_prompt_close (prompt, NULL, &error);
g_assert_no_error (error);
egg_test_wait ();
- password = gcr_system_prompt_password_finish (prompt, result, &error);
+ password = gcr_prompt_password_finish (GCR_PROMPT (prompt), result, &error);
g_assert_no_error (error);
g_assert (password == NULL);
g_clear_object (&result);
g_object_unref (prompt);
- g_assert (!G_IS_OBJECT (prompt));
+ egg_assert_not_object (prompt);
}
int
@@ -394,16 +493,20 @@ main (int argc, char **argv)
g_test_init (&argc, &argv, NULL);
g_set_prgname ("test-system-prompt");
+ g_test_add ("/gcr/system-prompt/open", Test, NULL, setup, test_open_prompt, teardown);
+ g_test_add ("/gcr/system-prompt/open-failure", Test, NULL, setup, test_open_failure, teardown);
g_test_add ("/gcr/system-prompt/password", Test, NULL, setup, test_prompt_password, teardown);
g_test_add ("/gcr/system-prompt/password-async", Test, NULL, setup, test_async_password, teardown);
g_test_add ("/gcr/system-prompt/password-cancel", Test, NULL, setup, test_cancel_password, teardown);
g_test_add ("/gcr/system-prompt/password-in-exchange", Test, NULL, setup, test_password_in_exchange, teardown);
+ g_test_add ("/gcr/system-prompt/password-custom-exchange", Test, NULL, setup, test_password_custom_exchange, teardown);
g_test_add ("/gcr/system-prompt/confirm", Test, NULL, setup, test_prompt_confirm, teardown);
g_test_add ("/gcr/system-prompt/confirm-async", Test, NULL, setup, test_async_confirm, teardown);
g_test_add ("/gcr/system-prompt/confirm-cancel", Test, NULL, setup, test_cancel_confirm, teardown);
g_test_add ("/gcr/system-prompt/properties", Test, NULL, setup, test_prompt_properties, teardown);
+ g_test_add ("/gcr/system-prompt/properties-unset", Test, NULL, setup, test_prompt_properties_unset, teardown);
g_test_add ("/gcr/system-prompt/close", Test, NULL, setup, test_prompt_close, teardown);
- g_test_add ("/gcr/system-prompt/finish-cancel", Test, NULL, setup, test_finish_cancels, teardown);
+ g_test_add ("/gcr/system-prompt/close-cancels", Test, NULL, setup, test_close_cancels, teardown);
return egg_tests_run_with_loop ();
}
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 29609a8..ec60cdd 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -25,7 +25,9 @@ gcr/gcr-parser.c
gcr/gcr-pkcs11-import-dialog.c
[type: gettext/glade]gcr/gcr-pkcs11-import-dialog.ui
gcr/gcr-pkcs11-import-interaction.c
+gcr/gcr-prompt-dialog.c
gcr/gcr-subject-public-key.c
+gcr/gcr-system-prompt.c
gcr/gcr-trust.c
[type: gettext/glade]gcr/gcr-unlock-options-widget.ui
gcr/gcr-unlock-renderer.c
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]