Blame gcr/gcr-system-prompt.c

Packit b00eeb
/*
Packit b00eeb
 * gnome-keyring
Packit b00eeb
 *
Packit b00eeb
 * Copyright (C) 2011 Stefan Walter
Packit b00eeb
 *
Packit b00eeb
 * This program is free software; you can redistribute it and/or modify
Packit b00eeb
 * it under the terms of the GNU Lesser General Public License as
Packit b00eeb
 * published by the Free Software Foundation; either version 2.1 of
Packit b00eeb
 * the License, or (at your option) any later version.
Packit b00eeb
 *
Packit b00eeb
 * This program is distributed in the hope that it will be useful, but
Packit b00eeb
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit b00eeb
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit b00eeb
 * Lesser General Public License for more details.
Packit b00eeb
 *
Packit b00eeb
 * You should have received a copy of the GNU Lesser General Public
Packit b00eeb
 * License along with this program; if not, see <http://www.gnu.org/licenses/>.
Packit b00eeb
 *
Packit b00eeb
 * Author: Stef Walter <stef@thewalter.net>
Packit b00eeb
 */
Packit b00eeb
Packit b00eeb
#include "config.h"
Packit b00eeb
Packit b00eeb
#include "gcr-dbus-constants.h"
Packit b00eeb
#include "gcr-internal.h"
Packit b00eeb
#include "gcr-library.h"
Packit b00eeb
#include "gcr-prompt.h"
Packit b00eeb
#include "gcr-secret-exchange.h"
Packit b00eeb
#include "gcr-system-prompt.h"
Packit b00eeb
Packit b00eeb
#include "gcr/gcr-dbus-generated.h"
Packit b00eeb
Packit b00eeb
#include "egg/egg-error.h"
Packit b00eeb
Packit b00eeb
#include <glib/gi18n.h>
Packit b00eeb
Packit b00eeb
/**
Packit b00eeb
 * SECTION:gcr-system-prompt
Packit b00eeb
 * @title: GcrSystemPrompt
Packit b00eeb
 * @short_description: a system modal prompt
Packit b00eeb
 *
Packit b00eeb
 * A #GcrPrompt implementation which calls to the system prompter to
Packit b00eeb
 * display prompts in a system modal fashion.
Packit b00eeb
 *
Packit b00eeb
 * Since the system prompter usually only displays one prompt at a time, you
Packit b00eeb
 * may have to wait for the prompt to be displayed. Use gcr_system_prompt_open()
Packit b00eeb
 * or a related function to open a prompt. Since this can take a long time, you
Packit b00eeb
 * should always check that the prompt is still needed after it is opened. A
Packit b00eeb
 * previous prompt may have already provided the information needed and you
Packit b00eeb
 * may no longer need to prompt.
Packit b00eeb
 *
Packit b00eeb
 * Use gcr_system_prompt_close() to close the prompt when you're done with it.
Packit b00eeb
 */
Packit b00eeb
Packit b00eeb
/**
Packit b00eeb
 * GcrSystemPrompt:
Packit b00eeb
 *
Packit b00eeb
 * A #GcrPrompt which shows a system prompt. This is usually a system modal
Packit b00eeb
 * dialog.
Packit b00eeb
 */
Packit b00eeb
Packit b00eeb
/**
Packit b00eeb
 * GcrSystemPromptClass:
Packit b00eeb
 * @parent_class: parent class
Packit b00eeb
 *
Packit b00eeb
 * The class for #GcrSystemPrompt.
Packit b00eeb
 */
Packit b00eeb
Packit b00eeb
/**
Packit b00eeb
 * GCR_SYSTEM_PROMPT_ERROR:
Packit b00eeb
 *
Packit b00eeb
 * The domain for errors returned from GcrSystemPrompt methods.
Packit b00eeb
 */
Packit b00eeb
Packit b00eeb
/**
Packit b00eeb
 * GcrSystemPromptError:
Packit b00eeb
 * @GCR_SYSTEM_PROMPT_IN_PROGRESS: another prompt is already in progress
Packit b00eeb
 *
Packit b00eeb
 * No error returned by the #GcrSystemPrompt is suitable for display or
Packit b00eeb
 * to the user.
Packit b00eeb
 *
Packit b00eeb
 * If the system prompter can only show one prompt at a time, and there is
Packit b00eeb
 * already a prompt being displayed, and the timeout waiting to open the
Packit b00eeb
 * prompt expires, then %GCR_SYSTEM_PROMPT_IN_PROGRESS is returned.
Packit b00eeb
 */
Packit b00eeb
Packit b00eeb
enum {
Packit b00eeb
	PROP_0,
Packit b00eeb
	PROP_BUS_NAME,
Packit b00eeb
	PROP_SECRET_EXCHANGE,
Packit b00eeb
	PROP_TIMEOUT_SECONDS,
Packit b00eeb
Packit b00eeb
	PROP_TITLE,
Packit b00eeb
	PROP_MESSAGE,
Packit b00eeb
	PROP_DESCRIPTION,
Packit b00eeb
	PROP_WARNING,
Packit b00eeb
	PROP_PASSWORD_NEW,
Packit b00eeb
	PROP_PASSWORD_STRENGTH,
Packit b00eeb
	PROP_CHOICE_LABEL,
Packit b00eeb
	PROP_CHOICE_CHOSEN,
Packit b00eeb
	PROP_CALLER_WINDOW,
Packit b00eeb
	PROP_CONTINUE_LABEL,
Packit b00eeb
	PROP_CANCEL_LABEL
Packit b00eeb
};
Packit b00eeb
Packit b00eeb
struct _GcrSystemPromptPrivate {
Packit b00eeb
	gchar *prompter_bus_name;
Packit b00eeb
	GcrSecretExchange *exchange;
Packit b00eeb
	gboolean received;
Packit b00eeb
	GHashTable *properties;
Packit b00eeb
	GHashTable *dirty_properties;
Packit b00eeb
	gint timeout_seconds;
Packit b00eeb
Packit b00eeb
	GDBusConnection *connection;
Packit b00eeb
	gboolean begun_prompting;
Packit b00eeb
	gboolean closed;
Packit b00eeb
	guint prompt_registered;
Packit b00eeb
	gchar *prompt_path;
Packit b00eeb
	gchar *prompt_owner;
Packit b00eeb
Packit b00eeb
	GSimpleAsyncResult *pending;
Packit b00eeb
	gchar *last_response;
Packit b00eeb
};
Packit b00eeb
Packit b00eeb
static void     gcr_system_prompt_prompt_iface         (GcrPromptIface *iface);
Packit b00eeb
Packit b00eeb
static void     gcr_system_prompt_initable_iface       (GInitableIface *iface);
Packit b00eeb
Packit b00eeb
static void     gcr_system_prompt_async_initable_iface (GAsyncInitableIface *iface);
Packit b00eeb
Packit b00eeb
static void     perform_init_async                     (GcrSystemPrompt *self,
Packit b00eeb
                                                        GSimpleAsyncResult *res);
Packit b00eeb
Packit b00eeb
G_DEFINE_TYPE_WITH_CODE (GcrSystemPrompt, gcr_system_prompt, G_TYPE_OBJECT,
Packit b00eeb
                         G_IMPLEMENT_INTERFACE (GCR_TYPE_PROMPT, gcr_system_prompt_prompt_iface);
Packit b00eeb
                         G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, gcr_system_prompt_initable_iface);
Packit b00eeb
                         G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, gcr_system_prompt_async_initable_iface);
