summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarek Kasik <mkasik@redhat.com>2018-03-01 16:22:29 +0100
committerMarek Kasik <mkasik@redhat.com>2018-03-01 16:23:59 +0100
commit07b346e4f99a912861978eb77058504af0871d3a (patch)
tree296912ba2d406fcc9f12843f876916c4d50738f8
parentd43e94283dcbec4ab59d426156079802f23fd109 (diff)
downloadgnome-settings-daemon-07b346e4f99a912861978eb77058504af0871d3a.tar.gz
printing: Notify user about need for authentication
Notify user about a need for authentication when a job changes state to "pending-held" and set "job-state-reasons" attribute to "cups-held-for-authentication" or "job-hold-until" attribute to "auth-info-required". Clicking the notification (default action) opens gnome-control-center's Printers panel with Jobs dialog which allows user to authenticate the jobs. https://bugzilla.gnome.org/show_bug.cgi?id=766563
-rw-r--r--plugins/print-notifications/gsd-print-notifications-manager.c171
-rw-r--r--plugins/print-notifications/meson.build1
2 files changed, 172 insertions, 0 deletions
diff --git a/plugins/print-notifications/gsd-print-notifications-manager.c b/plugins/print-notifications/gsd-print-notifications-manager.c
index f3dfdf2e..b8bfa8ae 100644
--- a/plugins/print-notifications/gsd-print-notifications-manager.c
+++ b/plugins/print-notifications/gsd-print-notifications-manager.c
@@ -52,6 +52,7 @@
#define REASON_TIMEOUT 15000
#define CUPS_CONNECTION_TEST_INTERVAL 300
#define CHECK_INTERVAL 60 /* secs */
+#define AUTHENTICATION_CHECK_TIMEOUT 3
#if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 5)
#define HAVE_CUPS_1_6 1
@@ -91,6 +92,7 @@ struct GsdPrintNotificationsManagerPrivate
guint renew_source_id;
gint last_notify_sequence_number;
guint start_idle_id;
+ GList *held_jobs;
};
static void gsd_print_notifications_manager_class_init (GsdPrintNotificationsManagerClass *klass);
@@ -205,6 +207,13 @@ struct
GsdPrintNotificationsManager *manager;
} typedef ReasonData;
+struct
+{
+ guint job_id;
+ gchar *printer_name;
+ guint timeout_id;
+} typedef HeldJob;
+
static void
free_timeout_data (gpointer user_data)
{
@@ -239,6 +248,17 @@ free_reason_data (gpointer user_data)
}
static void
+free_held_job (gpointer user_data)
+{
+ HeldJob *job = (HeldJob *) user_data;
+
+ if (job != NULL) {
+ g_free (job->printer_name);
+ g_free (job);
+ }
+}
+
+static void
notification_closed_cb (NotifyNotification *notification,
gpointer user_data)
{
@@ -398,6 +418,137 @@ get_statuses_second (guint i,
}
static void
+authenticate_cb (NotifyNotification *notification,
+ gchar *action,
+ gpointer user_data)
+{
+ GAppInfo *app_info;
+ gboolean ret;
+ GError *error = NULL;
+ gchar *commandline;
+ gchar *printer_name = user_data;
+
+ if (g_strcmp0 (action, "default") == 0) {
+ notify_notification_close (notification, NULL);
+
+ commandline = g_strdup_printf (BINDIR "/gnome-control-center printers show-jobs %s", printer_name);
+ app_info = g_app_info_create_from_commandline (commandline,
+ "gnome-control-center",
+ G_APP_INFO_CREATE_SUPPORTS_STARTUP_NOTIFICATION,
+ &error);
+ g_free (commandline);
+
+ if (app_info != NULL) {
+ ret = g_app_info_launch (app_info,
+ NULL,
+ NULL,
+ &error);
+
+ if (!ret) {
+ g_warning ("failed to launch gnome-control-center: %s", error->message);
+ g_error_free (error);
+ }
+
+ g_object_unref (app_info);
+ } else {
+ g_warning ("failed to create application info: %s", error->message);
+ g_error_free (error);
+ }
+ }
+}
+
+static void
+unref_notification (NotifyNotification *notification,
+ gpointer data)
+{
+ g_object_unref (notification);
+}
+
+static gint
+check_job_for_authentication (gpointer userdata)
+{
+ GsdPrintNotificationsManager *manager = userdata;
+ ipp_attribute_t *attr;
+ static gchar *requested_attributes[] = { "job-state-reasons", "job-hold-until", NULL };
+ gboolean needs_authentication = FALSE;
+ HeldJob *job;
+ gchar *primary_text;
+ gchar *secondary_text;
+ gchar *job_uri;
+ ipp_t *request, *response;
+ gint i;
+
+ if (manager->priv->held_jobs != NULL) {
+ job = (HeldJob *) manager->priv->held_jobs->data;
+
+ manager->priv->held_jobs = g_list_delete_link (manager->priv->held_jobs,
+ manager->priv->held_jobs);
+
+ request = ippNewRequest (IPP_GET_JOB_ATTRIBUTES);
+
+ job_uri = g_strdup_printf ("ipp://localhost/jobs/%u", job->job_id);
+ ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "job-uri", NULL, job_uri);
+ g_free (job_uri);
+ ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requesting-user-name", NULL, cupsUser ());
+ ippAddStrings (request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes", 2, NULL, (const char **) requested_attributes);
+
+ response = cupsDoRequest (CUPS_HTTP_DEFAULT, request, "/");
+ if (response != NULL) {
+ if (ippGetStatusCode (response) <= IPP_OK_CONFLICT) {
+ if ((attr = ippFindAttribute (response, "job-state-reasons", IPP_TAG_ZERO)) != NULL) {
+ for (i = 0; i < ippGetCount (attr); i++) {
+ if (g_strcmp0 (ippGetString (attr, i, NULL), "cups-held-for-authentication") == 0) {
+ needs_authentication = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (!needs_authentication && (attr = ippFindAttribute (response, "job-hold-until", IPP_TAG_ZERO)) != NULL) {
+ if (g_strcmp0 (ippGetString (attr, 0, NULL), "auth-info-required") == 0)
+ needs_authentication = TRUE;
+ }
+ }
+
+ ippDelete (response);
+ }
+
+ if (needs_authentication) {
+ NotifyNotification *notification;
+
+ /* Translators: The printer has a job to print but the printer needs authentication to continue with the print */
+ primary_text = g_strdup_printf (_("%s Requires Authentication"), job->printer_name);
+ /* Translators: A printer needs credentials to continue printing a job */
+ secondary_text = g_strdup_printf (_("Credentials required in order to print"));
+
+ notification = notify_notification_new (primary_text,
+ secondary_text,
+ "printer-symbolic");
+ notify_notification_set_app_name (notification, _("Printers"));
+ notify_notification_add_action (notification,
+ "default",
+ /* This is a default action so the label won't be shown */
+ "Authenticate",
+ authenticate_cb,
+ g_strdup (job->printer_name), g_free);
+ g_signal_connect (notification, "closed", G_CALLBACK (unref_notification), NULL);
+
+ notify_notification_show (notification, NULL);
+
+ g_free (primary_text);
+ g_free (secondary_text);
+ }
+
+ free_held_job (job);
+ }
+
+ return G_SOURCE_REMOVE;
+}
+
+static void
process_cups_notification (GsdPrintNotificationsManager *manager,
const char *notify_subscribed_event,
const char *notify_text,
@@ -415,6 +566,7 @@ process_cups_notification (GsdPrintNotificationsManager *manager,
ipp_attribute_t *attr;
gboolean my_job = FALSE;
gboolean known_reason;
+ HeldJob *held_job;
http_t *http;
gchar *primary_text = NULL;
gchar *secondary_text = NULL;
@@ -589,6 +741,17 @@ process_cups_notification (GsdPrintNotificationsManager *manager,
/* Translators: "print-job xy" on a printer */
secondary_text = g_strdup_printf (C_("print job", "ā€œ%sā€ on %s"), job_name, printer_name);
break;
+ case IPP_JOB_HELD:
+ held_job = g_new (HeldJob, 1);
+ held_job->job_id = notify_job_id;
+ held_job->printer_name = g_strdup (printer_name);
+ /* CUPS takes sometime to change the "job-state-reasons" to "cups-held-for-authentication"
+ after the job changes job-state to "held" state but this change is not signalized
+ by any event so we just check the job-state-reason (or job-hold-until) after some timeout */
+ held_job->timeout_id = g_timeout_add_seconds (AUTHENTICATION_CHECK_TIMEOUT, check_job_for_authentication, manager);
+
+ manager->priv->held_jobs = g_list_append (manager->priv->held_jobs, held_job);
+ break;
default:
break;
}
@@ -1393,6 +1556,7 @@ gsd_print_notifications_manager_start (GsdPrintNotificationsManager *manager,
manager->priv->cups_bus_connection = NULL;
manager->priv->cups_connection_timeout_id = 0;
manager->priv->last_notify_sequence_number = -1;
+ manager->priv->held_jobs = NULL;
manager->priv->start_idle_id = g_idle_add (gsd_print_notifications_manager_start_idle, manager);
g_source_set_name_by_id (manager->priv->start_idle_id, "[gnome-settings-daemon] gsd_print_notifications_manager_start_idle");
@@ -1407,6 +1571,7 @@ gsd_print_notifications_manager_stop (GsdPrintNotificationsManager *manager)
{
TimeoutData *data;
ReasonData *reason_data;
+ HeldJob *job;
GList *tmp;
g_debug ("Stopping print-notifications manager");
@@ -1459,6 +1624,12 @@ gsd_print_notifications_manager_stop (GsdPrintNotificationsManager *manager)
}
g_list_free_full (manager->priv->active_notifications, free_reason_data);
+ for (tmp = manager->priv->held_jobs; tmp; tmp = g_list_next (tmp)) {
+ job = (HeldJob *) tmp->data;
+ g_source_remove (job->timeout_id);
+ }
+ g_list_free_full (manager->priv->held_jobs, free_held_job);
+
scp_handler (manager, FALSE);
}
diff --git a/plugins/print-notifications/meson.build b/plugins/print-notifications/meson.build
index 89a78592..1e1c614b 100644
--- a/plugins/print-notifications/meson.build
+++ b/plugins/print-notifications/meson.build
@@ -10,6 +10,7 @@ deps = plugins_deps + [
]
cflags += ['-DLIBEXECDIR="@0@"'.format(gsd_libexecdir)]
+cflags += ['-DBINDIR="@0@"'.format(gsd_bindir)]
executable(
'gsd-' + plugin_name,