]> git.ipfire.org Git - thirdparty/cups.git/commitdiff
Convert dnssd backend to use cupsDNSSD APIs.
authorMichael R Sweet <msweet@msweet.org>
Wed, 24 Apr 2024 21:27:17 +0000 (17:27 -0400)
committerMichael R Sweet <msweet@msweet.org>
Wed, 24 Apr 2024 21:27:17 +0000 (17:27 -0400)
backend/dnssd.c

index 20f889e32aad8182a84890484a571d034cb7d7e4..2e7e72ecf9ed8300b1fdcd57ed267cf1c90ef74a 100644 (file)
-/*
- * DNS-SD discovery backend for CUPS.
- *
- * Copyright © 2020-2024 by OpenPrinting.
- * Copyright © 2008-2018 by Apple Inc.
- *
- * Licensed under Apache License v2.0.  See the file "LICENSE" for more
- * information.
- */
-
-/*
- * Include necessary headers.
- */
+//
+// DNS-SD discovery backend for CUPS.
+//
+// Copyright © 2020-2024 by OpenPrinting.
+// Copyright © 2008-2018 by Apple Inc.
+//
+// Licensed under Apache License v2.0.  See the file "LICENSE" for more
+// information.
+//
 
 #include "backend-private.h"
 #include <cups/array.h>
-#ifdef HAVE_MDNSRESPONDER
-#  include <dns_sd.h>
-#endif /* HAVE_MDNSRESPONDER */
-#ifdef HAVE_AVAHI
-#  include <avahi-client/client.h>
-#  include <avahi-client/lookup.h>
-#  include <avahi-common/simple-watch.h>
-#  include <avahi-common/domain.h>
-#  include <avahi-common/error.h>
-#  include <avahi-common/malloc.h>
-#define kDNSServiceMaxDomainName AVAHI_DOMAIN_NAME_MAX
-#endif /* HAVE_AVAHI */
+#include <cups/dnssd.h>
 
 
-/*
- * Device structure...
- */
+//
+// Device structure...
+//
 
 typedef enum
 {
-  CUPS_DEVICE_PRINTER = 0,             /* lpd://... */
-  CUPS_DEVICE_IPPS,                    /* ipps://... */
-  CUPS_DEVICE_IPP,                     /* ipp://... */
-  CUPS_DEVICE_FAX_IPP,                 /* ipp://... */
-  CUPS_DEVICE_PDL_DATASTREAM,          /* socket://... */
-  CUPS_DEVICE_RIOUSBPRINT              /* riousbprint://... */
+  CUPS_DEVICE_PRINTER = 0,             // lpd://...
+  CUPS_DEVICE_IPPS,                    // ipps://...
+  CUPS_DEVICE_IPP,                     // ipp://...
+  CUPS_DEVICE_FAX_IPP,                 // ipp://...
+  CUPS_DEVICE_PDL_DATASTREAM,          // socket://...
+  CUPS_DEVICE_RIOUSBPRINT              // riousbprint://...
 } cups_devtype_t;
 
 
 typedef struct
 {
-#ifdef HAVE_MDNSRESPONDER
-  DNSServiceRef        ref;                    /* Service reference for query */
-#endif /* HAVE_MDNSRESPONDER */
-#ifdef HAVE_AVAHI
-  AvahiRecordBrowser *ref;             /* Browser for query */
-#endif /* HAVE_AVAHI */
-  char         *name,                  /* Service name */
-               *domain,                /* Domain name */
-               *fullName,              /* Full name */
-               *make_and_model,        /* Make and model from TXT record */
-               *device_id,             /* 1284 device ID from TXT record */
-               *uuid;                  /* UUID from TXT record */
-  cups_devtype_t type;                 /* Device registration type */
-  int          priority,               /* Priority associated with type */
-               cups_shared,            /* CUPS shared printer? */
-               sent;                   /* Did we list the device? */
+  cups_dnssd_query_t *query;           // Query request
+  char         *name,                  // Service name
+               *domain,                // Domain name
+               *fullname,              // Full name
+               *make_and_model,        // Make and model from TXT record
+               *device_id,             // 1284 device ID from TXT record
+               *location,              // Location from TXT record
+               *uuid;                  // UUID from TXT record
+  cups_devtype_t type;                 // Device registration type
+  int          priority;               // Priority associated with type
+  bool         cups_shared,            // CUPS shared printer?
+               sent;                   // Did we list the device?
 } cups_device_t;
 
 
-/*
- * Local globals...
- */
+//
+// Local globals...
+//
 
-static int             job_canceled = 0;
-                                       /* Set to 1 on SIGTERM */
-#ifdef HAVE_AVAHI
-static AvahiSimplePoll *simple_poll = NULL;
-                                       /* Poll information */
-static int             got_data = 0;   /* Got data from poll? */
-static int             browsers = 0;   /* Number of running browsers */
-#endif /* HAVE_AVAHI */
+static cups_array_t    *Devices = NULL;// Found devices
+static cups_mutex_t    DevicesMutex = CUPS_MUTEX_INITIALIZER;
+                                       // Mutex for devices array
+static int             JobCanceled = 0;// Set to 1 on SIGTERM
 
 
-/*
- * Local functions...
- */
-
-#ifdef HAVE_MDNSRESPONDER
-static void            browse_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *serviceName, const char *regtype, const char *replyDomain, void *context) _CUPS_NONNULL(1,5,6,7,8);
-static void            browse_local_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *serviceName, const char *regtype, const char *replyDomain, void *context) _CUPS_NONNULL(1,5,6,7,8);
-#endif /* HAVE_MDNSRESPONDER */
-#ifdef HAVE_AVAHI
-static void            browse_callback(AvahiServiceBrowser *browser,
-                                       AvahiIfIndex interface,
-                                       AvahiProtocol protocol,
-                                       AvahiBrowserEvent event,
-                                       const char *serviceName,
-                                       const char *regtype,
-                                       const char *replyDomain,
-                                       AvahiLookupResultFlags flags,
-                                       void *context);
-static void            client_callback(AvahiClient *client,
-                                       AvahiClientState state,
-                                       void *context);
-#endif /* HAVE_AVAHI */
+//
+// Local functions...
+//
 
+static void            browse_callback(cups_dnssd_browse_t *browser, void *data, cups_dnssd_flags_t flags, uint32_t if_index, const char *name, const char *regtype, const char *domain);
 static int             compare_devices(cups_device_t *a, cups_device_t *b, void *data);
+static void            error_cb(void *data, const char *message);
 static void            exec_backend(char **argv) _CUPS_NORETURN;
