printing: Don't wake up Avahi printers unnecessarily

Use info available in Avahi TXT records for creation of gtk printer
and request details when needed (through gtk_printer_request_details()).
If there is a printer advertised on Avahi by a remote CUPS server
try to get its PPD file at first or get its capabilities through an IPP
request if it fails.

https://bugzilla.gnome.org/show_bug.cgi?id=712751
This commit is contained in:
Marek Kasik 2013-11-21 15:27:33 +01:00
parent da86918c32
commit 376e2c003d

View File

@ -2365,28 +2365,6 @@ set_default_printer (GtkPrintBackendCups *cups_backend,
}
#ifdef HAVE_CUPS_API_1_6
typedef struct
{
gchar *name;
gchar *type;
gchar *domain;
gchar *host;
gint port;
} AvahiService;
void
avahi_service_free (AvahiService *service)
{
if (service)
{
g_free (service->name);
g_free (service->type);
g_free (service->domain);
g_free (service->host);
g_free (service);
}
}
static void
cups_request_avahi_printer_info_cb (GtkPrintBackendCups *cups_backend,
GtkCupsResult *result,
@ -2395,9 +2373,7 @@ cups_request_avahi_printer_info_cb (GtkPrintBackendCups *cups_backend,
PrinterSetupInfo *info = g_slice_new0 (PrinterSetupInfo);
GtkPrintBackend *backend = GTK_PRINT_BACKEND (cups_backend);
ipp_attribute_t *attr;
AvahiService *service = (AvahiService *) user_data;
GtkPrinter *printer;
gboolean list_has_changed = FALSE;
gboolean status_changed = FALSE;
ipp_t *response;
@ -2432,42 +2408,28 @@ cups_request_avahi_printer_info_cb (GtkPrintBackendCups *cups_backend,
if (info->printer_name && info->printer_uri)
{
info->avahi_printer = TRUE;
set_info_state_message (info);
printer = gtk_print_backend_find_printer (backend, info->printer_name);
if (printer != NULL &&
GTK_PRINTER_CUPS (printer)->avahi_browsed)
{
g_object_ref (printer);
}
else
{
goto done;
}
if (info->got_printer_type &&
info->default_printer &&
cups_backend->avahi_default_printer == NULL)
cups_backend->avahi_default_printer = g_strdup (info->printer_name);
set_info_state_message (info);
printer = gtk_print_backend_find_printer (backend, info->printer_name);
if (!printer)
{
printer = cups_create_printer (cups_backend, info);
list_has_changed = TRUE;
}
else
{
g_object_ref (printer);
}
gtk_printer_set_is_paused (printer, info->is_paused);
gtk_printer_set_is_accepting_jobs (printer, info->is_accepting_jobs);
if (!gtk_printer_is_active (printer))
{
gtk_printer_set_is_active (printer, TRUE);
gtk_printer_set_is_new (printer, TRUE);
list_has_changed = TRUE;
}
GTK_PRINTER_CUPS (printer)->remote = info->remote_printer;
GTK_PRINTER_CUPS (printer)->avahi_name = g_strdup (service->name);
GTK_PRINTER_CUPS (printer)->avahi_type = g_strdup (service->type);
GTK_PRINTER_CUPS (printer)->avahi_domain = g_strdup (service->domain);
GTK_PRINTER_CUPS (printer)->hostname = g_strdup (service->host);
GTK_PRINTER_CUPS (printer)->port = service->port;
GTK_PRINTER_CUPS (printer)->state = info->state;
GTK_PRINTER_CUPS (printer)->ipp_version_major = info->ipp_version_major;
GTK_PRINTER_CUPS (printer)->ipp_version_minor = info->ipp_version_minor;
@ -2482,11 +2444,8 @@ cups_request_avahi_printer_info_cb (GtkPrintBackendCups *cups_backend,
set_printer_icon_name_from_info (printer, info);
if (gtk_printer_is_new (printer))
{
g_signal_emit_by_name (backend, "printer-added", printer);
gtk_printer_set_is_new (printer, FALSE);
}
gtk_printer_set_has_details (printer, TRUE);
g_signal_emit_by_name (printer, "details-acquired", TRUE);
if (status_changed)
g_signal_emit_by_name (GTK_PRINT_BACKEND (backend),
@ -2498,9 +2457,6 @@ cups_request_avahi_printer_info_cb (GtkPrintBackendCups *cups_backend,
}
done:
if (list_has_changed)
g_signal_emit_by_name (backend, "printer-list-changed");
if (!cups_backend->got_default_printer &&
gtk_print_backend_printer_list_is_done (backend) &&
cups_backend->avahi_default_printer != NULL)
@ -2508,6 +2464,7 @@ done:
set_default_printer (cups_backend, cups_backend->avahi_default_printer);
}
g_free (info->state_msg);
g_slice_free (PrinterSetupInfo, info);
gdk_threads_leave ();
@ -2517,25 +2474,14 @@ static void
cups_request_avahi_printer_info (const gchar *printer_uri,
const gchar *host,
gint port,
const gchar *name,
const gchar *type,
const gchar *domain,
GtkPrintBackendCups *backend)
{
GtkCupsRequest *request;
AvahiService *service;
http_t *http;
http = httpConnect (host, port);
if (http)
{
service = (AvahiService *) g_new0 (AvahiService, 1);
service->name = g_strdup (name);
service->type = g_strdup (type);
service->domain = g_strdup (domain);
service->host = g_strdup (host);
service->port = port;
request = gtk_cups_request_new_with_username (http,
GTK_CUPS_POST,
IPP_GET_PRINTER_ATTRIBUTES,
@ -2556,22 +2502,118 @@ cups_request_avahi_printer_info (const gchar *printer_uri,
cups_request_execute (backend,
request,
(GtkPrintCupsResponseCallbackFunc) cups_request_avahi_printer_info_cb,
service,
(GDestroyNotify) avahi_service_free);
NULL,
NULL);
}
}
typedef struct
{
gchar *printer_uri;
gchar *location;
gchar *host;
gint port;
gchar *printer_name;
gchar *name;
gboolean got_printer_type;
guint printer_type;
gboolean got_printer_state;
guint printer_state;
gchar *type;
gchar *domain;
GtkPrintBackendCups *backend;
} AvahiConnectionTestData;
/*
* Create new GtkPrinter from informations included in TXT records.
*/
static void
create_cups_printer_from_avahi_data (AvahiConnectionTestData *data)
{
PrinterSetupInfo *info = g_slice_new0 (PrinterSetupInfo);
GtkPrinter *printer;
info->avahi_printer = TRUE;
info->printer_name = data->printer_name;
info->printer_uri = data->printer_uri;
if (data->got_printer_state)
info->state = data->printer_state;
info->got_printer_type = data->got_printer_type;
if (data->got_printer_type)
{
if (data->printer_type & CUPS_PRINTER_DEFAULT)
info->default_printer = TRUE;
else
info->default_printer = FALSE;
if (data->printer_type & CUPS_PRINTER_REMOTE)
info->remote_printer = TRUE;
else
info->remote_printer = FALSE;
if (data->printer_type & CUPS_PRINTER_REJECTING)
info->is_accepting_jobs = FALSE;
else
info->is_accepting_jobs = TRUE;
if (info->default_printer &&
data->backend->avahi_default_printer == NULL)
data->backend->avahi_default_printer = g_strdup (info->printer_name);
}
set_info_state_message (info);
printer = gtk_print_backend_find_printer (GTK_PRINT_BACKEND (data->backend), data->printer_name);
if (printer == NULL)
{
printer = cups_create_printer (data->backend, info);
if (data->got_printer_type)
{
gtk_printer_set_is_accepting_jobs (printer, info->is_accepting_jobs);
GTK_PRINTER_CUPS (printer)->remote = info->remote_printer;
if (info->default_printer &&
data->backend->avahi_default_printer == NULL)
data->backend->avahi_default_printer = g_strdup (info->printer_name);
}
if (data->got_printer_state)
GTK_PRINTER_CUPS (printer)->state = info->state;
GTK_PRINTER_CUPS (printer)->avahi_name = g_strdup (data->name);
GTK_PRINTER_CUPS (printer)->avahi_type = g_strdup (data->type);
GTK_PRINTER_CUPS (printer)->avahi_domain = g_strdup (data->domain);
g_free (GTK_PRINTER_CUPS (printer)->hostname);
GTK_PRINTER_CUPS (printer)->hostname = g_strdup (data->host);
GTK_PRINTER_CUPS (printer)->port = data->port;
gtk_printer_set_location (printer, data->location);
gtk_printer_set_state_message (printer, info->state_msg);
set_printer_icon_name_from_info (printer, info);
if (!gtk_printer_is_active (printer))
gtk_printer_set_is_active (printer, TRUE);
g_signal_emit_by_name (data->backend, "printer-added", printer);
gtk_printer_set_is_new (printer, FALSE);
g_signal_emit_by_name (data->backend, "printer-list-changed");
if (!data->backend->got_default_printer &&
gtk_print_backend_printer_list_is_done (GTK_PRINT_BACKEND (data->backend)) &&
data->backend->avahi_default_printer != NULL)
set_default_printer (data->backend, data->backend->avahi_default_printer);
/* The ref is held by GtkPrintBackend, in add_printer() */
g_object_unref (printer);
}
g_free (info->state_msg);
g_slice_free (PrinterSetupInfo, info);
}
static void
avahi_connection_test_cb (GObject *source_object,
GAsyncResult *res,
@ -2590,23 +2632,46 @@ avahi_connection_test_cb (GObject *source_object,
g_io_stream_close (G_IO_STREAM (connection), NULL, NULL);
g_object_unref (connection);
cups_request_avahi_printer_info (data->printer_uri,
data->host,
data->port,
data->name,
data->type,
data->domain,
data->backend);
create_cups_printer_from_avahi_data (data);
}
g_free (data->printer_uri);
g_free (data->location);
g_free (data->host);
g_free (data->printer_name);
g_free (data->name);
g_free (data->type);
g_free (data->domain);
g_free (data);
}
gboolean
avahi_txt_get_key_value_pair (const gchar *entry,
gchar **key,
gchar **value)
{
const gchar *equal_sign;
*key = NULL;
*value = NULL;
if (entry != NULL)
{
/* See RFC 6763 section 6.3 */
equal_sign = strstr (entry, "=");
if (equal_sign != NULL)
{
*key = g_strndup (entry, equal_sign - entry);
*value = g_strdup (equal_sign + 1);
return TRUE;
}
}
return FALSE;
}
static void
avahi_service_resolver_cb (GObject *source_object,
GAsyncResult *res,
@ -2626,8 +2691,12 @@ avahi_service_resolver_cb (GObject *source_object,
guint32 flags;
guint16 port;
GError *error = NULL;
gchar *suffix = NULL;
gchar *queue_name = NULL;
gchar *tmp;
gchar *printer_name;
gchar *endptr;
gchar *key;
gchar *value;
gint interface;
gint protocol;
gint aprotocol;
@ -2653,6 +2722,8 @@ avahi_service_resolver_cb (GObject *source_object,
&txt,
&flags);
data = g_new0 (AvahiConnectionTestData, 1);
for (i = 0; i < g_variant_n_children (txt); i++)
{
child = g_variant_get_child_value (txt, i);
@ -2663,32 +2734,61 @@ avahi_service_resolver_cb (GObject *source_object,
tmp[j] = g_variant_get_byte (g_variant_get_child_value (child, j));
}
if (g_str_has_prefix (tmp, "rp="))
if (!avahi_txt_get_key_value_pair (tmp, &key, &value))
{
suffix = g_strdup (tmp + 3);
g_free (tmp);
break;
continue;
}
if (g_strcmp0 (key, "rp") == 0)
{
queue_name = g_strdup (value);
printer_name = g_strrstr (queue_name, "/");
if (printer_name != NULL)
data->printer_name = g_strdup (printer_name + 1);
else
data->printer_name = g_strdup (queue_name);
}
else if (g_strcmp0 (key, "note") == 0)
{
data->location = g_strdup (value);
}
else if (g_strcmp0 (key, "printer-type") == 0)
{
endptr = NULL;
data->printer_type = g_ascii_strtoull (value, &endptr, 16);
if (data->printer_type != 0 || endptr != value)
data->got_printer_type = TRUE;
}
else if (g_strcmp0 (key, "printer-state") == 0)
{
endptr = NULL;
data->printer_state = g_ascii_strtoull (value, &endptr, 10);
if (data->printer_state != 0 || endptr != value)
data->got_printer_state = TRUE;
}
g_clear_pointer (&key, g_free);
g_clear_pointer (&value, g_free);
g_free (tmp);
}
if (suffix)
if (queue_name)
{
if (g_strcmp0 (type, "_ipp._tcp") == 0)
protocol_string = "ipp";
else
protocol_string = "ipps";
data = g_new0 (AvahiConnectionTestData, 1);
if (aprotocol == AVAHI_PROTO_INET6)
data->printer_uri = g_strdup_printf ("%s://[%s]:%u/%s", protocol_string, address, port, suffix);
data->printer_uri = g_strdup_printf ("%s://[%s]:%u/%s", protocol_string, address, port, queue_name);
else
data->printer_uri = g_strdup_printf ("%s://%s:%u/%s", protocol_string, address, port, suffix);
data->printer_uri = g_strdup_printf ("%s://%s:%u/%s", protocol_string, address, port, queue_name);
data->host = g_strdup (address);
data->port = port;
data->name = g_strdup (name);
data->type = g_strdup (type);
data->domain = g_strdup (domain);
@ -2701,7 +2801,13 @@ avahi_service_resolver_cb (GObject *source_object,
backend->avahi_cancellable,
avahi_connection_test_cb,
data);
g_free (suffix);
g_free (queue_name);
}
else
{
g_free (data->printer_name);
g_free (data->location);
g_free (data);
}
g_variant_unref (output);
@ -3326,21 +3432,30 @@ cups_request_ppd_cb (GtkPrintBackendCups *print_backend,
{
gboolean success = FALSE;
/* If we get a 404 then it is just a raw printer without a ppd
and not an error. Standalone Avahi printers also don't have
PPD files. */
if (((gtk_cups_result_get_error_type (result) == GTK_CUPS_ERROR_HTTP) &&
(gtk_cups_result_get_error_status (result) == HTTP_NOT_FOUND))
#ifdef HAVE_CUPS_API_1_6
|| GTK_PRINTER_CUPS (printer)->avahi_browsed
#endif
)
/* Standalone Avahi printers don't have PPD files. */
if (GTK_PRINTER_CUPS (printer)->avahi_browsed)
{
gtk_printer_set_has_details (printer, TRUE);
success = TRUE;
cups_request_avahi_printer_info (GTK_PRINTER_CUPS (printer)->printer_uri,
GTK_PRINTER_CUPS (printer)->hostname,
GTK_PRINTER_CUPS (printer)->port,
GTK_PRINT_BACKEND_CUPS (gtk_printer_get_backend (printer)));
}
else
#endif
{
/* If we get a 404 then it is just a raw printer without a ppd
and not an error. */
if ((gtk_cups_result_get_error_type (result) == GTK_CUPS_ERROR_HTTP) &&
(gtk_cups_result_get_error_status (result) == HTTP_NOT_FOUND))
{
gtk_printer_set_has_details (printer, TRUE);
success = TRUE;
}
g_signal_emit_by_name (printer, "details-acquired", success);
}
g_signal_emit_by_name (printer, "details-acquired", success);
goto done;
}
@ -3377,7 +3492,11 @@ cups_request_ppd (GtkPrinter *printer)
GTK_NOTE (PRINTING,
g_print ("CUPS Backend: %s\n", G_STRFUNC));
if (cups_printer->remote)
if (cups_printer->remote
#ifdef HAVE_CUPS_API_1_6
&& !cups_printer->avahi_browsed
#endif
)
{
GtkCupsConnectionState state;
@ -3788,7 +3907,11 @@ cups_printer_request_details (GtkPrinter *printer)
if (!cups_printer->reading_ppd &&
gtk_printer_cups_get_ppd (cups_printer) == NULL)
{
if (cups_printer->remote)
if (cups_printer->remote
#ifdef HAVE_CUPS_API_1_6
&& !cups_printer->avahi_browsed
#endif
)
{
if (cups_printer->get_remote_ppd_poll == 0)
{