summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gtk/gtkmarshalers.list1
-rw-r--r--gtk/gtkprintbackend.c46
-rw-r--r--gtk/gtkprintbackend.h9
-rw-r--r--modules/printbackends/cups/Makefile.am6
-rw-r--r--modules/printbackends/cups/gtkcupssecretsutils.c1044
-rw-r--r--modules/printbackends/cups/gtkcupssecretsutils.h41
-rw-r--r--modules/printbackends/cups/gtkprintbackendcups.c169
7 files changed, 1292 insertions, 24 deletions
diff --git a/gtk/gtkmarshalers.list b/gtk/gtkmarshalers.list
index ab6983dbe8..c6f12a3d81 100644
--- a/gtk/gtkmarshalers.list
+++ b/gtk/gtkmarshalers.list
@@ -124,7 +124,6 @@ VOID:UINT,STRING,UINT
VOID:UINT,UINT
VOID:VOID
OBJECT:OBJECT,INT,INT
-VOID:POINTER,POINTER,POINTER,POINTER,STRING
VOID:OBJECT,STRING,POINTER,POINTER
INT:INT
VOID:POINTER,STRING,INT
diff --git a/gtk/gtkprintbackend.c b/gtk/gtkprintbackend.c
index 3de625f304..31a181bddc 100644
--- a/gtk/gtkprintbackend.c
+++ b/gtk/gtkprintbackend.c
@@ -47,6 +47,7 @@ struct _GtkPrintBackendPrivate
GtkPrintBackendStatus status;
char **auth_info_required;
char **auth_info;
+ gboolean store_auth_info;
};
enum {
@@ -360,7 +361,8 @@ static void request_password (GtkPrintBack
gpointer auth_info_default,
gpointer auth_info_display,
gpointer auth_info_visible,
- const gchar *prompt);
+ const gchar *prompt,
+ gboolean can_store_auth_info);
static void
gtk_print_backend_class_init (GtkPrintBackendClass *class)
@@ -437,9 +439,9 @@ gtk_print_backend_class_init (GtkPrintBackendClass *class)
G_TYPE_FROM_CLASS (class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GtkPrintBackendClass, request_password),
- NULL, NULL,
- _gtk_marshal_VOID__POINTER_POINTER_POINTER_POINTER_STRING,
- G_TYPE_NONE, 5, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_STRING);
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 6, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER,
+ G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_BOOLEAN);
}
static void
@@ -666,12 +668,24 @@ gtk_print_backend_print_stream (GtkPrintBackend *backend,
void
gtk_print_backend_set_password (GtkPrintBackend *backend,
gchar **auth_info_required,
- gchar **auth_info)
+ gchar **auth_info,
+ gboolean store_auth_info)
{
g_return_if_fail (GTK_IS_PRINT_BACKEND (backend));
if (GTK_PRINT_BACKEND_GET_CLASS (backend)->set_password)
- GTK_PRINT_BACKEND_GET_CLASS (backend)->set_password (backend, auth_info_required, auth_info);
+ GTK_PRINT_BACKEND_GET_CLASS (backend)->set_password (backend,
+ auth_info_required,
+ auth_info,
+ store_auth_info);
+}
+
+static void
+store_auth_info_toggled (GtkCheckButton *chkbtn,
+ gpointer user_data)
+{
+ gboolean *data = (gboolean *) user_data;
+ *data = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (chkbtn));
}
static void
@@ -698,9 +712,9 @@ password_dialog_response (GtkWidget *dialog,
gint i;
if (response_id == GTK_RESPONSE_OK)
- gtk_print_backend_set_password (backend, priv->auth_info_required, priv->auth_info);
+ gtk_print_backend_set_password (backend, priv->auth_info_required, priv->auth_info, priv->store_auth_info);
else
- gtk_print_backend_set_password (backend, priv->auth_info_required, NULL);
+ gtk_print_backend_set_password (backend, priv->auth_info_required, NULL, FALSE);
for (i = 0; i < g_strv_length (priv->auth_info_required); i++)
if (priv->auth_info[i] != NULL)
@@ -725,10 +739,11 @@ request_password (GtkPrintBackend *backend,
gpointer auth_info_default,
gpointer auth_info_display,
gpointer auth_info_visible,
- const gchar *prompt)
+ const gchar *prompt,
+ gboolean can_store_auth_info)
{
GtkPrintBackendPrivate *priv = backend->priv;
- GtkWidget *dialog, *box, *main_box, *label, *icon, *vbox, *entry;
+ GtkWidget *dialog, *box, *main_box, *label, *icon, *vbox, *entry, *chkbtn;
GtkWidget *focus = NULL;
GtkWidget *content_area;
gchar *markup;
@@ -742,6 +757,7 @@ request_password (GtkPrintBackend *backend,
priv->auth_info_required = g_strdupv (ai_required);
length = g_strv_length (ai_required);
priv->auth_info = g_new0 (gchar *, length);
+ priv->store_auth_info = FALSE;
dialog = gtk_dialog_new_with_buttons ( _("Authentication"), NULL, GTK_DIALOG_MODAL,
_("_Cancel"), GTK_RESPONSE_CANCEL,
@@ -812,6 +828,16 @@ request_password (GtkPrintBackend *backend,
}
}
+ if (can_store_auth_info)
+ {
+ chkbtn = gtk_check_button_new_with_mnemonic (_("_Remember password"));
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (chkbtn), FALSE);
+ gtk_box_pack_start (GTK_BOX (vbox), chkbtn, FALSE, FALSE, 6);
+ g_signal_connect (chkbtn, "toggled",
+ G_CALLBACK (store_auth_info_toggled),
+ &(priv->store_auth_info));
+ }
+
if (focus != NULL)
{
gtk_widget_grab_focus (focus);
diff --git a/gtk/gtkprintbackend.h b/gtk/gtkprintbackend.h
index 74bd291fe1..f4524e8965 100644
--- a/gtk/gtkprintbackend.h
+++ b/gtk/gtkprintbackend.h
@@ -124,12 +124,14 @@ struct _GtkPrintBackendClass
gpointer auth_info_default,
gpointer auth_info_display,
gpointer auth_info_visible,
- const gchar *prompt);
+ const gchar *prompt,
+ gboolean can_store_auth_info);
/* not a signal */
void (*set_password) (GtkPrintBackend *backend,
gchar **auth_info_required,
- gchar **auth_info);
+ gchar **auth_info,
+ gboolean store_auth_info);
/* Padding for future expansion */
void (*_gtk_reserved1) (void);
@@ -162,7 +164,8 @@ void gtk_print_backend_destroy (GtkPrintBackend *pri
GDK_AVAILABLE_IN_ALL
void gtk_print_backend_set_password (GtkPrintBackend *backend,
gchar **auth_info_required,
- gchar **auth_info);
+ gchar **auth_info,
+ gboolean can_store_auth_info);
/* Backend-only functions for GtkPrintBackend */
diff --git a/modules/printbackends/cups/Makefile.am b/modules/printbackends/cups/Makefile.am
index e9d4c2fdd1..33520bea48 100644
--- a/modules/printbackends/cups/Makefile.am
+++ b/modules/printbackends/cups/Makefile.am
@@ -29,12 +29,14 @@ backend_LTLIBRARIES = libprintbackend-cups.la
libprintbackend_cups_la_SOURCES = \
gtkprintbackendcups.c \
gtkprintercups.c \
- gtkcupsutils.c
+ gtkcupsutils.c \
+ gtkcupssecretsutils.c
noinst_HEADERS = \
gtkprintbackendcups.h \
gtkprintercups.h \
- gtkcupsutils.h
+ gtkcupsutils.h \
+ gtkcupssecretsutils.h
libprintbackend_cups_la_LDFLAGS = -avoid-version -module $(no_undefined)
libprintbackend_cups_la_LIBADD = $(LDADDS) $(CUPS_LIBS)
diff --git a/modules/printbackends/cups/gtkcupssecretsutils.c b/modules/printbackends/cups/gtkcupssecretsutils.c
new file mode 100644
index 0000000000..895e4bbcdb
--- /dev/null
+++ b/modules/printbackends/cups/gtkcupssecretsutils.c
@@ -0,0 +1,1044 @@
+/* gtkcupssecretsutils.h: Helper to use a secrets service for printer passwords
+ * Copyright (C) 2014, Intevation GmbH
+ *
+ * This library 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 of the License, or (at your option) any later version.
+ *
+ * This 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <gio/gio.h>
+#include <string.h>
+
+#include <gtk/gtk.h>
+
+#include "gtkcupssecretsutils.h"
+
+#define SECRETS_BUS "org.freedesktop.secrets"
+#define SECRETS_IFACE(interface) "org.freedesktop.Secret."interface
+#define SECRETS_PATH "/org/freedesktop/secrets"
+#define SECRETS_TIMEOUT 5000
+
+typedef enum
+{
+ SECRETS_SERVICE_ACTION_QUERY,
+ SECRETS_SERVICE_ACTION_STORE
+} SecretsServiceAction;
+
+typedef struct
+{
+ GDBusConnection *dbus_connection;
+ SecretsServiceAction action;
+ gchar **auth_info,
+ **auth_info_labels,
+ **auth_info_required,
+ *printer_uri,
+ *session_path,
+ *collection_path;
+ GDBusProxy *item_proxy;
+ guint prompt_subscription;
+} SecretsServiceData;
+
+/**
+ * create_attributes:
+ * @printer_uri: URI for the printer
+ * @additional_labels: Optional labels for additional attributes
+ * @additional_attrs: Optional additional attributes
+ *
+ * Creates a GVariant dictionary with key / value pairs that
+ * can be used to identify a secret item.
+ *
+ * Returns: A GVariant dictionary of string pairs or NULL on error.
+ */
+static GVariant *
+create_attributes (const gchar *printer_uri,
+ gchar **additional_attrs,
+ gchar **additional_labels)
+{
+ GVariantBuilder *attr_builder = NULL;
+ GVariant *ret = NULL;
+
+ if (printer_uri == NULL)
+ {
+ GTK_NOTE (PRINTING,
+ g_print ("create_attributes called with invalid parameters.\n"));
+ return NULL;
+ }
+
+ attr_builder = g_variant_builder_new (G_VARIANT_TYPE_DICTIONARY);
+ /* The printer uri is the main identifying part */
+ g_variant_builder_add (attr_builder, "{ss}", "uri", printer_uri);
+
+ if (additional_labels != NULL)
+ {
+ int i;
+ for (i = 0; additional_labels[i] != NULL; i++)
+ {
+ g_variant_builder_add (attr_builder, "{ss}",
+ additional_labels[i],
+ additional_attrs[i]);
+ }
+ }
+
+ ret = g_variant_builder_end (attr_builder);
+ g_variant_builder_unref (attr_builder);
+
+ return ret;
+}
+
+static void
+get_secret_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GTask *task;
+ SecretsServiceData *task_data;
+ GError *error = NULL;
+ GVariant *output,
+ *attributes;
+ gchar **auth_info = NULL,
+ *key = NULL,
+ *value = NULL;
+ GVariantIter *iter = NULL;
+ guint i;
+ gint pw_field = -1;
+
+ task = user_data;
+ task_data = g_task_get_task_data (task);
+
+ output = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object),
+ res,
+ &error);
+ if (output == NULL)
+ {
+ g_task_return_error (task, error);
+ return;
+ }
+
+ attributes = g_dbus_proxy_get_cached_property (task_data->item_proxy,
+ "Attributes");
+ if (attributes == NULL)
+ {
+ GTK_NOTE (PRINTING, g_print ("Failed to lookup attributes.\n"));
+ g_variant_unref (output);
+ g_task_return_pointer (task, NULL, NULL);
+ return;
+ }
+
+ /* Iterate over the attributes to fill the auth info */
+ g_variant_get (attributes, "a{ss}", &iter);
+
+ auth_info = g_new0 (gchar *,
+ g_strv_length (task_data->auth_info_required) + 1);
+
+ while (g_variant_iter_loop (iter, "{ss}", &key, &value))
+ {
+ /* Match attributes with required auth info */
+ for (i = 0; task_data->auth_info_required[i] != NULL; i++)
+ {
+ if ((strcmp (key, "user") == 0 ||
+ strcmp (key, "username") == 0) &&
+ strcmp (task_data->auth_info_required[i],
+ "username") == 0)
+ {
+ auth_info[i] = g_strdup (value);
+ }
+ else if (strcmp (key, "domain") == 0 &&
+ strcmp (task_data->auth_info_required[i], "domain") == 0)
+ {
+ auth_info[i] = g_strdup (value);
+ }
+ else if ((strcmp (key, "hostname") == 0 ||
+ strcmp (key, "server") == 0 ) &&
+ strcmp (task_data->auth_info_required[i], "hostname") == 0)
+ {
+ auth_info[i] = g_strdup (value);
+ }
+ else if (strcmp (task_data->auth_info_required[i], "password") == 0)
+ {
+ pw_field = i;
+ }
+ }
+ }
+
+ if (pw_field == -1)
+ {
+ /* should not happen... */
+ GTK_NOTE (PRINTING, g_print ("No password required?.\n"));
+ g_variant_unref (output);
+ goto fail;
+ }
+ else
+ {
+ GVariant *secret,
+ *s_value;
+ gconstpointer ba_passwd = NULL;
+ gsize len = 0;
+
+ secret = g_variant_get_child_value (output, 0);
+ g_variant_unref (output);
+ if (secret == NULL || g_variant_n_children (secret) != 4)
+ {
+ GTK_NOTE (PRINTING, g_print ("Get secret response invalid.\n"));
+ if (secret != NULL)
+ g_variant_unref (secret);
+ goto fail;
+ }
+ s_value = g_variant_get_child_value (secret, 2);
+ ba_passwd = g_variant_get_fixed_array (s_value,
+ &len,
+ sizeof (guchar));
+
+ g_variant_unref (secret);
+
+ if (ba_passwd == NULL || strlen (ba_passwd) > len + 1)
+ {
+ /* No secret or the secret is not a zero terminated value */
+ GTK_NOTE (PRINTING, g_print ("Invalid secret.\n"));
+ g_variant_unref (s_value);
+ goto fail;
+ }
+
+ auth_info[pw_field] = g_strndup (ba_passwd, len);
+ g_variant_unref (s_value);
+ }
+
+ for (i = 0; task_data->auth_info_required[i] != NULL; i++)
+ {
+ if (auth_info[i] == NULL)
+ {
+ /* Error out if we did not find everything */
+ GTK_NOTE (PRINTING, g_print ("Failed to lookup required attribute: %s.\n",
+ task_data->auth_info_required[i]));
+ goto fail;
+ }
+ }
+
+ g_task_return_pointer (task, auth_info, NULL);
+ return;
+
+fail:
+ /* Error out */
+ GTK_NOTE (PRINTING, g_print ("Failed to lookup secret.\n"));
+ for (i = 0; i < g_strv_length (task_data->auth_info_required); i++)
+ {
+ /* Not all fields of auth_info are neccessarily written so we can not
+ use strfreev here */
+ g_free (auth_info[i]);
+ }
+ g_free (auth_info);
+ g_task_return_pointer (task, NULL, NULL);
+}
+
+static void
+create_item_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GTask *task;
+ GError *error = NULL;
+ GVariant *output;
+ gchar *item = NULL;
+
+ task = user_data;
+
+ output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object),
+ res,
+ &error);
+ if (output == NULL)
+ {
+ g_task_return_error (task, error);
+ return;
+ }
+
+ g_variant_get (output, "(&o&o)", &item, NULL);
+ if (item != NULL && strlen (item) > 1)
+ {
+ GTK_NOTE (PRINTING, g_print ("Successfully stored auth info.\n"));
+ g_task_return_pointer (task, NULL, NULL);
+ return;
+ }
+ g_variant_unref (output);
+}
+
+static void
+do_store_auth_info (GTask *task)
+{
+ GVariant *attributes = NULL,
+ *properties = NULL,
+ *secret = NULL;
+ gchar **additional_attrs = NULL,
+ **additional_labels = NULL,
+ *password = NULL;
+ SecretsServiceData *task_data = g_task_get_task_data (task);
+ guint i,
+ length,
+ additional_count = 0;
+ GVariantBuilder *prop_builder = NULL;
+
+ length = g_strv_length (task_data->auth_info_labels);
+
+ additional_attrs = g_new0 (gchar *, length + 1);
+ additional_labels = g_new0 (gchar *, length + 1);
+ /* The labels user and server are chosen to be compatible with
+ the attributes used by system-config-printer */
+ for (i = 0; task_data->auth_info_labels[i] != NULL; i++)
+ {
+ if (g_strcmp0 (task_data->auth_info_labels[i], "username") == 0)
+ {
+ additional_attrs[additional_count] = task_data->auth_info[i];
+ additional_labels[additional_count++] = "user";
+ }
+ else if (g_strcmp0 (task_data->auth_info_labels[i], "hostname") == 0)
+ {
+ additional_attrs[additional_count] = task_data->auth_info[i];
+ additional_labels[additional_count++] = "server";
+ }
+ else if (g_strcmp0 (task_data->auth_info_labels[i], "password") == 0)
+ {
+ password = task_data->auth_info[i];
+ }
+ }
+
+ attributes = create_attributes (task_data->printer_uri,
+ additional_attrs,
+ additional_labels);
+ g_free (additional_labels);
+ g_free (additional_attrs);
+ if (attributes == NULL)
+ {
+ GTK_NOTE (PRINTING, g_print ("Failed to create attributes.\n"));
+ g_task_return_pointer (task, NULL, NULL);
+ return;
+ }
+
+ if (password == NULL)
+ {
+ GTK_NOTE (PRINTING, g_print ("No secret to store.\n"));
+ g_task_return_pointer (task, NULL, NULL);
+ return;
+ }
+
+ prop_builder = g_variant_builder_new (G_VARIANT_TYPE_DICTIONARY);
+
+ g_variant_builder_add (prop_builder, "{sv}", SECRETS_IFACE ("Item.Label"),
+ g_variant_new_string (task_data->printer_uri));
+ g_variant_builder_add (prop_builder, "{sv}", SECRETS_IFACE ("Item.Attributes"),
+ attributes);
+
+ properties = g_variant_builder_end (prop_builder);
+
+ g_variant_builder_unref (prop_builder);
+
+ secret = g_variant_new ("(oay@ays)",
+ task_data->session_path,
+ NULL,
+ g_variant_new_bytestring (password),
+ "text/plain");
+
+ g_dbus_connection_call (task_data->dbus_connection,
+ SECRETS_BUS,
+ task_data->collection_path,
+ SECRETS_IFACE ("Collection"),
+ "CreateItem",
+ g_variant_new ("(@a{sv}@(oayays)b)",
+ properties,
+ secret,
+ TRUE),
+ G_VARIANT_TYPE ("(oo)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ SECRETS_TIMEOUT,
+ g_task_get_cancellable (task),
+ create_item_cb,
+ task);
+}
+
+static void
+prompt_completed_cb (GDBusConnection *connection,
+ const gchar *sender_name,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *signal_name,
+ GVariant *parameters,
+ gpointer user_data)
+{
+ GTask *task;
+ SecretsServiceData *task_data;
+ GVariant *dismissed;
+ gboolean is_dismissed = TRUE;
+
+ task = user_data;
+ task_data = g_task_get_task_data (task);
+
+ g_dbus_connection_signal_unsubscribe (task_data->dbus_connection,
+ task_data->prompt_subscription);
+ task_data->prompt_subscription = 0;
+
+ dismissed = g_variant_get_child_value (parameters, 0);
+
+ if (dismissed == NULL)
+ {
+ GTK_NOTE (PRINTING, g_print ("Invalid prompt signal.\n"));
+ g_task_return_pointer (task, NULL, NULL);
+ return;
+ }
+
+ g_variant_get (dismissed, "b", &is_dismissed);
+ g_variant_unref (dismissed);
+
+ if (is_dismissed)
+ {
+ GTK_NOTE (PRINTING, g_print ("Collection unlock dismissed.\n"));
+ g_task_return_pointer (task, NULL, NULL);
+ return;
+ }
+
+ /* Prompt successfull, proceed to get or store secret */
+ switch (task_data->action)
+ {
+ case SECRETS_SERVICE_ACTION_STORE:
+ do_store_auth_info (task);
+ break;
+
+ case SECRETS_SERVICE_ACTION_QUERY:
+ g_dbus_proxy_call (task_data->item_proxy,
+ "GetSecret",
+ g_variant_new ("(o)",
+ task_data->session_path),
+ G_DBUS_CALL_FLAGS_NONE,
+ SECRETS_TIMEOUT,
+ g_task_get_cancellable (task),
+ get_secret_cb,
+ task);
+ break;
+ }
+}
+
+static void
+prompt_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GTask *task;
+ SecretsServiceData *task_data;
+ GError *error = NULL;
+ GVariant *output;
+
+ task = user_data;
+ task_data = g_task_get_task_data (task);
+
+ output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object),
+ res,
+ &error);
+ if (output == NULL)
+ {
+ g_task_return_error (task, error);
+ return;
+ }
+
+ g_variant_unref (output);
+
+ /* Connect to the prompt's completed signal */
+ task_data->prompt_subscription =
+ g_dbus_connection_signal_subscribe (task_data->dbus_connection,
+ NULL,
+ SECRETS_IFACE ("Prompt"),
+ "Completed",
+ NULL,
+ NULL,
+ G_DBUS_SIGNAL_FLAGS_NONE,
+ prompt_completed_cb,
+ task,
+ NULL);
+}
+
+static void
+unlock_collection_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GTask *task;
+ SecretsServiceData *task_data;
+ GError *error = NULL;
+ GVariant *output;
+ const gchar *prompt_path;
+
+ task = user_data;
+ task_data = g_task_get_task_data (task);
+
+ output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object),
+ res,
+ &error);
+ if (output == NULL)
+ {
+ g_task_return_error (task, error);
+ return;
+ }
+
+ g_variant_get (output, "(@ao&o)", NULL, &prompt_path);
+
+ if (prompt_path != NULL && strlen (prompt_path) > 1)
+ {
+ g_dbus_connection_call (task_data->dbus_connection,
+ SECRETS_BUS,
+ prompt_path,
+ SECRETS_IFACE ("Prompt"),
+ "Prompt",
+ g_variant_new ("(s)", "0"),
+ G_VARIANT_TYPE ("()"),
+ G_DBUS_CALL_FLAGS_NONE,
+ SECRETS_TIMEOUT,
+ g_task_get_cancellable (task),
+ prompt_cb,
+ task);
+ }
+ else
+ {
+ switch (task_data->action)
+ {
+ case SECRETS_SERVICE_ACTION_STORE:
+ do_store_auth_info (task);
+ break;
+
+ case SECRETS_SERVICE_ACTION_QUERY:
+ /* Prompt successfull proceed to get secret */
+ g_dbus_proxy_call (task_data->item_proxy,
+ "GetSecret",
+ g_variant_new ("(o)",
+ task_data->session_path),
+ G_DBUS_CALL_FLAGS_NONE,
+ SECRETS_TIMEOUT,
+ g_task_get_cancellable (task),
+ get_secret_cb,
+ task);
+ break;
+ }
+ }
+ g_variant_unref (output);
+}
+
+static void
+unlock_read_alias_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GTask *task;
+ SecretsServiceData *task_data;
+ GError *error = NULL;
+ GVariant *output,
+ *subresult;
+ gsize path_len = 0;
+ const gchar *collection_path;
+
+ task = user_data;
+ task_data = g_task_get_task_data (task);
+
+ output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object),
+ res,
+ &error);
+ if (output == NULL)
+ {
+ g_task_return_error (task, error);
+ return;
+ }
+
+ subresult = g_variant_get_child_value (output, 0);
+ g_variant_unref (output);
+
+ if (subresult == NULL)
+ {
+ GTK_NOTE (PRINTING, g_print ("Invalid ReadAlias response.\n"));
+ g_task_return_pointer (task, NULL, NULL);
+ return;
+ }
+
+ collection_path = g_variant_get_string (subresult, &path_len);
+
+ const gchar * const to_unlock[] =
+ {
+ collection_path, NULL
+ };
+
+ task_data->collection_path = g_strdup (collection_path);
+
+ g_dbus_connection_call (task_data->dbus_connection,
+ SECRETS_BUS,
+ SECRETS_PATH,
+ SECRETS_IFACE ("Service"),
+ "Unlock",
+ g_variant_new ("(^ao)", to_unlock),
+ G_VARIANT_TYPE ("(aoo)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ SECRETS_TIMEOUT,
+ g_task_get_cancellable (task),
+ unlock_collection_cb,
+ task);
+
+ g_variant_unref (subresult);
+}
+
+static void
+item_proxy_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GTask *task;
+ SecretsServiceData *task_data;
+ GError *error = NULL;
+ GDBusProxy *item_proxy;
+ GVariant *locked;
+ gboolean is_locked;
+
+ task = user_data;
+ task_data = g_task_get_task_data (task);
+
+ item_proxy = g_dbus_proxy_new_finish (res,
+ &error);
+ if (item_proxy == NULL)
+ {
+ g_task_return_error (task, error);
+ return;
+ }
+
+ task_data->item_proxy = item_proxy;
+
+ locked = g_dbus_proxy_get_cached_property (item_proxy, "Locked");
+
+ if (locked == NULL)
+ {
+ GTK_NOTE (PRINTING, g_print ("Failed to look up \"Locked\" property on item.\n"));
+ g_task_return_pointer (task, NULL, NULL);
+ return;
+ }
+
+ g_variant_get (locked, "b", &is_locked);
+ g_variant_unref (locked);
+
+ if (is_locked)
+ {
+ /* Go down the unlock -> lookup path */
+ g_dbus_connection_call (task_data->dbus_connection,
+ SECRETS_BUS,
+ SECRETS_PATH,
+ SECRETS_IFACE ("Service"),
+ "ReadAlias",
+ g_variant_new ("(s)", "default"),
+ G_VARIANT_TYPE ("(o)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ SECRETS_TIMEOUT,
+ g_task_get_cancellable (task),
+ unlock_read_alias_cb,
+ task);
+ return;
+ }
+
+ /* Unlocked proceed to get or store secret */
+ switch (task_data->action)
+ {
+ case SECRETS_SERVICE_ACTION_STORE:
+ do_store_auth_info (task);
+ break;
+
+ case SECRETS_SERVICE_ACTION_QUERY:
+ g_dbus_proxy_call (item_proxy,
+ "GetSecret",
+ g_variant_new ("(o)",
+ task_data->session_path),
+ G_DBUS_CALL_FLAGS_NONE,
+ SECRETS_TIMEOUT,
+ g_task_get_cancellable (task),
+ get_secret_cb,
+ task);
+ break;
+ }
+}
+
+static void
+search_items_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GTask *task;
+ SecretsServiceData *task_data;
+ GError *error = NULL;
+ GVariant *output;
+ gsize array_cnt,
+ i;
+ gboolean found_item = FALSE;
+
+ task = user_data;
+ task_data = g_task_get_task_data (task);
+
+ output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object),
+ res,
+ &error);
+ if (output == NULL)
+ {
+ g_task_return_error (task, error);
+ return;
+ }
+
+ array_cnt = g_variant_n_children (output);
+
+ for (i = 0; i < array_cnt; i++)
+ {
+ GVariant * const item_paths = g_variant_get_child_value (output, i);
+ const gchar **items = NULL;
+
+ if (item_paths == NULL)
+ {
+ GTK_NOTE (PRINTING,
+ g_print ("SearchItems returned invalid result.\n"));
+ continue;
+ }
+
+ items = g_variant_get_objv (item_paths, NULL);
+
+ if (*items == NULL)
+ {
+ g_variant_unref (item_paths);
+ g_free ((gpointer) items);
+ continue;
+ }
+
+ /* Access the first found item. */
+ found_item = TRUE;
+ g_dbus_proxy_new (task_data->dbus_connection,
+ G_DBUS_PROXY_FLAGS_NONE,
+ NULL,
+ SECRETS_BUS,
+ *items,
+ SECRETS_IFACE ("Item"),
+ g_task_get_cancellable (task),
+ item_proxy_cb,
+ task);
+ g_free ((gpointer) items);
+ g_variant_unref (item_paths);
+ break;
+ }
+ g_variant_unref (output);
+
+ if (!found_item)
+ {
+ GTK_NOTE (PRINTING, g_print ("No match found in secrets service.\n"));
+ g_task_return_pointer (task, NULL, NULL);
+ return;
+ }
+}
+
+static void
+open_session_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GTask *task;
+ GVariant *output,
+ *session_variant;
+ SecretsServiceData *task_data;
+ GError *error = NULL;
+
+ task = user_data;
+ task_data = g_task_get_task_data (task);
+
+ output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object),
+ res,
+ &error);
+ if (output == NULL)
+ {
+ g_task_return_error (task, error);
+ return;
+ }
+
+ session_variant = g_variant_get_child_value (output, 1);
+
+ if (session_variant == NULL)
+ {
+ GTK_NOTE (PRINTING, g_print ("Invalid session path response.\n"));
+ g_variant_unref (output);
+ g_task_return_pointer (task, NULL, NULL);
+ return;
+ }
+
+ task_data->session_path = g_variant_dup_string (session_variant, NULL);
+
+ if (task_data->session_path == NULL)
+ {
+ GTK_NOTE (PRINTING, g_print ("Invalid session path string value.\n"));
+ g_variant_unref (session_variant);
+ g_variant_unref (output);
+ g_task_return_pointer (task, NULL, NULL);
+ return;
+ }
+
+ g_variant_unref (session_variant);
+ g_variant_unref (output);
+
+ switch (task_data->action)
+ {
+ case SECRETS_SERVICE_ACTION_QUERY:
+ {
+ /* Search for the secret item */
+ GVariant *secrets_attrs;
+
+ secrets_attrs = create_attributes (task_data->printer_uri, NULL, NULL);
+ if (secrets_attrs == NULL)
+ {
+ GTK_NOTE (PRINTING, g_print ("Failed to create attributes.\n"));
+ g_task_return_pointer (task, NULL, NULL);
+ return;
+ }
+
+ g_dbus_connection_call (task_data->dbus_connection,
+ SECRETS_BUS,
+ SECRETS_PATH,
+ SECRETS_IFACE ("Service"),
+ "SearchItems",
+ g_variant_new ("(@a{ss})", secrets_attrs),
+ G_VARIANT_TYPE ("(aoao)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ SECRETS_TIMEOUT,
+ g_task_get_cancellable (task),
+ search_items_cb,
+ task);
+ break;
+ }
+
+ case SECRETS_SERVICE_ACTION_STORE:
+ {
+ /* Look up / unlock the default collection for storing */
+ g_dbus_connection_call (task_data->dbus_connection,
+ SECRETS_BUS,
+ SECRETS_PATH,
+ SECRETS_IFACE ("Service"),
+ "ReadAlias",
+ g_variant_new ("(s)", "default"),
+ G_VARIANT_TYPE ("(o)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ SECRETS_TIMEOUT,
+ g_task_get_cancellable (task),
+ unlock_read_alias_cb,
+ task);
+ break;
+ }
+ }
+}
+
+static void
+get_connection_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GTask *task;
+ SecretsServiceData *task_data;
+ GError *error = NULL;
+
+ task = user_data;
+ task_data = g_task_get_task_data (task);
+
+ task_data->dbus_connection = g_bus_get_finish (res, &error);
+ if (task_data->dbus_connection == NULL)
+ {
+ g_task_return_error (task, error);
+ return;
+ }
+
+ /* Now open a session */
+ g_dbus_connection_call (task_data->dbus_connection,
+ SECRETS_BUS,
+ SECRETS_PATH,
+ SECRETS_IFACE ("Service"),
+ "OpenSession",
+ g_variant_new ("(sv)", "plain",
+ g_variant_new_string ("")),
+ G_VARIANT_TYPE ("(vo)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ SECRETS_TIMEOUT,
+ g_task_get_cancellable (task),
+ open_session_cb,
+ task);
+}
+
+/**
+ * gtk_cups_secrets_service_watch:
+ * @appeared: The callback to call when the service interface appears
+ * @vanished: The callback to call when the service interface vanishes
+ * @user_data: A reference to the watching printbackend
+ *
+ * Registers a watch for the secrets service interface.
+ *
+ * Returns: The watcher id
+ */
+guint
+gtk_cups_secrets_service_watch (GBusNameAppearedCallback appeared,
+ GBusNameVanishedCallback vanished,
+ gpointer user_data)
+{
+ return g_bus_watch_name (G_BUS_TYPE_SESSION,
+ SECRETS_BUS,
+ G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
+ appeared,
+ vanished,
+ user_data,
+ NULL);
+}
+
+void
+cleanup_task_data (gpointer data)
+{
+ gint i;
+ SecretsServiceData *task_data = data;
+
+ g_free (task_data->collection_path);
+ g_strfreev (task_data->auth_info_labels);
+ g_strfreev (task_data->auth_info_required);
+ g_free (task_data->printer_uri);
+
+ if (task_data->auth_info != NULL)
+ {
+ for (i = 0; task_data->auth_info[i] != NULL; i++)
+ {
+ memset (task_data->auth_info[i], 0, strlen (task_data->auth_info[i]));
+ g_clear_pointer (&task_data->auth_info[i], g_free);
+ }
+ g_clear_pointer (&task_data->auth_info, g_free);
+ }
+
+ if (task_data->prompt_subscription != 0)
+ {
+ g_dbus_connection_signal_unsubscribe (task_data->dbus_connection,
+ task_data->prompt_subscription);
+ task_data->prompt_subscription = 0;
+ }
+
+ if (task_data->session_path != NULL)
+ {
+ g_dbus_connection_call (task_data->dbus_connection,
+ SECRETS_BUS,
+ task_data->session_path,
+ SECRETS_IFACE ("Session"),
+ "Close",
+ NULL,
+ G_VARIANT_TYPE ("()"),
+ G_DBUS_CALL_FLAGS_NONE,
+ SECRETS_TIMEOUT,
+ NULL,
+ NULL,
+ NULL);
+ }
+
+ g_clear_object (&task_data->dbus_connection);
+ g_clear_pointer (&task_data->session_path, g_free);
+ g_clear_object (&task_data->item_proxy);
+}
+
+/**
+ * gtk_cups_secrets_service_query_task:
+ * @source_object: Source object for this task
+ * @cancellable: Cancellable to cancel this task
+ * @callback: Callback to call once the query is finished
+ * @user_data: The user_data passed to the callback
+ * @printer_uri: URI of the printer
+ * @auth_info_required: Info required for authentication
+ *
+ * Checks if a secrets service as described by the secrets-service standard
+ * is available and if so it tries to find the authentication info in the
+ * default collection of the service.
+ *
+ * This is the entry point to a chain of async calls to open a session,
+ * search the secret, unlock the collection (if necessary) and finally
+ * to lookup the secret.
+ *
+ * See: http://standards.freedesktop.org/secret-service/ for documentation
+ * of the used API.
+ */
+void
+gtk_cups_secrets_service_query_task (gpointer source_object,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data,
+ const gchar *printer_uri,
+ gchar **auth_info_required)
+{
+ GTask *task;
+ SecretsServiceData *task_data;
+
+ task_data = g_new0 (SecretsServiceData, 1);
+ task_data->action = SECRETS_SERVICE_ACTION_QUERY;
+ task_data->printer_uri = g_strdup (printer_uri);
+ task_data->auth_info_required = g_strdupv (auth_info_required);
+
+ task = g_task_new (source_object, cancellable, callback, user_data);
+
+ g_task_set_task_data (task, task_data, cleanup_task_data);
+
+ g_bus_get (G_BUS_TYPE_SESSION, cancellable,
+ get_connection_cb, task);
+}
+
+static void
+store_done_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GTask *task = (GTask *) res;
+ GError *error = NULL;
+
+ g_task_propagate_pointer (task, &error);
+
+ if (error != NULL)
+ {
+ GTK_NOTE (PRINTING,
+ g_print ("Failed to store auth info: %s\n", error->message));
+ g_error_free (error);
+ }
+
+ g_object_unref (task);
+ GTK_NOTE (PRINTING,
+ g_print ("gtk_cups_secrets_service_store finished.\n"));
+}
+
+/**
+ * gtk_cups_secrets_service_store:
+ * @auth_info: Auth info that should be stored
+ * @auth_info_labels: The keys to use for the auth info
+ * @printer_uri: URI of the printer
+ *
+ * Tries to store the auth_info in a secrets service.
+ */
+void
+gtk_cups_secrets_service_store (gchar **auth_info,
+ gchar **auth_info_labels,
+ const gchar *printer_uri)
+{
+ GTask *task;
+ SecretsServiceData *task_data;
+
+ if (auth_info == NULL || auth_info_labels == NULL || printer_uri == NULL)
+ {
+ GTK_NOTE (PRINTING,
+ g_print ("Invalid call to gtk_cups_secrets_service_store.\n"));
+ return;
+ }
+
+ task_data = g_new0 (SecretsServiceData, 1);
+ task_data->action = SECRETS_SERVICE_ACTION_STORE;
+ task_data->printer_uri = g_strdup (printer_uri);
+ task_data->auth_info = g_strdupv (auth_info);
+ task_data->auth_info_labels = g_strdupv (auth_info_labels);
+
+ task = g_task_new (NULL, NULL, store_done_cb, NULL);
+
+ g_task_set_task_data (task, task_data, cleanup_task_data);
+
+ g_bus_get (G_BUS_TYPE_SESSION, NULL,
+ get_connection_cb, task);
+}
diff --git a/modules/printbackends/cups/gtkcupssecretsutils.h b/modules/printbackends/cups/gtkcupssecretsutils.h
new file mode 100644
index 0000000000..1a0424a3bf
--- /dev/null
+++ b/modules/printbackends/cups/gtkcupssecretsutils.h
@@ -0,0 +1,41 @@
+/* gtkcupssecretsutils.h: Helper to use a secrets service for printer passwords
+ * Copyright (C) 2014 Intevation GmbH
+ *
+ * This library 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 of the License, or (at your option) any later version.
+ *
+ * This 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __GTK_SECRETS_UTILS_H__
+#define __GTK_SECRETS_UTILS_H__
+
+#include <glib.h>
+
+#include "gtkcupsutils.h"
+
+G_BEGIN_DECLS
+
+void gtk_cups_secrets_service_query_task (gpointer source_object,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data,
+ const gchar *printer_uri,
+ gchar **auth_info_required);
+guint gtk_cups_secrets_service_watch (GBusNameAppearedCallback appeared,
+ GBusNameVanishedCallback vanished,
+ gpointer user_data);
+void gtk_cups_secrets_service_store (gchar **auth_info,
+ gchar **auth_info_labels,
+ const gchar *printer_uri);
+
+G_END_DECLS
+
+#endif /* __GTK_SECRETS_UTILS_H__ */
diff --git a/modules/printbackends/cups/gtkprintbackendcups.c b/modules/printbackends/cups/gtkprintbackendcups.c
index 69abd49784..06c1e68686 100644
--- a/modules/printbackends/cups/gtkprintbackendcups.c
+++ b/modules/printbackends/cups/gtkprintbackendcups.c
@@ -54,6 +54,7 @@
#include "gtkprintercups.h"
#include "gtkcupsutils.h"
+#include "gtkcupssecretsutils.h"
#ifdef HAVE_COLORD
#include <colord.h>
@@ -153,6 +154,9 @@ struct _GtkPrintBackendCups
gchar *avahi_service_browser_paths[2];
GCancellable *avahi_cancellable;
#endif
+ gboolean secrets_service_available;
+ guint secrets_service_watch_id;
+ GCancellable *secrets_service_cancellable;
};
static GObjectClass *backend_parent_class;
@@ -213,16 +217,26 @@ static cairo_surface_t * cups_printer_create_cairo_surface (GtkPrinter
static void gtk_print_backend_cups_set_password (GtkPrintBackend *backend,
gchar **auth_info_required,
- gchar **auth_info);
+ gchar **auth_info,
+ gboolean store_auth_info);
void overwrite_and_free (gpointer data);
static gboolean is_address_local (const gchar *address);
static gboolean request_auth_info (gpointer data);
+static void lookup_auth_info (gpointer data);
#ifdef HAVE_CUPS_API_1_6
static void avahi_request_printer_list (GtkPrintBackendCups *cups_backend);
#endif
+static void secrets_service_appeared_cb (GDBusConnection *connection,
+ const gchar *name,
+ const gchar *name_owner,
+ gpointer user_data);
+static void secrets_service_vanished_cb (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data);
+
static void
gtk_print_backend_cups_register_type (GTypeModule *module)
{
@@ -780,6 +794,13 @@ gtk_print_backend_cups_init (GtkPrintBackendCups *backend_cups)
#endif
cups_get_local_default_printer (backend_cups);
+
+ backend_cups->secrets_service_available = FALSE;
+ backend_cups->secrets_service_cancellable = g_cancellable_new ();
+ backend_cups->secrets_service_watch_id =
+ gtk_cups_secrets_service_watch (secrets_service_appeared_cb,
+ secrets_service_vanished_cb,
+ backend_cups);
}
static void
@@ -815,6 +836,12 @@ gtk_print_backend_cups_finalize (GObject *object)
g_clear_object (&backend_cups->dbus_connection);
#endif
+ g_clear_object (&backend_cups->secrets_service_cancellable);
+ if (backend_cups->secrets_service_watch_id != 0)
+ {
+ g_bus_unwatch_name (backend_cups->secrets_service_watch_id);
+ }
+
backend_parent_class->finalize (object);
}
@@ -895,7 +922,8 @@ is_address_local (const gchar *address)
static void
gtk_print_backend_cups_set_password (GtkPrintBackend *backend,
gchar **auth_info_required,
- gchar **auth_info)
+ gchar **auth_info,
+ gboolean store_auth_info)
{
GtkPrintBackendCups *cups_backend = GTK_PRINT_BACKEND_CUPS (backend);
GList *l;
@@ -924,7 +952,7 @@ gtk_print_backend_cups_set_password (GtkPrintBackend *backend,
gchar *key = g_strconcat (username, "@", hostname, NULL);
g_hash_table_insert (cups_backend->auth, key, g_strdup (password));
GTK_NOTE (PRINTING,
- g_print ("CUPS backend: storing password for %s\n", key));
+ g_print ("CUPS backend: caching password for %s\n", key));
}
g_free (cups_backend->username);
@@ -947,6 +975,17 @@ gtk_print_backend_cups_set_password (GtkPrintBackend *backend,
for (i = 0; i < length; i++)
dispatch->request->auth_info[i] = g_strdup (auth_info[i]);
}
+ /* Save the password if the user requested it */
+ if (password != NULL && store_auth_info)
+ {
+ const gchar *printer_uri =
+ gtk_cups_request_ipp_get_string (dispatch->request,
+ IPP_TAG_URI,
+ "printer-uri");
+
+ gtk_cups_secrets_service_store (auth_info, auth_info_required,
+ printer_uri);
+ }
dispatch->backend->authentication_lock = FALSE;
dispatch->request->need_auth_info = FALSE;
}
@@ -1074,7 +1113,9 @@ request_password (gpointer data)
g_free (printer_name);
g_signal_emit_by_name (dispatch->backend, "request-password",
- auth_info_required, auth_info_default, auth_info_display, auth_info_visible, prompt);
+ auth_info_required, auth_info_default,
+ auth_info_display, auth_info_visible, prompt,
+ FALSE); /* Cups password is only cached not stored. */
g_free (prompt);
}
@@ -1178,6 +1219,98 @@ check_auth_info (gpointer user_data)
return G_SOURCE_CONTINUE;
}
+static void
+lookup_auth_info_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GTask *task;
+ GtkPrintCupsDispatchWatch *dispatch;
+ gchar **auth_info;
+ GError *error = NULL;
+ gint i;
+
+ task = (GTask *) res;
+ dispatch = user_data;
+ auth_info = g_task_propagate_pointer (task, &error);
+
+ if (auth_info == NULL)
+ {
+ if (error != NULL)
+ {
+ GTK_NOTE (PRINTING,
+ g_print ("Failed to look up auth info: %s\n", error->message));
+ g_error_free (error);
+ }
+ else
+ {
+ /* Error note should have been shown by the function causing this */
+ GTK_NOTE (PRINTING, g_print ("Failed to look up auth info.\n"));
+ }
+ dispatch->backend->authentication_lock = FALSE;
+ g_object_unref (task);
+ request_auth_info (dispatch);
+ return;
+ }
+
+ gtk_print_backend_cups_set_password (GTK_PRINT_BACKEND (dispatch->backend),
+ dispatch->request->auth_info_required, auth_info,
+ FALSE);
+ for (i = 0; auth_info[i] != NULL; i++)
+ {
+ overwrite_and_free (auth_info[i]);
+ auth_info[i] = NULL;
+ }
+ g_clear_pointer (auth_info, g_free);
+
+ g_object_unref (task);
+}
+
+static void
+lookup_auth_info (gpointer user_data)
+{
+ GtkPrintCupsDispatchWatch *dispatch;
+ gsize length,
+ i;
+ gboolean need_secret_auth_info = FALSE;
+ const gchar *printer_uri;
+
+ dispatch = user_data;
+
+ if (dispatch->backend->authentication_lock)
+ return;
+
+ length = g_strv_length (dispatch->request->auth_info_required);
+
+ for (i = 0; i < length; i++)
+ {
+ if (g_strcmp0 (dispatch->request->auth_info_required[i], "password") == 0)
+ {
+ need_secret_auth_info = TRUE;
+ break;
+ }
+ }
+
+ g_idle_add (check_auth_info, user_data);
+
+ if (dispatch->backend->secrets_service_available && need_secret_auth_info)
+ {
+ dispatch->backend->authentication_lock = TRUE;
+ printer_uri = gtk_cups_request_ipp_get_string (dispatch->request,
+ IPP_TAG_URI,
+ "printer-uri");
+ gtk_cups_secrets_service_query_task (dispatch->backend,
+ dispatch->backend->secrets_service_cancellable,
+ lookup_auth_info_cb,
+ dispatch,
+ printer_uri,
+ dispatch->request->auth_info_required);
+ return;
+ }
+
+ request_auth_info (user_data);
+}
+
static gboolean
request_auth_info (gpointer user_data)
{
@@ -1254,7 +1387,8 @@ request_auth_info (gpointer user_data)
auth_info_default,
auth_info_display,
auth_info_visible,
- prompt);
+ prompt,
+ dispatch->backend->secrets_service_available);
for (i = 0; i < length; i++)
{
@@ -1267,8 +1401,6 @@ request_auth_info (gpointer user_data)
g_free (printer_name);
g_free (prompt);
- g_idle_add (check_auth_info, user_data);
-
return FALSE;
}
@@ -1469,7 +1601,7 @@ cups_request_execute (GtkPrintBackendCups *print_backend,
{
dispatch->callback = callback;
dispatch->callback_data = user_data;
- request_auth_info (dispatch);
+ lookup_auth_info (dispatch);
}
else
{
@@ -5924,3 +6056,24 @@ cups_printer_get_capabilities (GtkPrinter *printer)
return capabilities;
}
+
+static void
+secrets_service_appeared_cb (GDBusConnection *connection,
+ const gchar *name,
+ const gchar *name_owner,
+ gpointer user_data)
+{
+ GtkPrintBackendCups *backend = GTK_PRINT_BACKEND_CUPS (user_data);
+
+ backend->secrets_service_available = TRUE;
+}
+
+static void
+secrets_service_vanished_cb (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ GtkPrintBackendCups *backend = GTK_PRINT_BACKEND_CUPS (user_data);
+
+ backend->secrets_service_available = FALSE;
+}