summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2021-02-07 16:14:05 +0000
committerMatthias Clasen <mclasen@redhat.com>2021-02-07 16:14:05 +0000
commita0818f5bae2675f6cbca8b16256a63728036fdd5 (patch)
treeb6b00911b64a7c06ea360c1422d89418937656b1
parent89f3273651cd073f1745e6842e1f5f747fe27eef (diff)
parentde3e97309f91fc631a1a4b5ab48cd69dd1421ed5 (diff)
downloadgtk+-a0818f5bae2675f6cbca8b16256a63728036fdd5.tar.gz
Merge branch 'gtk-3-24' into 'gtk-3-24'
printing: Create temporary queues for Avahi printers (Gtk 3) See merge request GNOME/gtk!3161
-rw-r--r--modules/printbackends/cups/gtkprintbackendcups.c323
-rw-r--r--modules/printbackends/cups/gtkprintercups.h4
2 files changed, 267 insertions, 60 deletions
diff --git a/modules/printbackends/cups/gtkprintbackendcups.c b/modules/printbackends/cups/gtkprintbackendcups.c
index d95d632e0b..6b8c9e02ad 100644
--- a/modules/printbackends/cups/gtkprintbackendcups.c
+++ b/modules/printbackends/cups/gtkprintbackendcups.c
@@ -150,10 +150,14 @@ struct _GtkPrintBackendCups
guint avahi_service_browser_subscription_ids[2];
char *avahi_service_browser_paths[2];
GCancellable *avahi_cancellable;
+ guint unsubscribe_general_subscription_id;
gboolean secrets_service_available;
guint secrets_service_watch_id;
GCancellable *secrets_service_cancellable;
+
+ GList *temporary_queues_in_construction;
+ GList *temporary_queues_removed;
};
static GObjectClass *backend_parent_class;
@@ -238,6 +242,11 @@ static void secrets_service_vanished_cb (GDBusConnec
const gchar *name,
gpointer user_data);
+static void create_temporary_queue (GtkPrintBackendCups *backend,
+ const gchar *printer_name,
+ const gchar *printer_uri,
+ const gchar *device_uri);
+
static void
gtk_print_backend_cups_register_type (GTypeModule *module)
{
@@ -897,6 +906,9 @@ gtk_print_backend_cups_init (GtkPrintBackendCups *backend_cups)
gtk_cups_secrets_service_watch (secrets_service_appeared_cb,
secrets_service_vanished_cb,
backend_cups);
+
+ backend_cups->temporary_queues_in_construction = NULL;
+ backend_cups->temporary_queues_removed = NULL;
}
static void
@@ -933,6 +945,12 @@ gtk_print_backend_cups_finalize (GObject *object)
g_bus_unwatch_name (backend_cups->secrets_service_watch_id);
}
+ g_list_free_full (backend_cups->temporary_queues_in_construction, g_free);
+ backend_cups->temporary_queues_in_construction = NULL;
+
+ g_list_free_full (backend_cups->temporary_queues_removed, g_free);
+ backend_cups->temporary_queues_removed = NULL;
+
backend_parent_class->finalize (object);
}
@@ -992,6 +1010,12 @@ gtk_print_backend_cups_dispose (GObject *object)
backend_cups->avahi_service_browser_subscription_id = 0;
}
+ if (backend_cups->unsubscribe_general_subscription_id > 0)
+ {
+ g_source_remove (backend_cups->unsubscribe_general_subscription_id);
+ backend_cups->unsubscribe_general_subscription_id = 0;
+ }
+
backend_parent_class->dispose (object);
}
@@ -1861,8 +1885,28 @@ static void
mark_printer_inactive (GtkPrinter *printer,
GtkPrintBackend *backend)
{
- gtk_printer_set_is_active (printer, FALSE);
- g_signal_emit_by_name (backend, "printer-removed", printer);
+ GtkPrinterCups *cups_printer = GTK_PRINTER_CUPS (printer);
+ GList *iter;
+
+ if (cups_printer->is_temporary)
+ {
+ /* Do not recreate printers which disappeared from Avahi. */
+ iter = g_list_find_custom (GTK_PRINT_BACKEND_CUPS (backend)->temporary_queues_removed,
+ gtk_printer_get_name (printer), (GCompareFunc) g_strcmp0);
+ if (iter == NULL)
+ {
+ /* Recreate temporary queue since they are created for 60 seconds only. */
+ create_temporary_queue (GTK_PRINT_BACKEND_CUPS (backend),
+ gtk_printer_get_name (printer),
+ cups_printer->printer_uri,
+ cups_printer->temporary_queue_device_uri);
+ }
+ }
+ else
+ {
+ gtk_printer_set_is_active (printer, FALSE);
+ g_signal_emit_by_name (backend, "printer-removed", printer);
+ }
}
static gint
@@ -1913,7 +1957,8 @@ static const char * const printer_attrs[] =
"multiple-document-handling-supported",
"copies-supported",
"number-up-supported",
- "device-uri"
+ "device-uri",
+ "printer-is-temporary"
};
/* Attributes we're interested in for printers without PPD */
@@ -2010,6 +2055,7 @@ typedef struct
gchar *output_bin_default;
GList *output_bin_supported;
gchar *original_device_uri;
+ gboolean is_temporary;
} PrinterSetupInfo;
static void
@@ -2395,6 +2441,13 @@ cups_printer_handle_attribute (GtkPrintBackendCups *cups_backend,
{
info->original_device_uri = g_strdup (ippGetString (attr, 0, NULL));
}
+ else if (strcmp (ippGetName (attr), "printer-is-temporary") == 0)
+ {
+ if (ippGetBoolean (attr, 0) == 1)
+ info->is_temporary = TRUE;
+ else
+ info->is_temporary = FALSE;
+ }
else
{
GTK_NOTE (PRINTING,
@@ -2430,12 +2483,7 @@ cups_create_printer (GtkPrintBackendCups *cups_backend,
cups_printer = gtk_printer_cups_new (info->printer_name, backend, NULL);
#endif
- if (info->avahi_printer)
- {
- cups_printer->device_uri = g_strdup_printf ("/%s",
- info->avahi_resource_path);
- }
- else
+ if (!info->avahi_printer)
{
cups_printer->device_uri = g_strdup_printf ("/printers/%s",
info->printer_name);
@@ -2799,6 +2847,8 @@ cups_request_printer_info_cb (GtkPrintBackendCups *cups_backend,
GTK_PRINTER_CUPS (printer)->output_bin_default = info->output_bin_default;
GTK_PRINTER_CUPS (printer)->output_bin_supported = info->output_bin_supported;
+ GTK_PRINTER_CUPS (printer)->is_temporary = info->is_temporary;
+
gtk_printer_set_has_details (printer, TRUE);
g_signal_emit_by_name (printer, "details-acquired", TRUE);
@@ -2866,8 +2916,10 @@ cups_request_printer_info (GtkPrinterCups *printer)
typedef struct
{
gchar *printer_uri;
+ gchar *device_uri;
gchar *location;
- gchar *host;
+ gchar *address;
+ gchar *hostname;
gint port;
gchar *printer_name;
gchar *name;
@@ -2924,6 +2976,88 @@ find_printer_by_uuid (GtkPrintBackendCups *backend,
return result;
}
+static void
+cups_create_local_printer_cb (GtkPrintBackendCups *print_backend,
+ GtkCupsResult *result,
+ gpointer user_data)
+{
+ ipp_attribute_t *attr;
+ gchar *printer_name = NULL;
+ ipp_t *response;
+ GList *iter;
+
+ response = gtk_cups_result_get_response (result);
+
+ if (ippGetStatusCode (response) <= IPP_OK_CONFLICT)
+ {
+ if ((attr = ippFindAttribute (response, "printer-uri-supported", IPP_TAG_URI)) != NULL)
+ {
+ printer_name = g_strdup (g_strrstr (ippGetString (attr, 0, NULL), "/") + 1);
+ }
+
+ GTK_NOTE (PRINTING,
+ g_print ("CUPS Backend: Created local printer %s\n", printer_name));
+ }
+ else
+ {
+ GTK_NOTE (PRINTING,
+ g_print ("CUPS Backend: Creating of local printer failed: %d\n", ippGetStatusCode (response)));
+ }
+
+ iter = g_list_find_custom (print_backend->temporary_queues_in_construction, printer_name, (GCompareFunc) g_strcmp0);
+ if (iter != NULL)
+ {
+ g_free (iter->data);
+ print_backend->temporary_queues_in_construction = g_list_delete_link (print_backend->temporary_queues_in_construction, iter);
+ }
+
+ g_free (printer_name);
+}
+
+/*
+ * Create CUPS temporary queue.
+ */
+static void
+create_temporary_queue (GtkPrintBackendCups *backend,
+ const gchar *printer_name,
+ const gchar *printer_uri,
+ const gchar *device_uri)
+{
+ GtkCupsRequest *request;
+ GList *iter;
+
+ /* There can be several queues with the same name (ipp and ipps versions of the same printer) */
+ iter = g_list_find_custom (backend->temporary_queues_in_construction, printer_name, (GCompareFunc) g_strcmp0);
+ if (iter != NULL)
+ return;
+
+ GTK_NOTE (PRINTING,
+ g_print ("CUPS Backend: Creating local printer %s\n", printer_name));
+
+ backend->temporary_queues_in_construction = g_list_prepend (backend->temporary_queues_in_construction, g_strdup (printer_name));
+
+ request = gtk_cups_request_new_with_username (NULL,
+ GTK_CUPS_POST,
+ IPP_OP_CUPS_CREATE_LOCAL_PRINTER,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+
+ gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, printer_uri);
+ gtk_cups_request_ipp_add_string (request, IPP_TAG_PRINTER, IPP_TAG_NAME,
+ "printer-name", NULL, printer_name);
+ gtk_cups_request_ipp_add_string (request, IPP_TAG_PRINTER, IPP_TAG_URI,
+ "device-uri", NULL, device_uri);
+
+ cups_request_execute (backend,
+ request,
+ (GtkPrintCupsResponseCallbackFunc) cups_create_local_printer_cb,
+ NULL,
+ NULL);
+}
+
/*
* Create new GtkPrinter from informations included in TXT records.
*/
@@ -2933,6 +3067,15 @@ create_cups_printer_from_avahi_data (AvahiConnectionTestData *data)
PrinterSetupInfo *info = g_slice_new0 (PrinterSetupInfo);
GtkPrinter *printer;
+ printer = gtk_print_backend_find_printer (GTK_PRINT_BACKEND (data->backend), data->printer_name);
+ if (printer != NULL)
+ {
+ /* A printer with this name is already present in this backend. It is probably the same printer
+ * on another protocol (IPv4 vs IPv6).
+ */
+ return;
+ }
+
info->avahi_printer = TRUE;
info->printer_name = data->printer_name;
info->printer_uri = data->printer_uri;
@@ -2997,8 +3140,9 @@ create_cups_printer_from_avahi_data (AvahiConnectionTestData *data)
GTK_PRINTER_CUPS (printer)->avahi_type = g_strdup (data->type);
GTK_PRINTER_CUPS (printer)->avahi_domain = g_strdup (data->domain);
GTK_PRINTER_CUPS (printer)->printer_uri = g_strdup (data->printer_uri);
+ GTK_PRINTER_CUPS (printer)->temporary_queue_device_uri = g_strdup (data->device_uri);
g_free (GTK_PRINTER_CUPS (printer)->hostname);
- GTK_PRINTER_CUPS (printer)->hostname = g_strdup (data->host);
+ GTK_PRINTER_CUPS (printer)->hostname = g_strdup (data->hostname);
GTK_PRINTER_CUPS (printer)->port = data->port;
gtk_printer_set_location (printer, data->location);
gtk_printer_set_state_message (printer, info->state_msg);
@@ -3031,10 +3175,11 @@ avahi_connection_test_cb (GObject *source_object,
{
AvahiConnectionTestData *data = (AvahiConnectionTestData *) user_data;
GSocketConnection *connection;
+ GError *error = NULL;
connection = g_socket_client_connect_to_host_finish (G_SOCKET_CLIENT (source_object),
res,
- NULL);
+ &error);
g_object_unref (source_object);
if (connection != NULL)
@@ -3044,15 +3189,25 @@ avahi_connection_test_cb (GObject *source_object,
create_cups_printer_from_avahi_data (data);
}
+ else
+ {
+ GTK_NOTE (PRINTING,
+ g_warning ("CUPS Backend: Can not connect to %s: %s\n",
+ data->address,
+ error->message));
+ g_error_free (error);
+ }
g_free (data->printer_uri);
g_free (data->location);
- g_free (data->host);
+ g_free (data->address);
+ g_free (data->hostname);
g_free (data->printer_name);
g_free (data->name);
g_free (data->resource_path);
g_free (data->type);
g_free (data->domain);
+ g_free (data->device_uri);
g_free (data);
}
@@ -3091,17 +3246,17 @@ avahi_service_resolver_cb (GObject *source_object,
AvahiConnectionTestData *data;
GtkPrintBackendCups *backend;
const gchar *name;
- const gchar *host;
+ const gchar *hostname;
const gchar *type;
const gchar *domain;
const gchar *address;
- const gchar *protocol_string;
GVariant *output;
GVariant *txt;
GVariant *child;
guint32 flags;
guint16 port;
GError *error = NULL;
+ GList *iter;
gchar *tmp;
gchar *printer_name;
gchar **printer_name_strv;
@@ -3128,7 +3283,7 @@ avahi_service_resolver_cb (GObject *source_object,
&name,
&type,
&domain,
- &host,
+ &hostname,
&aprotocol,
&address,
&port,
@@ -3193,51 +3348,50 @@ avahi_service_resolver_cb (GObject *source_object,
if (data->resource_path != NULL)
{
- if (data->got_printer_type &&
- (g_str_has_prefix (data->resource_path, "printers/") ||
- g_str_has_prefix (data->resource_path, "classes/")))
- {
- /* This is a CUPS printer advertised via Avahi */
- printer_name = g_strrstr (data->resource_path, "/");
- if (printer_name != NULL && printer_name[0] != '\0')
- data->printer_name = g_strdup (printer_name + 1);
- else
- data->printer_name = g_strdup (data->resource_path);
- }
- else
+ /*
+ * Create name of temporary queue from the name of the discovered service.
+ * This emulates the way how CUPS creates the name.
+ */
+ printer_name = g_strdup_printf ("%s", name);
+ g_strcanon (printer_name, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", '_');
+
+ printer_name_strv = g_strsplit_set (printer_name, "_", -1);
+ printer_name_compressed_strv = g_new0 (gchar *, g_strv_length (printer_name_strv) + 1);
+ for (i = 0, j = 0; printer_name_strv[i] != NULL; i++)
{
- printer_name = g_strdup (name);
- g_strcanon (printer_name, PRINTER_NAME_ALLOWED_CHARACTERS, '-');
-
- printer_name_strv = g_strsplit_set (printer_name, "-", -1);
- printer_name_compressed_strv = g_new0 (gchar *, g_strv_length (printer_name_strv) + 1);
- for (i = 0, j = 0; printer_name_strv[i] != NULL; i++)
+ if (printer_name_strv[i][0] != '\0')
{
- if (printer_name_strv[i][0] != '\0')
- {
- printer_name_compressed_strv[j] = printer_name_strv[i];
- j++;
- }
+ printer_name_compressed_strv[j] = printer_name_strv[i];
+ j++;
}
+ }
- data->printer_name = g_strjoinv ("-", printer_name_compressed_strv);
+ data->printer_name = g_strjoinv ("_", printer_name_compressed_strv);
- g_strfreev (printer_name_strv);
- g_free (printer_name_compressed_strv);
- g_free (printer_name);
+ g_strfreev (printer_name_strv);
+ g_free (printer_name_compressed_strv);
+ g_free (printer_name);
+
+ iter = g_list_find_custom (backend->temporary_queues_removed, data->printer_name, (GCompareFunc) g_strcmp0);
+ if (iter != NULL)
+ {
+ g_free (iter->data);
+ backend->temporary_queues_removed = g_list_delete_link (backend->temporary_queues_removed, iter);
}
if (g_strcmp0 (type, "_ipp._tcp") == 0)
- protocol_string = "ipp";
- else
- protocol_string = "ipps";
-
- if (aprotocol == AVAHI_PROTO_INET6)
- data->printer_uri = g_strdup_printf ("%s://[%s]:%u/%s", protocol_string, address, port, data->resource_path);
+ {
+ data->printer_uri = g_strdup_printf ("ipp://localhost/printers/%s", data->printer_name);
+ data->device_uri = g_strdup_printf ("ipp://%s:%d/%s", hostname, port, data->resource_path);
+ }
else
- data->printer_uri = g_strdup_printf ("%s://%s:%u/%s", protocol_string, address, port, data->resource_path);
+ {
+ data->printer_uri = g_strdup_printf ("ipps://localhost/printers/%s", data->printer_name);
+ data->device_uri = g_strdup_printf ("ipps://%s:%d/%s", hostname, port, data->resource_path);
+ }
- data->host = g_strdup (address);
+ data->address = g_strdup (address);
+ data->hostname = g_strdup (hostname);
data->port = port;
data->name = g_strdup (name);
@@ -3351,6 +3505,9 @@ avahi_service_browser_signal_handler (GDBusConnection *connection,
backend->avahi_default_printer) == 0)
g_clear_pointer (&backend->avahi_default_printer, g_free);
+ backend->temporary_queues_removed = g_list_prepend (backend->temporary_queues_removed,
+ g_strdup (gtk_printer_get_name (GTK_PRINTER (printer))));
+
g_signal_emit_by_name (backend, "printer-removed", printer);
gtk_print_backend_remove_printer (GTK_PRINT_BACKEND (backend),
GTK_PRINTER (printer));
@@ -3364,6 +3521,19 @@ avahi_service_browser_signal_handler (GDBusConnection *connection,
}
}
+static gboolean
+unsubscribe_general_subscription_cb (gpointer user_data)
+{
+ GtkPrintBackendCups *cups_backend = user_data;
+
+ g_dbus_connection_signal_unsubscribe (cups_backend->dbus_connection,
+ cups_backend->avahi_service_browser_subscription_id);
+ cups_backend->avahi_service_browser_subscription_id = 0;
+ cups_backend->unsubscribe_general_subscription_id = 0;
+
+ return G_SOURCE_REMOVE;
+}
+
static void
avahi_service_browser_new_cb (GObject *source_object,
GAsyncResult *res,
@@ -3405,9 +3575,10 @@ avahi_service_browser_new_cb (GObject *source_object,
cups_backend->avahi_service_browser_paths[1] &&
cups_backend->avahi_service_browser_subscription_id > 0)
{
- g_dbus_connection_signal_unsubscribe (cups_backend->dbus_connection,
- cups_backend->avahi_service_browser_subscription_id);
- cups_backend->avahi_service_browser_subscription_id = 0;
+ /* We need to unsubscribe in idle since signals in queue destined for emit
+ * are emitted in idle and check whether the subscriber is still subscribed.
+ */
+ cups_backend->unsubscribe_general_subscription_id = g_idle_add (unsubscribe_general_subscription_cb, cups_backend);
}
g_variant_unref (output);
@@ -3463,7 +3634,6 @@ avahi_create_browsers (GObject *source_object,
avahi_service_browser_signal_handler,
cups_backend,
NULL);
-
/*
* Create service browsers for _ipp._tcp and _ipps._tcp services.
*/
@@ -3591,6 +3761,12 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
continue;
}
+ /* Do not show printer for queue which was removed from Avahi. */
+ iter = g_list_find_custom (GTK_PRINT_BACKEND_CUPS (backend)->temporary_queues_removed,
+ info->printer_name, (GCompareFunc) g_strcmp0);
+ if (iter != NULL)
+ continue;
+
if (info->got_printer_type)
{
if (info->default_printer && !cups_backend->got_default_printer)
@@ -3626,7 +3802,24 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
printer = cups_create_printer (cups_backend, info);
list_has_changed = TRUE;
}
-
+ else if (GTK_PRINTER_CUPS (printer)->avahi_browsed && info->is_temporary)
+ {
+ /*
+ * A temporary queue was created for a printer found via Avahi.
+ * We modify the placeholder GtkPrinter to point to the temporary queue
+ * instead of removing the placeholder GtkPrinter and creating new GtkPrinter.
+ */
+
+ g_object_ref (printer);
+
+ GTK_PRINTER_CUPS (printer)->avahi_browsed = FALSE;
+ GTK_PRINTER_CUPS (printer)->is_temporary = TRUE;
+ g_free (GTK_PRINTER_CUPS (printer)->device_uri);
+ GTK_PRINTER_CUPS (printer)->device_uri = g_strdup_printf ("/printers/%s",
+ info->printer_name);
+ gtk_printer_set_has_details (printer, FALSE);
+ cups_printer_request_details (printer);
+ }
else
g_object_ref (printer);
@@ -3657,6 +3850,7 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
GTK_PRINTER_CUPS (printer)->supports_number_up = info->supports_number_up;
GTK_PRINTER_CUPS (printer)->number_of_covers = info->number_of_covers;
GTK_PRINTER_CUPS (printer)->covers = g_strdupv (info->covers);
+ GTK_PRINTER_CUPS (printer)->is_temporary = info->is_temporary;
status_changed = gtk_printer_set_job_count (printer, info->job_count);
status_changed |= gtk_printer_set_location (printer, info->location);
status_changed |= gtk_printer_set_description (printer,
@@ -3979,7 +4173,10 @@ cups_request_ppd (GtkPrinter *printer)
}
else
{
- hostname = cups_printer->hostname;
+ if (cups_printer->is_temporary)
+ hostname = cupsServer ();
+ else
+ hostname = cups_printer->hostname;
port = cups_printer->port;
resource = g_strdup_printf ("/printers/%s.ppd",
gtk_printer_cups_get_ppd_name (GTK_PRINTER_CUPS (printer)));
@@ -4352,8 +4549,16 @@ cups_printer_request_details (GtkPrinter *printer)
GtkPrinterCups *cups_printer;
cups_printer = GTK_PRINTER_CUPS (printer);
- if (!cups_printer->reading_ppd &&
- gtk_printer_cups_get_ppd (cups_printer) == NULL)
+
+ if (cups_printer->avahi_browsed)
+ {
+ create_temporary_queue (GTK_PRINT_BACKEND_CUPS (gtk_printer_get_backend (printer)),
+ gtk_printer_get_name (printer),
+ cups_printer->printer_uri,
+ cups_printer->temporary_queue_device_uri);
+ }
+ else if (!cups_printer->reading_ppd &&
+ gtk_printer_cups_get_ppd (cups_printer) == NULL)
{
if (cups_printer->remote && !cups_printer->avahi_browsed)
{
diff --git a/modules/printbackends/cups/gtkprintercups.h b/modules/printbackends/cups/gtkprintercups.h
index bdc30ca4f3..c8ad83fcb9 100644
--- a/modules/printbackends/cups/gtkprintercups.h
+++ b/modules/printbackends/cups/gtkprintercups.h
@@ -56,7 +56,9 @@ struct _GtkPrinterCups
gchar *original_hostname;
gchar *original_resource;
gint original_port;
- gboolean request_original_uri; /* Request PPD from original hostname */
+ gboolean request_original_uri; /* Request PPD from original hostname */
+ gboolean is_temporary; /* This printer is temporary queue */
+ gchar *temporary_queue_device_uri; /* Device uri of temporary queue for this printer */
ipp_pstate_t state;
gboolean reading_ppd;