]> git.ipfire.org Git - thirdparty/cups.git/commitdiff
For local services use "localhost" in device URI of temporary queue
authorTill Kamppeter <till.kamppeter@gmail.com>
Sun, 13 Mar 2022 20:31:58 +0000 (21:31 +0100)
committerZdenek Dohnal <zdohnal@redhat.com>
Thu, 16 Jun 2022 09:43:09 +0000 (11:43 +0200)
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.

scheduler/ipp.c

index 14cadb02a741fb3e6d5f158df1f606d5d0ec6608..e2bdb04d19f9cf3c5d135bca6d37e76554e84da2 100644 (file)
@@ -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));