]> git.ipfire.org Git - thirdparty/cups.git/commitdiff
Back-port more compatibility fixes from CUPS 2.3.x - IPP/1.1 compatibility with
authorMichael R Sweet <michael.r.sweet@gmail.com>
Tue, 28 May 2019 18:54:01 +0000 (14:54 -0400)
committerMichael R Sweet <michael.r.sweet@gmail.com>
Tue, 28 May 2019 18:54:01 +0000 (14:54 -0400)
old versions of CUPS... (Issue #5587)

CHANGES.md
cups/cups-private.h
cups/dest-options.c
cups/dest.c
cups/testdest.c

index 6ddae30828c34a330ffe82145f1ea1475a9bd768..9ac73bd83e1b400f48ce066df334719482aa77a4 100644 (file)
@@ -1,4 +1,4 @@
-CHANGES - 2.2.12 - 2019-05-24
+CHANGES - 2.2.12 - 2019-05-28
 =============================
 
 
@@ -19,6 +19,7 @@ Changes in CUPS v2.2.12
   (Issue #5574)
 - The libusb-based USB backend now enforces read limits, improving print speed
   in many cases (Issue #5583)
+- Fixed some compatibility issues with old releases of CUPS (Issue #5587)
 - Fixed a command ordering issue in the Zebra ZPL driver.
 
 
index 6fd66a9cedd1d0893b6945748650978fa42da396..4ec4e6864bef7c4eaac816354f3f815b45dfd714 100644 (file)
@@ -239,8 +239,7 @@ extern http_t               *_cupsConnect(void);
 extern char            *_cupsCreateDest(const char *name, const char *info, const char *device_id, const char *device_uri, char *uri, size_t urisize);
 extern int             _cupsGet1284Values(const char *device_id,
                                           cups_option_t **values);
-extern const char      *_cupsGetDestResource(cups_dest_t *dest, char *resource,
-                                             size_t resourcesize);
+extern const char      *_cupsGetDestResource(cups_dest_t *dest, unsigned flags, char *resource, size_t resourcesize);
 extern int             _cupsGetDests(http_t *http, ipp_op_t op,
                                      const char *name, cups_dest_t **dests,
                                      cups_ptype_t type, cups_ptype_t mask);
index cddc2f9550d0b17c02d972a724b9eb68a9e482fb..e9361adf78b5436ac7082367355eec181edb3630 100644 (file)
@@ -129,10 +129,10 @@ cupsCheckDestSupported(
     */
 
     pwg_media_t        *pwg;           /* Current PWG media size info */
-    int                        min_width,      /* Minimum width */
-                       min_length,     /* Minimum length */
-                       max_width,      /* Maximum width */
-                       max_length;     /* Maximum length */
+    int                min_width,      /* Minimum width */
+               min_length,     /* Minimum length */
+               max_width,      /* Maximum width */
+               max_length;     /* Maximum length */
 
    /*
     * Get the minimum and maximum size...
@@ -581,6 +581,7 @@ cupsCopyDestInfo(
     cups_dest_t *dest)                 /* I - Destination */
 {
   cups_dinfo_t *dinfo;                 /* Destination information */
+  unsigned     dflags;                 /* Destination flags */
   ipp_t                *request,               /* Get-Printer-Attributes request */
                *response;              /* Supported attributes */
   int          tries,                  /* Number of tries so far */
@@ -590,6 +591,7 @@ cupsCopyDestInfo(
   char         resource[1024];         /* Resource path */
   int          version;                /* IPP version */
   ipp_status_t status;                 /* Status of request */
+  _cups_globals_t *cg = _cupsGlobals();        /* Pointer to library globals */
   static const char * const requested_attrs[] =
   {                                    /* Requested attributes */
     "job-template",
@@ -598,14 +600,35 @@ cupsCopyDestInfo(
   };
 
 
-  DEBUG_printf(("cupsCopyDestSupported(http=%p, dest=%p(%s))", (void *)http, (void *)dest, dest ? dest->name : ""));
+  DEBUG_printf(("cupsCopyDestInfo(http=%p, dest=%p(%s))", (void *)http, (void *)dest, dest ? dest->name : ""));
 
  /*
   * Get the default connection as needed...
   */
 
   if (!http)
-    http = _cupsConnect();
+  {
+    DEBUG_puts("1cupsCopyDestInfo: Default server connection.");
+    http   = _cupsConnect();
+    dflags = CUPS_DEST_FLAGS_NONE;
+  }
+#ifdef AF_LOCAL
+  else if (httpAddrFamily(http->hostaddr) == AF_LOCAL)
+  {
+    DEBUG_puts("1cupsCopyDestInfo: Connection to server (domain socket).");
+    dflags = CUPS_DEST_FLAGS_NONE;
+  }
+#endif /* AF_LOCAL */
+  else if ((strcmp(http->hostname, cg->server) && cg->server[0] != '/') || cg->ipp_port != httpAddrPort(http->hostaddr))
+  {
+    DEBUG_printf(("1cupsCopyDestInfo: Connection to device (%s).", http->hostname));
+    dflags = CUPS_DEST_FLAGS_DEVICE;
+  }
+  else
+  {
+    DEBUG_printf(("1cupsCopyDestInfo: Connection to server (%s).", http->hostname));
+    dflags = CUPS_DEST_FLAGS_NONE;
+  }
 
  /*
   * Range check input...
@@ -618,8 +641,11 @@ cupsCopyDestInfo(
   * Get the printer URI and resource path...
   */
 
-  if ((uri = _cupsGetDestResource(dest, resource, sizeof(resource))) == NULL)
+  if ((uri = _cupsGetDestResource(dest, dflags, resource, sizeof(resource))) == NULL)
+  {
+    DEBUG_puts("1cupsCopyDestInfo: Unable to get resource.");
     return (NULL);
+  }
 
  /*
   * Get the supported attributes...
@@ -637,28 +663,25 @@ cupsCopyDestInfo(
     */
 
     request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
-    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL,
-                uri);
-    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
-                 "requesting-user-name", NULL, cupsUser());
-    ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
-                 "requested-attributes",
-                 (int)(sizeof(requested_attrs) / sizeof(requested_attrs[0])),
-                 NULL, requested_attrs);
+
+    ippSetVersion(request, version / 10, version % 10);
+    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
+    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser());
+    ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", (int)(sizeof(requested_attrs) / sizeof(requested_attrs[0])), NULL, requested_attrs);
     response = cupsDoRequest(http, request, resource);
     status   = cupsLastError();
 
     if (status > IPP_STATUS_OK_IGNORED_OR_SUBSTITUTED)
     {
-      DEBUG_printf(("cupsCopyDestSupported: Get-Printer-Attributes for '%s' "
-                   "returned %s (%s)", dest->name, ippErrorString(status),
-                   cupsLastErrorString()));
+      DEBUG_printf(("1cupsCopyDestInfo: Get-Printer-Attributes for '%s' returned %s (%s)", dest->name, ippErrorString(status), cupsLastErrorString()));
 
       ippDelete(response);
       response = NULL;
 
-      if (status == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED && version > 11)
+      if ((status == IPP_STATUS_ERROR_BAD_REQUEST || status == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED) && version > 11)
+      {
         version = 11;
+      }
       else if (status == IPP_STATUS_ERROR_BUSY)
       {
         sleep((unsigned)delay);
@@ -674,7 +697,10 @@ cupsCopyDestInfo(
   while (!response && tries < 10);
 
   if (!response)
+  {
+    DEBUG_puts("1cupsCopyDestInfo: Unable to get printer attributes.");
     return (NULL);
+  }
 
  /*
   * Allocate a cups_dinfo_t structure and return it...
@@ -687,6 +713,8 @@ cupsCopyDestInfo(
     return (NULL);
   }
 
+  DEBUG_printf(("1cupsCopyDestInfo: version=%d, uri=\"%s\", resource=\"%s\".", version, uri, resource));
+
   dinfo->version  = version;
   dinfo->uri      = uri;
   dinfo->resource = _cupsStrAlloc(resource);
@@ -947,10 +975,10 @@ cupsGetDestMediaByIndex(
     return (0);
   }
 
-  if (nsize->size_name)
-    strlcpy(size->media, nsize->size_name, sizeof(size->media));
-  else if (nsize->key)
+  if (nsize->key)
     strlcpy(size->media, nsize->key, sizeof(size->media));
+  else if (nsize->size_name)
+    strlcpy(size->media, nsize->size_name, sizeof(size->media));
   else if ((pwg = pwgMediaForSize(nsize->width, nsize->length)) != NULL)
     strlcpy(size->media, pwg->pwg, sizeof(size->media));
   else
@@ -1211,25 +1239,19 @@ cupsGetDestMediaDefault(
   * Get the default media size, if any...
   */
 
-  if ((media = cupsGetOption("media", dest->num_options,
-                             dest->options)) == NULL)
+  if ((media = cupsGetOption("media", dest->num_options, dest->options)) == NULL)
     media = "na_letter_8.5x11in";
 
   if (cupsGetDestMediaByName(http, dest, dinfo, media, flags, size))
     return (1);
 
-  if (strcmp(media, "na_letter_8.5x11in") &&
-      cupsGetDestMediaByName(http, dest, dinfo, "iso_a4_210x297mm", flags,
-                             size))
+  if (strcmp(media, "na_letter_8.5x11in") && cupsGetDestMediaByName(http, dest, dinfo, "iso_a4_210x297mm", flags, size))
     return (1);
 
-  if (strcmp(media, "iso_a4_210x297mm") &&
-      cupsGetDestMediaByName(http, dest, dinfo, "na_letter_8.5x11in", flags,
-                             size))
+  if (strcmp(media, "iso_a4_210x297mm") && cupsGetDestMediaByName(http, dest, dinfo, "na_letter_8.5x11in", flags, size))
     return (1);
 
-  if ((flags & CUPS_MEDIA_FLAGS_BORDERLESS) &&
-      cupsGetDestMediaByName(http, dest, dinfo, "na_index_4x6in", flags, size))
+  if ((flags & CUPS_MEDIA_FLAGS_BORDERLESS) && cupsGetDestMediaByName(http, dest, dinfo, "na_index_4x6in", flags, size))
     return (1);
 
  /*
@@ -1522,6 +1544,7 @@ cups_create_media_db(
   pwg_media_t          *pwg;           /* PWG media info */
   cups_array_t         *db;            /* New media database array */
   _cups_media_db_t     mdb;            /* Media entry */
+  char                 media_key[256]; /* Synthesized media-key value */
 
 
   db = cupsArrayNew3((cups_array_func_t)cups_compare_media_db,
@@ -1622,61 +1645,92 @@ cups_create_media_db(
        }
       }
 
-      if ((media_attr = ippFindAttribute(val->collection, "media-color",
-                                         IPP_TAG_ZERO)) != NULL &&
-          (media_attr->value_tag == IPP_TAG_NAME ||
-           media_attr->value_tag == IPP_TAG_NAMELANG ||
-           media_attr->value_tag == IPP_TAG_KEYWORD))
+      if ((media_attr = ippFindAttribute(val->collection, "media-color", IPP_TAG_ZERO)) != NULL && (media_attr->value_tag == IPP_TAG_NAME || media_attr->value_tag == IPP_TAG_NAMELANG || media_attr->value_tag == IPP_TAG_KEYWORD))
         mdb.color = media_attr->values[0].string.text;
 
-      if ((media_attr = ippFindAttribute(val->collection, "media-info",
-                                         IPP_TAG_TEXT)) != NULL)
+      if ((media_attr = ippFindAttribute(val->collection, "media-info", IPP_TAG_TEXT)) != NULL)
         mdb.info = media_attr->values[0].string.text;
 
-      if ((media_attr = ippFindAttribute(val->collection, "media-key",
-                                         IPP_TAG_ZERO)) != NULL &&
-          (media_attr->value_tag == IPP_TAG_NAME ||
-           media_attr->value_tag == IPP_TAG_NAMELANG ||
-           media_attr->value_tag == IPP_TAG_KEYWORD))
+      if ((media_attr = ippFindAttribute(val->collection, "media-key", IPP_TAG_ZERO)) != NULL && (media_attr->value_tag == IPP_TAG_NAME || media_attr->value_tag == IPP_TAG_NAMELANG || media_attr->value_tag == IPP_TAG_KEYWORD))
         mdb.key = media_attr->values[0].string.text;
 
-      if ((media_attr = ippFindAttribute(val->collection, "media-size-name",
-                                         IPP_TAG_ZERO)) != NULL &&
-          (media_attr->value_tag == IPP_TAG_NAME ||
-           media_attr->value_tag == IPP_TAG_NAMELANG ||
-           media_attr->value_tag == IPP_TAG_KEYWORD))
+      if ((media_attr = ippFindAttribute(val->collection, "media-size-name", IPP_TAG_ZERO)) != NULL && (media_attr->value_tag == IPP_TAG_NAME || media_attr->value_tag == IPP_TAG_NAMELANG || media_attr->value_tag == IPP_TAG_KEYWORD))
         mdb.size_name = media_attr->values[0].string.text;
 
-      if ((media_attr = ippFindAttribute(val->collection, "media-source",
-                                         IPP_TAG_ZERO)) != NULL &&
-          (media_attr->value_tag == IPP_TAG_NAME ||
-           media_attr->value_tag == IPP_TAG_NAMELANG ||
-           media_attr->value_tag == IPP_TAG_KEYWORD))
+      if ((media_attr = ippFindAttribute(val->collection, "media-source", IPP_TAG_ZERO)) != NULL && (media_attr->value_tag == IPP_TAG_NAME || media_attr->value_tag == IPP_TAG_NAMELANG || media_attr->value_tag == IPP_TAG_KEYWORD))
         mdb.source = media_attr->values[0].string.text;
 
-      if ((media_attr = ippFindAttribute(val->collection, "media-type",
-                                         IPP_TAG_ZERO)) != NULL &&
-          (media_attr->value_tag == IPP_TAG_NAME ||
-           media_attr->value_tag == IPP_TAG_NAMELANG ||
-           media_attr->value_tag == IPP_TAG_KEYWORD))
+      if ((media_attr = ippFindAttribute(val->collection, "media-type", IPP_TAG_ZERO)) != NULL && (media_attr->value_tag == IPP_TAG_NAME || media_attr->value_tag == IPP_TAG_NAMELANG || media_attr->value_tag == IPP_TAG_KEYWORD))
         mdb.type = media_attr->values[0].string.text;
 
-      if ((media_attr = ippFindAttribute(val->collection, "media-bottom-margin",
-                                         IPP_TAG_INTEGER)) != NULL)
+      if ((media_attr = ippFindAttribute(val->collection, "media-bottom-margin", IPP_TAG_INTEGER)) != NULL)
         mdb.bottom = media_attr->values[0].integer;
 
-      if ((media_attr = ippFindAttribute(val->collection, "media-left-margin",
-                                         IPP_TAG_INTEGER)) != NULL)
+      if ((media_attr = ippFindAttribute(val->collection, "media-left-margin", IPP_TAG_INTEGER)) != NULL)
         mdb.left = media_attr->values[0].integer;
 
-      if ((media_attr = ippFindAttribute(val->collection, "media-right-margin",
-                                         IPP_TAG_INTEGER)) != NULL)
+      if ((media_attr = ippFindAttribute(val->collection, "media-right-margin", IPP_TAG_INTEGER)) != NULL)
         mdb.right = media_attr->values[0].integer;
 
-      if ((media_attr = ippFindAttribute(val->collection, "media-top-margin",
-                                         IPP_TAG_INTEGER)) != NULL)
+      if ((media_attr = ippFindAttribute(val->collection, "media-top-margin", IPP_TAG_INTEGER)) != NULL)
         mdb.top = media_attr->values[0].integer;
 
+      if (!mdb.key)
+      {
+        if (!mdb.size_name && (pwg = pwgMediaForSize(mdb.width, mdb.length)) != NULL)
+         mdb.size_name = (char *)pwg->pwg;
+
+        if (!mdb.size_name)
+        {
+         /*
+          * Use a CUPS-specific identifier if we don't have a size name...
+          */
+
+         if (flags & CUPS_MEDIA_FLAGS_READY)
+           snprintf(media_key, sizeof(media_key), "cups-media-ready-%d", i + 1);
+         else
+           snprintf(media_key, sizeof(media_key), "cups-media-%d", i + 1);
+        }
+        else if (mdb.source)
+        {
+         /*
+          * Generate key using size name, source, and type (if set)...
+          */
+
+          if (mdb.type)
+            snprintf(media_key, sizeof(media_key), "%s_%s_%s", mdb.size_name, mdb.source, mdb.type);
+         else
+            snprintf(media_key, sizeof(media_key), "%s_%s", mdb.size_name, mdb.source);
+        }
+        else if (mdb.type)
+        {
+         /*
+          * Generate key using size name and type...
+          */
+
+         snprintf(media_key, sizeof(media_key), "%s_%s", mdb.size_name, mdb.type);
+        }
+        else
+        {
+         /*
+          * Key is just the size name...
+          */
+
+          strlcpy(media_key, mdb.size_name, sizeof(media_key));
+        }
+
+       /*
+        * Append "_borderless" for borderless media...
+        */
+
+        if (!mdb.bottom && !mdb.left && !mdb.right && !mdb.top)
+          strlcat(media_key, "_borderless", sizeof(media_key));
+
+        mdb.key = media_key;
+      }
+
+      DEBUG_printf(("1cups_create_media_db: Adding media: key=\"%s\", width=%d, length=%d, source=\"%s\", type=\"%s\".", mdb.key, mdb.width, mdb.length, mdb.source, mdb.type));
+
       cupsArrayAdd(db, &mdb);
     }
 
@@ -2036,12 +2090,14 @@ cups_get_media_db(http_t       *http,   /* I - Connection to destination */
     * Return the matching size...
     */
 
-    if (best->size_name)
-      strlcpy(size->media, best->size_name, sizeof(size->media));
-    else if (best->key)
+    if (best->key)
       strlcpy(size->media, best->key, sizeof(size->media));
-    else
+    else if (best->size_name)
+      strlcpy(size->media, best->size_name, sizeof(size->media));
+    else if (pwg && pwg->pwg)
       strlcpy(size->media, pwg->pwg, sizeof(size->media));
+    else
+      strlcpy(size->media, "unknown", sizeof(size->media));
 
     size->width  = best->width;
     size->length = best->length;
index 7ef85a1b9150cccdc1f78fd571ccd0d06504b7d3..fd635b1111b6b0eeb077b306832c723bd240a3f9 100644 (file)
@@ -79,7 +79,6 @@ typedef enum _cups_dnssd_state_e      /* Enumerated device state */
   _CUPS_DNSSD_QUERY,
   _CUPS_DNSSD_PENDING,
   _CUPS_DNSSD_ACTIVE,
-  _CUPS_DNSSD_LOCAL,
   _CUPS_DNSSD_INCOMPATIBLE,
   _CUPS_DNSSD_ERROR
 } _cups_dnssd_state_t;
@@ -99,6 +98,10 @@ typedef struct _cups_dnssd_data_s    /* Enumeration data */
   cups_ptype_t         type,           /* Printer type filter */
                        mask;           /* Printer type mask */
   cups_array_t         *devices;       /* Devices found so far */
+  int                  num_dests;      /* Number of lpoptions destinations */
+  cups_dest_t          *dests;         /* lpoptions destinations */
+  char                 def_name[1024], /* Default printer name, if any */
+                       *def_instance;  /* Default printer instance, if any */
 } _cups_dnssd_data_t;
 
 typedef struct _cups_dnssd_device_s    /* Enumerated device */
@@ -125,8 +128,10 @@ typedef struct _cups_dnssd_resolve_s       /* Data for resolving URI */
 
 typedef struct _cups_getdata_s
 {
-  int         num_dests;                /* Number of destinations */
-  cups_dest_t *dests;                   /* Destinations */
+  int          num_dests;              /* Number of destinations */
+  cups_dest_t  *dests;                 /* Destinations */
+  char         def_name[1024],         /* Default printer name, if any */
+               *def_instance;          /* Default printer instance, if any */
 } _cups_getdata_t;
 
 typedef struct _cups_namedata_s
@@ -192,14 +197,6 @@ static _cups_dnssd_device_t *
                                              const char *regtype,
                                              const char *replyDomain);
 #  ifdef HAVE_DNSSD
-static void            cups_dnssd_local_cb(DNSServiceRef sdRef,
-                                           DNSServiceFlags flags,
-                                           uint32_t interfaceIndex,
-                                           DNSServiceErrorType errorCode,
-                                           const char *serviceName,
-                                           const char *regtype,
-                                           const char *replyDomain,
-                                           void *context);
 static void            cups_dnssd_query_cb(DNSServiceRef sdRef,
                                            DNSServiceFlags flags,
                                            uint32_t interfaceIndex,
@@ -237,9 +234,7 @@ static int          cups_find_dest(const char *name, const char *instance,
 static int              cups_get_cb(_cups_getdata_t *data, unsigned flags, cups_dest_t *dest);
 static char            *cups_get_default(const char *filename, char *namebuf,
                                          size_t namesize, const char **instance);
-static int             cups_get_dests(const char *filename, const char *match_name,
-                                      const char *match_inst, int user_default_set,
-                                      int num_dests, cups_dest_t **dests);
+static int             cups_get_dests(const char *filename, const char *match_name, const char *match_inst, int load_all, int user_default_set, int num_dests, cups_dest_t **dests);
 static char            *cups_make_string(ipp_attribute_t *attr, char *buffer,
                                          size_t bufsize);
 static int              cups_name_cb(_cups_namedata_t *data, unsigned flags, cups_dest_t *dest);
@@ -574,7 +569,7 @@ _cupsAppleSetUseLastPrinter(
 
 
 /*
- * 'cupsConnectDest()' - Open a conection to the destination.
+ * 'cupsConnectDest()' - Open a connection to the destination.
  *
  * Connect to the destination, returning a new @code http_t@ connection object
  * and optionally the resource path to use for the destination.  These calls
@@ -583,7 +578,7 @@ _cupsAppleSetUseLastPrinter(
  * returns 0.  The caller is responsible for calling @link httpClose@ on the
  * returned connection.
  *
- * Starting with CUPS 2.2.4, the caller can pass  @code CUPS_DEST_FLAGS_DEVICE@
+ * Starting with CUPS 2.2.4, the caller can pass @code CUPS_DEST_FLAGS_DEVICE@
  * for the "flags" argument to connect directly to the device associated with
  * the destination.  Otherwise, the connection is made to the CUPS scheduler
  * associated with the destination.
@@ -851,6 +846,8 @@ cupsCopyDest(cups_dest_t *dest,         /* I  - Destination to copy */
 
   if (new_dest)
   {
+    new_dest->is_default = dest->is_default;
+
     if ((new_dest->options = calloc(sizeof(cups_option_t), (size_t)dest->num_options)) == NULL)
       return (cupsRemoveDest(dest->name, dest->instance, num_dests, dests));
 
@@ -1103,20 +1100,23 @@ cupsGetDest(const char  *name,          /* I - Destination name or @code NULL@ for the d
  * '_cupsGetDestResource()' - Get the resource path and URI for a destination.
  */
 
-const char *                           /* O - Printer URI */
+const char *                           /* O - URI */
 _cupsGetDestResource(
     cups_dest_t *dest,                 /* I - Destination */
+    unsigned    flags,                 /* I - Destination flags */
     char        *resource,             /* I - Resource buffer */
     size_t      resourcesize)          /* I - Size of resource buffer */
 {
-  const char   *uri;                   /* Printer URI */
+  const char   *uri,                   /* URI */
+               *device_uri,            /* Device URI */
+               *printer_uri;           /* Printer URI */
   char         scheme[32],             /* URI scheme */
                userpass[256],          /* Username and password (unused) */
                hostname[256];          /* Hostname */
   int          port;                   /* Port number */
 
 
-  DEBUG_printf(("_cupsGetDestResource(dest=%p(%s), resource=%p, resourcesize=%d)", (void *)dest, dest->name, (void *)resource, (int)resourcesize));
+  DEBUG_printf(("_cupsGetDestResource(dest=%p(%s), flags=%u, resource=%p, resourcesize=%d)", (void *)dest, dest->name, flags, (void *)resource, (int)resourcesize));
 
  /*
   * Range check input...
@@ -1132,25 +1132,46 @@ _cupsGetDestResource(
   }
 
  /*
-  * Grab the printer URI...
+  * Grab the printer and device URIs...
   */
 
-  if ((uri = cupsGetOption("printer-uri-supported", dest->num_options, dest->options)) == NULL)
+  device_uri  = cupsGetOption("device-uri", dest->num_options, dest->options);
+  printer_uri = cupsGetOption("printer-uri-supported", dest->num_options, dest->options);
+
+  DEBUG_printf(("1_cupsGetDestResource: device-uri=\"%s\", printer-uri-supported=\"%s\".", device_uri, printer_uri));
+
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
+  if (((flags & CUPS_DEST_FLAGS_DEVICE) || !printer_uri) && strstr(device_uri, "._tcp"))
   {
-    if ((uri = cupsGetOption("device-uri", dest->num_options, dest->options)) != NULL)
+    if ((device_uri = cups_dnssd_resolve(dest, device_uri, 5000, NULL, NULL, NULL)) != NULL)
     {
-#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
-      if (strstr(uri, "._tcp"))
-        uri = cups_dnssd_resolve(dest, uri, 5000, NULL, NULL, NULL);
-#endif /* HAVE_DNSSD || HAVE_AVAHI */
+      DEBUG_printf(("1_cupsGetDestResource: Resolved device-uri=\"%s\".", device_uri));
     }
-
-    if (uri)
+    else
     {
-      DEBUG_printf(("1_cupsGetDestResource: Resolved printer-uri-supported=\"%s\"", uri));
+      DEBUG_puts("1_cupsGetDestResource: Unable to resolve device.");
 
-      uri = _cupsCreateDest(dest->name, cupsGetOption("printer-info", dest->num_options, dest->options), NULL, uri, resource, resourcesize);
+      if (resource)
+       *resource = '\0';
+
+      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(ENOENT), 0);
+
+      return (NULL);
     }
+  }
+#endif /* HAVE_DNSSD || HAVE_AVAHI */
+
+  if (flags & CUPS_DEST_FLAGS_DEVICE)
+  {
+    uri = device_uri;
+  }
+  else if (printer_uri)
+  {
+    uri = printer_uri;
+  }
+  else
+  {
+    uri = _cupsCreateDest(dest->name, cupsGetOption("printer-info", dest->num_options, dest->options), NULL, device_uri, resource, resourcesize);
 
     if (uri)
     {
@@ -1160,30 +1181,24 @@ _cupsGetDestResource(
 
       uri = cupsGetOption("printer-uri-supported", dest->num_options, dest->options);
     }
-    else
-    {
-      DEBUG_puts("1_cupsGetDestResource: No printer-uri-supported found.");
+  }
 
-      if (resource)
-        *resource = '\0';
+  if (!uri)
+  {
+    DEBUG_puts("1_cupsGetDestResource: No printer-uri-supported or device-uri found.");
 
-      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(ENOENT), 0);
+    if (resource)
+      *resource = '\0';
 
-      return (NULL);
-    }
+    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(ENOENT), 0);
+
+    return (NULL);
   }
-  else
+  else if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme), userpass, sizeof(userpass), hostname, sizeof(hostname), &port, resource, (int)resourcesize) < HTTP_URI_STATUS_OK)
   {
-    DEBUG_printf(("1_cupsGetDestResource: printer-uri-supported=\"%s\"", uri));
-
-    if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme),
-                        userpass, sizeof(userpass), hostname, sizeof(hostname),
-                        &port, resource, (int)resourcesize) < HTTP_URI_STATUS_OK)
-    {
-      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad printer-uri."), 1);
+    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad URI."), 1);
 
-      return (NULL);
-    }
+    return (NULL);
   }
 
   DEBUG_printf(("1_cupsGetDestResource: resource=\"%s\"", resource));
@@ -1271,6 +1286,12 @@ cupsGetDestWithURI(const char *name,     /* I - Desired printer name or @code NULL@
       name = resource + 10;
       info = temp;
     }
+    else if (!strncmp(resource, "/ipp/print/", 11))
+    {
+      snprintf(temp, sizeof(temp), "%s @ %s", resource + 11, hostname);
+      name = resource + 11;
+      info = temp;
+    }
     else
     {
       name = hostname;
@@ -1631,16 +1652,6 @@ cupsGetDests2(http_t      *http, /* I - Connection to server or @code CUPS_HTTP_
               cups_dest_t **dests)     /* O - Destinations */
 {
   _cups_getdata_t data;                 /* Enumeration data */
-  cups_dest_t   *dest;                  /* Current destination */
-  const char   *home;                  /* HOME environment variable */
-  char         filename[1024];         /* Local ~/.cups/lpoptions file */
-  const char   *defprinter;            /* Default printer */
-  char         name[1024],             /* Copy of printer name */
-               *instance,              /* Pointer to instance name */
-               *user_default;          /* User default printer */
-  int          num_reals;              /* Number of real queues */
-  cups_dest_t  *reals;                 /* Real queues */
-  _cups_globals_t *cg = _cupsGlobals();        /* Pointer to library globals */
 
 
   DEBUG_printf(("cupsGetDests2(http=%p, dests=%p)", (void *)http, (void *)dests));
@@ -1696,107 +1707,6 @@ cupsGetDests2(http_t      *http,        /* I - Connection to server or @code CUPS_HTTP_
     cups_enum_dests(http, 0, _CUPS_DNSSD_GET_DESTS, NULL, 0, 0, (cups_dest_cb_t)cups_get_cb, &data);
   }
 
- /*
-  * Make a copy of the "real" queues for a later sanity check...
-  */
-
-  if (data.num_dests > 0)
-  {
-    num_reals = data.num_dests;
-    reals     = calloc((size_t)num_reals, sizeof(cups_dest_t));
-
-    if (reals)
-      memcpy(reals, data.dests, (size_t)num_reals * sizeof(cups_dest_t));
-    else
-      num_reals = 0;
-  }
-  else
-  {
-    num_reals = 0;
-    reals     = NULL;
-  }
-
- /*
-  * Grab the default destination...
-  */
-
-  if ((user_default = _cupsUserDefault(name, sizeof(name))) != NULL)
-    defprinter = name;
-  else if ((defprinter = cupsGetDefault2(http)) != NULL)
-  {
-    strlcpy(name, defprinter, sizeof(name));
-    defprinter = name;
-  }
-
-  if (defprinter)
-  {
-   /*
-    * Separate printer and instance name...
-    */
-
-    if ((instance = strchr(name, '/')) != NULL)
-      *instance++ = '\0';
-
-   /*
-    * Lookup the printer and instance and make it the default...
-    */
-
-    if ((dest = cupsGetDest(name, instance, data.num_dests, data.dests)) != NULL)
-      dest->is_default = 1;
-  }
-  else
-    instance = NULL;
-
- /*
-  * Load the /etc/cups/lpoptions and ~/.cups/lpoptions files...
-  */
-
-  snprintf(filename, sizeof(filename), "%s/lpoptions", cg->cups_serverroot);
-  data.num_dests = cups_get_dests(filename, NULL, NULL, user_default != NULL, data.num_dests, &data.dests);
-
-  if ((home = getenv("HOME")) != NULL)
-  {
-    snprintf(filename, sizeof(filename), "%s/.cups/lpoptions", home);
-
-    data.num_dests = cups_get_dests(filename, NULL, NULL, user_default != NULL, data.num_dests, &data.dests);
-  }
-
- /*
-  * Validate the current default destination - this prevents old
-  * Default lines in /etc/cups/lpoptions and ~/.cups/lpoptions from
-  * pointing to a non-existent printer or class...
-  */
-
-  if (num_reals)
-  {
-   /*
-    * See if we have a default printer...
-    */
-
-    if ((dest = cupsGetDest(NULL, NULL, data.num_dests, data.dests)) != NULL)
-    {
-     /*
-      * Have a default; see if it is real...
-      */
-
-      if (!cupsGetDest(dest->name, NULL, num_reals, reals))
-      {
-       /*
-        * Remove the non-real printer from the list, since we don't want jobs
-        * going to an unexpected printer... (<rdar://problem/14216472>)
-        */
-
-        data.num_dests = cupsRemoveDest(dest->name, dest->instance, data.num_dests, &data.dests);
-      }
-    }
-
-   /*
-    * Free memory...
-    */
-
-    free(reals);
-  }
-
  /*
   * Return the number of destinations...
   */
@@ -1883,6 +1793,9 @@ cupsGetNamedDest(http_t     *http,        /* I - Connection to server or @code CUPS_HTT
       snprintf(filename, sizeof(filename), "%s/.cups/lpoptions", home);
 
       dest_name = cups_get_default(filename, defname, sizeof(defname), &instance);
+
+      if (dest_name)
+        set_as_default = 2;
     }
 
     if (!dest_name)
@@ -1893,6 +1806,9 @@ cupsGetNamedDest(http_t     *http,        /* I - Connection to server or @code CUPS_HTT
 
       snprintf(filename, sizeof(filename), "%s/lpoptions", cg->cups_serverroot);
       dest_name = cups_get_default(filename, defname, sizeof(defname), &instance);
+
+      if (dest_name)
+        set_as_default = 3;
     }
 
     if (!dest_name)
@@ -1901,7 +1817,8 @@ cupsGetNamedDest(http_t     *http,        /* I - Connection to server or @code CUPS_HTT
       * No locally-set default destination, ask the server...
       */
 
-      op = IPP_OP_CUPS_GET_DEFAULT;
+      op             = IPP_OP_CUPS_GET_DEFAULT;
+      set_as_default = 4;
 
       DEBUG_puts("1cupsGetNamedDest: Asking server for default printer...");
     }
@@ -1932,7 +1849,36 @@ cupsGetNamedDest(http_t     *http,       /* I - Connection to server or @code CUPS_HTT
       dest = data.dest;
     }
     else
+    {
+      switch (set_as_default)
+      {
+        default :
+            break;
+
+        case 1 : /* Set from env vars */
+            if (getenv("LPDEST"))
+              _cupsSetError(IPP_STATUS_ERROR_NOT_FOUND, _("LPDEST environment variable names default destination that does not exist."), 1);
+           else if (getenv("PRINTER"))
+              _cupsSetError(IPP_STATUS_ERROR_NOT_FOUND, _("PRINTER environment variable names default destination that does not exist."), 1);
+           else
+              _cupsSetError(IPP_STATUS_ERROR_NOT_FOUND, _("No default destination."), 1);
+            break;
+
+        case 2 : /* Set from ~/.cups/lpoptions */
+           _cupsSetError(IPP_STATUS_ERROR_NOT_FOUND, _("~/.cups/lpoptions file names default destination that does not exist."), 1);
+            break;
+
+        case 3 : /* Set from /etc/cups/lpoptions */
+           _cupsSetError(IPP_STATUS_ERROR_NOT_FOUND, _("/etc/cups/lpoptions file names default destination that does not exist."), 1);
+            break;
+
+        case 4 : /* Set from server */
+           _cupsSetError(IPP_STATUS_ERROR_NOT_FOUND, _("No default destination."), 1);
+            break;
+      }
+
       return (NULL);
+    }
   }
 
   DEBUG_printf(("1cupsGetNamedDest: Got dest=%p", (void *)dest));
@@ -1948,13 +1894,13 @@ cupsGetNamedDest(http_t     *http,      /* I - Connection to server or @code CUPS_HTT
   */
 
   snprintf(filename, sizeof(filename), "%s/lpoptions", cg->cups_serverroot);
-  cups_get_dests(filename, dest_name, instance, 1, 1, &dest);
+  cups_get_dests(filename, dest_name, instance, 0, 1, 1, &dest);
 
   if (home)
   {
     snprintf(filename, sizeof(filename), "%s/.cups/lpoptions", home);
 
-    cups_get_dests(filename, dest_name, instance, 1, 1, &dest);
+    cups_get_dests(filename, dest_name, instance, 0, 1, 1, &dest);
   }
 
  /*
@@ -2129,12 +2075,6 @@ cupsSetDests2(http_t      *http, /* I - Connection to server or @code CUPS_HTTP_
 #ifndef _WIN32
   if (getuid())
   {
-   /*
-    * Merge in server defaults...
-    */
-
-    num_temps = cups_get_dests(filename, NULL, NULL, 0, num_temps, &temps);
-
    /*
     * Point to user defaults...
     */
@@ -2195,8 +2135,7 @@ cupsSetDests2(http_t      *http,  /* I - Connection to server or @code CUPS_HTTP_
       else
         wrote = 0;
 
-      if ((temp = cupsGetDest(dest->name, dest->instance, num_temps, temps)) == NULL)
-        temp = cupsGetDest(dest->name, NULL, num_temps, temps);
+      temp = cupsGetDest(dest->name, NULL, num_temps, temps);
 
       for (j = dest->num_options, option = dest->options; j > 0; j --, option ++)
       {
@@ -2204,19 +2143,14 @@ cupsSetDests2(http_t      *http,        /* I - Connection to server or @code CUPS_HTTP_
         * See if this option is a printer attribute; if so, skip it...
        */
 
-        if ((match = _ippFindOption(option->name)) != NULL &&
-           match->group_tag == IPP_TAG_PRINTER)
+        if ((match = _ippFindOption(option->name)) != NULL && match->group_tag == IPP_TAG_PRINTER)
          continue;
 
        /*
-       * See if the server/global options match these; if so, don't
-       * write 'em.
+       * See if the server options match these; if so, don't write 'em.
        */
 
-        if (temp &&
-           (val = cupsGetOption(option->name, temp->num_options,
-                                temp->options)) != NULL &&
-            !_cups_strcasecmp(val, option->value))
+        if (temp && (val = cupsGetOption(option->name, temp->num_options, temp->options)) != NULL && !_cups_strcasecmp(val, option->value))
          continue;
 
        /*
@@ -2233,10 +2167,7 @@ cupsSetDests2(http_t      *http, /* I - Connection to server or @code CUPS_HTTP_
 
         if (option->value[0])
        {
-         if (strchr(option->value, ' ') ||
-             strchr(option->value, '\\') ||
-             strchr(option->value, '\"') ||
-             strchr(option->value, '\''))
+         if (strchr(option->value, ' ') || strchr(option->value, '\\') || strchr(option->value, '\"') || strchr(option->value, '\''))
          {
           /*
            * Quote the value...
@@ -2287,9 +2218,7 @@ cupsSetDests2(http_t      *http,  /* I - Connection to server or @code CUPS_HTTP_
 
   if ((dest = cupsGetDest(NULL, NULL, num_dests, dests)) != NULL)
   {
-    CFStringRef name = CFStringCreateWithCString(kCFAllocatorDefault,
-                                                 dest->name,
-                                                 kCFStringEncodingUTF8);
+    CFStringRef name = CFStringCreateWithCString(kCFAllocatorDefault, dest->name, kCFStringEncodingUTF8);
                                        /* Default printer name */
 
     if (name)
@@ -2720,22 +2649,7 @@ cups_dnssd_browse_cb(
        * This object is new on the network.
        */
 
-       if (flags & AVAHI_LOOKUP_RESULT_LOCAL)
-       {
-        /*
-         * This comes from the local machine so ignore it.
-         */
-
-         DEBUG_printf(("cups_dnssd_browse_cb: Ignoring local service \"%s\".", name));
-       }
-       else
-       {
-        /*
-         * Create a device entry for it if it doesn't yet exist.
-         */
-
-         cups_dnssd_get_device(data, name, type, domain);
-       }
+       cups_dnssd_get_device(data, name, type, domain);
        break;
 
     case AVAHI_BROWSER_REMOVE :
@@ -2956,66 +2870,6 @@ cups_dnssd_get_device(
 }
 
 
-#  ifdef HAVE_DNSSD
-/*
- * 'cups_dnssd_local_cb()' - Browse for local printers.
- */
-
-static void
-cups_dnssd_local_cb(
-    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_data_t   *data = (_cups_dnssd_data_t *)context;
-                                       /* Enumeration data */
-  _cups_dnssd_device_t *device;        /* Device */
-
-
-  DEBUG_printf(("5cups_dnssd_local_cb(sdRef=%p, flags=%x, interfaceIndex=%d, errorCode=%d, serviceName=\"%s\", regtype=\"%s\", replyDomain=\"%s\", context=%p)", (void *)sdRef, flags, interfaceIndex, errorCode, serviceName, regtype, replyDomain, context));
-
- /*
-  * Only process "add" data...
-  */
-
-  if (errorCode != kDNSServiceErr_NoError || !(flags & kDNSServiceFlagsAdd))
-    return;
-
- /*
-  * Get the device...
-  */
-
-  device = cups_dnssd_get_device(data, serviceName, regtype, replyDomain);
-
- /*
-  * Hide locally-registered devices...
-  */
-
-  DEBUG_printf(("6cups_dnssd_local_cb: Hiding local printer '%s'.",
-                serviceName));
-
-  if (device->ref)
-  {
-    DNSServiceRefDeallocate(device->ref);
-    device->ref = 0;
-  }
-
-  if (device->state == _CUPS_DNSSD_ACTIVE)
-  {
-    DEBUG_printf(("6cups_dnssd_local_cb: Remove callback for \"%s\".", device->dest.name));
-    (*data->cb)(data->user_data, CUPS_DEST_FLAGS_REMOVED, &device->dest);
-  }
-
-  device->state = _CUPS_DNSSD_LOCAL;
-}
-#  endif /* HAVE_DNSSD */
-
-
 #  ifdef HAVE_AVAHI
 /*
  * 'cups_dnssd_poll_cb()' - Wait for input on the specified file descriptors.
@@ -3065,9 +2919,9 @@ cups_dnssd_poll_cb(
  * 'cups_dnssd_query_cb()' - Process query data.
  */
 
-#  ifdef HAVE_DNSSD
 static void
 cups_dnssd_query_cb(
+#  ifdef HAVE_DNSSD
     DNSServiceRef       sdRef,         /* I - Service reference */
     DNSServiceFlags     flags,         /* I - Data flags */
     uint32_t            interfaceIndex,        /* I - Interface */
@@ -3078,11 +2932,7 @@ cups_dnssd_query_cb(
     uint16_t            rdlen,         /* I - Length of record data */
     const void          *rdata,                /* I - Record data */
     uint32_t            ttl,           /* I - Time-to-live */
-    void                *context)      /* I - Enumeration data */
-{
 #  else /* HAVE_AVAHI */
-static void
-cups_dnssd_query_cb(
     AvahiRecordBrowser     *browser,   /* I - Record browser */
     AvahiIfIndex           interfaceIndex,
                                        /* I - Interface index (unused) */
@@ -3094,13 +2944,13 @@ cups_dnssd_query_cb(
     const void             *rdata,     /* I - TXT record */
     size_t                 rdlen,      /* I - Length of TXT record */
     AvahiLookupResultFlags flags,      /* I - Flags */
-    void                   *context)   /* I - Enumeration data */
+#  endif /* HAVE_DNSSD */
+    void                *context)      /* I - Enumeration data */
 {
-#    ifdef DEBUG
+#  if defined(DEBUG) && defined(HAVE_AVAHI)
   AvahiClient          *client = avahi_record_browser_get_client(browser);
                                        /* Client information */
-#    endif /* DEBUG */
-#  endif /* HAVE_DNSSD */
+#  endif /* DEBUG && HAVE_AVAHI */
   _cups_dnssd_data_t   *data = (_cups_dnssd_data_t *)context;
                                        /* Enumeration data */
   char                 serviceName[256],/* Service name */
@@ -3543,29 +3393,26 @@ cups_enum_dests(
   cups_dest_cb_t cb,                    /* I - Callback function */
   void           *user_data)            /* I - User data */
 {
-  int           i,                      /* Looping var */
+  int           i, j,                  /* Looping vars */
                 num_dests;              /* Number of destinations */
   cups_dest_t   *dests = NULL,          /* Destinations */
-                *dest;                  /* Current destination */
-  const char    *defprinter;            /* Default printer */
-  char          name[1024],             /* Copy of printer name */
-                *instance,              /* Pointer to instance name */
-                *user_default;          /* User default printer */
+                *dest,                  /* Current destination */
+                *user_dest;            /* User destination */
+  cups_option_t        *option;                /* Current option */
+  char          *user_default;          /* User default printer */
 #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
   int           count,                  /* Number of queries started */
                 completed,              /* Number of completed queries */
                 remaining;              /* Remainder of timeout */
   struct timeval curtime;               /* Current time */
-  _cups_dnssd_data_t data;              /* Data for callback */
+  _cups_dnssd_data_t data;             /* Data for callback */
   _cups_dnssd_device_t *device;         /* Current device */
 #  ifdef HAVE_DNSSD
   int           nfds,                   /* Number of files responded */
                 main_fd;                /* File descriptor for lookups */
-  DNSServiceRef ipp_ref = NULL,         /* IPP browser */
-                local_ipp_ref = NULL;   /* Local IPP browser */
+  DNSServiceRef ipp_ref = NULL;                /* IPP browser */
 #    ifdef HAVE_SSL
-  DNSServiceRef ipps_ref = NULL,        /* IPPS browser */
-                local_ipps_ref = NULL;  /* Local IPPS browser */
+  DNSServiceRef ipps_ref = NULL;       /* IPPS browser */
 #    endif /* HAVE_SSL */
 #    ifdef HAVE_POLL
   struct pollfd pfd;                    /* Polling data */
@@ -3580,7 +3427,12 @@ cups_enum_dests(
   AvahiServiceBrowser *ipps_ref = NULL; /* IPPS browser */
 #    endif /* HAVE_SSL */
 #  endif /* HAVE_DNSSD */
+#else
+  _cups_getdata_t data;                        /* Data for callback */
 #endif /* HAVE_DNSSD || HAVE_AVAHI */
+  const char   *home;                  /* HOME environment variable */
+  char         filename[1024];         /* Local lpoptions file */
+  _cups_globals_t *cg = _cupsGlobals();        /* Pointer to library globals */
 
 
   DEBUG_printf(("cups_enum_dests(flags=%x, msec=%d, cancel=%p, type=%x, mask=%x, cb=%p, user_data=%p)", flags, msec, (void *)cancel, type, mask, (void *)cb, (void *)user_data));
@@ -3598,12 +3450,47 @@ cups_enum_dests(
   }
 
  /*
-  * Get ready to enumerate...
+  * Load the /etc/cups/lpoptions and ~/.cups/lpoptions files...
   */
 
-#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
   memset(&data, 0, sizeof(data));
 
+  if ((user_default = _cupsUserDefault(data.def_name, sizeof(data.def_name))) == NULL)
+  {
+    const char *defprinter = cupsGetDefault2(http);
+                                       /* Server default, if any */
+
+    if (defprinter)
+      strlcpy(data.def_name, defprinter, sizeof(data.def_name));
+  }
+
+  if (data.def_name[0])
+  {
+   /*
+    * Separate printer and instance name...
+    */
+
+    if ((data.def_instance = strchr(data.def_name, '/')) != NULL)
+      *data.def_instance++ = '\0';
+  }
+
+  DEBUG_printf(("1cups_enum_dests: def_name=\"%s\", def_instance=\"%s\"", data.def_name, data.def_instance));
+
+  snprintf(filename, sizeof(filename), "%s/lpoptions", cg->cups_serverroot);
+  data.num_dests = cups_get_dests(filename, NULL, NULL, 1, user_default != NULL, data.num_dests, &data.dests);
+
+  if ((home = getenv("HOME")) != NULL)
+  {
+    snprintf(filename, sizeof(filename), "%s/.cups/lpoptions", home);
+
+    data.num_dests = cups_get_dests(filename, NULL, NULL, 1, user_default != NULL, data.num_dests, &data.dests);
+  }
+
+ /*
+  * Get ready to enumerate...
+  */
+
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
   data.type      = type;
   data.mask      = mask;
   data.cb        = cb;
@@ -3619,29 +3506,17 @@ cups_enum_dests(
 
     num_dests = _cupsGetDests(http, IPP_OP_CUPS_GET_PRINTERS, NULL, &dests, type, mask);
 
-    if ((user_default = _cupsUserDefault(name, sizeof(name))) != NULL)
-      defprinter = name;
-    else if ((defprinter = cupsGetDefault2(http)) != NULL)
-    {
-      strlcpy(name, defprinter, sizeof(name));
-      defprinter = name;
-    }
-
-    if (defprinter)
+    if (data.def_name[0])
     {
      /*
-      * Separate printer and instance name...
+      * Lookup the named default printer and instance and make it the default...
       */
 
-      if ((instance = strchr(name, '/')) != NULL)
-        *instance++ = '\0';
-
-     /*
-      * Lookup the printer and instance and make it the default...
-      */
-
-      if ((dest = cupsGetDest(name, instance, num_dests, dests)) != NULL)
+      if ((dest = cupsGetDest(data.def_name, data.def_instance, num_dests, dests)) != NULL)
+      {
+       DEBUG_printf(("1cups_enum_dests: Setting is_default on \"%s/%s\".", dest->name, dest->instance));
         dest->is_default = 1;
+      }
     }
 
     for (i = num_dests, dest = dests;
@@ -3652,6 +3527,16 @@ cups_enum_dests(
       const char *device_uri;    /* Device URI */
 #endif /* HAVE_DNSSD || HAVE_AVAHI */
 
+      if ((user_dest = cupsGetDest(dest->name, dest->instance, data.num_dests, data.dests)) != NULL)
+      {
+       /*
+        * Apply user defaults to this destination...
+        */
+
+        for (j = user_dest->num_options, option = user_dest->options; j > 0; j --, option ++)
+          dest->num_options = cupsAddOption(option->name, option->value, dest->num_options, &dest->options);
+      }
+
       if (!(*cb)(user_data, i > 1 ? CUPS_DEST_FLAGS_MORE : CUPS_DEST_FLAGS_NONE, dest))
         break;
 
@@ -3714,6 +3599,9 @@ cups_enum_dests(
   if (DNSServiceCreateConnection(&data.main_ref) != kDNSServiceErr_NoError)
   {
     DEBUG_puts("1cups_enum_dests: Unable to create service browser, returning 0.");
+
+    cupsFreeDests(data.num_dests, data.dests);
+
     return (0);
   }
 
@@ -3724,14 +3612,9 @@ cups_enum_dests(
   {
     DEBUG_puts("1cups_enum_dests: Unable to create IPP browser, returning 0.");
     DNSServiceRefDeallocate(data.main_ref);
-    return (0);
-  }
 
-  local_ipp_ref = data.main_ref;
-  if (DNSServiceBrowse(&local_ipp_ref, kDNSServiceFlagsShareConnection, kDNSServiceInterfaceIndexLocalOnly, "_ipp._tcp", NULL, (DNSServiceBrowseReply)cups_dnssd_local_cb, &data) != kDNSServiceErr_NoError)
-  {
-    DEBUG_puts("1cups_enum_dests: Unable to create local IPP browser, returning 0.");
-    DNSServiceRefDeallocate(data.main_ref);
+    cupsFreeDests(data.num_dests, data.dests);
+
     return (0);
   }
 
@@ -3741,14 +3624,9 @@ cups_enum_dests(
   {
     DEBUG_puts("1cups_enum_dests: Unable to create IPPS browser, returning 0.");
     DNSServiceRefDeallocate(data.main_ref);
-    return (0);
-  }
 
-  local_ipps_ref = data.main_ref;
-  if (DNSServiceBrowse(&local_ipps_ref, kDNSServiceFlagsShareConnection, kDNSServiceInterfaceIndexLocalOnly, "_ipps._tcp", NULL, (DNSServiceBrowseReply)cups_dnssd_local_cb, &data) != kDNSServiceErr_NoError)
-  {
-    DEBUG_puts("1cups_enum_dests: Unable to create local IPPS browser, returning 0.");
-    DNSServiceRefDeallocate(data.main_ref);
+    cupsFreeDests(data.num_dests, data.dests);
+
     return (0);
   }
 #    endif /* HAVE_SSL */
@@ -3757,6 +3635,9 @@ cups_enum_dests(
   if ((data.simple_poll = avahi_simple_poll_new()) == NULL)
   {
     DEBUG_puts("1cups_enum_dests: Unable to create Avahi poll, returning 0.");
+
+    cupsFreeDests(data.num_dests, data.dests);
+
     return (0);
   }
 
@@ -3769,6 +3650,9 @@ cups_enum_dests(
   {
     DEBUG_puts("1cups_enum_dests: Unable to create Avahi client, returning 0.");
     avahi_simple_poll_free(data.simple_poll);
+
+    cupsFreeDests(data.num_dests, data.dests);
+
     return (0);
   }
 
@@ -3779,6 +3663,9 @@ cups_enum_dests(
 
     avahi_client_free(data.client);
     avahi_simple_poll_free(data.simple_poll);
+
+    cupsFreeDests(data.num_dests, data.dests);
+
     return (0);
   }
 
@@ -3791,6 +3678,9 @@ cups_enum_dests(
     avahi_service_browser_free(ipp_ref);
     avahi_client_free(data.client);
     avahi_simple_poll_free(data.simple_poll);
+
+    cupsFreeDests(data.num_dests, data.dests);
+
     return (0);
   }
 #    endif /* HAVE_SSL */
@@ -3903,8 +3793,26 @@ cups_enum_dests(
 
         if ((device->type & mask) == type)
         {
+          dest = &device->dest;
+
+         if ((user_dest = cupsGetDest(dest->name, dest->instance, data.num_dests, data.dests)) != NULL)
+         {
+          /*
+           * Apply user defaults to this destination...
+           */
+
+           for (j = user_dest->num_options, option = user_dest->options; j > 0; j --, option ++)
+             dest->num_options = cupsAddOption(option->name, option->value, dest->num_options, &dest->options);
+         }
+
+          if (!strcasecmp(dest->name, data.def_name) && !data.def_instance)
+         {
+           DEBUG_printf(("1cups_enum_dests: Setting is_default on discovered \"%s\".", dest->name));
+            dest->is_default = 1;
+         }
+
           DEBUG_printf(("1cups_enum_dests: Add callback for \"%s\".", device->dest.name));
-          if (!(*cb)(user_data, CUPS_DEST_FLAGS_NONE, &device->dest))
+          if (!(*cb)(user_data, CUPS_DEST_FLAGS_NONE, dest))
           {
             remaining = -1;
             break;
@@ -3935,20 +3843,18 @@ cups_enum_dests(
 
   enum_finished:
 
+  cupsFreeDests(data.num_dests, data.dests);
+
 #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
   cupsArrayDelete(data.devices);
 
 #  ifdef HAVE_DNSSD
   if (ipp_ref)
     DNSServiceRefDeallocate(ipp_ref);
-  if (local_ipp_ref)
-    DNSServiceRefDeallocate(local_ipp_ref);
 
 #    ifdef HAVE_SSL
   if (ipps_ref)
     DNSServiceRefDeallocate(ipps_ref);
-  if (local_ipps_ref)
-    DNSServiceRefDeallocate(local_ipps_ref);
 #    endif /* HAVE_SSL */
 
   if (data.main_ref)
@@ -4166,6 +4072,7 @@ cups_get_dests(
     const char  *filename,             /* I - File to read from */
     const char  *match_name,           /* I - Destination name we want */
     const char  *match_inst,           /* I - Instance name we want */
+    int         load_all,              /* I - Load all saved destinations? */
     int         user_default_set,      /* I - User default printer set? */
     int         num_dests,             /* I - Number of destinations */
     cups_dest_t **dests)               /* IO - Destinations */
@@ -4180,7 +4087,7 @@ cups_get_dests(
   int          linenum;                /* Current line number */
 
 
-  DEBUG_printf(("7cups_get_dests(filename=\"%s\", match_name=\"%s\", match_inst=\"%s\", user_default_set=%d, num_dests=%d, dests=%p)", filename, match_name, match_inst, user_default_set, num_dests, (void *)dests));
+  DEBUG_printf(("7cups_get_dests(filename=\"%s\", match_name=\"%s\", match_inst=\"%s\", load_all=%d, user_default_set=%d, num_dests=%d, dests=%p)", filename, match_name, match_inst, load_all, user_default_set, num_dests, (void *)dests));
 
  /*
   * Try to open the file...
@@ -4248,8 +4155,7 @@ cups_get_dests(
                   instance));
 
    /*
-    * See if the primary instance of the destination exists; if not,
-    * ignore this entry and move on...
+    * Match and/or ignore missing destinations...
     */
 
     if (match_name)
@@ -4262,7 +4168,7 @@ cups_get_dests(
 
       dest = *dests;
     }
-    else if (cupsGetDest(name, NULL, num_dests, *dests) == NULL)
+    else if (!load_all && cupsGetDest(name, NULL, num_dests, *dests) == NULL)
     {
       DEBUG_puts("9cups_get_dests: Not found!");
       continue;
@@ -4290,8 +4196,7 @@ cups_get_dests(
     * Add options until we hit the end of the line...
     */
 
-    dest->num_options = cupsParseOptions(lineptr, dest->num_options,
-                                         &(dest->options));
+    dest->num_options = cupsParseOptions(lineptr, dest->num_options, &(dest->options));
 
    /*
     * If we found what we were looking for, stop now...
index 9eab8d2eff74ddab0a4353457e0cfb3cc0b463b9..a65e09960d84cd1219e8c1f010331595f023a2d0 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * CUPS destination API test program for CUPS.
  *
- * Copyright 2012-2018 by Apple Inc.
+ * Copyright © 2012-2018 by Apple Inc.
  *
- * These coded instructions, statements, and computer programs are the
- * property of Apple Inc. and are protected by Federal copyright
- * law.  Distribution and use rights are outlined in the file "LICENSE.txt"
- * which should have been included with this file.  If this file is
- * missing or damaged, see the license at "http://www.cups.org/".
- *
- * This file is subject to the Apple OS-Developed Software exception.
+ * Licensed under Apache License v2.0.  See the file "LICENSE" for more information.
  */
 
 /*
@@ -43,17 +37,31 @@ int                                 /* O - Exit status */
 main(int  argc,                                /* I - Number of command-line arguments */
      char *argv[])                     /* I - Command-line arguments */
 {
+  int          i;                      /* Looping var */
   http_t       *http;                  /* Connection to destination */
   cups_dest_t  *dest = NULL;           /* Destination */
   cups_dinfo_t *dinfo;                 /* Destination info */
+  unsigned     dflags = CUPS_DEST_FLAGS_NONE;
+                                       /* Destination flags */
 
 
   if (argc < 2)
-    usage(NULL);
+    return (0);
 
-  if (!strcmp(argv[1], "--enum"))
+  if (!strcmp(argv[1], "--get"))
+  {
+    cups_dest_t        *dests;                 /* Destinations */
+    int                num_dests = cupsGetDests2(CUPS_HTTP_DEFAULT, &dests);
+                                       /* Number of destinations */
+
+    for (i = 0; i < num_dests; i ++)
+      enum_cb(NULL, 0, dests + i);
+
+    cupsFreeDests(num_dests, dests);
+    return (0);
+  }
+  else if (!strcmp(argv[1], "--enum"))
   {
-    int                        i;              /* Looping var */
     cups_ptype_t       type = 0,       /* Printer type filter */
                        mask = 0;       /* Printer type mask */
 
@@ -103,78 +111,91 @@ main(int  argc,                           /* I - Number of command-line arguments */
 
     return (0);
   }
-  else if (!strncmp(argv[1], "ipp://", 6) || !strncmp(argv[1], "ipps://", 7))
-    dest = cupsGetDestWithURI(NULL, argv[1]);
-  else if (!strcmp(argv[1], "default"))
+
+  i = 1;
+  if (!strcmp(argv[i], "--device"))
+  {
+    dflags = CUPS_DEST_FLAGS_DEVICE;
+    i ++;
+  }
+
+  if (!strncmp(argv[i], "ipp://", 6) || !strncmp(argv[i], "ipps://", 7))
+    dest = cupsGetDestWithURI(NULL, argv[i]);
+  else if (!strcmp(argv[i], "default"))
   {
     dest = cupsGetNamedDest(CUPS_HTTP_DEFAULT, NULL, NULL);
     if (dest && dest->instance)
       printf("default is \"%s/%s\".\n", dest->name, dest->instance);
-    else
+    else if (dest)
       printf("default is \"%s\".\n", dest->name);
+    else
+      puts("no default destination.");
   }
   else
-    dest = cupsGetNamedDest(CUPS_HTTP_DEFAULT, argv[1], NULL);
+    dest = cupsGetNamedDest(CUPS_HTTP_DEFAULT, argv[i], NULL);
 
   if (!dest)
   {
-    printf("testdest: Unable to get destination \"%s\": %s\n", argv[1], cupsLastErrorString());
+    printf("testdest: Unable to get destination \"%s\": %s\n", argv[i], cupsLastErrorString());
     return (1);
   }
 
-  if ((http = cupsConnectDest(dest, CUPS_DEST_FLAGS_NONE, 30000, NULL, NULL, 0, NULL, NULL)) == NULL)
+  i ++;
+
+  if ((http = cupsConnectDest(dest, dflags, 30000, NULL, NULL, 0, NULL, NULL)) == NULL)
   {
-    printf("testdest: Unable to connect to destination \"%s\": %s\n", argv[1], cupsLastErrorString());
+    printf("testdest: Unable to connect to destination \"%s\": %s\n", dest->name, cupsLastErrorString());
     return (1);
   }
 
   if ((dinfo = cupsCopyDestInfo(http, dest)) == NULL)
   {
-    printf("testdest: Unable to get information for destination \"%s\": %s\n", argv[1], cupsLastErrorString());
+    printf("testdest: Unable to get information for destination \"%s\": %s\n", dest->name, cupsLastErrorString());
     return (1);
   }
 
-  if (argc == 2 || (!strcmp(argv[2], "supported") && argc < 6))
+  if (i == argc || !strcmp(argv[i], "supported"))
   {
-    if (argc > 3)
-      show_supported(http, dest, dinfo, argv[3], argv[4]);
+    i ++;
+
+    if ((i + 1) < argc)
+      show_supported(http, dest, dinfo, argv[i], argv[i + 1]);
     else if (argc > 2)
-      show_supported(http, dest, dinfo, argv[3], NULL);
+      show_supported(http, dest, dinfo, argv[i], NULL);
     else
       show_supported(http, dest, dinfo, NULL, NULL);
   }
-  else if (!strcmp(argv[2], "conflicts") && argc > 3)
+  else if (!strcmp(argv[i], "conflicts") && (i + 1) < argc)
   {
-    int                        i,              /* Looping var */
-                       num_options = 0;/* Number of options */
+    int                        num_options = 0;/* Number of options */
     cups_option_t      *options = NULL;/* Options */
 
-    for (i = 3; i < argc; i ++)
+    for (i ++; i < argc; i ++)
       num_options = cupsParseOptions(argv[i], num_options, &options);
 
     show_conflicts(http, dest, dinfo, num_options, options);
   }
-  else if (!strcmp(argv[2], "default") && argc == 4)
+  else if (!strcmp(argv[i], "default") && (i + 1) < argc)
   {
-    show_default(http, dest, dinfo, argv[3]);
+    show_default(http, dest, dinfo, argv[i + 1]);
   }
-  else if (!strcmp(argv[2], "localize") && argc < 6)
+  else if (!strcmp(argv[i], "localize"))
   {
-    if (argc > 3)
-      localize(http, dest, dinfo, argv[3], argv[4]);
+    i ++;
+    if ((i + 1) < argc)
+      localize(http, dest, dinfo, argv[i], argv[i + 1]);
     else if (argc > 2)
-      localize(http, dest, dinfo, argv[3], NULL);
+      localize(http, dest, dinfo, argv[i], NULL);
     else
       localize(http, dest, dinfo, NULL, NULL);
   }
-  else if (!strcmp(argv[2], "media"))
+  else if (!strcmp(argv[i], "media"))
   {
-    int                i;                      /* Looping var */
     const char *name = NULL;           /* Media name, if any */
     unsigned   flags = CUPS_MEDIA_FLAGS_DEFAULT;
                                        /* Media selection flags */
 
-    for (i = 3; i < argc; i ++)
+    for (i ++; i < argc; i ++)
     {
       if (!strcmp(argv[i], "borderless"))
        flags = CUPS_MEDIA_FLAGS_BORDERLESS;
@@ -192,19 +213,19 @@ main(int  argc,                           /* I - Number of command-line arguments */
 
     show_media(http, dest, dinfo, flags, name);
   }
-  else if (!strcmp(argv[2], "print") && argc > 3)
+  else if (!strcmp(argv[i], "print") && (i + 1) < argc)
   {
-    int                        i,              /* Looping var */
-                       num_options = 0;/* Number of options */
+    int                        num_options = 0;/* Number of options */
     cups_option_t      *options = NULL;/* Options */
+    const char         *filename = argv[i + 1];
 
-    for (i = 4; i < argc; i ++)
+    for (i += 2; i < argc; i ++)
       num_options = cupsParseOptions(argv[i], num_options, &options);
 
-    print_file(http, dest, dinfo, argv[3], num_options, options);
+    print_file(http, dest, dinfo, filename, num_options, options);
   }
   else
-    usage(argv[2]);
+    usage(argv[i]);
 
   return (0);
 }
@@ -226,13 +247,15 @@ enum_cb(void        *user_data,           /* I - User data (unused) */
   (void)flags;
 
   if (dest->instance)
-    printf("%s%s/%s:\n", (flags & CUPS_DEST_FLAGS_REMOVED) ? "REMOVE " : "", dest->name, dest->instance);
+    printf("%s%s/%s%s:\n", (flags & CUPS_DEST_FLAGS_REMOVED) ? "REMOVE " : "", dest->name, dest->instance, dest->is_default ? " (Default)" : "");
   else
-    printf("%s%s:\n", (flags & CUPS_DEST_FLAGS_REMOVED) ? "REMOVE " : "", dest->name);
+    printf("%s%s%s:\n", (flags & CUPS_DEST_FLAGS_REMOVED) ? "REMOVE " : "", dest->name, dest->is_default ? " (Default)" : "");
 
   for (i = 0; i < dest->num_options; i ++)
     printf("    %s=\"%s\"\n", dest->options[i].name, dest->options[i].value);
 
+  puts("");
+
   return (1);
 }
 
@@ -740,9 +763,10 @@ usage(const char *arg)                     /* I - Argument for usage message */
     printf("testdest: Unknown option \"%s\".\n", arg);
 
   puts("Usage:");
-  puts("  ./testdest name [operation ...]");
-  puts("  ./testdest ipp://... [operation ...]");
-  puts("  ./testdest ipps://... [operation ...]");
+  puts("  ./testdest [--device] name [operation ...]");
+  puts("  ./testdest [--device] ipp://... [operation ...]");
+  puts("  ./testdest [--device] ipps://... [operation ...]");
+  puts("  ./testdest --get");
   puts("  ./testdest --enum [grayscale] [color] [duplex] [staple] [small]\n"
        "                    [medium] [large]");
   puts("");