Packit b00eeb
);
Packit b00eeb
Packit b00eeb
static gint unique_prompt_id = 0;
Packit b00eeb
Packit b00eeb
typedef struct {
Packit b00eeb
	GSource *timeout;
Packit b00eeb
	GSource *waiting;
Packit b00eeb
	GMainContext *context;
Packit b00eeb
	GCancellable *cancellable;
Packit b00eeb
	guint watch_id;
Packit b00eeb
} CallClosure;
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
call_closure_free (gpointer data)
Packit b00eeb
{
Packit b00eeb
	CallClosure *closure = data;
Packit b00eeb
	if (closure->timeout) {
Packit b00eeb
		g_source_destroy (closure->timeout);
Packit b00eeb
		g_source_unref (closure->timeout);
Packit b00eeb
	}
Packit b00eeb
	if (closure->waiting) {
Packit b00eeb
		g_source_destroy (closure->waiting);
Packit b00eeb
		g_source_unref (closure->waiting);
Packit b00eeb
	}
Packit b00eeb
	if (closure->watch_id)
Packit b00eeb
		g_bus_unwatch_name (closure->watch_id);
Packit b00eeb
	g_object_unref (closure->cancellable);
Packit b00eeb
	g_free (data);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
on_propagate_cancelled (GCancellable *cancellable,
Packit b00eeb
                        gpointer user_data)
Packit b00eeb
{
Packit b00eeb
	/* Propagate the cancelled signal */
Packit b00eeb
	GCancellable *cancel = G_CANCELLABLE (user_data);
Packit b00eeb
	g_cancellable_cancel (cancel);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static CallClosure *
Packit b00eeb
call_closure_new (GCancellable *cancellable)
Packit b00eeb
{
Packit b00eeb
	CallClosure *call;
Packit b00eeb
Packit b00eeb
	/*
Packit b00eeb
	 * We use our own cancellable object, since we cancel it it in
Packit b00eeb
	 * situations other than when the caller cancels.
Packit b00eeb
	 */
Packit b00eeb
Packit b00eeb
	call = g_new0 (CallClosure, 1);
Packit b00eeb
	call->cancellable = g_cancellable_new ();
Packit b00eeb
Packit b00eeb
	if (cancellable) {
Packit b00eeb
		g_cancellable_connect (cancellable, G_CALLBACK (on_propagate_cancelled),
Packit b00eeb
		                       g_object_ref (call->cancellable), g_object_unref);
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	return call;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
gcr_system_prompt_init (GcrSystemPrompt *self)
Packit b00eeb
{
Packit b00eeb
	self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_SYSTEM_PROMPT,
Packit b00eeb
	                                        GcrSystemPromptPrivate);
Packit b00eeb
Packit b00eeb
	self->pv->timeout_seconds = -1;
Packit b00eeb
	self->pv->properties = g_hash_table_new_full (g_direct_hash, g_direct_equal,
Packit b00eeb
	                                              NULL, (GDestroyNotify)g_variant_unref);
Packit b00eeb
	self->pv->dirty_properties = g_hash_table_new (g_direct_hash, g_direct_equal);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static const gchar *
Packit b00eeb
prompt_get_string_property (GcrSystemPrompt *self,
Packit b00eeb
                            const gchar *property_name,
Packit b00eeb
                            gboolean collapse_empty_to_null)
Packit b00eeb
{
Packit b00eeb
	const gchar *value = NULL;
Packit b00eeb
	GVariant *variant;
Packit b00eeb
	gconstpointer key;
Packit b00eeb
Packit b00eeb
	g_return_val_if_fail (GCR_IS_SYSTEM_PROMPT (self), NULL);
Packit b00eeb
Packit b00eeb
	key = g_intern_string (property_name);
Packit b00eeb
	variant = g_hash_table_lookup (self->pv->properties, key);
Packit b00eeb
	if (variant != NULL) {
Packit b00eeb
		value = g_variant_get_string (variant, NULL);
Packit b00eeb
		if (collapse_empty_to_null && value != NULL && value[0] == '\0')
Packit b00eeb
			value = NULL;
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	return value;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
prompt_set_string_property (GcrSystemPrompt *self,
Packit b00eeb
                            const gchar *property_name,
Packit b00eeb
                            const gchar *value)
Packit b00eeb
{
Packit b00eeb
	GVariant *variant;
Packit b00eeb
	gpointer key;
Packit b00eeb
Packit b00eeb
	g_return_if_fail (GCR_IS_SYSTEM_PROMPT (self));
Packit b00eeb
Packit b00eeb
	key = (gpointer)g_intern_string (property_name);
Packit b00eeb
	variant = g_variant_ref_sink (g_variant_new_string (value ? value : ""));
Packit b00eeb
	g_hash_table_insert (self->pv->properties, key, variant);
Packit b00eeb
	g_hash_table_insert (self->pv->dirty_properties, key, key);
Packit b00eeb
	g_object_notify (G_OBJECT (self), property_name);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static gint
Packit b00eeb
prompt_get_int_property (GcrSystemPrompt *self,
Packit b00eeb
                         const gchar *property_name)
Packit b00eeb
{
Packit b00eeb
	GVariant *variant;
Packit b00eeb
	gconstpointer key;
Packit b00eeb
Packit b00eeb
	g_return_val_if_fail (GCR_IS_SYSTEM_PROMPT (self), 0);
Packit b00eeb
Packit b00eeb
	key = g_intern_string (property_name);
Packit b00eeb
	variant = g_hash_table_lookup (self->pv->properties, key);
Packit b00eeb
	if (variant != NULL)
Packit b00eeb
		return g_variant_get_int32 (variant);
Packit b00eeb
Packit b00eeb
	return 0;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static gboolean
Packit b00eeb
prompt_get_boolean_property (GcrSystemPrompt *self,
Packit b00eeb
                             const gchar *property_name)
Packit b00eeb
{
Packit b00eeb
	GVariant *variant;
Packit b00eeb
	gconstpointer key;
Packit b00eeb
Packit b00eeb
	g_return_val_if_fail (GCR_IS_SYSTEM_PROMPT (self), FALSE);
Packit b00eeb
Packit b00eeb
	key = g_intern_string (property_name);
Packit b00eeb
	variant = g_hash_table_lookup (self->pv->properties, key);
Packit b00eeb
	if (variant != NULL)
Packit b00eeb
		return g_variant_get_boolean (variant);
Packit b00eeb
Packit b00eeb
	return FALSE;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
prompt_set_boolean_property (GcrSystemPrompt *self,
Packit b00eeb
                             const gchar *property_name,
Packit b00eeb
                             gboolean value)
Packit b00eeb
{
Packit b00eeb
	GVariant *variant;
Packit b00eeb
	gpointer key;
Packit b00eeb
Packit b00eeb
	g_return_if_fail (GCR_IS_SYSTEM_PROMPT (self));
Packit b00eeb
Packit b00eeb
	key = (gpointer)g_intern_string (property_name);
Packit b00eeb
	variant = g_variant_ref_sink (g_variant_new_boolean (value));
Packit b00eeb
	g_hash_table_insert (self->pv->properties, key, variant);
Packit b00eeb
	g_hash_table_insert (self->pv->dirty_properties, key, key);
Packit b00eeb
	g_object_notify (G_OBJECT (self), property_name);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
gcr_system_prompt_set_property (GObject *obj,
Packit b00eeb
                                guint prop_id,
Packit b00eeb
                                const GValue *value,
Packit b00eeb
                                GParamSpec *pspec)
Packit b00eeb
{
Packit b00eeb
	GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (obj);
Packit b00eeb
Packit b00eeb
	switch (prop_id) {
Packit b00eeb
	case PROP_BUS_NAME:
Packit b00eeb
		g_assert (self->pv->prompter_bus_name == NULL);
Packit b00eeb
		self->pv->prompter_bus_name = g_value_dup_string (value);
Packit b00eeb
		break;
Packit b00eeb
	case PROP_SECRET_EXCHANGE:
Packit b00eeb
		if (self->pv->exchange) {
Packit b00eeb
			g_warning ("The secret exchange is already in use, and cannot be changed");
Packit b00eeb
			return;
Packit b00eeb
		}
Packit b00eeb
		self->pv->exchange = g_value_dup_object (value);
Packit b00eeb
		g_object_notify (G_OBJECT (self), "secret-exchange");
Packit b00eeb
		break;
Packit b00eeb
	case PROP_TIMEOUT_SECONDS:
Packit b00eeb
		self->pv->timeout_seconds = g_value_get_int (value);
Packit b00eeb
		break;
Packit b00eeb
	case PROP_TITLE:
Packit b00eeb
		prompt_set_string_property (self, "title", g_value_get_string (value));
Packit b00eeb
		break;
Packit b00eeb
	case PROP_MESSAGE:
Packit b00eeb
		prompt_set_string_property (self, "message", g_value_get_string (value));
Packit b00eeb
		break;
Packit b00eeb
	case PROP_DESCRIPTION:
Packit b00eeb
		prompt_set_string_property (self, "description", g_value_get_string (value));
Packit b00eeb
		break;
Packit b00eeb
	case PROP_WARNING:
Packit b00eeb
		prompt_set_string_property (self, "warning", g_value_get_string (value));
Packit b00eeb
		break;
Packit b00eeb
	case PROP_PASSWORD_NEW:
Packit b00eeb
		prompt_set_boolean_property (self, "password-new", g_value_get_boolean (value));
Packit b00eeb
		break;
Packit b00eeb
	case PROP_CHOICE_LABEL:
Packit b00eeb
		prompt_set_string_property (self, "choice-label", g_value_get_string (value));
Packit b00eeb
		break;
Packit b00eeb
	case PROP_CHOICE_CHOSEN:
Packit b00eeb
		prompt_set_boolean_property (self, "choice-chosen", g_value_get_boolean (value));
Packit b00eeb
		break;
Packit b00eeb
	case PROP_CALLER_WINDOW:
Packit b00eeb
		prompt_set_string_property (self, "caller-window", g_value_get_string (value));
Packit b00eeb
		break;
Packit b00eeb
	case PROP_CONTINUE_LABEL:
Packit b00eeb
		prompt_set_string_property (self, "continue-label", g_value_get_string (value));
Packit b00eeb
		break;
Packit b00eeb
	case PROP_CANCEL_LABEL:
Packit b00eeb
		prompt_set_string_property (self, "cancel-label", g_value_get_string (value));
Packit b00eeb
		break;
Packit b00eeb
	default:
Packit b00eeb
		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
Packit b00eeb
		break;
Packit b00eeb
	}
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
gcr_system_prompt_get_property (GObject *obj,
Packit b00eeb
                                guint prop_id,
Packit b00eeb
                                GValue *value,
Packit b00eeb
                                GParamSpec *pspec)
Packit b00eeb
{
Packit b00eeb
	GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (obj);
Packit b00eeb
Packit b00eeb
	switch (prop_id) {
Packit b00eeb
	case PROP_BUS_NAME:
Packit b00eeb
		g_value_set_string (value, self->pv->prompter_bus_name);
Packit b00eeb
		break;
Packit b00eeb
	case PROP_SECRET_EXCHANGE:
Packit b00eeb
		g_value_set_object (value, gcr_system_prompt_get_secret_exchange (self));
Packit b00eeb
		break;
Packit b00eeb
	case PROP_TITLE:
Packit b00eeb
		g_value_set_string (value, prompt_get_string_property (self, "title", FALSE));
Packit b00eeb
		break;
Packit b00eeb
	case PROP_MESSAGE:
Packit b00eeb
		g_value_set_string (value, prompt_get_string_property (self, "message", FALSE));
Packit b00eeb
		break;
Packit b00eeb
	case PROP_DESCRIPTION:
Packit b00eeb
		g_value_set_string (value, prompt_get_string_property (self, "description", FALSE));
Packit b00eeb
		break;
Packit b00eeb
	case PROP_WARNING:
Packit b00eeb
		g_value_set_string (value, prompt_get_string_property (self, "warning", TRUE));
Packit b00eeb
		break;
Packit b00eeb
	case PROP_PASSWORD_NEW:
Packit b00eeb
		g_value_set_boolean (value, prompt_get_boolean_property (self, "password-new"));
Packit b00eeb
		break;
Packit b00eeb
	case PROP_PASSWORD_STRENGTH:
Packit b00eeb
		g_value_set_int (value, prompt_get_int_property (self, "password-strength"));
Packit b00eeb
		break;
Packit b00eeb
	case PROP_CHOICE_LABEL:
Packit b00eeb
		g_value_set_string (value, prompt_get_string_property (self, "choice-label", TRUE));
Packit b00eeb
		break;
Packit b00eeb
	case PROP_CHOICE_CHOSEN:
Packit b00eeb
		g_value_set_boolean (value, prompt_get_boolean_property (self, "choice-chosen"));
Packit b00eeb
		break;
Packit b00eeb
	case PROP_CALLER_WINDOW:
Packit b00eeb
		g_value_set_string (value, prompt_get_string_property (self, "caller-window", TRUE));
Packit b00eeb
		break;
Packit b00eeb
	case PROP_CONTINUE_LABEL:
Packit b00eeb
		g_value_set_string (value, prompt_get_string_property (self, "continue-label", TRUE));
Packit b00eeb
		break;
Packit b00eeb
	case PROP_CANCEL_LABEL:
Packit b00eeb
		g_value_set_string (value, prompt_get_string_property (self, "cancel-label", TRUE));
Packit b00eeb
		break;
Packit b00eeb
	default:
Packit b00eeb
		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
Packit b00eeb
		break;
Packit b00eeb
	}
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
gcr_system_prompt_constructed (GObject *obj)
Packit b00eeb
{
Packit b00eeb
	GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (obj);
Packit b00eeb
	gint seed;
Packit b00eeb
Packit b00eeb
	G_OBJECT_CLASS (gcr_system_prompt_parent_class)->constructed (obj);
Packit b00eeb
Packit b00eeb
	seed = g_atomic_int_add (&unique_prompt_id, 1);
Packit b00eeb
Packit b00eeb
	self->pv->prompt_path = g_strdup_printf ("%s/p%d", GCR_DBUS_PROMPT_OBJECT_PREFIX, seed);
Packit b00eeb
Packit b00eeb
	if (self->pv->prompter_bus_name == NULL)
Packit b00eeb
		self->pv->prompter_bus_name = g_strdup (GCR_DBUS_PROMPTER_SYSTEM_BUS_NAME);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
on_prompter_stop_prompting (GObject *source,
Packit b00eeb
                            GAsyncResult *result,
Packit b00eeb
                            gpointer user_data)
Packit b00eeb
{
Packit b00eeb
	GSimpleAsyncResult *async = NULL;
Packit b00eeb
	GError *error = NULL;
Packit b00eeb
	GVariant *retval;
Packit b00eeb
Packit b00eeb
	retval = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error);
Packit b00eeb
	if (error != NULL) {
Packit b00eeb
		g_debug ("failed to stop prompting: %s", egg_error_message (error));
Packit b00eeb
		g_clear_error (&error);
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	if (retval)
Packit b00eeb
		g_variant_unref (retval);
Packit b00eeb
Packit b00eeb
	if (user_data) {
Packit b00eeb
		async = G_SIMPLE_ASYNC_RESULT (user_data);
Packit b00eeb
		g_simple_async_result_complete (async);
Packit b00eeb
		g_object_unref (async);
Packit b00eeb
	}
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
perform_close (GcrSystemPrompt *self,
Packit b00eeb
               GSimpleAsyncResult *async,
Packit b00eeb
               GCancellable *cancellable)
Packit b00eeb
{
Packit b00eeb
	GSimpleAsyncResult *res;
Packit b00eeb
	CallClosure *closure;
Packit b00eeb
	gboolean called = FALSE;
Packit b00eeb
	gboolean closed;
Packit b00eeb
Packit b00eeb
	closed = self->pv->closed;
Packit b00eeb
	self->pv->closed = TRUE;
Packit b00eeb
Packit b00eeb
	if (!closed)
Packit b00eeb
		g_debug ("closing prompt");
Packit b00eeb
Packit b00eeb
	if (self->pv->pending) {
Packit b00eeb
		res = g_object_ref (self->pv->pending);
Packit b00eeb
		g_clear_object (&self->pv->pending);
Packit b00eeb
		closure = g_simple_async_result_get_op_res_gpointer (res);
Packit b00eeb
		g_cancellable_cancel (closure->cancellable);
Packit b00eeb
		g_simple_async_result_complete_in_idle (res);
Packit b00eeb
		g_object_unref (res);
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	if (self->pv->prompt_registered) {
Packit b00eeb
		g_dbus_connection_unregister_object (self->pv->connection,
Packit b00eeb
		                                     self->pv->prompt_registered);
Packit b00eeb
		self->pv->prompt_registered = 0;
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	if (self->pv->begun_prompting) {
Packit b00eeb
		if (self->pv->connection && self->pv->prompt_path && self->pv->prompt_owner) {
Packit b00eeb
			g_debug ("Calling the prompter %s method", GCR_DBUS_PROMPTER_METHOD_STOP);
Packit b00eeb
			g_dbus_connection_call (self->pv->connection,
Packit b00eeb
			                        self->pv->prompter_bus_name,
Packit b00eeb
			                        GCR_DBUS_PROMPTER_OBJECT_PATH,
Packit b00eeb
			                        GCR_DBUS_PROMPTER_INTERFACE,
Packit b00eeb
			                        GCR_DBUS_PROMPTER_METHOD_STOP,
Packit b00eeb
			                        g_variant_new ("(o)", self->pv->prompt_path),
Packit b00eeb
			                        G_VARIANT_TYPE ("()"),
Packit b00eeb
			                        G_DBUS_CALL_FLAGS_NO_AUTO_START,
Packit b00eeb
			                        -1, cancellable,
Packit b00eeb
			                        on_prompter_stop_prompting,
Packit b00eeb
			                        async ? g_object_ref (async) : NULL);
Packit b00eeb
			called = TRUE;
Packit b00eeb
		}
Packit b00eeb
		self->pv->begun_prompting = FALSE;
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	g_free (self->pv->prompt_path);
Packit b00eeb
	self->pv->prompt_path = NULL;
Packit b00eeb
Packit b00eeb
	g_clear_object (&self->pv->connection);
Packit b00eeb
Packit b00eeb
	if (!called && async)
Packit b00eeb
		g_simple_async_result_complete_in_idle (async);
Packit b00eeb
Packit b00eeb
	/* Emit the signal if necessary, after closed */
Packit b00eeb
	if (!closed)
Packit b00eeb
		gcr_prompt_close (GCR_PROMPT (self));
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
gcr_system_prompt_dispose (GObject *obj)
Packit b00eeb
{
Packit b00eeb
	GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (obj);
Packit b00eeb
Packit b00eeb
	g_clear_object (&self->pv->exchange);
Packit b00eeb
	perform_close (self, NULL, NULL);
Packit b00eeb
Packit b00eeb
	g_hash_table_remove_all (self->pv->properties);
Packit b00eeb
	g_hash_table_remove_all (self->pv->dirty_properties);
Packit b00eeb
Packit b00eeb
	G_OBJECT_CLASS (gcr_system_prompt_parent_class)->dispose (obj);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
gcr_system_prompt_finalize (GObject *obj)
Packit b00eeb
{
Packit b00eeb
	GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (obj);
Packit b00eeb
Packit b00eeb
	g_free (self->pv->prompter_bus_name);
Packit b00eeb
	g_free (self->pv->prompt_owner);
Packit b00eeb
	g_free (self->pv->last_response);
Packit b00eeb
	g_hash_table_destroy (self->pv->properties);
Packit b00eeb
	g_hash_table_destroy (self->pv->dirty_properties);
Packit b00eeb
Packit b00eeb
	G_OBJECT_CLASS (gcr_system_prompt_parent_class)->finalize (obj);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
gcr_system_prompt_class_init (GcrSystemPromptClass *klass)
Packit b00eeb
{
Packit b00eeb
	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
Packit b00eeb
Packit b00eeb
	gobject_class->constructed = gcr_system_prompt_constructed;
Packit b00eeb
	gobject_class->get_property = gcr_system_prompt_get_property;
Packit b00eeb
	gobject_class->set_property = gcr_system_prompt_set_property;
Packit b00eeb
	gobject_class->dispose = gcr_system_prompt_dispose;
Packit b00eeb
	gobject_class->finalize = gcr_system_prompt_finalize;
Packit b00eeb
Packit b00eeb
	g_type_class_add_private (gobject_class, sizeof (GcrSystemPromptPrivate));
Packit b00eeb
Packit b00eeb
	/**
Packit b00eeb
	 * GcrSystemPrompt:bus-name:
Packit b00eeb
	 *
Packit b00eeb
	 * The DBus bus name of the prompter to use for prompting, or %NULL
Packit b00eeb
	 * for the default prompter.
Packit b00eeb
	 */
Packit b00eeb
	g_object_class_install_property (gobject_class, PROP_BUS_NAME,
Packit b00eeb
	            g_param_spec_string ("bus-name", "Bus name", "Prompter bus name",
Packit b00eeb
	                                 NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
Packit b00eeb
Packit b00eeb
	/**
Packit b00eeb
	 * GcrSystemPrompt:timeout-seconds:
Packit b00eeb
	 *
Packit b00eeb
	 * The timeout in seconds to wait when opening the prompt.
Packit b00eeb
	 */
Packit b00eeb
	g_object_class_install_property (gobject_class, PROP_TIMEOUT_SECONDS,
Packit b00eeb
	               g_param_spec_int ("timeout-seconds", "Timeout seconds", "Timeout (in seconds) for opening prompt",
Packit b00eeb
	                                 -1, G_MAXINT, -1, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
Packit b00eeb
Packit b00eeb
	/**
Packit b00eeb
	 * GcrSystemPrompt:secret-exchange:
Packit b00eeb
	 *
Packit b00eeb
	 * The #GcrSecretExchange to use when transferring passwords. A default
Packit b00eeb
	 * secret exchange will be used if this is not set.
Packit b00eeb
	 */
Packit b00eeb
	g_object_class_install_property (gobject_class, PROP_SECRET_EXCHANGE,
Packit b00eeb
	            g_param_spec_object ("secret-exchange", "Secret exchange", "Secret exchange for passing passwords",
Packit b00eeb
	                                 GCR_TYPE_SECRET_EXCHANGE, G_PARAM_READWRITE));
Packit b00eeb
Packit b00eeb
	g_object_class_override_property (gobject_class, PROP_TITLE, "title");
Packit b00eeb
	g_object_class_override_property (gobject_class, PROP_MESSAGE, "message");
Packit b00eeb
	g_object_class_override_property (gobject_class, PROP_DESCRIPTION, "description");
Packit b00eeb
	g_object_class_override_property (gobject_class, PROP_WARNING, "warning");
Packit b00eeb
	g_object_class_override_property (gobject_class, PROP_PASSWORD_NEW, "password-new");
Packit b00eeb
	g_object_class_override_property (gobject_class, PROP_PASSWORD_STRENGTH, "password-strength");
Packit b00eeb
	g_object_class_override_property (gobject_class, PROP_CHOICE_LABEL, "choice-label");
Packit b00eeb
	g_object_class_override_property (gobject_class, PROP_CHOICE_CHOSEN, "choice-chosen");
Packit b00eeb
	g_object_class_override_property (gobject_class, PROP_CALLER_WINDOW, "caller-window");
Packit b00eeb
	g_object_class_override_property (gobject_class, PROP_CONTINUE_LABEL, "continue-label");
Packit b00eeb
	g_object_class_override_property (gobject_class, PROP_CANCEL_LABEL, "cancel-label");
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
/**
Packit b00eeb
 * gcr_system_prompt_get_secret_exchange:
Packit b00eeb
 * @self: a prompter
Packit b00eeb
 *
Packit b00eeb
 * Get the current #GcrSecretExchange used to transfer secrets in this prompt.
Packit b00eeb
 *
Packit b00eeb
 * Returns: (transfer none): the secret exchange
Packit b00eeb
 */
Packit b00eeb
GcrSecretExchange *
Packit b00eeb
gcr_system_prompt_get_secret_exchange (GcrSystemPrompt *self)
Packit b00eeb
{
Packit b00eeb
	g_return_val_if_fail (GCR_IS_SYSTEM_PROMPT (self), NULL);
Packit b00eeb
Packit b00eeb
	if (!self->pv->exchange) {
Packit b00eeb
		g_debug ("creating new secret exchange");
Packit b00eeb
		self->pv->exchange = gcr_secret_exchange_new (NULL);
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	return self->pv->exchange;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
update_properties_from_iter (GcrSystemPrompt *self,
Packit b00eeb
                             GVariantIter *iter)
Packit b00eeb
{
Packit b00eeb
	GObject *obj = G_OBJECT (self);
Packit b00eeb
	GVariant *variant;
Packit b00eeb
	GVariant *value;
Packit b00eeb
	GVariant *already;
Packit b00eeb
	gpointer key;
Packit b00eeb
	gchar *name;
Packit b00eeb
Packit b00eeb
	g_object_freeze_notify (obj);
Packit b00eeb
	while (g_variant_iter_loop (iter, "{sv}", &name, &variant)) {
Packit b00eeb
		key = (gpointer)g_intern_string (name);
Packit b00eeb
		value = g_variant_get_variant (variant);
Packit b00eeb
		already = g_hash_table_lookup (self->pv->properties, key);
Packit b00eeb
		if (!already || !g_variant_equal (already, value)) {
Packit b00eeb
			g_hash_table_replace (self->pv->properties, key, g_variant_ref (value));
Packit b00eeb
			g_object_notify (obj, name);
Packit b00eeb
		}
Packit b00eeb
		g_variant_unref (value);
Packit b00eeb
	}
Packit b00eeb
	g_object_thaw_notify (obj);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
prompt_method_ready (GcrSystemPrompt *self,
Packit b00eeb
                     GDBusMethodInvocation *invocation,
Packit b00eeb
                     GVariant *parameters)
Packit b00eeb
{
Packit b00eeb
	GcrSecretExchange *exchange;
Packit b00eeb
	GSimpleAsyncResult *res;
Packit b00eeb
	GVariantIter *iter;
Packit b00eeb
	gchar *received;
Packit b00eeb
Packit b00eeb
	g_return_if_fail (G_IS_SIMPLE_ASYNC_RESULT (self->pv->pending));
Packit b00eeb
Packit b00eeb
	g_free (self->pv->last_response);
Packit b00eeb
	g_variant_get (parameters, "(sa{sv}s)",
Packit b00eeb
	               &self->pv->last_response,
Packit b00eeb
	               &iter, &received);
Packit b00eeb
Packit b00eeb
	g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
Packit b00eeb
Packit b00eeb
	update_properties_from_iter (self, iter);
Packit b00eeb
	g_variant_iter_free (iter);
Packit b00eeb
Packit b00eeb
	exchange = gcr_system_prompt_get_secret_exchange (self);
Packit b00eeb
	if (gcr_secret_exchange_receive (exchange, received))
Packit b00eeb
		self->pv->received = TRUE;
Packit b00eeb
	else
Packit b00eeb
		g_warning ("received invalid secret exchange string");
Packit b00eeb
	g_free (received);
Packit b00eeb
Packit b00eeb
	res = g_object_ref (self->pv->pending);
Packit b00eeb
	g_clear_object (&self->pv->pending);
Packit b00eeb
	g_simple_async_result_complete (res);
Packit b00eeb
	g_object_unref (res);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
prompt_method_done (GcrSystemPrompt *self,
Packit b00eeb
                    GDBusMethodInvocation *invocation,
Packit b00eeb
                    GVariant *parameters)
Packit b00eeb
{
Packit b00eeb
	g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
Packit b00eeb
Packit b00eeb
	/*
Packit b00eeb
	 * At this point we're done prompting, and calling StopPrompting
Packit b00eeb
	 * on the prompter is no longer necessary. It may have already been
Packit b00eeb
	 * called, or the prompter may have stopped on its own accord.
Packit b00eeb
	 */
Packit b00eeb
	self->pv->begun_prompting = FALSE;
Packit b00eeb
	perform_close (self, NULL, NULL);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
prompt_method_call (GDBusConnection *connection,
Packit b00eeb
                    const gchar *sender,
Packit b00eeb
                    const gchar *object_path,
Packit b00eeb
                    const gchar *interface_name,
Packit b00eeb
                    const gchar *method_name,
Packit b00eeb
                    GVariant *parameters,
Packit b00eeb
                    GDBusMethodInvocation *invocation,
Packit b00eeb
                    gpointer user_data)
Packit b00eeb
{
Packit b00eeb
	GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (user_data);
Packit b00eeb
Packit b00eeb
	g_return_if_fail (method_name != NULL);
Packit b00eeb
Packit b00eeb
	if (g_str_equal (method_name, GCR_DBUS_CALLBACK_METHOD_READY)) {
Packit b00eeb
		prompt_method_ready (self, invocation, parameters);
Packit b00eeb
Packit b00eeb
	} else if (g_str_equal (method_name, GCR_DBUS_CALLBACK_METHOD_DONE)) {
Packit b00eeb
		prompt_method_done (self, invocation, parameters);
Packit b00eeb
Packit b00eeb
	} else {
Packit b00eeb
		g_return_if_reached ();
Packit b00eeb
	}
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static GVariant *
Packit b00eeb
prompt_get_property (GDBusConnection *connection,
Packit b00eeb
                     const gchar *sender,
Packit b00eeb
                     const gchar *object_path,
Packit b00eeb
                     const gchar *interface_name,
Packit b00eeb
                     const gchar *property_name,
Packit b00eeb
                     GError **error,
Packit b00eeb
                     gpointer user_data)
Packit b00eeb
{
Packit b00eeb
	g_return_val_if_reached (NULL);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static gboolean
Packit b00eeb
prompt_set_property (GDBusConnection *connection,
Packit b00eeb
                     const gchar *sender,
Packit b00eeb
                     const gchar *object_path,
Packit b00eeb
                     const gchar *interface_name,
Packit b00eeb
                     const gchar *property_name,
Packit b00eeb
                     GVariant *value,
Packit b00eeb
                     GError **error,
Packit b00eeb
                     gpointer user_data)
Packit b00eeb
{
Packit b00eeb
	g_return_val_if_reached (FALSE);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
Packit b00eeb
static GDBusInterfaceVTable prompt_dbus_vtable = {
Packit b00eeb
	prompt_method_call,
Packit b00eeb
	prompt_get_property,
Packit b00eeb
	prompt_set_property,
Packit b00eeb
};
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
register_prompt_object (GcrSystemPrompt *self,
Packit b00eeb
                        GError **error)
Packit b00eeb
{
Packit b00eeb
	GError *lerror = NULL;
Packit b00eeb
	guint id;
Packit b00eeb
Packit b00eeb
	/*
Packit b00eeb
	 * The unregister/reregister allows us to register this under a whatever
Packit b00eeb
	 * GMainContext has been pushed as the thread default context.
Packit b00eeb
	 */
Packit b00eeb
Packit b00eeb
	if (self->pv->prompt_registered)
Packit b00eeb
		g_dbus_connection_unregister_object (self->pv->connection,
Packit b00eeb
		                                     self->pv->prompt_registered);
Packit b00eeb
Packit b00eeb
	id = g_dbus_connection_register_object (self->pv->connection,
Packit b00eeb
	                                        self->pv->prompt_path,
Packit b00eeb
	                                        _gcr_dbus_prompter_callback_interface_info (),
Packit b00eeb
	                                        &prompt_dbus_vtable,
Packit b00eeb
	                                        self, NULL, &lerror);
Packit b00eeb
	self->pv->prompt_registered = id;
Packit b00eeb
Packit b00eeb
	if (lerror != NULL) {
Packit b00eeb
		g_warning ("error registering prompter %s", egg_error_message (lerror));
Packit b00eeb
		g_propagate_error (error, lerror);
Packit b00eeb
	}
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
on_prompter_present (GDBusConnection *connection,
Packit b00eeb
                     const gchar *name,
Packit b00eeb
                     const gchar *name_owner,
Packit b00eeb
                     gpointer user_data)
Packit b00eeb
{
Packit b00eeb
	GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (g_async_result_get_source_object (user_data));
Packit b00eeb
Packit b00eeb
	g_free (self->pv->prompt_owner);
Packit b00eeb
	self->pv->prompt_owner = g_strdup (name_owner);
Packit b00eeb
Packit b00eeb
	g_object_unref (self);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
on_prompter_vanished (GDBusConnection *connection,
Packit b00eeb
                      const gchar *name,
Packit b00eeb
                      gpointer user_data)
Packit b00eeb
{
Packit b00eeb
	GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (g_async_result_get_source_object (user_data));
Packit b00eeb
	CallClosure *call = g_simple_async_result_get_op_res_gpointer (user_data);
Packit b00eeb
Packit b00eeb
	if (self->pv->prompt_owner) {
Packit b00eeb
		g_free (self->pv->prompt_owner);
Packit b00eeb
		self->pv->prompt_owner = NULL;
Packit b00eeb
		g_debug ("prompter name owner has vanished: %s", name);
Packit b00eeb
		g_cancellable_cancel (call->cancellable);
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	g_object_unref (self);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
on_bus_connected (GObject *source,
Packit b00eeb
                  GAsyncResult *result,
Packit b00eeb
                  gpointer user_data)
Packit b00eeb
{
Packit b00eeb
	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
Packit b00eeb
	GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (g_async_result_get_source_object (user_data));
Packit b00eeb
	CallClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
Packit b00eeb
	GError *error = NULL;
Packit b00eeb
Packit b00eeb
	g_assert (self->pv->connection == NULL);
Packit b00eeb
	self->pv->connection = g_bus_get_finish (result, &error);
Packit b00eeb
Packit b00eeb
	if (error != NULL) {
Packit b00eeb
		g_debug ("failed to connect to bus: %s", egg_error_message (error));
Packit b00eeb
Packit b00eeb
	} else {
Packit b00eeb
		g_return_if_fail (self->pv->connection != NULL);
Packit b00eeb
		g_debug ("connected to bus");
Packit b00eeb
Packit b00eeb
		g_main_context_push_thread_default (closure->context);
Packit b00eeb
Packit b00eeb
		closure->watch_id = g_bus_watch_name_on_connection (self->pv->connection,
Packit b00eeb
		                                                    self->pv->prompter_bus_name,
Packit b00eeb
		                                                    G_BUS_NAME_WATCHER_FLAGS_NONE,
Packit b00eeb
		                                                    on_prompter_present,
Packit b00eeb
		                                                    on_prompter_vanished,
Packit b00eeb
		                                                    res, NULL);
Packit b00eeb
Packit b00eeb
		register_prompt_object (self, &error);
Packit b00eeb
Packit b00eeb
		g_main_context_pop_thread_default (closure->context);
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	if (error == NULL) {
Packit b00eeb
		perform_init_async (self, res);
Packit b00eeb
	} else {
Packit b00eeb
		g_simple_async_result_take_error (res, error);
Packit b00eeb
		g_simple_async_result_complete (res);
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	g_object_unref (self);
Packit b00eeb
	g_object_unref (res);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
on_prompter_begin_prompting (GObject *source,
Packit b00eeb
                             GAsyncResult *result,
Packit b00eeb
                             gpointer user_data)
Packit b00eeb
{
Packit b00eeb
	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
Packit b00eeb
	GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (g_async_result_get_source_object (user_data));
Packit b00eeb
	GError *error = NULL;
Packit b00eeb
	GVariant *ret;
Packit b00eeb
Packit b00eeb
	ret = g_dbus_connection_call_finish (self->pv->connection, result, &error);
Packit b00eeb
Packit b00eeb
	if (error == NULL) {
Packit b00eeb
		self->pv->begun_prompting = TRUE;
Packit b00eeb
		g_variant_unref (ret);
Packit b00eeb
Packit b00eeb
		g_debug ("registered prompt %s: %s",
Packit b00eeb
		         self->pv->prompter_bus_name, self->pv->prompt_path);
Packit b00eeb
Packit b00eeb
		g_return_if_fail (self->pv->prompt_path != NULL);
Packit b00eeb
		perform_init_async (self, res);
Packit b00eeb
Packit b00eeb
	} else {
Packit b00eeb
		g_debug ("failed to register prompt %s: %s",
Packit b00eeb
		         self->pv->prompter_bus_name, egg_error_message (error));
Packit b00eeb
Packit b00eeb
		g_simple_async_result_take_error (res, error);
Packit b00eeb
		g_simple_async_result_complete (res);
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	g_object_unref (self);
Packit b00eeb
	g_object_unref (res);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static gboolean
Packit b00eeb
on_call_timeout (gpointer user_data)
Packit b00eeb
{
Packit b00eeb
	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
Packit b00eeb
	CallClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
Packit b00eeb
	GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (g_async_result_get_source_object (user_data));
Packit b00eeb
Packit b00eeb
	g_source_destroy (closure->timeout);
Packit b00eeb
	g_source_unref (closure->timeout);
Packit b00eeb
	closure->timeout = NULL;
Packit b00eeb
Packit b00eeb
	/* Tell the prompter we're no longer interested */
Packit b00eeb
	gcr_system_prompt_close_async (self, NULL, NULL, NULL);
Packit b00eeb
Packit b00eeb
	g_simple_async_result_set_error (res, GCR_SYSTEM_PROMPT_ERROR,
Packit b00eeb
	                                 GCR_SYSTEM_PROMPT_IN_PROGRESS,
Packit b00eeb
	                                 _("Another prompt is already in progress"));
Packit b00eeb
	g_simple_async_result_complete (res);
Packit b00eeb
Packit b00eeb
	g_object_unref (self);
Packit b00eeb
	return FALSE; /* Don't call this function again */
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static gboolean
Packit b00eeb
on_call_cancelled (GCancellable *cancellable,
Packit b00eeb
                   gpointer user_data)
Packit b00eeb
{
Packit b00eeb
	GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
Packit b00eeb
	CallClosure *call = g_simple_async_result_get_op_res_gpointer (async);
Packit b00eeb
	GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (g_async_result_get_source_object (user_data));
Packit b00eeb
Packit b00eeb
	g_source_destroy (call->waiting);
Packit b00eeb
	g_source_unref (call->waiting);
Packit b00eeb
	call->waiting = NULL;
Packit b00eeb
Packit b00eeb
	g_simple_async_result_set_error (async, G_IO_ERROR, G_IO_ERROR_CANCELLED,
Packit b00eeb
	                                 _("The operation was cancelled"));
Packit b00eeb
Packit b00eeb
	/* Tell the prompter we're no longer interested */
Packit b00eeb
	gcr_system_prompt_close_async (self, NULL, NULL, NULL);
Packit b00eeb
Packit b00eeb
	g_object_unref (self);
Packit b00eeb
	return FALSE; /* Don't call this function again */
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
void
Packit b00eeb
perform_init_async (GcrSystemPrompt *self,
Packit b00eeb
                    GSimpleAsyncResult *res)
Packit b00eeb
{
Packit b00eeb
	CallClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
Packit b00eeb
Packit b00eeb
	g_main_context_push_thread_default (closure->context);
Packit b00eeb
Packit b00eeb
	/* 1. Connect to the session bus */
Packit b00eeb
	if (!self->pv->connection) {
Packit b00eeb
		g_debug ("connecting to bus");
Packit b00eeb
		g_bus_get (G_BUS_TYPE_SESSION, closure->cancellable,
Packit b00eeb
		           on_bus_connected, g_object_ref (res));
Packit b00eeb
Packit b00eeb
	/* 2. Export our object, BeginPrompting on prompter */
Packit b00eeb
	} else if (!self->pv->begun_prompting) {
Packit b00eeb
		g_assert (self->pv->prompt_path != NULL);
Packit b00eeb
Packit b00eeb
		g_debug ("calling %s method on prompter", GCR_DBUS_PROMPTER_METHOD_BEGIN);
Packit b00eeb
		g_dbus_connection_call (self->pv->connection,
Packit b00eeb
		                        self->pv->prompter_bus_name,
Packit b00eeb
		                        GCR_DBUS_PROMPTER_OBJECT_PATH,
Packit b00eeb
		                        GCR_DBUS_PROMPTER_INTERFACE,
Packit b00eeb
		                        GCR_DBUS_PROMPTER_METHOD_BEGIN,
Packit b00eeb
		                        g_variant_new ("(o)", self->pv->prompt_path),
Packit b00eeb
		                        G_VARIANT_TYPE ("()"),
Packit b00eeb
		                        G_DBUS_CALL_FLAGS_NONE,
Packit b00eeb
		                        -1, closure->cancellable,
Packit b00eeb
		                        on_prompter_begin_prompting,
Packit b00eeb
		                        g_object_ref (res));
Packit b00eeb
Packit b00eeb
	/* 3. Wait for iterate */
Packit b00eeb
	} else if (!self->pv->pending) {
Packit b00eeb
		self->pv->pending = g_object_ref (res);
Packit b00eeb
		if (self->pv->timeout_seconds > 0) {
Packit b00eeb
			g_assert (closure->timeout == NULL);
Packit b00eeb
			closure->timeout = g_timeout_source_new_seconds (self->pv->timeout_seconds);
Packit b00eeb
			g_source_set_callback (closure->timeout, on_call_timeout, res, NULL);
Packit b00eeb
			g_source_attach (closure->timeout, closure->context);
Packit b00eeb
		}
Packit b00eeb
Packit b00eeb
		g_assert (closure->waiting == NULL);
Packit b00eeb
		closure->waiting = g_cancellable_source_new (closure->cancellable);
Packit b00eeb
		g_source_set_callback (closure->waiting, (GSourceFunc)on_call_cancelled, res, NULL);
Packit b00eeb
		g_source_attach (closure->waiting, closure->context);
Packit b00eeb
Packit b00eeb
	/* 4. All done */
Packit b00eeb
	} else {
Packit b00eeb
		g_assert_not_reached ();
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	g_main_context_pop_thread_default (closure->context);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
gcr_system_prompt_real_init_async (GAsyncInitable *initable,
Packit b00eeb
                                   int io_priority,
Packit b00eeb
                                   GCancellable *cancellable,
Packit b00eeb
                                   GAsyncReadyCallback callback,
Packit b00eeb
                                   gpointer user_data)
Packit b00eeb
{
Packit b00eeb
	GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (initable);
Packit b00eeb
	GSimpleAsyncResult *res;
Packit b00eeb
	CallClosure *closure;
Packit b00eeb
Packit b00eeb
	res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
Packit b00eeb
	                                 gcr_system_prompt_real_init_async);
Packit b00eeb
	closure = call_closure_new (cancellable);
Packit b00eeb
	closure->context = g_main_context_get_thread_default ();
Packit b00eeb
	if (closure->context)
Packit b00eeb
		g_main_context_ref (closure->context);
Packit b00eeb
	g_simple_async_result_set_op_res_gpointer (res, closure, call_closure_free);
Packit b00eeb
Packit b00eeb
	perform_init_async (self, res);
Packit b00eeb
Packit b00eeb
	g_object_unref (res);
Packit b00eeb
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static gboolean
Packit b00eeb
gcr_system_prompt_real_init_finish (GAsyncInitable *initable,
Packit b00eeb
                                    GAsyncResult *result,
Packit b00eeb
                                    GError **error)
Packit b00eeb
{
Packit b00eeb
	GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (initable);
Packit b00eeb
Packit b00eeb
	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
Packit b00eeb
	                      gcr_system_prompt_real_init_async), FALSE);
Packit b00eeb
Packit b00eeb
	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
Packit b00eeb
		return FALSE;
Packit b00eeb
Packit b00eeb
	return TRUE;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
gcr_system_prompt_async_initable_iface (GAsyncInitableIface *iface)
Packit b00eeb
{
Packit b00eeb
	iface->init_async = gcr_system_prompt_real_init_async;
Packit b00eeb
	iface->init_finish = gcr_system_prompt_real_init_finish;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
typedef struct {
Packit b00eeb
	GAsyncResult *result;
Packit b00eeb
	GMainContext *context;
Packit b00eeb
	GMainLoop *loop;
Packit b00eeb
} SyncClosure;
Packit b00eeb
Packit b00eeb
static SyncClosure *
Packit b00eeb
sync_closure_new (void)
Packit b00eeb
{
Packit b00eeb
	SyncClosure *closure;
Packit b00eeb
Packit b00eeb
	closure = g_new0 (SyncClosure, 1);
Packit b00eeb
Packit b00eeb
	closure->context = g_main_context_new ();
Packit b00eeb
	closure->loop = g_main_loop_new (closure->context, FALSE);
Packit b00eeb
Packit b00eeb
	return closure;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
sync_closure_free (gpointer data)
Packit b00eeb
{
Packit b00eeb
	SyncClosure *closure = data;
Packit b00eeb
Packit b00eeb
	g_clear_object (&closure->result);
Packit b00eeb
	g_main_loop_unref (closure->loop);
Packit b00eeb
	g_main_context_unref (closure->context);
Packit b00eeb
	g_free (closure);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
on_sync_result (GObject *source,
Packit b00eeb
                GAsyncResult *result,
Packit b00eeb
                gpointer user_data)
Packit b00eeb
{
Packit b00eeb
	SyncClosure *closure = user_data;
Packit b00eeb
	closure->result = g_object_ref (result);
Packit b00eeb
	g_main_loop_quit (closure->loop);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static gboolean
Packit b00eeb
gcr_system_prompt_real_init (GInitable *initable,
Packit b00eeb
                             GCancellable *cancellable,
Packit b00eeb
                             GError **error)
Packit b00eeb
{
Packit b00eeb
	SyncClosure *closure;
Packit b00eeb
	gboolean result;
Packit b00eeb
Packit b00eeb
	closure = sync_closure_new ();
Packit b00eeb
	g_main_context_push_thread_default (closure->context);
Packit b00eeb
Packit b00eeb
	gcr_system_prompt_real_init_async (G_ASYNC_INITABLE (initable),
Packit b00eeb
	                                   G_PRIORITY_DEFAULT, cancellable,
Packit b00eeb
	                                   on_sync_result, closure);
Packit b00eeb
Packit b00eeb
	g_main_loop_run (closure->loop);
Packit b00eeb
Packit b00eeb
	result = gcr_system_prompt_real_init_finish (G_ASYNC_INITABLE (initable),
Packit b00eeb
	                                             closure->result, error);
Packit b00eeb
Packit b00eeb
	g_main_context_pop_thread_default (closure->context);
Packit b00eeb
	sync_closure_free (closure);
Packit b00eeb
Packit b00eeb
	return result;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
gcr_system_prompt_initable_iface (GInitableIface *iface)
Packit b00eeb
{
Packit b00eeb
	iface->init = gcr_system_prompt_real_init;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static GVariantBuilder *
Packit b00eeb
build_dirty_properties (GcrSystemPrompt *self)
Packit b00eeb
{
Packit b00eeb
	GVariantBuilder *builder;
Packit b00eeb
	GHashTableIter iter;
Packit b00eeb
	GVariant *variant;
Packit b00eeb
	gpointer key;
Packit b00eeb
Packit b00eeb
	builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
Packit b00eeb
Packit b00eeb
	g_hash_table_iter_init (&iter, self->pv->dirty_properties);
Packit b00eeb
	while (g_hash_table_iter_next (&iter, &key, NULL)) {
Packit b00eeb
		variant = g_hash_table_lookup (self->pv->properties, key);
Packit b00eeb
		g_variant_builder_add (builder, "{sv}", (const gchar *)key, variant);
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	g_hash_table_remove_all (self->pv->dirty_properties);
Packit b00eeb
	return builder;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
on_perform_prompt_complete (GObject *source,
Packit b00eeb
                            GAsyncResult *result,
Packit b00eeb
                            gpointer user_data)
Packit b00eeb
{
Packit b00eeb
	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
Packit b00eeb
	GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (g_async_result_get_source_object (user_data));
Packit b00eeb
	CallClosure *call = g_simple_async_result_get_op_res_gpointer (res);
Packit b00eeb
	GError *error = NULL;
Packit b00eeb
	GVariant *retval;
Packit b00eeb
Packit b00eeb
	retval = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error);
Packit b00eeb
	if (error != NULL) {
Packit b00eeb
		self->pv->pending = NULL;
Packit b00eeb
		g_simple_async_result_take_error (res, error);
Packit b00eeb
		g_simple_async_result_complete (res);
Packit b00eeb
	} else {
Packit b00eeb
		g_assert (call->waiting == NULL);
Packit b00eeb
		call->waiting = g_cancellable_source_new (call->cancellable);
Packit b00eeb
		g_source_set_callback (call->waiting, (GSourceFunc)on_call_cancelled, res, NULL);
Packit b00eeb
		g_source_attach (call->waiting, call->context);
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	if (retval)
Packit b00eeb
		g_variant_unref (retval);
Packit b00eeb
Packit b00eeb
	g_object_unref (self);
Packit b00eeb
	g_object_unref (res);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
perform_prompt_async (GcrSystemPrompt *self,
Packit b00eeb
                      const gchar *type,
Packit b00eeb
                      gpointer source_tag,
Packit b00eeb
                      GCancellable *cancellable,
Packit b00eeb
                      GAsyncReadyCallback callback,
Packit b00eeb
                      gpointer user_data)
Packit b00eeb
{
Packit b00eeb
	GSimpleAsyncResult *res;
Packit b00eeb
	GcrSecretExchange *exchange;
Packit b00eeb
	GVariantBuilder *builder;
Packit b00eeb
	CallClosure *closure;
Packit b00eeb
	gchar *sent;
Packit b00eeb
Packit b00eeb
	g_return_if_fail (GCR_IS_SYSTEM_PROMPT (self));
Packit b00eeb
	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
Packit b00eeb
Packit b00eeb
	if (self->pv->pending != NULL) {
Packit b00eeb
		g_warning ("another operation is already pending on this prompt");
Packit b00eeb
		return;
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	res = g_simple_async_result_new (G_OBJECT (self), callback, user_data, source_tag);
Packit b00eeb
	closure = call_closure_new (cancellable);
Packit b00eeb
	g_simple_async_result_set_op_res_gpointer (res, closure, call_closure_free);
Packit b00eeb
Packit b00eeb
	if (self->pv->closed) {
Packit b00eeb
		g_free (self->pv->last_response);
Packit b00eeb
		self->pv->last_response = g_strdup (GCR_DBUS_PROMPT_REPLY_NONE);
Packit b00eeb
		g_simple_async_result_complete_in_idle (res);
Packit b00eeb
		g_object_unref (res);
Packit b00eeb
		return;
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	g_debug ("prompting for password");
Packit b00eeb
Packit b00eeb
	exchange = gcr_system_prompt_get_secret_exchange (self);
Packit b00eeb
	if (self->pv->received)
Packit b00eeb
		sent = gcr_secret_exchange_send (exchange, NULL, 0);
Packit b00eeb
	else
Packit b00eeb
		sent = gcr_secret_exchange_begin (exchange);
Packit b00eeb
Packit b00eeb
	closure->watch_id = g_bus_watch_name_on_connection (self->pv->connection,
Packit b00eeb
	                                                    self->pv->prompter_bus_name,
Packit b00eeb
	                                                    G_BUS_NAME_WATCHER_FLAGS_NONE,
Packit b00eeb
	                                                    on_prompter_present,
Packit b00eeb
	                                                    on_prompter_vanished,
Packit b00eeb
	                                                    res, NULL);
Packit b00eeb
Packit b00eeb
	builder = build_dirty_properties (self);
Packit b00eeb
Packit b00eeb
	/* Reregister the prompt object in the current GMainContext */
Packit b00eeb
	register_prompt_object (self, NULL);
Packit b00eeb
Packit b00eeb
	g_dbus_connection_call (self->pv->connection,
Packit b00eeb
	                        self->pv->prompter_bus_name,
Packit b00eeb
	                        GCR_DBUS_PROMPTER_OBJECT_PATH,
Packit b00eeb
	                        GCR_DBUS_PROMPTER_INTERFACE,
Packit b00eeb
	                        GCR_DBUS_PROMPTER_METHOD_PERFORM,
Packit b00eeb
	                        g_variant_new ("(osa{sv}s)", self->pv->prompt_path,
Packit b00eeb
	                                       type, builder, sent),
Packit b00eeb
	                        G_VARIANT_TYPE ("()"),
Packit b00eeb
	                        G_DBUS_CALL_FLAGS_NO_AUTO_START,
Packit b00eeb
	                        -1, cancellable,
Packit b00eeb
	                        on_perform_prompt_complete,
Packit b00eeb
	                        g_object_ref (res));
Packit b00eeb
	g_variant_builder_unref(builder);
Packit b00eeb
Packit b00eeb
	self->pv->pending = res;
Packit b00eeb
	g_free (sent);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static GcrPromptReply
Packit b00eeb
handle_last_response (GcrSystemPrompt *self)
Packit b00eeb
{
Packit b00eeb
	GcrPromptReply response;
Packit b00eeb
Packit b00eeb
	g_return_val_if_fail (self->pv->last_response != NULL,
Packit b00eeb
	                      GCR_PROMPT_REPLY_CANCEL);
Packit b00eeb
Packit b00eeb
	if (g_str_equal (self->pv->last_response, GCR_DBUS_PROMPT_REPLY_YES)) {
Packit b00eeb
		response = GCR_PROMPT_REPLY_CONTINUE;
Packit b00eeb
Packit b00eeb
	} else if (g_str_equal (self->pv->last_response, GCR_DBUS_PROMPT_REPLY_NO) ||
Packit b00eeb
	           g_str_equal (self->pv->last_response, GCR_DBUS_PROMPT_REPLY_NONE)) {
Packit b00eeb
		response = GCR_PROMPT_REPLY_CANCEL;
Packit b00eeb
Packit b00eeb
	} else {
Packit b00eeb
		g_warning ("unknown response from prompter: %s", self->pv->last_response);
Packit b00eeb
		response = GCR_PROMPT_REPLY_CANCEL;
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	return response;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
gcr_system_prompt_password_async (GcrPrompt *prompt,
Packit b00eeb
                                  GCancellable *cancellable,
Packit b00eeb
                                  GAsyncReadyCallback callback,
Packit b00eeb
                                  gpointer user_data)
Packit b00eeb
{
Packit b00eeb
	GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (prompt);
Packit b00eeb
	perform_prompt_async (self, GCR_DBUS_PROMPT_TYPE_PASSWORD,
Packit b00eeb
	                      gcr_system_prompt_password_async,
Packit b00eeb
	                      cancellable, callback, user_data);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static const gchar *
Packit b00eeb
gcr_system_prompt_password_finish (GcrPrompt *prompt,
Packit b00eeb
                                   GAsyncResult *result,
Packit b00eeb
                                   GError **error)
Packit b00eeb
{
Packit b00eeb
	GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (prompt);
Packit b00eeb
	GSimpleAsyncResult *res;
Packit b00eeb
Packit b00eeb
	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
Packit b00eeb
	                      gcr_system_prompt_password_async), FALSE);
Packit b00eeb
Packit b00eeb
	res = G_SIMPLE_ASYNC_RESULT (result);
Packit b00eeb
	if (g_simple_async_result_propagate_error (res, error))
Packit b00eeb
		return FALSE;
Packit b00eeb
Packit b00eeb
	if (handle_last_response (self) == GCR_PROMPT_REPLY_CONTINUE)
Packit b00eeb
		return gcr_secret_exchange_get_secret (self->pv->exchange, NULL);
Packit b00eeb
Packit b00eeb
	return NULL;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
gcr_system_prompt_confirm_async (GcrPrompt *prompt,
Packit b00eeb
                                 GCancellable *cancellable,
Packit b00eeb
                                 GAsyncReadyCallback callback,
Packit b00eeb
                                 gpointer user_data)
Packit b00eeb
{
Packit b00eeb
	GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (prompt);
Packit b00eeb
	perform_prompt_async (self, GCR_DBUS_PROMPT_TYPE_CONFIRM,
Packit b00eeb
	                      gcr_system_prompt_confirm_async,
Packit b00eeb
	                      cancellable, callback, user_data);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static GcrPromptReply
Packit b00eeb
gcr_system_prompt_confirm_finish (GcrPrompt *prompt,
Packit b00eeb
                                  GAsyncResult *result,
Packit b00eeb
                                  GError **error)
Packit b00eeb
{
Packit b00eeb
	GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (prompt);
Packit b00eeb
	GSimpleAsyncResult *res;
Packit b00eeb
Packit b00eeb
	g_return_val_if_fail (GCR_IS_SYSTEM_PROMPT (self), FALSE);
Packit b00eeb
	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
Packit b00eeb
	                      gcr_system_prompt_confirm_async), FALSE);
Packit b00eeb
Packit b00eeb
	res = G_SIMPLE_ASYNC_RESULT (result);
Packit b00eeb
	if (g_simple_async_result_propagate_error (res, error))
Packit b00eeb
		return FALSE;
Packit b00eeb
Packit b00eeb
	return handle_last_response (self);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
gcr_system_prompt_real_close (GcrPrompt *prompt)
Packit b00eeb
{
Packit b00eeb
	GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (prompt);
Packit b00eeb
Packit b00eeb
	/*
Packit b00eeb
	 * Setting this before calling close_async allows us to prevent firing
Packit b00eeb
	 * this signal again in a loop.
Packit b00eeb
	 */
Packit b00eeb
Packit b00eeb
	if (!self->pv->closed) {
Packit b00eeb
		self->pv->closed = TRUE;
Packit b00eeb
		perform_close (self, NULL, NULL);
Packit b00eeb
	}
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
gcr_system_prompt_prompt_iface (GcrPromptIface *iface)
Packit b00eeb
{
Packit b00eeb
	iface->prompt_password_async = gcr_system_prompt_password_async;
Packit b00eeb
	iface->prompt_password_finish = gcr_system_prompt_password_finish;
Packit b00eeb
	iface->prompt_confirm_async = gcr_system_prompt_confirm_async;
Packit b00eeb
	iface->prompt_confirm_finish = gcr_system_prompt_confirm_finish;
Packit b00eeb
	iface->prompt_close = gcr_system_prompt_real_close;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
/**
Packit b00eeb
 * gcr_system_prompt_open_async:
Packit b00eeb
 * @timeout_seconds: the number of seconds to wait to access the prompt, or -1
Packit b00eeb
 * @cancellable: optional cancellation object
Packit b00eeb
 * @callback: called when the operation completes
Packit b00eeb
 * @user_data: data to pass the callback
Packit b00eeb
 *
Packit b00eeb
 * Asynchronously open a system prompt with the default system prompter.
Packit b00eeb
 *
Packit b00eeb
 * Most system prompters only allow showing one prompt at a time, and if
Packit b00eeb
 * another prompt is shown then this method will block for up to
Packit b00eeb
 * @timeout_seconds seconds. If @timeout_seconds is equal to -1, then this
Packit b00eeb
 * will block indefinitely until the prompt can be opened. If @timeout_seconds
Packit b00eeb
 * expires, then this operation will fail with a %GCR_SYSTEM_PROMPT_IN_PROGRESS
Packit b00eeb
 * error.
Packit b00eeb
 */
Packit b00eeb
void
Packit b00eeb
gcr_system_prompt_open_async (gint timeout_seconds,
Packit b00eeb
                              GCancellable *cancellable,
Packit b00eeb
                              GAsyncReadyCallback callback,
Packit b00eeb
                              gpointer user_data)
Packit b00eeb
{
Packit b00eeb
	g_return_if_fail (timeout_seconds >= -1);
Packit b00eeb
	g_return_if_fail (cancellable == NULL || G_CANCELLABLE (cancellable));
Packit b00eeb
Packit b00eeb
	gcr_system_prompt_open_for_prompter_async (NULL, timeout_seconds,
Packit b00eeb
	                                           cancellable, callback,
Packit b00eeb
	                                           user_data);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
/**
Packit b00eeb
 * gcr_system_prompt_open_for_prompter_async:
Packit b00eeb
 * @prompter_name: (allow-none): the prompter dbus name
Packit b00eeb
 * @timeout_seconds: the number of seconds to wait to access the prompt, or -1
Packit b00eeb
 * @cancellable: optional cancellation object
Packit b00eeb
 * @callback: called when the operation completes
Packit b00eeb
 * @user_data: data to pass the callback
Packit b00eeb
 *
Packit b00eeb
 * Opens a system prompt asynchronously. If prompter_name is %NULL, then the
Packit b00eeb
 * default system prompter is used.
Packit b00eeb
 *
Packit b00eeb
 * Most system prompters only allow showing one prompt at a time, and if
Packit b00eeb
 * another prompt is shown then this method will block for up to
Packit b00eeb
 * @timeout_seconds seconds. If @timeout_seconds is equal to -1, then this
Packit b00eeb
 * will block indefinitely until the prompt can be opened. If @timeout_seconds
Packit b00eeb
 * expires, then this operation will fail with a %GCR_SYSTEM_PROMPT_IN_PROGRESS
Packit b00eeb
 * error.
Packit b00eeb
 */
Packit b00eeb
void
Packit b00eeb
gcr_system_prompt_open_for_prompter_async (const gchar *prompter_name,
Packit b00eeb
                                           gint timeout_seconds,
Packit b00eeb
                                           GCancellable *cancellable,
Packit b00eeb
                                           GAsyncReadyCallback callback,
Packit b00eeb
                                           gpointer user_data)
Packit b00eeb
{
Packit b00eeb
	g_return_if_fail (timeout_seconds >= -1);
Packit b00eeb
	g_return_if_fail (cancellable == NULL || G_CANCELLABLE (cancellable));
Packit b00eeb
Packit b00eeb
	if (prompter_name == NULL)
Packit b00eeb
		g_debug ("opening prompt");
Packit b00eeb
	else
Packit b00eeb
		g_debug ("opening prompt for prompter: %s", prompter_name);
Packit b00eeb
Packit b00eeb
	g_async_initable_new_async (GCR_TYPE_SYSTEM_PROMPT,
Packit b00eeb
	                            G_PRIORITY_DEFAULT,
Packit b00eeb
	                            cancellable,
Packit b00eeb
	                            callback,
Packit b00eeb
	                            user_data,
Packit b00eeb
	                            "timeout-seconds", timeout_seconds,
Packit b00eeb
	                            "bus-name", prompter_name,
Packit b00eeb
	                            NULL);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
/**
Packit b00eeb
 * gcr_system_prompt_open_finish:
Packit b00eeb
 * @result: the asynchronous result
Packit b00eeb
 * @error: location to place an error on failure
Packit b00eeb
 *
Packit b00eeb
 * Complete an operation to asynchronously open a system prompt.
Packit b00eeb
 *
Packit b00eeb
 * Returns: (transfer full) (type Gcr.SystemPrompt): the prompt, or %NULL if
Packit b00eeb
 *          prompt could not be opened
Packit b00eeb
 */
Packit b00eeb
GcrPrompt *
Packit b00eeb
gcr_system_prompt_open_finish (GAsyncResult *result,
Packit b00eeb
                               GError **error)
Packit b00eeb
{
Packit b00eeb
	GObject *object;
Packit b00eeb
	GObject *source_object;
Packit b00eeb
Packit b00eeb
	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
Packit b00eeb
	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
Packit b00eeb
Packit b00eeb
	source_object = g_async_result_get_source_object (result);
Packit b00eeb
	g_assert (source_object != NULL);
Packit b00eeb
Packit b00eeb
	object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object),
Packit b00eeb
	                                      result, error);
Packit b00eeb
	g_object_unref (source_object);
Packit b00eeb
Packit b00eeb
	if (object != NULL)
Packit b00eeb
		return GCR_PROMPT (object);
Packit b00eeb
	else
Packit b00eeb
		return NULL;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
/**
Packit b00eeb
 * gcr_system_prompt_open:
Packit b00eeb
 * @timeout_seconds: the number of seconds to wait to access the prompt, or -1
Packit b00eeb
 * @cancellable: optional cancellation object
Packit b00eeb
 * @error: location to place error on failure
Packit b00eeb
 *
Packit b00eeb
 * Opens a system prompt with the default prompter.
Packit b00eeb
 *
Packit b00eeb
 * Most system prompters only allow showing one prompt at a time, and if
Packit b00eeb
 * another prompt is shown then this method will block for up to
Packit b00eeb
 * @timeout_seconds seconds. If @timeout_seconds is equal to -1, then this
Packit b00eeb
 * will block indefinitely until the prompt can be opened. If @timeout_seconds
Packit b00eeb
 * expires, then this function will fail with a %GCR_SYSTEM_PROMPT_IN_PROGRESS
Packit b00eeb
 * error.
Packit b00eeb
 *
Packit b00eeb
 * Returns: (transfer full) (type Gcr.SystemPrompt): the prompt, or %NULL if
Packit b00eeb
 *          prompt could not be opened
Packit b00eeb
 */
Packit b00eeb
GcrPrompt *
Packit b00eeb
gcr_system_prompt_open (gint timeout_seconds,
Packit b00eeb
                        GCancellable *cancellable,
Packit b00eeb
                        GError **error)
Packit b00eeb
{
Packit b00eeb
	g_return_val_if_fail (timeout_seconds >= -1, NULL);
Packit b00eeb
	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
Packit b00eeb
	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
Packit b00eeb
Packit b00eeb
	return gcr_system_prompt_open_for_prompter (NULL, timeout_seconds,
Packit b00eeb
	                                            cancellable, error);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
/**
Packit b00eeb
 * gcr_system_prompt_open_for_prompter:
Packit b00eeb
 * @prompter_name: (allow-none): the prompter dbus name
Packit b00eeb
 * @timeout_seconds: the number of seconds to wait to access the prompt, or -1
Packit b00eeb
 * @cancellable: optional cancellation object
Packit b00eeb
 * @error: location to place error on failure
Packit b00eeb
 *
Packit b00eeb
 * Opens a system prompt. If prompter_name is %NULL, then the default
Packit b00eeb
 * system prompter is used.
Packit b00eeb
 *
Packit b00eeb
 * Most system prompters only allow showing one prompt at a time, and if
Packit b00eeb
 * another prompt is shown then this method will block for up to
Packit b00eeb
 * @timeout_seconds seconds. If @timeout_seconds is equal to -1, then this
Packit b00eeb
 * will block indefinitely until the prompt can be opened. If @timeout_seconds
Packit b00eeb
 * expires, then this function will fail with a %GCR_SYSTEM_PROMPT_IN_PROGRESS
Packit b00eeb
 * error.
Packit b00eeb
 *
Packit b00eeb
 * Returns: (transfer full) (type Gcr.SystemPrompt): the prompt, or %NULL if
Packit b00eeb
 *          prompt could not be opened
Packit b00eeb
 */
Packit b00eeb
GcrPrompt *
Packit b00eeb
gcr_system_prompt_open_for_prompter (const gchar *prompter_name,
Packit b00eeb
                                     gint timeout_seconds,
Packit b00eeb
                                     GCancellable *cancellable,
Packit b00eeb
                                     GError **error)
Packit b00eeb
{
Packit b00eeb
	g_return_val_if_fail (timeout_seconds >= -1, NULL);
Packit b00eeb
	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
Packit b00eeb
	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
Packit b00eeb
Packit b00eeb
	if (prompter_name == NULL)
Packit b00eeb
		g_debug ("opening prompt");
Packit b00eeb
	else
Packit b00eeb
		g_debug ("opening prompt for prompter: %s", prompter_name);
Packit b00eeb
Packit b00eeb
	return g_initable_new (GCR_TYPE_SYSTEM_PROMPT, cancellable, error,
Packit b00eeb
	                       "timeout-seconds", timeout_seconds,
Packit b00eeb
	                       "bus-name", prompter_name,
Packit b00eeb
	                       NULL);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
/**
Packit b00eeb
 * gcr_system_prompt_close:
Packit b00eeb
 * @self: the prompt
Packit b00eeb
 * @cancellable: an optional cancellation object
Packit b00eeb
 * @error: location to place an error on failure
Packit b00eeb
 *
Packit b00eeb
 * Close this prompt. After calling this function, no further prompts will
Packit b00eeb
 * succeed on this object. The prompt object is not unreferenced by this
Packit b00eeb
 * function, and you must unreference it once done.
Packit b00eeb
 *
Packit b00eeb
 * This call may block, use the gcr_system_prompt_close_async() to perform
Packit b00eeb
 * this action indefinitely.
Packit b00eeb
 *
Packit b00eeb
 * Whether or not this function returns %TRUE, the system prompt object is
Packit b00eeb
 * still closed and may not be further used.
Packit b00eeb
 *
Packit b00eeb
 * Returns: whether close was cleanly completed
Packit b00eeb
 */
Packit b00eeb
gboolean
Packit b00eeb
gcr_system_prompt_close (GcrSystemPrompt *self,
Packit b00eeb
                         GCancellable *cancellable,
Packit b00eeb
                         GError **error)
Packit b00eeb
{
Packit b00eeb
	SyncClosure *closure;
Packit b00eeb
	gboolean result;
Packit b00eeb
Packit b00eeb
	closure = sync_closure_new ();
Packit b00eeb
	g_main_context_push_thread_default (closure->context);
Packit b00eeb
Packit b00eeb
	gcr_system_prompt_close_async (self, cancellable,
Packit b00eeb
	                               on_sync_result, closure);
Packit b00eeb
Packit b00eeb
	g_main_loop_run (closure->loop);
Packit b00eeb
Packit b00eeb
	result = gcr_system_prompt_close_finish (self, closure->result, error);
Packit b00eeb
Packit b00eeb
	g_main_context_pop_thread_default (closure->context);
Packit b00eeb
	sync_closure_free (closure);
Packit b00eeb
Packit b00eeb
	return result;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
/**
Packit b00eeb
 * gcr_system_prompt_close_async:
Packit b00eeb
 * @self: the prompt
Packit b00eeb
 * @cancellable: an optional cancellation object
Packit b00eeb
 * @callback: called when the operation completes
Packit b00eeb
 * @user_data: data to pass to the callback
Packit b00eeb
 *
Packit b00eeb
 * Close this prompt asynchronously. After calling this function, no further
Packit b00eeb
 * methods may be called on this object. The prompt object is not unreferenced
Packit b00eeb
 * by this function, and you must unreference it once done.
Packit b00eeb
 *
Packit b00eeb
 * This call returns immediately and completes asynchronously.
Packit b00eeb
 */
Packit b00eeb
void
Packit b00eeb
gcr_system_prompt_close_async (GcrSystemPrompt *self,
Packit b00eeb
                               GCancellable *cancellable,
Packit b00eeb
                               GAsyncReadyCallback callback,
Packit b00eeb
                               gpointer user_data)
Packit b00eeb
{
Packit b00eeb
	GSimpleAsyncResult *res;
Packit b00eeb
	CallClosure *closure;
Packit b00eeb
Packit b00eeb
	g_return_if_fail (GCR_SYSTEM_PROMPT (self));
Packit b00eeb
	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
Packit b00eeb
Packit b00eeb
	res = g_simple_async_result_new (NULL, callback, user_data,
Packit b00eeb
	                                 gcr_system_prompt_close_async);
Packit b00eeb
	closure = call_closure_new (cancellable);
Packit b00eeb
	closure->context = g_main_context_get_thread_default ();
Packit b00eeb
	if (closure->context != NULL)
Packit b00eeb
		g_main_context_ref (closure->context);
Packit b00eeb
	g_simple_async_result_set_op_res_gpointer (res, closure, call_closure_free);
Packit b00eeb
Packit b00eeb
	perform_close (self, res, closure->cancellable);
Packit b00eeb
Packit b00eeb
	g_object_unref (res);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
/**
Packit b00eeb
 * gcr_system_prompt_close_finish:
Packit b00eeb
 * @self: the prompt
Packit b00eeb
 * @result: asynchronous operation result
Packit b00eeb
 * @error: location to place an error on failure
Packit b00eeb
 *
Packit b00eeb
 * Complete operation to close this prompt.
Packit b00eeb
 *
Packit b00eeb
 * Whether or not this function returns %TRUE, the system prompt object is
Packit b00eeb
 * still closed and may not be further used.
Packit b00eeb
 *
Packit b00eeb
 * Returns: whether close was cleanly completed
Packit b00eeb
 */
Packit b00eeb
gboolean
Packit b00eeb
gcr_system_prompt_close_finish (GcrSystemPrompt *self,
Packit b00eeb
                                GAsyncResult *result,
Packit b00eeb
                                GError **error)
Packit b00eeb
{
Packit b00eeb
	g_return_val_if_fail (GCR_IS_SYSTEM_PROMPT (self), FALSE);
Packit b00eeb
	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
Packit b00eeb
Packit b00eeb
	g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL,
Packit b00eeb
	                      gcr_system_prompt_close_async), FALSE);
Packit b00eeb
Packit b00eeb
	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
Packit b00eeb
		return FALSE;
Packit b00eeb
Packit b00eeb
	return TRUE;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static const GDBusErrorEntry SYSTEM_PROMPT_ERRORS[] = {
Packit b00eeb
	{ GCR_SYSTEM_PROMPT_IN_PROGRESS, GCR_DBUS_PROMPT_ERROR_IN_PROGRESS },
Packit b00eeb
};
Packit b00eeb
Packit b00eeb
GQuark
Packit b00eeb
gcr_system_prompt_error_get_domain (void)
Packit b00eeb
{
Packit b00eeb
	static volatile gsize quark_volatile = 0;
Packit b00eeb
	g_dbus_error_register_error_domain ("gcr-system-prompt-error-domain",
Packit b00eeb
	                                    &quark_volatile,
Packit b00eeb
	                                    SYSTEM_PROMPT_ERRORS,
Packit b00eeb
	                                    G_N_ELEMENTS (SYSTEM_PROMPT_ERRORS));
Packit b00eeb
	G_STATIC_ASSERT (G_N_ELEMENTS (SYSTEM_PROMPT_ERRORS) == GCR_SYSTEM_PROMPT_IN_PROGRESS);
Packit b00eeb
	return (GQuark) quark_volatile;
Packit b00eeb
}