diff options
author | Stef Walter <stefw@collabora.co.uk> | 2011-10-31 17:43:54 +0100 |
---|---|---|
committer | Stef Walter <stefw@collabora.co.uk> | 2011-12-13 21:45:09 +0100 |
commit | cf51303c1b38857d3aa04cece982d6e8e58fea5a (patch) | |
tree | 260d2fc3ebba66e7dc533c68b777a5877c8833d9 | |
parent | 4edd77e47f1f6ee6ed138a4d3f4f06cd5896cafa (diff) |
gcr: Make prompter tests work properly, add debugging
* Run mock prompter in a separate thread to fix blocking
and concurrency issues.
* Run tests in in the main process thread
* Add more debugging output
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | egg/egg-error.h | 10 | ||||
-rw-r--r-- | egg/egg-testing.c | 85 | ||||
-rw-r--r-- | egg/egg-testing.h | 2 | ||||
-rw-r--r-- | gcr/gcr-mock-prompter.c | 332 | ||||
-rw-r--r-- | gcr/gcr-mock-prompter.h | 22 | ||||
-rw-r--r-- | gcr/gcr-system-prompt.c | 195 | ||||
-rw-r--r-- | gcr/gcr-system-prompt.h | 16 | ||||
-rw-r--r-- | gcr/gcr-system-prompter.c | 72 | ||||
-rw-r--r-- | gcr/gcr-system-prompter.h | 4 | ||||
-rw-r--r-- | gcr/tests/frob-system-prompt.c | 106 | ||||
-rw-r--r-- | gcr/tests/test-system-prompt.c | 409 |
12 files changed, 1161 insertions, 94 deletions
@@ -83,9 +83,11 @@ stamp-* /gck/gck-marshal.* /gcr/*.pc +/gcr/gcr-dbus-generated.* /gcr/gcr-enum-types* /gcr/gcr-oids.* /gcr/gcr-marshal.* +/gcr/gcr-prompter /gcr/gcr-viewer /gcr/gcr-viewer.desktop diff --git a/egg/egg-error.h b/egg/egg-error.h index 50f459c..9e7b74e 100644 --- a/egg/egg-error.h +++ b/egg/egg-error.h @@ -24,11 +24,19 @@ #include <glib.h> -static inline const gchar* +static inline const gchar * egg_error_message (GError *error) { g_return_val_if_fail (error, "(unknown)"); return error->message ? error->message : "(null)"; } +static inline const gchar * +egg_error_result_message (GError **error) +{ + if (error == NULL) + return "(unknown)"; + return (*error) && (*error)->message ? (*error)->message : "(null)"; +} + #endif /* EGG_ERROR_H_ */ diff --git a/egg/egg-testing.c b/egg/egg-testing.c index 88d647d..e220fbd 100644 --- a/egg/egg-testing.c +++ b/egg/egg-testing.c @@ -105,6 +105,9 @@ egg_assertion_message_cmpmem (const char *domain, g_free (s); } +static void (*wait_stop_impl) (void); +static gboolean (*wait_until_impl) (int timeout); + void egg_assertion_not_object (const char *domain, const char *file, @@ -131,6 +134,20 @@ egg_assertion_not_object (const char *domain, void egg_test_wait_stop (void) { + g_assert (wait_stop_impl != NULL); + (wait_stop_impl) (); +} + +gboolean +egg_test_wait_until (int timeout) +{ + g_assert (wait_until_impl != NULL); + return (wait_until_impl) (timeout); +} + +static void +thread_wait_stop (void) +{ GTimeVal tv; g_get_current_time (&tv); @@ -146,8 +163,8 @@ egg_test_wait_stop (void) g_mutex_unlock (wait_mutex); } -gboolean -egg_test_wait_until (int timeout) +static gboolean +thread_wait_until (int timeout) { GTimeVal tv; gboolean ret; @@ -169,11 +186,70 @@ egg_test_wait_until (int timeout) return ret; } +static GMainLoop *wait_loop = NULL; + +static void +loop_wait_stop (void) +{ + g_assert (wait_loop != NULL); + g_main_loop_quit (wait_loop); +} + +static gboolean +on_loop_wait_timeout (gpointer data) +{ + gboolean *timed_out = data; + *timed_out = TRUE; + + g_assert (wait_loop != NULL); + g_main_loop_quit (wait_loop); + + return TRUE; /* we remove this source later */ +} + +static gboolean +loop_wait_until (int timeout) +{ + gboolean ret = FALSE; + gboolean timed_out = FALSE; + guint source; + + g_assert (wait_loop == NULL); + wait_loop = g_main_loop_new (g_main_context_get_thread_default (), FALSE); + + source = g_timeout_add (timeout, on_loop_wait_timeout, &timed_out); + + g_main_loop_run (wait_loop); + + if (timed_out) { + g_source_remove (source); + ret = FALSE; + } else { + ret = TRUE; + } + + g_main_loop_unref (wait_loop); + wait_loop = NULL; + return ret; + + g_assert (wait_loop != NULL); + g_main_loop_quit (wait_loop); +} + static gpointer testing_thread (gpointer loop) { - /* Must have been defined by the test including this file */ - gint ret = g_test_run (); + gint ret; + + wait_stop_impl = thread_wait_stop; + wait_until_impl = thread_wait_until; + + ret = g_test_run (); + + wait_stop_impl = NULL; + wait_until_impl = NULL; + + /* Quit the main loop now that tests are done */ g_main_loop_quit (loop); return GINT_TO_POINTER (ret); } @@ -205,6 +281,7 @@ egg_tests_run_with_loop (void) return GPOINTER_TO_INT (ret); } +<<<<<<< HEAD #endif diff --git a/egg/egg-testing.h b/egg/egg-testing.h index a15925a..0995e4d 100644 --- a/egg/egg-testing.h +++ b/egg/egg-testing.h @@ -73,4 +73,6 @@ gboolean egg_test_wait_until (int timeout); gint egg_tests_run_with_loop (void); +gint egg_tests_run_with_loop (void); + #endif /* EGG_DH_H_ */ diff --git a/gcr/gcr-mock-prompter.c b/gcr/gcr-mock-prompter.c index 412c101..836ef35 100644 --- a/gcr/gcr-mock-prompter.c +++ b/gcr/gcr-mock-prompter.c @@ -51,34 +51,62 @@ * The class for #GcrMockPrompter. */ + +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)) +typedef struct _GcrMockPrompter GcrMockPrompter; typedef struct _GcrMockPrompterClass GcrMockPrompterClass; typedef struct _GcrMockPrompterPrivate GcrMockPrompterPrivate; enum { PROP_0, PROP_CONNECTION, + PROP_SHOWING, + PROP_DELAY_MSEC }; -typedef struct { - gboolean proceed; - gchar *password; - GList *properties; -} MockResponse; - struct _GcrMockPrompter { GcrSystemPrompter parent; GDBusConnection *connection; GQueue *responses; + gboolean showing; + guint delay_msec; + guint delay_source; }; struct _GcrMockPrompterClass { GcrSystemPrompterClass parent_class; }; +typedef struct { + gboolean proceed; + gchar *password; + GList *properties; + + /* Used while responding */ + GcrMockPrompter *prompter; +} MockResponse; + +typedef struct { + /* Owned by the calling thread */ + GMutex *mutex; + GCond *start_cond; + GThread *thread; + + /* Owned by the prompter thread*/ + GcrMockPrompter *prompter; + const gchar *bus_name; + GMainLoop *loop; +} ThreadData; + +static ThreadData *running = NULL; + G_DEFINE_TYPE (GcrMockPrompter, gcr_mock_prompter, GCR_TYPE_SYSTEM_PROMPTER); static void @@ -95,6 +123,8 @@ mock_response_free (gpointer data) MockResponse *response = data; g_free (response->password); g_list_free_full (response->properties, mock_property_free); + g_clear_object (&response->prompter); + g_free (response); } static void @@ -115,6 +145,9 @@ gcr_mock_prompter_set_property (GObject *obj, case PROP_CONNECTION: self->connection = g_value_get_object (value); break; + case PROP_DELAY_MSEC: + self->delay_msec = g_value_get_uint (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); break; @@ -133,6 +166,12 @@ gcr_mock_prompter_get_property (GObject *obj, 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); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); break; @@ -146,6 +185,11 @@ gcr_mock_prompter_dispose (GObject *obj) GcrMockPrompter *self = GCR_MOCK_PROMPTER (obj); MockResponse *response; + 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), @@ -251,6 +295,42 @@ prompter_set_properties (GcrMockPrompter *self, } } +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) +{ + GcrMockPrompter *self = GCR_MOCK_PROMPTER (prompter); + + if (self->delay_source != 0) { + g_source_remove (self->delay_source); + self->delay_source = 0; + } + + self->showing = FALSE; +} + +static gboolean +on_timeout_prompt_confirm (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); + + return FALSE; +} + static gboolean gcr_mock_prompter_prompt_confirm (GcrSystemPrompter *prompter) { @@ -268,14 +348,35 @@ gcr_mock_prompter_prompt_confirm (GcrSystemPrompter *prompter) } prompter_set_properties (self, response->properties); + response->prompter = g_object_ref (prompter); + + if (self->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); + } else { + on_timeout_prompt_confirm (response); + mock_response_free (response); + } + + return TRUE; +} + +static gboolean +on_timeout_prompt_password (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 (GCR_SYSTEM_PROMPTER (self)); + gcr_system_prompter_respond_cancelled (prompter); else - gcr_system_prompter_respond_confirmed (GCR_SYSTEM_PROMPTER (self)); + gcr_system_prompter_respond_with_password (prompter, response->password); - mock_response_free (response); - return TRUE; + return FALSE; } static gboolean @@ -296,13 +397,18 @@ gcr_mock_prompter_prompt_password (GcrSystemPrompter *prompter) } prompter_set_properties (self, response->properties); + response->prompter = g_object_ref (prompter); + + if (self->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); + } else { + on_timeout_prompt_password (response); + mock_response_free (response); + } - if (!response->proceed) - gcr_system_prompter_respond_cancelled (GCR_SYSTEM_PROMPTER (self)); - else - gcr_system_prompter_respond_with_password (GCR_SYSTEM_PROMPTER (self), response->password); - - mock_response_free (response); return TRUE; } @@ -317,12 +423,22 @@ gcr_mock_prompter_class_init (GcrMockPrompterClass *klass) 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; 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)); + + 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 GList * @@ -375,82 +491,224 @@ build_properties (GcrMockPrompter *self, return result; } +gboolean +gcr_mock_prompter_get_showing (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; +} + +guint +gcr_mock_prompter_get_delay_msec (void) +{ + guint delay_msec; + + g_assert (running != NULL); + g_mutex_lock (running->mutex); + g_object_get (running->prompter, "delay-msec", &delay_msec, NULL); + g_mutex_unlock (running->mutex); + + return delay_msec; +} + +void +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); + g_mutex_unlock (running->mutex); +} + void -gcr_mock_prompter_expect_confirm_ok (GcrMockPrompter *self, - const gchar *first_property_name, +gcr_mock_prompter_expect_confirm_ok (const gchar *first_property_name, ...) { MockResponse *response; va_list var_args; - g_return_if_fail (GCR_IS_MOCK_PROMPTER (self)); + g_assert (running != NULL); + + g_mutex_lock (running->mutex); response = g_new0 (MockResponse, 1); response->password = NULL; response->proceed = TRUE; va_start (var_args, first_property_name); - response->properties = build_properties (self, first_property_name, var_args); + response->properties = build_properties (running->prompter, first_property_name, var_args); va_end (var_args); - g_queue_push_tail (self->responses, response); + g_queue_push_tail (running->prompter->responses, response); + g_mutex_unlock (running->mutex); } void -gcr_mock_prompter_expect_confirm_cancel (GcrMockPrompter *self) +gcr_mock_prompter_expect_confirm_cancel (void) { MockResponse *response; - g_return_if_fail (GCR_IS_MOCK_PROMPTER (self)); + g_assert (running != NULL); + + g_mutex_lock (running->mutex); response = g_new0 (MockResponse, 1); response->password = NULL; response->proceed = FALSE; - g_queue_push_tail (self->responses, response); + g_queue_push_tail (running->prompter->responses, response); + g_mutex_unlock (running->mutex); } void -gcr_mock_prompter_expect_password_ok (GcrMockPrompter *self, - const gchar *password, +gcr_mock_prompter_expect_password_ok (const gchar *password, const gchar *first_property_name, ...) { MockResponse *response; va_list var_args; - g_return_if_fail (GCR_IS_MOCK_PROMPTER (self)); - g_return_if_fail (password != NULL); + g_assert (running != NULL); + g_assert (password != NULL); + + g_mutex_lock (running->mutex); response = g_new0 (MockResponse, 1); response->password = g_strdup (password); response->proceed = TRUE; va_start (var_args, first_property_name); - response->properties = build_properties (self, first_property_name, var_args); + response->properties = build_properties (running->prompter, first_property_name, var_args); va_end (var_args); - g_queue_push_tail (self->responses, response); + g_queue_push_tail (running->prompter->responses, response); + + g_mutex_unlock (running->mutex); } void -gcr_mock_prompter_expect_password_cancel (GcrMockPrompter *self) +gcr_mock_prompter_expect_password_cancel (void) { MockResponse *response; - g_return_if_fail (GCR_IS_MOCK_PROMPTER (self)); + g_assert (running != NULL); + + g_mutex_lock (running->mutex); response = g_new0 (MockResponse, 1); response->password = g_strdup (""); response->proceed = FALSE; - g_queue_push_tail (self->responses, response); + g_queue_push_tail (running->prompter->responses, response); + + g_mutex_unlock (running->mutex); +} + +static gpointer +mock_prompter_thread (gpointer data) +{ + ThreadData *thread_data = data; + GDBusConnection *connection; + GMainContext *context; + GError *error = NULL; + 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); + + address = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SESSION, NULL, &error); + if (error == NULL) { + connection = g_dbus_connection_new_for_address_sync (address, + G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT | + G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION, + NULL, NULL, &error); + if (error == NULL) { + gcr_system_prompter_register (GCR_SYSTEM_PROMPTER (thread_data->prompter), + connection); + thread_data->bus_name = g_dbus_connection_get_unique_name (connection); + } + + g_free (address); + } + + if (error != NULL) { + g_critical ("mock prompter couldn't get session bus address: %s", + egg_error_message (error)); + g_clear_error (&error); + } + + thread_data->loop = g_main_loop_new (context, FALSE); + g_cond_signal (thread_data->start_cond); + g_mutex_unlock (thread_data->mutex); + + 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); + } + + g_mutex_unlock (thread_data->mutex); + return thread_data; } -GcrMockPrompter * -gcr_mock_prompter_new () +const gchar * +gcr_mock_prompter_start (void) { - return g_object_new (GCR_TYPE_MOCK_PROMPTER, - NULL); + GError *error = NULL; + + g_assert (running == NULL); + + running = g_new0 (ThreadData, 1); + running->mutex = g_mutex_new (); + running->start_cond = g_cond_new (); + + g_mutex_lock (running->mutex); + running->thread = g_thread_create (mock_prompter_thread, running, TRUE, &error); + + if (error != NULL) + g_error ("mock prompter couldn't start thread: %s", error->message); + + g_cond_wait (running->start_cond, running->mutex); + g_assert (running->loop); + g_assert (running->prompter); + g_mutex_unlock (running->mutex); + + return running->bus_name; +} + +void +gcr_mock_prompter_stop (void) +{ + ThreadData *check; + + g_assert (running != NULL); + + g_mutex_lock (running->mutex); + g_assert (running->loop != NULL); + g_main_loop_quit (running->loop); + g_mutex_unlock (running->mutex); + + check = g_thread_join (running->thread); + g_assert (check == running); + + g_cond_free (running->start_cond); + g_mutex_free (running->mutex); + g_free (running); + running = NULL; } diff --git a/gcr/gcr-mock-prompter.h b/gcr/gcr-mock-prompter.h index 4b5f302..f2068ec 100644 --- a/gcr/gcr-mock-prompter.h +++ b/gcr/gcr-mock-prompter.h @@ -34,28 +34,26 @@ G_BEGIN_DECLS -#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)) +const gchar * gcr_mock_prompter_start (void); -typedef struct _GcrMockPrompter GcrMockPrompter; +void gcr_mock_prompter_stop (void); -GType gcr_mock_prompter_get_type (void) G_GNUC_CONST; +gboolean gcr_mock_prompter_get_showing (void); -GcrMockPrompter * gcr_mock_prompter_new (void); +guint gcr_mock_prompter_get_delay_msec (void); -void gcr_mock_prompter_expect_confirm_ok (GcrMockPrompter *self, - const gchar *property_name, +void gcr_mock_prompter_set_delay_msec (guint delay_msec); + +void gcr_mock_prompter_expect_confirm_ok (const gchar *property_name, ...); -void gcr_mock_prompter_expect_confirm_cancel (GcrMockPrompter *self); +void gcr_mock_prompter_expect_confirm_cancel (void); -void gcr_mock_prompter_expect_password_ok (GcrMockPrompter *self, - const gchar *password, +void gcr_mock_prompter_expect_password_ok (const gchar *password, const gchar *property_name, ...); -void gcr_mock_prompter_expect_password_cancel (GcrMockPrompter *self); +void gcr_mock_prompter_expect_password_cancel (void); G_END_DECLS diff --git a/gcr/gcr-system-prompt.c b/gcr/gcr-system-prompt.c index 5caac14..43868d7 100644 --- a/gcr/gcr-system-prompt.c +++ b/gcr/gcr-system-prompt.c @@ -25,11 +25,15 @@ #include "gcr-dbus-constants.h" #include "gcr-dbus-generated.h" +#define DEBUG_FLAG GCR_DEBUG_PROMPT +#include "gcr-debug.h" #include "gcr-internal.h" #include "gcr-library.h" #include "gcr-secret-exchange.h" #include "gcr-system-prompt.h" +#include "egg/egg-error.h" + /** * SECTION:gcr-system-prompt * @title: GcrSystemPrompt @@ -205,12 +209,14 @@ 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); + 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 ("()"), + 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); @@ -315,8 +321,10 @@ gcr_system_prompt_get_secret_exchange (GcrSystemPrompt *self) { g_return_val_if_fail (GCR_IS_SYSTEM_PROMPT (self), NULL); - if (!self->pv->exchange) + if (!self->pv->exchange) { + _gcr_debug ("creating new secret exchange"); self->pv->exchange = gcr_secret_exchange_new (NULL); + } return self->pv->exchange; } @@ -554,10 +562,16 @@ gcr_system_prompt_real_init (GInitable *initable, /* 1. Connect to the session bus */ if (!self->pv->connection) { + self->pv->connection = g_bus_get_sync (G_BUS_TYPE_SESSION, cancellable, error); - if (self->pv->connection == NULL) + if (self->pv->connection == NULL) { + _gcr_debug ("failed to connect to bus: %s", + egg_error_result_message (error)); return FALSE; + } + + _gcr_debug ("connected to bus"); } /* 2. Tell the prompter we want to begin prompting */ @@ -573,13 +587,18 @@ gcr_system_prompt_real_init (GInitable *initable, G_VARIANT_TYPE ("(o)"), G_DBUS_CALL_FLAGS_NONE, -1, cancellable, error); - if (ret == NULL) + if (ret == NULL) { + _gcr_debug ("failed to open prompt: %s", + egg_error_result_message (error)); return FALSE; + } 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", self->pv->prompt_path); } /* 3. Create a dbus proxy */ @@ -591,10 +610,14 @@ gcr_system_prompt_real_init (GInitable *initable, self->pv->prompt_path, GCR_DBUS_PROMPT_INTERFACE, cancellable, error); - if (self->pv->prompt_proxy == NULL) + 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"); } return TRUE; @@ -633,9 +656,12 @@ on_bus_connected (GObject *source, if (error == NULL) { g_return_if_fail (self->pv->connection != NULL); + + _gcr_debug ("connected to bus"); 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); } @@ -662,10 +688,14 @@ on_prompter_begin_prompting (GObject *source, g_variant_get (ret, "(o)", &self->pv->prompt_path); g_variant_unref (ret); + _gcr_debug ("opened prompt: %s", 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", egg_error_message (error)); + g_simple_async_result_take_error (res, error); g_simple_async_result_complete (res); } @@ -687,11 +717,16 @@ on_prompt_proxy_new (GObject *source, 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); } else { + _gcr_debug ("failed to create prompt proxy: %s", egg_error_message (error)); + g_simple_async_result_take_error (res, error); + g_simple_async_result_complete (res); } g_object_unref (self); @@ -706,11 +741,13 @@ perform_init_async (GcrSystemPrompt *self, /* 1. Connect to the session bus */ if (!self->pv->connection) { + _gcr_debug ("connecting to bus"); 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"); g_dbus_connection_call (self->pv->connection, self->pv->prompter_bus_name, GCR_DBUS_PROMPTER_OBJECT_PATH, @@ -725,6 +762,7 @@ perform_init_async (GcrSystemPrompt *self, /* 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 (), @@ -735,9 +773,11 @@ perform_init_async (GcrSystemPrompt *self, on_prompt_proxy_new, g_object_ref (res)); + /* 4. All done */ + } else { + _gcr_debug ("successfully initialized prompt"); + g_simple_async_result_complete (res); } - - g_simple_async_result_complete (res); } static void @@ -799,6 +839,7 @@ parameter_properties (GcrSystemPrompt *self) 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); @@ -823,6 +864,7 @@ return_properties (GcrSystemPrompt *self, 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, @@ -842,10 +884,13 @@ parameters_for_password (GcrSystemPrompt *self) exchange = gcr_system_prompt_get_secret_exchange (self); - if (self->pv->exchanged) + if (self->pv->exchanged) { + _gcr_debug ("sending secret exchange"); input = gcr_secret_exchange_send (exchange, NULL, 0); - else + } else { + _gcr_debug ("beginning secret exchange"); input = gcr_secret_exchange_begin (exchange); + } self->pv->exchanged = TRUE; properties = parameter_properties (self); @@ -872,11 +917,15 @@ return_for_password (GcrSystemPrompt *self, 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"); } g_variant_unref (properties); @@ -904,8 +953,10 @@ on_prompt_requested_password (GObject *source, g_variant_unref (retval); } - if (error != NULL) + 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 (res); g_object_unref (self); @@ -926,6 +977,8 @@ gcr_system_prompt_password_async (GcrSystemPrompt *self, res = g_simple_async_result_new (G_OBJECT (self), callback, user_data, gcr_system_prompt_password_async); + _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), @@ -970,6 +1023,8 @@ gcr_system_prompt_password (GcrSystemPrompt *self, return NULL; } + _gcr_debug ("prompting for password"); + retval = g_dbus_proxy_call_sync (self->pv->prompt_proxy, GCR_DBUS_PROMPT_METHOD_PASSWORD, parameters_for_password (self), @@ -1007,6 +1062,11 @@ return_for_confirm (GcrSystemPrompt *self, g_variant_unref (properties); + if (confirm) + _gcr_debug ("prompt confirmed"); + else + _gcr_debug ("prompt was cancelled"); + return confirm; } @@ -1028,8 +1088,10 @@ on_prompt_requested_confirm (GObject *source, g_simple_async_result_set_op_res_gboolean (res, ret); } - if (error != NULL) + 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); @@ -1057,6 +1119,8 @@ gcr_system_prompt_confirm_async (GcrSystemPrompt *self, 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), @@ -1118,6 +1182,8 @@ gcr_system_prompt_confirm (GcrSystemPrompt *self, 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), @@ -1190,6 +1256,11 @@ gcr_system_prompt_open_for_prompter_async (const gchar *prompter_name, g_return_if_fail (timeout_seconds >= -1); g_return_if_fail (cancellable == NULL || G_CANCELLABLE (cancellable)); + if (prompter_name == NULL) + _gcr_debug ("opening prompt"); + else + _gcr_debug ("opening prompt for prompter: %s", prompter_name); + g_async_initable_new_async (GCR_TYPE_SYSTEM_PROMPT, G_PRIORITY_DEFAULT, cancellable, @@ -1294,6 +1365,11 @@ gcr_system_prompt_open_for_prompter (const gchar *prompter_name, g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); + if (prompter_name == NULL) + _gcr_debug ("opening prompt"); + else + _gcr_debug ("opening prompt for prompter: %s", prompter_name); + return g_initable_new (GCR_TYPE_SYSTEM_PROMPT, cancellable, error, "timeout-seconds", timeout_seconds, "bus-name", prompter_name, @@ -1308,12 +1384,103 @@ gcr_system_prompt_open_for_prompter (const gchar *prompter_name, * called on this object. The prompt object is not unreferenced by this * function, and you must unreference it once done. */ +gboolean +gcr_system_prompt_close (GcrSystemPrompt *self, + GCancellable *cancellable, + GError **error) +{ + GVariant *retval; + + 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); + + _gcr_debug ("closing prompt"); + + 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_variant_unref (retval); + g_free (self->pv->prompt_path); + self->pv->prompt_path = NULL; + return TRUE; +} + +static void +on_prompt_close_async (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; + + 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); + } + + g_simple_async_result_complete (res); + g_object_unref (self); + g_object_unref (res); +} + void -gcr_system_prompt_close (GcrSystemPrompt *self) +gcr_system_prompt_close_async (GcrSystemPrompt *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { - g_return_if_fail (GCR_IS_SYSTEM_PROMPT (self)); + GSimpleAsyncResult *res; + + g_return_if_fail (GCR_SYSTEM_PROMPT (self)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (self->pv->prompt_path != NULL); + + res = g_simple_async_result_new (G_OBJECT (self), callback, user_data, + gcr_system_prompt_close_async); + + _gcr_debug ("closing prompt"); + + 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_object_unref (res); +} - g_object_run_dispose (G_OBJECT (self)); +gboolean +gcr_system_prompt_close_finish (GcrSystemPrompt *self, + GAsyncResult *result, + GError **error) +{ + 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), + gcr_system_prompt_close_async), FALSE); + + if (!g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error)) + return FALSE; + + return TRUE; } static const GDBusErrorEntry SYSTEM_PROMPT_ERRORS[] = { diff --git a/gcr/gcr-system-prompt.h b/gcr/gcr-system-prompt.h index 19ffa1d..3fe2b33 100644 --- a/gcr/gcr-system-prompt.h +++ b/gcr/gcr-system-prompt.h @@ -39,7 +39,8 @@ G_BEGIN_DECLS typedef enum { GCR_SYSTEM_PROMPT_IN_PROGRESS = 1, GCR_SYSTEM_PROMPT_NOT_HAPPENING, - GCR_SYSTEM_PROMPT_FAILED + GCR_SYSTEM_PROMPT_FAILED, + GCR_SYSTEM_PROMPT_CLOSED } GcrSystemPromptError; #define GCR_SYSTEM_PROMPT_ERROR (gcr_system_prompt_error_get_domain ()) @@ -167,7 +168,18 @@ gboolean gcr_system_prompt_confirm (GcrSystemPromp GCancellable *cancellable, GError **error); -void gcr_system_prompt_close (GcrSystemPrompt *self); +gboolean gcr_system_prompt_close (GcrSystemPrompt *self, + GCancellable *cancellable, + GError **error); + +void gcr_system_prompt_close_async (GcrSystemPrompt *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +gboolean gcr_system_prompt_close_finish (GcrSystemPrompt *self, + GAsyncResult *result, + GError **error); G_END_DECLS diff --git a/gcr/gcr-system-prompter.c b/gcr/gcr-system-prompter.c index 7a60fc7..cf7eaa9 100644 --- a/gcr/gcr-system-prompter.c +++ b/gcr/gcr-system-prompter.c @@ -25,6 +25,8 @@ #include "gcr-dbus-constants.h" #include "gcr-dbus-generated.h" +#define DEBUG_FLAG GCR_DEBUG_PROMPT +#include "gcr-debug.h" #include "gcr-internal.h" #include "gcr-library.h" #include "gcr-secret-exchange.h" @@ -69,11 +71,11 @@ enum { }; enum { - SHOW_PROMPT, + OPEN, PROMPT_PASSWORD, PROMPT_CONFIRM, RESPONDED, - HIDE_PROMPT, + CLOSE, LAST_SIGNAL }; @@ -88,7 +90,7 @@ struct _GcrSystemPrompterPrivate { guint owner_watching_id; GcrSecretExchange *exchange; GDBusMethodInvocation *invocation; - gboolean shown; + gboolean opened; /* Properties */ GHashTable *properties; @@ -297,9 +299,10 @@ prompt_method_request_password (GcrSystemPrompter *self, prompt_update_properties (self, properties); - if (!self->pv->shown) { - self->pv->shown = TRUE; - g_signal_emit (self, signals[SHOW_PROMPT], 0); + if (!self->pv->opened) { + self->pv->opened = TRUE; + _gcr_debug ("prompter opening prompt"); + g_signal_emit (self, signals[OPEN], 0); } self->pv->invocation = invocation; @@ -330,9 +333,10 @@ prompt_method_request_confirm (GcrSystemPrompter *self, prompt_update_properties (self, properties); - if (!self->pv->shown) { - self->pv->shown = TRUE; - g_signal_emit (self, signals[SHOW_PROMPT], 0); + if (!self->pv->opened) { + self->pv->opened = TRUE; + _gcr_debug ("prompter opening prompt"); + g_signal_emit (self, signals[OPEN], 0); } self->pv->invocation = invocation; @@ -400,6 +404,7 @@ begin_prompting (GcrSystemPrompter *self, 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); @@ -424,12 +429,14 @@ finish_prompting (GcrSystemPrompter *self) prompt_clear_properties (self); /* Tell the implementation to hide the display */ - if (self->pv->shown) { - self->pv->shown = FALSE; - g_signal_emit (self, signals[HIDE_PROMPT], 0); + 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; } @@ -438,6 +445,7 @@ finish_prompting (GcrSystemPrompter *self) 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 (); @@ -530,6 +538,8 @@ gcr_system_prompter_dispose (GObject *obj) { GcrSystemPrompter *self = GCR_SYSTEM_PROMPTER (obj); + _gcr_debug ("disposing prompter"); + if (self->pv->invocation) gcr_system_prompter_respond_cancelled (self); @@ -546,6 +556,8 @@ gcr_system_prompter_finalize (GObject *obj) { GcrSystemPrompter *self = GCR_SYSTEM_PROMPTER (obj); + _gcr_debug ("finalizing prompter"); + g_hash_table_destroy (self->pv->properties); g_queue_free (self->pv->properties_changed); @@ -586,10 +598,10 @@ gcr_system_prompter_class_init (GcrSystemPrompterClass *klass) gobject_class->dispose = gcr_system_prompter_dispose; gobject_class->finalize = gcr_system_prompter_finalize; - klass->show_prompt = gcr_system_prompter_real_show_prompt; + 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->hide_prompt = gcr_system_prompter_real_hide_prompt; + klass->close = gcr_system_prompter_real_hide_prompt; g_type_class_add_private (gobject_class, sizeof (GcrSystemPrompterPrivate)); @@ -629,9 +641,9 @@ gcr_system_prompter_class_init (GcrSystemPrompterClass *klass) g_param_spec_string ("caller-window", "Caller window", "Window id of caller", "", G_PARAM_READABLE)); - signals[SHOW_PROMPT] = g_signal_new ("show-prompt", GCR_TYPE_SYSTEM_PROMPTER, G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GcrSystemPrompterClass, show_prompt), - NULL, NULL, NULL, G_TYPE_NONE, 0); + 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); signals[PROMPT_PASSWORD] = g_signal_new ("prompt-password", GCR_TYPE_SYSTEM_PROMPTER, G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GcrSystemPrompterClass, prompt_password), @@ -647,9 +659,9 @@ gcr_system_prompter_class_init (GcrSystemPrompterClass *klass) G_STRUCT_OFFSET (GcrSystemPrompterClass, responded), NULL, NULL, NULL, G_TYPE_NONE, 0); - signals[HIDE_PROMPT] = g_signal_new ("hide-prompt", GCR_TYPE_SYSTEM_PROMPTER, G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GcrSystemPrompterClass, hide_prompt), - NULL, NULL, NULL, G_TYPE_NONE, 0); + 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); } static void @@ -713,6 +725,7 @@ prompter_method_begin_prompting (GcrSystemPrompter *self, 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, @@ -730,6 +743,7 @@ prompter_method_finish_prompting (GcrSystemPrompter *self, const gchar *prompt) { 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, @@ -738,6 +752,7 @@ prompter_method_finish_prompting (GcrSystemPrompter *self, } 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, @@ -745,6 +760,8 @@ prompter_method_finish_prompting (GcrSystemPrompter *self, return; } + _gcr_debug ("finishing prompting owned by caller %s", self->pv->owner_name); + /* Close a prompt that's prompting */ if (self->pv->invocation != NULL) gcr_system_prompter_respond_cancelled (self); @@ -800,6 +817,8 @@ gcr_system_prompter_register (GcrSystemPrompter *self, g_return_if_fail (self->pv->prompter_registered == 0); g_return_if_fail (self->pv->connection == NULL); + _gcr_debug ("registering prompter"); + self->pv->connection = connection; g_object_add_weak_pointer (G_OBJECT (connection), (gpointer *)&self->pv->connection); @@ -825,6 +844,8 @@ gcr_system_prompter_unregister (GcrSystemPrompter *self, 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); @@ -1036,6 +1057,8 @@ gcr_system_prompter_respond_cancelled (GcrSystemPrompter *self) /* 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, @@ -1076,11 +1099,13 @@ gcr_system_prompter_respond_with_password (GcrSystemPrompter *self, 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); - method = g_dbus_method_invocation_get_method_name (invocation); - g_return_if_fail (method != NULL && g_str_equal (method, GCR_DBUS_PROMPT_METHOD_PASSWORD)); + _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)", @@ -1115,6 +1140,9 @@ gcr_system_prompter_respond_confirmed (GcrSystemPrompter *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)); diff --git a/gcr/gcr-system-prompter.h b/gcr/gcr-system-prompter.h index ad84ecb..b697473 100644 --- a/gcr/gcr-system-prompter.h +++ b/gcr/gcr-system-prompter.h @@ -53,7 +53,7 @@ struct _GcrSystemPrompter { struct _GcrSystemPrompterClass { GObjectClass parent_class; - void (*show_prompt) (GcrSystemPrompter *self); + void (*open) (GcrSystemPrompter *self); gboolean (*prompt_password) (GcrSystemPrompter *self); @@ -61,7 +61,7 @@ struct _GcrSystemPrompterClass { void (*responded) (GcrSystemPrompter *self); - void (*hide_prompt) (GcrSystemPrompter *self); + void (*close) (GcrSystemPrompter *self); }; GType gcr_system_prompter_get_type (void) G_GNUC_CONST; diff --git a/gcr/tests/frob-system-prompt.c b/gcr/tests/frob-system-prompt.c new file mode 100644 index 0000000..ef01139 --- /dev/null +++ b/gcr/tests/frob-system-prompt.c @@ -0,0 +1,106 @@ +/* + * gnome-keyring + * + * Copyright (C) 2011 Collabora Ltd. + * + * 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 <stefw@collabora.co.uk> + */ + +#include "config.h" + +#include "gcr/gcr.h" + +#include <gtk/gtk.h> +#include <gdk/gdkx.h> + +#include <unistd.h> +#include <string.h> +#include <errno.h> + +static void +on_prompt_clicked (GtkToolButton *button, + gpointer user_data) +{ + GcrSystemPrompt *prompt; + GError *error = NULL; + const gchar *password; + GtkWidget *parent = user_data; + gchar *caller_id; + + prompt = gcr_system_prompt_open (-1, NULL, &error); + if (error != NULL) { + g_warning ("couldn't open prompt: %s", error->message); + g_error_free (error); + 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"); + + caller_id = g_strdup_printf ("%lu", (gulong)GDK_WINDOW_XID (gtk_widget_get_window (parent))); + gcr_system_prompt_set_caller_window (prompt, caller_id); + g_free (caller_id); + + password = gcr_system_prompt_password (prompt, NULL, &error); + if (error != NULL) { + g_warning ("couldn't prompt for password: %s", error->message); + g_error_free (error); + g_object_unref (prompt); + return; + } + + g_print ("password: %s\n", password); + g_object_unref (prompt); +} + +static gboolean +on_window_delete (GtkWidget *widget, + GdkEvent *event, + gpointer user_data) +{ + gtk_main_quit (); + return FALSE; +} + +int +main (int argc, char *argv[]) +{ + GtkWidget *window; + GtkToolbar *toolbar; + GtkToolItem *item; + + gtk_init (&argc, &argv); + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + g_signal_connect (window, "delete-event", G_CALLBACK (on_window_delete), NULL); + + toolbar = GTK_TOOLBAR (gtk_toolbar_new ()); + gtk_toolbar_set_style (toolbar, GTK_TOOLBAR_TEXT); + item = gtk_tool_button_new (NULL, "Prompt"); + g_signal_connect (item, "clicked", G_CALLBACK (on_prompt_clicked), window); + gtk_toolbar_insert (toolbar, item, 0); + gtk_container_add (GTK_CONTAINER (window), GTK_WIDGET (toolbar)); + + gtk_window_set_default_size (GTK_WINDOW (window), 400, 80); + gtk_widget_show_all (window); + + gtk_main (); + + return 0; +} diff --git a/gcr/tests/test-system-prompt.c b/gcr/tests/test-system-prompt.c new file mode 100644 index 0000000..aec1ce6 --- /dev/null +++ b/gcr/tests/test-system-prompt.c @@ -0,0 +1,409 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* + Copyright (C) 2011 Collabora Ltd + + The Gnome Keyring Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Gnome Keyring Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Gnome Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Stef Walter <stefw@collabora.co.uk> +*/ + +#include "config.h" + +#include "gcr/gcr-base.h" +#include "gcr/gcr-mock-prompter.h" + +#include "egg/egg-testing.h" + +#include <glib.h> + +typedef struct { + const gchar *prompter_name; +} Test; + +static void +setup (Test *test, + gconstpointer unused) +{ + test->prompter_name = gcr_mock_prompter_start (); +} + +static void +teardown (Test *test, + gconstpointer unused) +{ + gcr_mock_prompter_stop (); +} + +static void +test_prompt_password (Test *test, + gconstpointer unused) +{ + GcrSystemPrompt *prompt; + GError *error = NULL; + const gchar *password; + + gcr_mock_prompter_expect_password_ok ("booo", NULL); + + 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)); + + password = gcr_system_prompt_password (prompt, NULL, &error); + g_assert_no_error (error); + g_assert_cmpstr (password, ==, "booo"); + + g_object_unref (prompt); + g_assert (!G_IS_OBJECT (prompt)); +} + +static void +test_password_in_exchange (Test *test, + gconstpointer unused) +{ + GcrSystemPrompt *prompt; + GError *error = NULL; + GcrSecretExchange *exchange; + + gcr_mock_prompter_expect_password_ok ("booo", NULL); + + 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)); + + gcr_system_prompt_password (prompt, NULL, &error); + g_assert_no_error (error); + + g_object_get (prompt, "secret-exchange", &exchange, NULL); + g_assert (GCR_IS_SECRET_EXCHANGE (exchange)); + g_assert_cmpstr (gcr_secret_exchange_get_secret (exchange, NULL), ==, "booo"); + + g_object_unref (exchange); + g_object_unref (prompt); + g_assert (!G_IS_OBJECT (prompt)); +} + +static void +on_async_result (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GAsyncResult **ret = user_data; + *ret = g_object_ref (result); + egg_test_wait_stop (); +} + +static void +test_async_password (Test *test, + gconstpointer unused) +{ + GAsyncResult *result = NULL; + GcrSystemPrompt *prompt; + GError *error = NULL; + const gchar *password; + + gcr_mock_prompter_expect_password_ok ("booo", NULL); + + gcr_system_prompt_open_for_prompter_async (test->prompter_name, 0, NULL, + on_async_result, &result); + g_assert (result == NULL); + egg_test_wait (); + + g_assert (result != NULL); + prompt = gcr_system_prompt_open_finish (result, &error); + g_assert_no_error (error); + g_assert (GCR_IS_SYSTEM_PROMPT (prompt)); + g_clear_object (&result); + + gcr_system_prompt_password_async (prompt, NULL, + on_async_result, &result); + g_assert (result == NULL); + egg_test_wait (); + + password = gcr_system_prompt_password_finish (prompt, result, &error); + g_assert_no_error (error); + g_assert_cmpstr (password, ==, "booo"); + g_clear_object (&result); + + g_object_unref (prompt); +} + +static void +test_prompt_confirm (Test *test, + gconstpointer unused) +{ + GcrSystemPrompt *prompt; + GError *error = NULL; + gboolean ret; + + gcr_mock_prompter_expect_confirm_ok (NULL); + + 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)); + + ret = gcr_system_prompt_confirm (prompt, NULL, &error); + g_assert_no_error (error); + g_assert (ret == TRUE); + + g_object_unref (prompt); + g_assert (!G_IS_OBJECT (prompt)); +} + +static void +test_async_confirm (Test *test, + gconstpointer unused) +{ + GAsyncResult *result = NULL; + GcrSystemPrompt *prompt; + GError *error = NULL; + gboolean confirm; + + gcr_mock_prompter_expect_confirm_ok (NULL); + + gcr_system_prompt_open_for_prompter_async (test->prompter_name, 0, NULL, + on_async_result, &result); + g_assert (result == NULL); + egg_test_wait (); + + g_assert (result != NULL); + prompt = gcr_system_prompt_open_finish (result, &error); + g_assert_no_error (error); + g_assert (GCR_IS_SYSTEM_PROMPT (prompt)); + g_clear_object (&result); + + gcr_system_prompt_confirm_async (prompt, NULL, + on_async_result, &result); + g_assert (result == NULL); + egg_test_wait (); + + confirm = gcr_system_prompt_confirm_finish (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)); +} + +static void +test_cancel_password (Test *test, + gconstpointer unused) +{ + GcrSystemPrompt *prompt; + GError *error = NULL; + const gchar *password; + + gcr_mock_prompter_expect_password_cancel (); + + 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)); + + password = gcr_system_prompt_password (prompt, NULL, &error); + g_assert_no_error (error); + g_assert_cmpstr (password, ==, NULL); + + g_object_unref (prompt); + g_assert (!G_IS_OBJECT (prompt)); +} + +static void +test_cancel_confirm (Test *test, + gconstpointer unused) +{ + GcrSystemPrompt *prompt; + GError *error = NULL; + gboolean ret; + + gcr_mock_prompter_expect_confirm_cancel (); + + 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)); + + ret = gcr_system_prompt_confirm (prompt, NULL, &error); + g_assert_no_error (error); + g_assert (ret == FALSE); + + g_object_unref (prompt); + g_assert (!G_IS_OBJECT (prompt)); +} + +static void +test_prompt_properties (Test *test, + gconstpointer unused) +{ + GcrSystemPrompt *prompt; + GError *error = NULL; + gboolean ret; + + gcr_mock_prompter_expect_confirm_ok ("title", "My Title", + "description", "My Description", + "warning", "My Warning", + "message", "My Message", + "caller-window", "01010", + "choice-label", "My Choice", + "choice-chosen", TRUE, + "password-new", TRUE, + "password-strength", 2, + NULL); + + 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_set (prompt, + "title", "Other Title", + "choice-label", "Other Choice", + "description", "Other Description", + "message", "Other Message", + "caller-window", "01012", + "warning", "Other Warning", + "password-new", FALSE, + "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_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_object_unref (prompt); + g_assert (!G_IS_OBJECT (prompt)); +} + +static void +test_prompt_close (Test *test, + gconstpointer unused) +{ + 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); + 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); + 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); + g_assert_no_error (error); + g_assert (ret == TRUE); + + prompt2 = gcr_system_prompt_open_for_prompter (test->prompter_name, 0, 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); + g_assert_no_error (error); + g_assert (GCR_IS_SYSTEM_PROMPT (prompt2)); + + g_object_unref (prompt); + g_assert (!G_IS_OBJECT (prompt)); + + g_object_unref (prompt2); + g_assert (!G_IS_OBJECT (prompt2)); +} + +static void +test_finish_cancels (Test *test, + gconstpointer unused) +{ + GcrSystemPrompt *prompt; + GError *error = NULL; + const gchar *password = NULL; + GAsyncResult *result = NULL; + + gcr_mock_prompter_set_delay_msec (3000); + gcr_mock_prompter_expect_password_ok ("booo", NULL); + + 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)); + + gcr_system_prompt_password_async (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); + g_assert_no_error (error); + g_assert (password == NULL); + g_clear_object (&result); + + g_object_unref (prompt); + g_assert (!G_IS_OBJECT (prompt)); +} + +int +main (int argc, char **argv) +{ + g_type_init (); + g_test_init (&argc, &argv, NULL); + g_set_prgname ("test-system-prompt"); + + 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/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/close", Test, NULL, setup, test_prompt_close, teardown); + g_test_add ("/gcr/system-prompt/finish-cancel", Test, NULL, setup, test_finish_cancels, teardown); + + return egg_tests_run_with_loop (); +} |