From: Till Kamppeter Date: Sun, 13 Mar 2022 20:31:58 +0000 (+0100) Subject: For local services use "localhost" in device URI of temporary queue X-Git-Tag: v2.4.3~170^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f63c112dc774e751f1e3d2de4c92f93ac1ea6831;p=thirdparty%2Fcups.git For local services use "localhost" in device URI of temporary queue To print to a temporary CUPS queue for a discovered IPP printer the client has to send an IPP_OP_CUPS_CREATE_LOCAL_PRINTER IPP request to the CUPS daemon with the details for creating the temporary queue. CUPS then calls its create_local_printer() function to actually create the queue. This is already automatically and correctly done if the client uses the convenience API of libcups. The GTK print dialog does not use the convenience API though. It displays all IPP printers for which CUPS can create temporary queues correctly, but it fails on services which are only available on the local machine and not on the network (loopback interface, "localhost") whereas printing via temporary queue on network/remote services works perfectly. The problem is that Avahi advertises the local services not with the "localhost" host name but with the network host name of the local machine. The libcups convenience API functions can cope with this and send correct device URIs with the "localhost" host name to CUPS and so the temporary queue gets created correctly. The GTK dialog wants fully asynchronous CUPS operation and throws the libcups API completely overboard doing all by itself, and sending incorrect device URIs with the network hostname for the local services. CUPS creates the temporary queue with this URI then and fails to do the get-printer-attributes request on the printer to generate the PPD file, leaving the temporary queue in a non-functional state. This commit correct/works around this by checking whether the device URI's host name is the same as the DNS-SD host name of the local machine and if so, replaces the device URI's host name by "localhost". Now one can select local services like IPP-over-USB printers or Printer Applications in the GTK print dialog and printing on them through an auto-generated temporary CUPS queue works. I decided to fix/work around this problem in CUPS as we see that no every print client developer uses the libcups convenience API. --- diff --git a/scheduler/ipp.c b/scheduler/ipp.c index 14cadb02a7..e2bdb04d19 100644 --- a/scheduler/ipp.c +++ b/scheduler/ipp.c @@ -5439,6 +5439,11 @@ create_local_printer( *nameptr, /* Pointer into name */ uri[1024]; /* printer-uri-supported value */ const char *ptr; /* Pointer into attribute value */ + char scheme[HTTP_MAX_URI], /* Scheme portion of URI */ + userpass[HTTP_MAX_URI], /* Username portion of URI */ + host[HTTP_MAX_URI], /* Host portion of URI */ + resource[HTTP_MAX_URI]; /* Resource portion of URI */ + int port; /* Port portion of URI */ /* @@ -5502,6 +5507,13 @@ create_local_printer( return; } + ptr = ippGetString(device_uri, 0, NULL); + if (!ptr || !ptr[0]) + { + send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Attribute \"%s\" has empty value."), "device-uri"); + + return; + } printer_geo_location = ippFindAttribute(con->request, "printer-geo-location", IPP_TAG_URI); printer_info = ippFindAttribute(con->request, "printer-info", IPP_TAG_TEXT); @@ -5530,7 +5542,22 @@ create_local_printer( printer->shared = 0; printer->temporary = 1; - cupsdSetDeviceURI(printer, ippGetString(device_uri, 0, NULL)); + /* + * Check device URI if it has the same hostname as we have, if so, replace + * the hostname by local host. This way we assure that local-only services + * like ipp-usb or Printer Applications always work. + */ + + httpSeparateURI(HTTP_URI_CODING_ALL, ptr, + scheme, sizeof(scheme), userpass, sizeof(userpass), host, + sizeof(host), &port, resource, sizeof(resource)); + if (strcmp(host, DNSSDHostName) == 0) + ptr = "localhost"; + else + ptr = host; + httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri), scheme, userpass, + ptr, port, resource); + cupsdSetDeviceURI(printer, uri); if (printer_geo_location) cupsdSetString(&printer->geo_location, ippGetString(printer_geo_location, 0, NULL));