-static cups_device_t   *get_device(cups_array_t *devices, const char *serviceName, const char *regtype, const char *replyDomain) _CUPS_NONNULL(1,2,3,4);
-#ifdef HAVE_MDNSRESPONDER
-static void            query_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *fullName, uint16_t rrtype, uint16_t rrclass, uint16_t rdlen, const void *rdata, uint32_t ttl, void *context) _CUPS_NONNULL(1,5,9,11);
-#elif defined(HAVE_AVAHI)
-static int             poll_callback(struct pollfd *pollfds,
-                                     unsigned int num_pollfds, int timeout,
-                                     void *context);
-static void            query_callback(AvahiRecordBrowser *browser,
-                                      AvahiIfIndex interface,
-                                      AvahiProtocol protocol,
-                                      AvahiBrowserEvent event,
-                                      const char *name, uint16_t rrclass,
-                                      uint16_t rrtype, const void *rdata,
-                                      size_t rdlen,
-                                      AvahiLookupResultFlags flags,
-                                      void *context);
-#endif /* HAVE_MDNSRESPONDER */
+static cups_device_t   *get_device(const char *serviceName, const char *regtype, const char *replyDomain);
+static void            query_callback(cups_dnssd_query_t *query, cups_device_t *device, cups_dnssd_flags_t flags, uint32_t if_index, const char *fullname, uint16_t rrtype, const void *qdata, uint16_t qlen);
 static void            sigterm_handler(int sig);
 static void            unquote(char *dst, const char *src, size_t dstsize) _CUPS_NONNULL(1,2);
 
 
-/*
- * 'main()' - Browse for printers.
- */
+//
+// 'main()' - Browse for printers.
+//
 
