diff --git a/modules/printbackends/cups/gtkprintbackendcups.c b/modules/printbackends/cups/gtkprintbackendcups.c index 90907338e0..53c7de162d 100644 --- a/modules/printbackends/cups/gtkprintbackendcups.c +++ b/modules/printbackends/cups/gtkprintbackendcups.c @@ -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) {