-int                                    /* O - Exit status */
-main(int  argc,                                /* I - Number of command-line args */
-     char *argv[])                     /* I - Command-line arguments */
+int                                    // O - Exit status
+main(int  argc,                                // I - Number of command-line args
+     char *argv[])                     // I - Command-line arguments
 {
-  const char   *name;                  /* Backend name */
-  cups_array_t *devices;               /* Device array */
-  cups_device_t        *device;                /* Current device */
-  char         uriName[1024];          /* Unquoted fullName for URI */
-#ifdef HAVE_MDNSRESPONDER
-  int          fd;                     /* Main file descriptor */
-  fd_set       input;                  /* Input set for select() */
-  struct timeval timeout;              /* Timeout for select() */
-  DNSServiceRef        main_ref,               /* Main service reference */
-               fax_ipp_ref,            /* IPP fax service reference */
-               ipp_ref,                /* IPP service reference */
-               ipp_tls_ref,            /* IPP w/TLS service reference */
-               ipps_ref,               /* IPP service reference */
-               local_fax_ipp_ref,      /* Local IPP fax service reference */
-               local_ipp_ref,          /* Local IPP service reference */
-               local_ipp_tls_ref,      /* Local IPP w/TLS service reference */
-               local_ipps_ref,         /* Local IPP service reference */
-               local_printer_ref,      /* Local LPD service reference */
-               pdl_datastream_ref,     /* AppSocket service reference */
-               printer_ref,            /* LPD service reference */
-               riousbprint_ref;        /* Remote IO service reference */
-#endif /* HAVE_MDNSRESPONDER */
-#ifdef HAVE_AVAHI
-  AvahiClient  *client;                /* Client information */
-  int          error;                  /* Error code, if any */
-#endif /* HAVE_AVAHI */
-  struct sigaction action;             /* Actions for POSIX signals */
-
+  const char   *name;                  // Backend name
+  cups_device_t        *device;                // Current device
+  char         uriName[1024];          // Unquoted fullname for URI
+  cups_dnssd_t *dnssd;                 // DNS-SD context
+  struct sigaction action;             // Actions for POSIX signals
+  time_t       start;                  // Start time
 
- /*
-  * Don't buffer stderr, and catch SIGTERM...
-  */
 
+  // Don't buffer stderr, and catch SIGTERM...
   setbuf(stderr, NULL);
 
   memset(&action, 0, sizeof(action));
@@ -173,24 +94,18 @@ main(int  argc,                            /* I - Number of command-line args */
   action.sa_handler = sigterm_handler;
   sigaction(SIGTERM, &action, NULL);
 
- /*
-  * Check command-line...
-  */
-
+  // Check command-line...
   if (argc >= 6)
+  {
     exec_backend(argv);
+  }
   else if (argc != 1)
   {
-    _cupsLangPrintf(stderr,
-                    _("Usage: %s job-id user title copies options [file]"),
-                   argv[0]);
+    _cupsLangPrintf(stderr, _("Usage: %s job-id user title copies options [file]"), argv[0]);
     return (1);
   }
 
- /*
-  * Only do discovery when run as "dnssd"...
-  */
-
+  // Only do discovery when run as "dnssd"...
   if ((name = strrchr(argv[0], '/')) != NULL)
     name ++;
   else
@@ -199,294 +114,92 @@ main(int  argc,                          /* I - Number of command-line args */
   if (strcmp(name, "dnssd"))
     return (0);
 
- /*
-  * Create an array to track devices...
-  */
-
-  devices = cupsArrayNew((cups_array_func_t)compare_devices, NULL);
-
- /*
-  * Browse for different kinds of printers...
-  */
+  // Create an array to track devices...
+  Devices = cupsArrayNew((cups_array_func_t)compare_devices, /*cb_data*/NULL);
 
-#ifdef HAVE_MDNSRESPONDER
-  if (DNSServiceCreateConnection(&main_ref) != kDNSServiceErr_NoError)
-  {
-    perror("ERROR: Unable to create service connection");
+  // Browse for different kinds of printers...
+  if ((dnssd = cupsDNSSDNew(error_cb, /*cb_data*/NULL)) == NULL)
     return (1);
-  }
-
-  fd = DNSServiceRefSockFD(main_ref);
-
-  fax_ipp_ref = main_ref;
-  DNSServiceBrowse(&fax_ipp_ref, kDNSServiceFlagsShareConnection, 0,
-                   "_fax-ipp._tcp", NULL, browse_callback, devices);
-
-  ipp_ref = main_ref;
-  DNSServiceBrowse(&ipp_ref, kDNSServiceFlagsShareConnection, 0,
-                   "_ipp._tcp", NULL, browse_callback, devices);
 
-  ipp_tls_ref = main_ref;
-  DNSServiceBrowse(&ipp_tls_ref, kDNSServiceFlagsShareConnection, 0,
-                   "_ipp-tls._tcp", NULL, browse_callback, devices);
+  cupsDNSSDBrowseNew(dnssd, CUPS_DNSSD_IF_INDEX_ANY, "_fax-ipp._tcp", /*domain*/NULL, (cups_dnssd_browse_cb_t)browse_callback, /*cb_data*/NULL);
+  cupsDNSSDBrowseNew(dnssd, CUPS_DNSSD_IF_INDEX_ANY, "_ipp._tcp", /*domain*/NULL, (cups_dnssd_browse_cb_t)browse_callback, /*cb_data*/NULL);
+  cupsDNSSDBrowseNew(dnssd, CUPS_DNSSD_IF_INDEX_ANY, "_ipp-tls._tcp", /*domain*/NULL, (cups_dnssd_browse_cb_t)browse_callback, /*cb_data*/NULL);
+  cupsDNSSDBrowseNew(dnssd, CUPS_DNSSD_IF_INDEX_ANY, "_ipps._tcp", /*domain*/NULL, (cups_dnssd_browse_cb_t)browse_callback, /*cb_data*/NULL);
+  cupsDNSSDBrowseNew(dnssd, CUPS_DNSSD_IF_INDEX_ANY, "_pdl-datastream._tcp", /*domain*/NULL, (cups_dnssd_browse_cb_t)browse_callback, /*cb_data*/NULL);
+  cupsDNSSDBrowseNew(dnssd, CUPS_DNSSD_IF_INDEX_ANY, "_printer._tcp", /*domain*/NULL, (cups_dnssd_browse_cb_t)browse_callback, /*cb_data*/NULL);
+  cupsDNSSDBrowseNew(dnssd, CUPS_DNSSD_IF_INDEX_ANY, "_riousbprint._tcp", /*domain*/NULL, (cups_dnssd_browse_cb_t)browse_callback, /*cb_data*/NULL);
 
-  ipps_ref = main_ref;
-  DNSServiceBrowse(&ipps_ref, kDNSServiceFlagsShareConnection, 0,
-                   "_ipps._tcp", NULL, browse_callback, devices);
+  // Loop until we are killed...
+  start = time(NULL);
 
-  local_fax_ipp_ref = main_ref;
-  DNSServiceBrowse(&local_fax_ipp_ref, kDNSServiceFlagsShareConnection,
-                   kDNSServiceInterfaceIndexLocalOnly,
-                  "_fax-ipp._tcp", NULL, browse_local_callback, devices);
-
-  local_ipp_ref = main_ref;
-  DNSServiceBrowse(&local_ipp_ref, kDNSServiceFlagsShareConnection,
-                   kDNSServiceInterfaceIndexLocalOnly,
-                  "_ipp._tcp", NULL, browse_local_callback, devices);
-
-  local_ipp_tls_ref = main_ref;
-  DNSServiceBrowse(&local_ipp_tls_ref, kDNSServiceFlagsShareConnection,
-                   kDNSServiceInterfaceIndexLocalOnly,
-                   "_ipp-tls._tcp", NULL, browse_local_callback, devices);
-
-  local_ipps_ref = main_ref;
-  DNSServiceBrowse(&local_ipps_ref, kDNSServiceFlagsShareConnection,
-                   kDNSServiceInterfaceIndexLocalOnly,
-                  "_ipps._tcp", NULL, browse_local_callback, devices);
-
-  local_printer_ref = main_ref;
-  DNSServiceBrowse(&local_printer_ref, kDNSServiceFlagsShareConnection,
-                   kDNSServiceInterfaceIndexLocalOnly,
-                   "_printer._tcp", NULL, browse_local_callback, devices);
-
-  pdl_datastream_ref = main_ref;
-  DNSServiceBrowse(&pdl_datastream_ref, kDNSServiceFlagsShareConnection, 0,
-                   "_pdl-datastream._tcp", NULL, browse_callback, devices);
-
-  printer_ref = main_ref;
-  DNSServiceBrowse(&printer_ref, kDNSServiceFlagsShareConnection, 0,
-                   "_printer._tcp", NULL, browse_callback, devices);
-
-  riousbprint_ref = main_ref;
-  DNSServiceBrowse(&riousbprint_ref, kDNSServiceFlagsShareConnection, 0,
-                   "_riousbprint._tcp", NULL, browse_callback, devices);
-#endif /* HAVE_MDNSRESPONDER */
-
-#ifdef HAVE_AVAHI
-  if ((simple_poll = avahi_simple_poll_new()) == NULL)
-  {
-    fputs("DEBUG: Unable to create Avahi simple poll object.\n", stderr);
-    return (0);
-  }
-
-  avahi_simple_poll_set_func(simple_poll, poll_callback, NULL);
-
-  client = avahi_client_new(avahi_simple_poll_get(simple_poll),
-                           0, client_callback, simple_poll, &error);
-  if (!client)
+  while (!JobCanceled)
   {
-    fputs("DEBUG: Unable to create Avahi client.\n", stderr);
-    return (0);
-  }
-
-  browsers = 6;
-  avahi_service_browser_new(client, AVAHI_IF_UNSPEC,
-                           AVAHI_PROTO_UNSPEC,
-                           "_fax-ipp._tcp", NULL, 0,
-                           browse_callback, devices);
-  avahi_service_browser_new(client, AVAHI_IF_UNSPEC,
-                           AVAHI_PROTO_UNSPEC,
-                           "_ipp._tcp", NULL, 0,
-                           browse_callback, devices);
-  avahi_service_browser_new(client, AVAHI_IF_UNSPEC,
-                           AVAHI_PROTO_UNSPEC,
-                           "_ipp-tls._tcp", NULL, 0,
-                           browse_callback, devices);
-  avahi_service_browser_new(client, AVAHI_IF_UNSPEC,
-                           AVAHI_PROTO_UNSPEC,
-                           "_ipps._tcp", NULL, 0,
-                           browse_callback, devices);
-  avahi_service_browser_new(client, AVAHI_IF_UNSPEC,
-                           AVAHI_PROTO_UNSPEC,
-                           "_pdl-datastream._tcp",
-                           NULL, 0,
-                           browse_callback,
-                           devices);
-  avahi_service_browser_new(client, AVAHI_IF_UNSPEC,
-                           AVAHI_PROTO_UNSPEC,
-                           "_printer._tcp", NULL, 0,
-                           browse_callback, devices);
-#endif /* HAVE_AVAHI */
-
- /*
-  * Loop until we are killed...
-  */
-
-  while (!job_canceled)
-  {
-    int announce = 0;                  /* Announce printers? */
-
-#ifdef HAVE_MDNSRESPONDER
-    FD_ZERO(&input);
-    FD_SET(fd, &input);
+    sleep(1);
 
-    timeout.tv_sec  = 0;
-    timeout.tv_usec = 500000;
-
-    if (select(fd + 1, &input, NULL, NULL, &timeout) < 0)
-      continue;
+    cupsMutexLock(&DevicesMutex);
 
-    if (FD_ISSET(fd, &input))
+    if (cupsArrayGetCount(Devices) > 0)
     {
-     /*
-      * Process results of our browsing...
-      */
-
-      DNSServiceProcessResult(main_ref);
-    }
-    else
-      announce = 1;
+      // Announce any devices we've found...
+      cups_device_t *best;             // Best matching device
+      char     device_uri[1024];       // Device URI
+      int      count;                  // Number of queries
+      int      sent;                   // Number of sent
 
-#elif defined(HAVE_AVAHI)
-    got_data = 0;
-
-    if ((error = avahi_simple_poll_iterate(simple_poll, 500)) > 0)
-    {
-     /*
-      * We've been told to exit the loop.  Perhaps the connection to
-      * Avahi failed.
-      */
-
-      break;
-    }
-
-    if (!got_data)
-      announce = 1;
-#endif /* HAVE_MDNSRESPONDER */
-
-/*    fprintf(stderr, "DEBUG: announce=%d\n", announce);*/
-
-    if (announce)
-    {
-     /*
-      * Announce any devices we've found...
-      */
-
-#ifdef HAVE_MDNSRESPONDER
-      DNSServiceErrorType status;      /* DNS query status */
-#endif /* HAVE_MDNSRESPONDER */
-      cups_device_t *best;             /* Best matching device */
-      char     device_uri[1024];       /* Device URI */
-      int      count;                  /* Number of queries */
-      int      sent;                   /* Number of sent */
-
-      for (device = (cups_device_t *)cupsArrayFirst(devices),
-               best = NULL, count = 0, sent = 0;
-           device;
-          device = (cups_device_t *)cupsArrayNext(devices))
+      for (device = (cups_device_t *)cupsArrayGetFirst(Devices), best = NULL, count = 0, sent = 0; device; device = (cups_device_t *)cupsArrayGetNext(Devices))
       {
         if (device->sent)
          sent ++;
 
-        if (device->ref)
+        if (device->query)
          count ++;
 
-        if (!device->ref && !device->sent)
+        if (!device->query && !device->sent)
        {
-        /*
-         * Found the device, now get the TXT record(s) for it...
-         */
-
+         // Found the device, now get the TXT record(s) for it...
           if (count < 50)
          {
-           fprintf(stderr, "DEBUG: Querying \"%s\"...\n", device->fullName);
-
-#ifdef HAVE_MDNSRESPONDER
-           device->ref = main_ref;
-
-           status = DNSServiceQueryRecord(&(device->ref),
-                                          kDNSServiceFlagsShareConnection,
-                                          0, device->fullName,
-                                          kDNSServiceType_TXT,
-                                          kDNSServiceClass_IN, query_callback,
-                                          device);
-            if (status != kDNSServiceErr_NoError)
-             fprintf(stderr,
-                     "ERROR: Unable to query \"%s\" for TXT records: %d\n",
-                     device->fullName, status);
-                                       /* Users never see this */
-           else
-             count ++;
+           fprintf(stderr, "DEBUG: Querying \"%s\"...\n", device->fullname);
 
-#else
-           if ((device->ref = avahi_record_browser_new(client, AVAHI_IF_UNSPEC,
-                                                       AVAHI_PROTO_UNSPEC,
-                                                       device->fullName,
-                                                       AVAHI_DNS_CLASS_IN,
-                                                       AVAHI_DNS_TYPE_TXT,
-                                                       0,
-                                                       query_callback,
-                                                       device)) == NULL)
-             fprintf(stderr,
-                     "ERROR: Unable to query \"%s\" for TXT records: %s\n",
-                     device->fullName,
-                     avahi_strerror(avahi_client_errno(client)));
-                                       /* Users never see this */
-           else
+            if ((device->query = cupsDNSSDQueryNew(dnssd, CUPS_DNSSD_IF_INDEX_ANY, device->fullname, CUPS_DNSSD_RRTYPE_TXT, (cups_dnssd_query_cb_t)query_callback, device)) != NULL)
              count ++;
-#endif /* HAVE_AVAHI */
           }
        }
        else if (!device->sent)
        {
-#ifdef HAVE_MDNSRESPONDER
-        /*
-         * Got the TXT records, now report the device...
-         */
-
-         DNSServiceRefDeallocate(device->ref);
-#else
-          avahi_record_browser_free(device->ref);
-#endif /* HAVE_MDNSRESPONDER */
-
-         device->ref = NULL;
+         // Got the TXT records, now report the device...
+         cupsDNSSDQueryDelete(device->query);
+         device->query = NULL;
 
           if (!best)
+          {
            best = device;
-         else if (_cups_strcasecmp(best->name, device->name) ||
-                  _cups_strcasecmp(best->domain, device->domain))
+         }
+         else if (_cups_strcasecmp(best->name, device->name) || _cups_strcasecmp(best->domain, device->domain))
           {
-           unquote(uriName, best->fullName, sizeof(uriName));
+           unquote(uriName, best->fullname, sizeof(uriName));
 
             if (best->uuid)
-             httpAssembleURIf(HTTP_URI_CODING_ALL, device_uri,
-                              sizeof(device_uri), "dnssd", NULL, uriName, 0,
-                              best->cups_shared ? "/cups?uuid=%s" : "/?uuid=%s",
-                              best->uuid);
+             httpAssembleURIf(HTTP_URI_CODING_ALL, device_uri, sizeof(device_uri), "dnssd", /*userpass*/NULL, uriName, /*port*/0, best->cups_shared ? "/cups?uuid=%s" : "/?uuid=%s", best->uuid);
            else
-             httpAssembleURI(HTTP_URI_CODING_ALL, device_uri,
-                             sizeof(device_uri), "dnssd", NULL, uriName, 0,
-                             best->cups_shared ? "/cups" : "/");
+             httpAssembleURI(HTTP_URI_CODING_ALL, device_uri, sizeof(device_uri), "dnssd", /*userpass*/NULL, uriName, /*port*/0, best->cups_shared ? "/cups" : "/");
 
-           cupsBackendReport("network", device_uri, best->make_and_model,
-                             best->name, best->device_id, NULL);
-           best->sent = 1;
+           cupsBackendReport("network", device_uri, best->make_and_model, best->name, best->device_id, best->location);
+           best->sent = true;
            best       = device;
 
            sent ++;
          }
-         else if (best->priority > device->priority ||
-                  (best->priority == device->priority &&
-                   best->type < device->type))
+         else if (best->priority > device->priority || (best->priority == device->priority && best->type < device->type))
           {
-           best->sent = 1;
+           best->sent = true;
            best       = device;
 
            sent ++;
          }
          else
          {
-           device->sent = 1;
+           device->sent = true;
 
            sent ++;
          }
@@ -495,31 +208,25 @@ main(int  argc,                           /* I - Number of command-line args */
 
       if (best)
       {
-       unquote(uriName, best->fullName, sizeof(uriName));
+       unquote(uriName, best->fullname, sizeof(uriName));
 
        if (best->uuid)
-         httpAssembleURIf(HTTP_URI_CODING_ALL, device_uri,
-                          sizeof(device_uri), "dnssd", NULL, uriName, 0,
-                          best->cups_shared ? "/cups?uuid=%s" : "/?uuid=%s",
-                          best->uuid);
+         httpAssembleURIf(HTTP_URI_CODING_ALL, device_uri, sizeof(device_uri), "dnssd", /*userpass*/NULL, uriName, /*port*/0, best->cups_shared ? "/cups?uuid=%s" : "/?uuid=%s", best->uuid);
        else
-         httpAssembleURI(HTTP_URI_CODING_ALL, device_uri,
-                         sizeof(device_uri), "dnssd", NULL, uriName, 0,
-                         best->cups_shared ? "/cups" : "/");
+         httpAssembleURI(HTTP_URI_CODING_ALL, device_uri, sizeof(device_uri), "dnssd", /*userpass*/NULL, uriName, /*port*/0, best->cups_shared ? "/cups" : "/");
 
-       cupsBackendReport("network", device_uri, best->make_and_model,
-                         best->name, best->device_id, NULL);
-       best->sent = 1;
+       cupsBackendReport("network", device_uri, best->make_and_model, best->name, best->device_id, best->location);
+       best->sent = true;
        sent ++;
       }
 
       fprintf(stderr, "DEBUG: sent=%d, count=%d\n", sent, count);
 
-#ifdef HAVE_AVAHI
-      if (sent == cupsArrayCount(devices) && browsers == 0)
-#else
-      if (sent == cupsArrayCount(devices))
-#endif /* HAVE_AVAHI */
+      bool done = sent == cupsArrayGetCount(Devices) && (time(NULL) - start) > 5;
+
+      cupsMutexUnlock(&DevicesMutex);
+
+      if (done)
        break;
     }
   }
@@ -528,219 +235,77 @@ main(int  argc,                          /* I - Number of command-line args */
 }
 
 
-#ifdef HAVE_MDNSRESPONDER
-/*
- * 'browse_callback()' - Browse devices.
- */
+//
+// 'browse_callback()' - Browse devices.
+//
 
 static void
 browse_callback(
-    DNSServiceRef       sdRef,         /* I - Service reference */
-    DNSServiceFlags     flags,         /* I - Option flags */
-    uint32_t            interfaceIndex,        /* I - Interface number */
-    DNSServiceErrorType errorCode,     /* I - Error, if any */
-    const char          *serviceName,  /* I - Name of service/device */
-    const char          *regtype,      /* I - Type of service */
-    const char          *replyDomain,  /* I - Service domain */
-    void                *context)      /* I - Devices array */
+    cups_dnssd_browse_t *browser,      // I - Service browser
+    void                *data,         // I - Callback data (unused)
+    cups_dnssd_flags_t  flags,         // I - Browse flags
+    uint32_t            if_index,      // I - Interface index
+    const char          *name,         // I - Service name
+    const char          *regtype,      // I - Service type
+    const char          *domain)       // I - Domain
 {
-  fprintf(stderr, "DEBUG2: browse_callback(sdRef=%p, flags=%x, "
-                  "interfaceIndex=%u, errorCode=%d, serviceName=\"%s\", "
-                 "regtype=\"%s\", replyDomain=\"%s\", context=%p)\n",
-          (void *)sdRef, flags, interfaceIndex, errorCode,
-         serviceName, regtype, replyDomain, context);
+  fprintf(stderr, "DEBUG2: browse_callback(browser=%p, data=%p, flags=%x, if_index==%u, name=\"%s\", regtype=\"%s\", domain=\"%s\")\n", browser, data, flags, if_index, name, regtype, domain);
 
- /*
-  * Only process "add" data...
-  */
-
-  if (errorCode != kDNSServiceErr_NoError || !(flags & kDNSServiceFlagsAdd))
+  // Only process "add" data...
+  if (!(flags & CUPS_DNSSD_FLAGS_ADD))
     return;
 
- /*
-  * Get the device...
-  */
-
-  get_device((cups_array_t *)context, serviceName, regtype, replyDomain);
+  // Get the device...
+  get_device(name, regtype, domain);
 }
 
 
-/*
- * 'browse_local_callback()' - Browse local devices.
- */
+//
+// 'compare_devices()' - Compare two devices.
+//
 
-static void
-browse_local_callback(
-    DNSServiceRef       sdRef,         /* I - Service reference */
-    DNSServiceFlags     flags,         /* I - Option flags */
-    uint32_t            interfaceIndex,        /* I - Interface number */
-    DNSServiceErrorType errorCode,     /* I - Error, if any */
-    const char          *serviceName,  /* I - Name of service/device */
-    const char          *regtype,      /* I - Type of service */
-    const char          *replyDomain,  /* I - Service domain */
-    void                *context)      /* I - Devices array */
+static int                             // O - Result of comparison
+compare_devices(cups_device_t *a,      // I - First device
+                cups_device_t *b,      // I - Second device
+                void          *data)   // I - Callback data (unused)
 {
-  cups_device_t        *device;                /* Device */
-
-
-  fprintf(stderr, "DEBUG2: browse_local_callback(sdRef=%p, flags=%x, "
-                  "interfaceIndex=%u, errorCode=%d, serviceName=\"%s\", "
-                 "regtype=\"%s\", replyDomain=\"%s\", context=%p)\n",
-          (void *)sdRef, flags, interfaceIndex, errorCode,
-         serviceName, regtype, replyDomain, context);
-
- /*
-  * Only process "add" data...
-  */
-
-  if (errorCode != kDNSServiceErr_NoError || !(flags & kDNSServiceFlagsAdd))
-    return;
-
- /*
-  * Get the device...
-  */
-
-  device = get_device((cups_array_t *)context, serviceName, regtype,
-                      replyDomain);
-
- /*
-  * Hide locally-registered devices...
-  */
-
-  fprintf(stderr, "DEBUG: Hiding local printer \"%s\"...\n",
-         device->fullName);
-  device->sent = 1;
-}
-#endif /* HAVE_MDNSRESPONDER */
-
-
-#ifdef HAVE_AVAHI
-/*
- * 'browse_callback()' - Browse devices.
- */
-
-static void
-browse_callback(
-    AvahiServiceBrowser    *browser,   /* I - Browser */
-    AvahiIfIndex           interface,  /* I - Interface index (unused) */
-    AvahiProtocol          protocol,   /* I - Network protocol (unused) */
-    AvahiBrowserEvent      event,      /* I - What happened */
-    const char             *name,      /* I - Service name */
-    const char             *type,      /* I - Registration type */
-    const char             *domain,    /* I - Domain */
-    AvahiLookupResultFlags flags,      /* I - Flags */
-    void                   *context)   /* I - Devices array */
-{
-  AvahiClient *client = avahi_service_browser_get_client(browser);
-                                       /* Client information */
-
-
-  (void)interface;
-  (void)protocol;
-  (void)context;
-
-  switch (event)
-  {
-    case AVAHI_BROWSER_FAILURE:
-       fprintf(stderr, "DEBUG: browse_callback: %s\n",
-               avahi_strerror(avahi_client_errno(client)));
-       avahi_simple_poll_quit(simple_poll);
-       break;
-
-    case AVAHI_BROWSER_NEW:
-       /*
-       * This object is new on the network.
-       */
-
-       if (flags & AVAHI_LOOKUP_RESULT_LOCAL)
-       {
-        /*
-         * This comes from the local machine so ignore it.
-         */
-
-         fprintf(stderr, "DEBUG: Ignoring local service %s.\n", name);
-       }
-       else
-       {
-        /*
-         * Create a device entry for it if it doesn't yet exist.
-         */
-
-         get_device((cups_array_t *)context, name, type, domain);
-       }
-       break;
-
-    case AVAHI_BROWSER_REMOVE:
-    case AVAHI_BROWSER_CACHE_EXHAUSTED:
-        break;
+  (void)data;
 
-    case AVAHI_BROWSER_ALL_FOR_NOW:
-       browsers--;
-       break;
-  }
+  return (strcmp(a->name, b->name));
 }
 
 
-/*
- * 'client_callback()' - Avahi client callback function.
- */
+//
+// 'error_cb()' - Log an error message.
+//
 
 static void
-client_callback(
-    AvahiClient      *client,          /* I - Client information (unused) */
-    AvahiClientState state,            /* I - Current state */
-    void             *context)         /* I - User data (unused) */
-{
-  (void)client;
-  (void)context;
-
- /*
-  * If the connection drops, quit.
-  */
-
-  if (state == AVAHI_CLIENT_FAILURE)
-  {
-    fputs("DEBUG: Avahi connection failed.\n", stderr);
-    avahi_simple_poll_quit(simple_poll);
-  }
-}
-#endif /* HAVE_AVAHI */
-
-
-/*
- * 'compare_devices()' - Compare two devices.
- */
-
-static int                             /* O - Result of comparison */
-compare_devices(cups_device_t *a,      /* I - First device */
-                cups_device_t *b,      /* I - Second device */
-                void       *data)      /* I - Unused */
+error_cb(void       *data,             // I - Callback data (unused)
+         const char *message)          // I - Error message
 {
   (void)data;
-  return (strcmp(a->name, b->name));
+
+  fprintf(stderr, "ERROR: %s\n", message);
 }
 
 
-/*
- * 'exec_backend()' - Execute the backend that corresponds to the
- *                    resolved service name.
- */
+//
+// 'exec_backend()' - Execute the backend that corresponds to the
+//                    resolved service name.
+//
 
 static void
-exec_backend(char **argv)              /* I - Command-line arguments */
+exec_backend(char **argv)              // I - Command-line arguments
 {
-  const char   *resolved_uri,          /* Resolved device URI */
-               *cups_serverbin;        /* Location of programs */
-  char         scheme[1024],           /* Scheme from URI */
-               *ptr,                   /* Pointer into scheme */
-               filename[1024];         /* Backend filename */
+  const char   *resolved_uri,          // Resolved device URI
+               *cups_serverbin;        // Location of programs
+  char         scheme[1024],           // Scheme from URI
+               *ptr,                   // Pointer into scheme
+               filename[1024];         // Backend filename
 
 
- /*
-  * Resolve the device URI...
-  */
-
-  job_canceled = -1;
+  // Resolve the device URI...
+  JobCanceled = -1;
 
   while ((resolved_uri = cupsBackendDeviceURI(argv)) == NULL)
   {
@@ -786,12 +351,12 @@ exec_backend(char **argv)         /* I - Command-line arguments */
 }
 
 
-/*
- * 'device_type()' - Get DNS-SD type enumeration from string.
- */
+//
+// 'device_type()' - Get DNS-SD type enumeration from string.
+//
 
-static cups_devtype_t                  /* O - Device type */
-device_type(const char *regtype)       /* I - Service registration type */
+static cups_devtype_t                  // O - Device type
+device_type(const char *regtype)       // I - Service registration type
 {
 #ifdef HAVE_AVAHI
   if (!strcmp(regtype, "_ipp._tcp"))
@@ -815,247 +380,131 @@ device_type(const char *regtype)        /* I - Service registration type */
     return (CUPS_DEVICE_PRINTER);
   else if (!strcmp(regtype, "_pdl-datastream._tcp."))
     return (CUPS_DEVICE_PDL_DATASTREAM);
-#endif /* HAVE_AVAHI */
+#endif // HAVE_AVAHI
 
   return (CUPS_DEVICE_RIOUSBPRINT);
 }
 
 
-/*
- * 'get_device()' - Create or update a device.
- */
+//
+// 'get_device()' - Create or update a device.
+//
 
-static cups_device_t *                 /* O - Device */
-get_device(cups_array_t *devices,      /* I - Device array */
-           const char   *serviceName,  /* I - Name of service/device */
-           const char   *regtype,      /* I - Type of service */
-           const char   *replyDomain)  /* I - Service domain */
+static cups_device_t *                 // O - Device
+get_device(const char   *name,         // I - Name of service/device
+           const char   *regtype,      // I - Type of service
+           const char   *domain)       // I - Service domain
 {
-  cups_device_t        key,                    /* Search key */
-               *device;                /* Device */
-  char         fullName[kDNSServiceMaxDomainName];
-                                       /* Full name for query */
+  cups_device_t        key,                    // Search key
+               *device;                // Device
+  char         fullname[1024];         // Full name for query
 
 
- /*
-  * See if this is a new device...
-  */
+  // See if this is a new device...
+  cupsMutexLock(&DevicesMutex);
 
-  key.name = (char *)serviceName;
+  key.name = (char *)name;
   key.type = device_type(regtype);
 
-  for (device = cupsArrayFind(devices, &key);
-       device;
-       device = cupsArrayNext(devices))
+  for (device = cupsArrayFind(Devices, &key); device; device = cupsArrayGetNext(Devices))
+  {
     if (_cups_strcasecmp(device->name, key.name))
+    {
+      // Out of matches...
       break;
+    }
     else if (device->type == key.type)
     {
-      if (!_cups_strcasecmp(device->domain, "local.") &&
-          _cups_strcasecmp(device->domain, replyDomain))
+      // Match!
+      if (!_cups_strcasecmp(device->domain, "local.") && _cups_strcasecmp(device->domain, domain))
       {
-       /*
-        * Update the .local listing to use the "global" domain name instead.
-       * The backend will try local lookups first, then the global domain name.
-       */
-
+        // Update the .local listing to use the "global" domain name instead.
+       // The backend will try local lookups first, then the global domain name.
         free(device->domain);
-       device->domain = strdup(replyDomain);
-
-#ifdef HAVE_MDNSRESPONDER
-       DNSServiceConstructFullName(fullName, device->name, regtype,
-                                   replyDomain);
-#else /* HAVE_AVAHI */
-       avahi_service_name_join(fullName, kDNSServiceMaxDomainName,
-                               serviceName, regtype, replyDomain);
-#endif /* HAVE_MDNSRESPONDER */
-
-       free(device->fullName);
-       device->fullName = strdup(fullName);
+       device->domain = strdup(domain);
+
+        cupsDNSSDAssembleFullName(fullname, sizeof(fullname), name, regtype, domain);
+       free(device->fullname);
+       device->fullname = strdup(fullname);
       }
 
+      cupsMutexUnlock(&DevicesMutex);
+
       return (device);
     }
+  }
 
- /*
-  * Yes, add the device...
-  */
-
+  // New device, add it...
   if ((device = calloc(1, sizeof(cups_device_t))) == NULL)
   {
     perror("DEBUG: Out of memory adding a device");
     return (NULL);
   }
 
-  device->name     = strdup(serviceName);
-  device->domain   = strdup(replyDomain);
+  device->name     = strdup(name);
+  device->domain   = strdup(domain);
   device->type     = key.type;
   device->priority = 50;
 
-  cupsArrayAdd(devices, device);
-
- /*
-  * Set the "full name" of this service, which is used for queries...
-  */
+  cupsArrayAdd(Devices, device);
 
-#ifdef HAVE_MDNSRESPONDER
-  DNSServiceConstructFullName(fullName, serviceName, regtype, replyDomain);
-#else /* HAVE_AVAHI */
-  avahi_service_name_join(fullName, kDNSServiceMaxDomainName, serviceName, regtype, replyDomain);
-#endif /* HAVE_MDNSRESPONDER */
+  // Set the "full name" of this service, which is used for queries...
+  cupsDNSSDAssembleFullName(fullname, sizeof(fullname), name, regtype, domain);
+  device->fullname = strdup(fullname);
 
-  device->fullName = strdup(fullName);
+  cupsMutexUnlock(&DevicesMutex);
 
   return (device);
 }
 
 
-#ifdef HAVE_AVAHI
-/*
- * 'poll_callback()' - Wait for input on the specified file descriptors.
- *
- * Note: This function is needed because avahi_simple_poll_iterate is broken
- *       and always uses a timeout of 0 (!) milliseconds.
- *       (https://github.com/lathiat/avahi/issues/127)
- */
-
-static int                             /* O - Number of file descriptors matching */
-poll_callback(
-    struct pollfd *pollfds,            /* I - File descriptors */
-    unsigned int  num_pollfds,         /* I - Number of file descriptors */
-    int           timeout,             /* I - Timeout in milliseconds (unused) */
-    void          *context)            /* I - User data (unused) */
-{
-  int  val;                            /* Return value */
-
-
-  (void)timeout;
-  (void)context;
-
-  val = poll(pollfds, num_pollfds, 500);
-
-  if (val < 0)
-    fprintf(stderr, "DEBUG: poll_callback: %s\n", strerror(errno));
-  else if (val > 0)
-    got_data = 1;
-
-  return (val);
-}
-#endif /* HAVE_AVAHI */
-
-
-#ifdef HAVE_MDNSRESPONDER
-/*
- * 'query_callback()' - Process query data.
- */
-
-static void
-query_callback(
-    DNSServiceRef       sdRef,         /* I - Service reference */
-    DNSServiceFlags     flags,         /* I - Data flags */
-    uint32_t            interfaceIndex,        /* I - Interface */
-    DNSServiceErrorType errorCode,     /* I - Error, if any */
-    const char          *fullName,     /* I - Full service name */
-    uint16_t            rrtype,                /* I - Record type */
-    uint16_t            rrclass,       /* I - Record class */
-    uint16_t            rdlen,         /* I - Length of record data */
-    const void          *rdata,                /* I - Record data */
-    uint32_t            ttl,           /* I - Time-to-live */
-    void                *context)      /* I - Device */
-{
-#  else
-/*
- * 'query_callback()' - Process query data.
- */
+//
+// 'query_callback()' - Process query data.
+//
 
 static void
 query_callback(
-    AvahiRecordBrowser     *browser,   /* I - Record browser */
-    AvahiIfIndex           interfaceIndex,
-                                       /* I - Interface index (unused) */
-    AvahiProtocol          protocol,   /* I - Network protocol (unused) */
-    AvahiBrowserEvent      event,      /* I - What happened? */
-    const char             *fullName,  /* I - Service name */
-    uint16_t               rrclass,    /* I - Record class */
-    uint16_t               rrtype,     /* I - Record type */
-    const void             *rdata,     /* I - TXT record */
-    size_t                 rdlen,      /* I - Length of TXT record */
-    AvahiLookupResultFlags flags,      /* I - Flags */
-    void                   *context)   /* I - Device */
+    cups_dnssd_query_t *query,         // I - Query request
+    cups_device_t      *device,                // I - Device
+    cups_dnssd_flags_t flags,          // I - Query flags
+    uint32_t           if_index,       // I - Response interface index
+    const char         *fullname,      // I - Fullname
+    uint16_t           rrtype,         // I - RR type (TXT)
+    const void         *qdata,         // I - Data
+    uint16_t           qlen)           // I - Length of data
 {
-  AvahiClient          *client = avahi_record_browser_get_client(browser);
-                                       /* Client information */
-#  endif /* HAVE_MDNSRESPONDER */
-  char         *ptr;                   /* Pointer into string */
-  cups_device_t        *device = (cups_device_t *)context;
-                                       /* Device */
-  const uint8_t        *data,                  /* Pointer into data */
-               *datanext,              /* Next key/value pair */
-               *dataend;               /* End of entire TXT record */
-  uint8_t      datalen;                /* Length of current key/value pair */
-  char         key[256],               /* Key string */
-               value[256],             /* Value string */
-               make_and_model[512],    /* Manufacturer and model */
-               model[256],             /* Model */
-               pdl[256],               /* PDL */
-               device_id[2048];        /* 1284 device ID */
-
-
-#  ifdef HAVE_MDNSRESPONDER
-  fprintf(stderr, "DEBUG2: query_callback(sdRef=%p, flags=%x, "
-                  "interfaceIndex=%u, errorCode=%d, fullName=\"%s\", "
-                 "rrtype=%u, rrclass=%u, rdlen=%u, rdata=%p, ttl=%u, "
-                 "context=%p)\n",
-          (void *)sdRef, flags, interfaceIndex, errorCode, fullName, rrtype, rrclass, rdlen, rdata, ttl, context);
-
- /*
-  * Only process "add" data...
-  */
-
-  if (errorCode != kDNSServiceErr_NoError || !(flags & kDNSServiceFlagsAdd))
-    return;
-
-#  else
-  fprintf(stderr, "DEBUG2: query_callback(browser=%p, interfaceIndex=%u, "
-                  "protocol=%d, event=%d, fullName=\"%s\", rrclass=%u, "
-                 "rrtype=%u, rdata=%p, rdlen=%u, flags=%x, context=%p)\n",
-          browser, interfaceIndex, protocol, event, fullName, rrclass, rrtype, rdata, (unsigned)rdlen, flags, context);
-
- /*
-  * Only process "add" data...
-  */
-
-  if (event != AVAHI_BROWSER_NEW)
-  {
-    if (event == AVAHI_BROWSER_FAILURE)
-      fprintf(stderr, "ERROR: %s\n",
-             avahi_strerror(avahi_client_errno(client)));
-
+  char         *ptr;                   // Pointer into string
+  const uint8_t        *data,                  // Pointer into data
+               *datanext,              // Next key/value pair
+               *dataend;               // End of entire TXT record
+  uint8_t      datalen;                // Length of current key/value pair
+  char         key[256],               // Key string
+               value[256],             // Value string
+               make_and_model[512],    // Manufacturer and model
+               model[256],             // Model
+               pdl[256],               // PDL
+               device_id[2048];        // 1284 device ID
+
+
+  fprintf(stderr, "DEBUG2: query_callback(query=%p, device=%p, flags=%x, if_index=%u, fullname=\"%s\", rrtype=%u, qdata=%p, qlen=%u)\n", query, device, flags, if_index, fullname, rrtype, qdata, qlen);
+
+  // Only process "add" data...
+  if (!(flags & CUPS_DNSSD_FLAGS_ADD))
     return;
-  }
-#  endif /* HAVE_MDNSRESPONDER */
-
- /*
-  * Pull out the priority and make and model from the TXT
-  * record and save it...
-  */
 
+  // Pull out the priority, location, make and model, and pdl list from the TXT
+  // record and save it...
   device_id[0]      = '\0';
   make_and_model[0] = '\0';
   pdl[0]            = '\0';
 
   cupsCopyString(model, "Unknown", sizeof(model));
 
-  for (data = rdata, dataend = data + rdlen;
-       data < dataend;
-       data = datanext)
+  for (data = qdata, dataend = data + qlen; data < dataend; data = datanext)
   {
-   /*
-    * Read a key/value pair starting with an 8-bit length.  Since the
-    * length is 8 bits and the size of the key/value buffers is 256, we
-    * don't need to check for overflow...
-    */
-
+    // Read a key/value pair starting with an 8-bit length.  Since the
+    // length is 8 bits and the size of the key/value buffers is 256, we
+    // don't need to check for overflow...
     datalen = *data++;
 
     if (!datalen || (data + datalen) > dataend)
@@ -1075,46 +524,43 @@ query_callback(
        memcpy(value, data, (size_t)(datanext - data));
       value[datanext - data] = '\0';
 
-      fprintf(stderr, "DEBUG2: query_callback: \"%s=%s\".\n",
-             key, value);
+      fprintf(stderr, "DEBUG2: query_callback: \"%s=%s\".\n", key, value);
     }
     else
     {
-      fprintf(stderr, "DEBUG2: query_callback: \"%s\" with no value.\n",
-             key);
+      fprintf(stderr, "DEBUG2: query_callback: \"%s\" with no value.\n", key);
       continue;
     }
 
     if (!_cups_strncasecmp(key, "usb_", 4))
     {
-     /*
-      * Add USB device ID information...
-      */
-
+      // Add USB device ID information...
       ptr = device_id + strlen(device_id);
       snprintf(ptr, sizeof(device_id) - (size_t)(ptr - device_id), "%s:%s;", key + 4, value);
     }
 
-    if (!_cups_strcasecmp(key, "usb_MFG") || !_cups_strcasecmp(key, "usb_MANU") ||
-       !_cups_strcasecmp(key, "usb_MANUFACTURER"))
+    if (!_cups_strcasecmp(key, "usb_MFG") || !_cups_strcasecmp(key, "usb_MANU") || !_cups_strcasecmp(key, "usb_MANUFACTURER"))
+    {
       cupsCopyString(make_and_model, value, sizeof(make_and_model));
+    }
     else if (!_cups_strcasecmp(key, "usb_MDL") || !_cups_strcasecmp(key, "usb_MODEL"))
+    {
       cupsCopyString(model, value, sizeof(model));
+    }
     else if (!_cups_strcasecmp(key, "product") && !strstr(value, "Ghostscript"))
     {
       if (value[0] == '(')
       {
-       /*
-       * Strip parenthesis...
-       */
-
+        // Strip parenthesis...
        if ((ptr = value + strlen(value) - 1) > value && *ptr == ')')
          *ptr = '\0';
 
        cupsCopyString(model, value + 1, sizeof(model));
       }
       else
+      {
        cupsCopyString(model, value, sizeof(model));
+      }
     }
     else if (!_cups_strcasecmp(key, "ty"))
     {
@@ -1124,25 +570,29 @@ query_callback(
        *ptr = '\0';
     }
     else if (!_cups_strcasecmp(key, "pdl"))
+    {
       cupsCopyString(pdl, value, sizeof(pdl));
+    }
     else if (!_cups_strcasecmp(key, "priority"))
+    {
       device->priority = atoi(value);
-    else if ((device->type == CUPS_DEVICE_IPP ||
-             device->type == CUPS_DEVICE_IPPS ||
-             device->type == CUPS_DEVICE_PRINTER) &&
-            !_cups_strcasecmp(key, "printer-type"))
+    }
+    else if ((device->type == CUPS_DEVICE_IPP || device->type == CUPS_DEVICE_IPPS || device->type == CUPS_DEVICE_PRINTER) && !_cups_strcasecmp(key, "printer-type"))
     {
-     /*
-      * This is a CUPS printer!
-      */
-
-      device->cups_shared = 1;
+      // This is a CUPS printer.
+      device->cups_shared = true;
 
       if (device->type == CUPS_DEVICE_PRINTER)
-       device->sent = 1;
+       device->sent = true;
+    }
+    else if (!_cups_strcasecmp(key, "note") && value[0])
+    {
+      device->location = strdup(value);
     }
     else if (!_cups_strcasecmp(key, "UUID"))
+    {
       device->uuid = strdup(value);
+    }
   }
 
   if (device->device_id)
@@ -1151,33 +601,28 @@ query_callback(
   if (!device_id[0] && strcmp(model, "Unknown"))
   {
     if (make_and_model[0])
-      snprintf(device_id, sizeof(device_id), "MFG:%s;MDL:%s;",
-              make_and_model, model);
+    {
+      snprintf(device_id, sizeof(device_id), "MFG:%s;MDL:%s;", make_and_model, model);
+    }
     else if (!_cups_strncasecmp(model, "designjet ", 10))
+    {
       snprintf(device_id, sizeof(device_id), "MFG:HP;MDL:%s;", model + 10);
+    }
     else if (!_cups_strncasecmp(model, "stylus ", 7))
+    {
       snprintf(device_id, sizeof(device_id), "MFG:EPSON;MDL:%s;", model + 7);
+    }
     else if ((ptr = strchr(model, ' ')) != NULL)
     {
-     /*
-      * Assume the first word is the make...
-      */
-
+      // Assume the first word is the make...
       memcpy(make_and_model, model, (size_t)(ptr - model));
       make_and_model[ptr - model] = '\0';
 
-      snprintf(device_id, sizeof(device_id), "MFG:%s;MDL:%s;",
-              make_and_model, ptr + 1);
+      snprintf(device_id, sizeof(device_id), "MFG:%s;MDL:%s;", make_and_model, ptr + 1);
     }
   }
 
-  if (device_id[0] &&
-      !strstr(device_id, "CMD:") &&
-      !strstr(device_id, "COMMAND SET:") &&
-      (strstr(pdl, "application/pdf") ||
-       strstr(pdl, "application/postscript") ||
-       strstr(pdl, "application/vnd.hp-PCL") ||
-       strstr(pdl, "image/")))
+  if (device_id[0] && !strstr(device_id, "CMD:") && !strstr(device_id, "COMMAND SET:") && (strstr(pdl, "application/pdf") || strstr(pdl, "application/postscript") || strstr(pdl, "application/vnd.hp-PCL") || strstr(pdl, "image/")))
   {
     value[0] = '\0';
     if (strstr(pdl, "application/pdf"))
@@ -1189,7 +634,7 @@ query_callback(
     for (ptr = strstr(pdl, "image/"); ptr; ptr = strstr(ptr, "image/"))
     {
       char *valptr = value + strlen(value);
-                                       /* Pointer into value */
+                                       // Pointer into value
 
       if (valptr < (value + sizeof(value) - 1))
         *valptr++ = ',';
@@ -1233,36 +678,38 @@ query_callback(
     device->make_and_model = strdup(make_and_model);
   }
   else
+  {
     device->make_and_model = strdup(model);
+  }
 }
 
 
-/*
- * 'sigterm_handler()' - Handle termination signals.
- */
+//
+// 'sigterm_handler()' - Handle termination signals.
+//
 
 static void
-sigterm_handler(int sig)               /* I - Signal number (unused) */
+sigterm_handler(int sig)               // I - Signal number (unused)
 {
   (void)sig;
 
-  if (job_canceled)
+  if (JobCanceled)
     _exit(CUPS_BACKEND_OK);
   else
-    job_canceled = 1;
+    JobCanceled = 1;
 }
 
 
-/*
- * 'unquote()' - Unquote a name string.
- */
+//
+// 'unquote()' - Unquote a name string.
+//
 
 static void
-unquote(char       *dst,               /* I - Destination buffer */
-        const char *src,               /* I - Source string */
-       size_t     dstsize)             /* I - Size of destination buffer */
+unquote(char       *dst,               // I - Destination buffer
+        const char *src,               // I - Source string
+       size_t     dstsize)             // I - Size of destination buffer
 {
-  char *dstend = dst + dstsize - 1;    /* End of destination buffer */
+  char *dstend = dst + dstsize - 1;    // End of destination buffer
 
 
   while (*src && dst < dstend)
@@ -1270,17 +717,20 @@ unquote(char       *dst,         /* I - Destination buffer */
     if (*src == '\\')
     {
       src ++;
-      if (isdigit(src[0] & 255) && isdigit(src[1] & 255) &&
-          isdigit(src[2] & 255))
+      if (isdigit(src[0] & 255) && isdigit(src[1] & 255) && isdigit(src[2] & 255))
       {
         *dst++ = ((((src[0] - '0') * 10) + src[1] - '0') * 10) + src[2] - '0';
        src += 3;
       }
       else
+      {
         *dst++ = *src++;
+      }
     }
     else
+    {
       *dst++ = *src ++;
+    }
   }
 
   *dst = '\0';