Blame SOURCES/0001-Printing-to-old-CUPS-servers-has-been-fixed-Issue-52.patch

1d75c0
diff --git a/cups/cups-private.h b/cups/cups-private.h
1d75c0
index 6fd66a9..1f66fd7 100644
1d75c0
--- a/cups/cups-private.h
1d75c0
+++ b/cups/cups-private.h
1d75c0
@@ -237,13 +237,9 @@ extern void		_cupsBufferRelease(char *b);
1d75c0
 
1d75c0
 extern http_t		*_cupsConnect(void);
1d75c0
 extern char		*_cupsCreateDest(const char *name, const char *info, const char *device_id, const char *device_uri, char *uri, size_t urisize);
1d75c0
-extern int		_cupsGet1284Values(const char *device_id,
1d75c0
-			                   cups_option_t **values);
1d75c0
-extern const char	*_cupsGetDestResource(cups_dest_t *dest, char *resource,
1d75c0
-			                      size_t resourcesize);
1d75c0
-extern int		_cupsGetDests(http_t *http, ipp_op_t op,
1d75c0
-			              const char *name, cups_dest_t **dests,
1d75c0
-			              cups_ptype_t type, cups_ptype_t mask);
1d75c0
+extern int		_cupsGet1284Values(const char *device_id, cups_option_t **values);
1d75c0
+extern const char	*_cupsGetDestResource(cups_dest_t *dest, unsigned flags, char *resource, size_t resourcesize);
1d75c0
+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);
1d75c0
 extern const char	*_cupsGetPassword(const char *prompt);
1d75c0
 extern void		_cupsGlobalLock(void);
1d75c0
 extern _cups_globals_t	*_cupsGlobals(void);
1d75c0
@@ -253,13 +249,10 @@ extern const char	*_cupsGSSServiceName(void);
1d75c0
 #  endif /* HAVE_GSSAPI */
1d75c0
 extern int		_cupsNextDelay(int current, int *previous);
1d75c0
 extern void		_cupsSetDefaults(void);
1d75c0
-extern void		_cupsSetError(ipp_status_t status, const char *message,
1d75c0
-			              int localize);
1d75c0
+extern void		_cupsSetError(ipp_status_t status, const char *message, int localize);
1d75c0
 extern void		_cupsSetHTTPError(http_status_t status);
1d75c0
 #  ifdef HAVE_GSSAPI
1d75c0
-extern int		_cupsSetNegotiateAuthString(http_t *http,
1d75c0
-			                            const char *method,
1d75c0
-						    const char *resource);
1d75c0
+extern int		_cupsSetNegotiateAuthString(http_t *http, const char *method, const char *resource);
1d75c0
 #  endif /* HAVE_GSSAPI */
1d75c0
 extern char		*_cupsUserDefault(char *name, size_t namesize);
1d75c0
 
1d75c0
diff --git a/cups/dest-options.c b/cups/dest-options.c
1d75c0
index 51705a5..cfa28ce 100644
1d75c0
--- a/cups/dest-options.c
1d75c0
+++ b/cups/dest-options.c
1d75c0
@@ -572,6 +572,7 @@ cupsCopyDestInfo(
1d75c0
     cups_dest_t *dest)			/* I - Destination */
1d75c0
 {
1d75c0
   cups_dinfo_t	*dinfo;			/* Destination information */
1d75c0
+  unsigned	dflags;			/* Destination flags */
1d75c0
   ipp_t		*request,		/* Get-Printer-Attributes request */
1d75c0
 		*response;		/* Supported attributes */
1d75c0
   int		tries,			/* Number of tries so far */
1d75c0
@@ -581,6 +582,7 @@ cupsCopyDestInfo(
1d75c0
   char		resource[1024];		/* Resource path */
1d75c0
   int		version;		/* IPP version */
1d75c0
   ipp_status_t	status;			/* Status of request */
1d75c0
+  _cups_globals_t *cg = _cupsGlobals();	/* Pointer to library globals */
1d75c0
   static const char * const requested_attrs[] =
1d75c0
   {					/* Requested attributes */
1d75c0
     "job-template",
1d75c0
@@ -589,14 +591,25 @@ cupsCopyDestInfo(
1d75c0
   };
1d75c0
 
1d75c0
 
1d75c0
-  DEBUG_printf(("cupsCopyDestSupported(http=%p, dest=%p(%s))", (void *)http, (void *)dest, dest ? dest->name : ""));
1d75c0
+  DEBUG_printf(("cupsCopyDestInfo(http=%p, dest=%p(%s))", (void *)http, (void *)dest, dest ? dest->name : ""));
1d75c0
 
1d75c0
  /*
1d75c0
   * Get the default connection as needed...
1d75c0
   */
1d75c0
 
1d75c0
   if (!http)
1d75c0
-    http = _cupsConnect();
1d75c0
+  {
1d75c0
+    http   = _cupsConnect();
1d75c0
+    dflags = CUPS_DEST_FLAGS_NONE;
1d75c0
+  }
1d75c0
+#ifdef AF_LOCAL
1d75c0
+  else if (strcmp(http->hostname, cg->server) || (httpAddrFamily(http->hostaddr) != AF_LOCAL && cg->ipp_port != httpAddrPort(http->hostaddr)))
1d75c0
+#else
1d75c0
+  else if (strcmp(http->hostname, cg->server) || cg->ipp_port != httpAddrPort(http->hostaddr))
1d75c0
+#endif /* AF_LOCAL */
1d75c0
+    dflags = CUPS_DEST_FLAGS_DEVICE;
1d75c0
+  else
1d75c0
+    dflags = CUPS_DEST_FLAGS_NONE;
1d75c0
 
1d75c0
  /*
1d75c0
   * Range check input...
1d75c0
@@ -609,8 +622,11 @@ cupsCopyDestInfo(
1d75c0
   * Get the printer URI and resource path...
1d75c0
   */
1d75c0
 
1d75c0
-  if ((uri = _cupsGetDestResource(dest, resource, sizeof(resource))) == NULL)
1d75c0
+  if ((uri = _cupsGetDestResource(dest, dflags, resource, sizeof(resource))) == NULL)
1d75c0
+  {
1d75c0
+    DEBUG_puts("1cupsCopyDestInfo: Unable to get resource.");
1d75c0
     return (NULL);
1d75c0
+  }
1d75c0
 
1d75c0
  /*
1d75c0
   * Get the supported attributes...
1d75c0
@@ -628,28 +644,25 @@ cupsCopyDestInfo(
1d75c0
     */
1d75c0
 
1d75c0
     request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
1d75c0
-    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL,
1d75c0
-		 uri);
1d75c0
-    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1d75c0
-                 "requesting-user-name", NULL, cupsUser());
1d75c0
-    ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1d75c0
-		  "requested-attributes",
1d75c0
-		  (int)(sizeof(requested_attrs) / sizeof(requested_attrs[0])),
1d75c0
-		  NULL, requested_attrs);
1d75c0
+
1d75c0
+    ippSetVersion(request, version / 10, version % 10);
1d75c0
+    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
1d75c0
+    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser());
1d75c0
+    ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", (int)(sizeof(requested_attrs) / sizeof(requested_attrs[0])), NULL, requested_attrs);
1d75c0
     response = cupsDoRequest(http, request, resource);
1d75c0
     status   = cupsLastError();
1d75c0
 
1d75c0
     if (status > IPP_STATUS_OK_IGNORED_OR_SUBSTITUTED)
1d75c0
     {
1d75c0
-      DEBUG_printf(("cupsCopyDestSupported: Get-Printer-Attributes for '%s' "
1d75c0
-		    "returned %s (%s)", dest->name, ippErrorString(status),
1d75c0
-		    cupsLastErrorString()));
1d75c0
+      DEBUG_printf(("1cupsCopyDestInfo: Get-Printer-Attributes for '%s' returned %s (%s)", dest->name, ippErrorString(status), cupsLastErrorString()));
1d75c0
 
1d75c0
       ippDelete(response);
1d75c0
       response = NULL;
1d75c0
 
1d75c0
-      if (status == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED && version > 11)
1d75c0
+      if ((status == IPP_STATUS_ERROR_BAD_REQUEST || status == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED) && version > 11)
1d75c0
+      {
1d75c0
         version = 11;
1d75c0
+      }
1d75c0
       else if (status == IPP_STATUS_ERROR_BUSY)
1d75c0
       {
1d75c0
         sleep((unsigned)delay);
1d75c0
@@ -665,7 +678,10 @@ cupsCopyDestInfo(
1d75c0
   while (!response && tries < 10);
1d75c0
 
1d75c0
   if (!response)
1d75c0
+  {
1d75c0
+    DEBUG_puts("1cupsCopyDestInfo: Unable to get printer attributes.");
1d75c0
     return (NULL);
1d75c0
+  }
1d75c0
 
1d75c0
  /*
1d75c0
   * Allocate a cups_dinfo_t structure and return it...
1d75c0
@@ -678,6 +694,8 @@ cupsCopyDestInfo(
1d75c0
     return (NULL);
1d75c0
   }
1d75c0
 
1d75c0
+  DEBUG_printf(("1cupsCopyDestInfo: version=%d, uri=\"%s\", resource=\"%s\".", version, uri, resource));
1d75c0
+
1d75c0
   dinfo->version  = version;
1d75c0
   dinfo->uri      = uri;
1d75c0
   dinfo->resource = _cupsStrAlloc(resource);
1d75c0
diff --git a/cups/dest.c b/cups/dest.c
1d75c0
index 57a8dc9..3537572 100644
1d75c0
--- a/cups/dest.c
1d75c0
+++ b/cups/dest.c
1d75c0
@@ -1103,13 +1103,16 @@ cupsGetDest(const char  *name,		/* I - Destination name or @code NULL@ for the d
1d75c0
  * '_cupsGetDestResource()' - Get the resource path and URI for a destination.
1d75c0
  */
1d75c0
 
1d75c0
-const char *				/* O - Printer URI */
1d75c0
+const char *				/* O - URI */
1d75c0
 _cupsGetDestResource(
1d75c0
     cups_dest_t *dest,			/* I - Destination */
1d75c0
+    unsigned    flags,			/* I - Destination flags */
1d75c0
     char        *resource,		/* I - Resource buffer */
1d75c0
     size_t      resourcesize)		/* I - Size of resource buffer */
1d75c0
 {
1d75c0
-  const char	*uri;			/* Printer URI */
1d75c0
+  const char	*uri,			/* URI */
1d75c0
+		*device_uri,		/* Device URI */
1d75c0
+		*printer_uri;		/* Printer URI */
1d75c0
   char		scheme[32],		/* URI scheme */
1d75c0
 		userpass[256],		/* Username and password (unused) */
1d75c0
 		hostname[256];		/* Hostname */
1d75c0
@@ -1132,25 +1135,46 @@ _cupsGetDestResource(
1d75c0
   }
1d75c0
 
1d75c0
  /*
1d75c0
-  * Grab the printer URI...
1d75c0
+  * Grab the printer and device URIs...
1d75c0
   */
1d75c0
 
1d75c0
-  if ((uri = cupsGetOption("printer-uri-supported", dest->num_options, dest->options)) == NULL)
1d75c0
+  device_uri  = cupsGetOption("device-uri", dest->num_options, dest->options);
1d75c0
+  printer_uri = cupsGetOption("printer-uri-supported", dest->num_options, dest->options);
1d75c0
+
1d75c0
+  DEBUG_printf(("1_cupsGetDestResource: device-uri=\"%s\", printer-uri-supported=\"%s\".", device_uri, printer_uri));
1d75c0
+
1d75c0
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
1d75c0
+  if (((flags & CUPS_DEST_FLAGS_DEVICE) || !printer_uri) && strstr(device_uri, "._tcp"))
1d75c0
   {
1d75c0
-    if ((uri = cupsGetOption("device-uri", dest->num_options, dest->options)) != NULL)
1d75c0
+    if ((device_uri = cups_dnssd_resolve(dest, device_uri, 5000, NULL, NULL, NULL)) != NULL)
1d75c0
     {
1d75c0
-#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
1d75c0
-      if (strstr(uri, "._tcp"))
1d75c0
-        uri = cups_dnssd_resolve(dest, uri, 5000, NULL, NULL, NULL);
1d75c0
-#endif /* HAVE_DNSSD || HAVE_AVAHI */
1d75c0
+      DEBUG_printf(("1_cupsGetDestResource: Resolved device-uri=\"%s\".", device_uri));
1d75c0
     }
1d75c0
-
1d75c0
-    if (uri)
1d75c0
+    else
1d75c0
     {
1d75c0
-      DEBUG_printf(("1_cupsGetDestResource: Resolved printer-uri-supported=\"%s\"", uri));
1d75c0
+      DEBUG_puts("1_cupsGetDestResource: Unable to resolve device.");
1d75c0
 
1d75c0
-      uri = _cupsCreateDest(dest->name, cupsGetOption("printer-info", dest->num_options, dest->options), NULL, uri, resource, resourcesize);
1d75c0
+      if (resource)
1d75c0
+	*resource = '\0';
1d75c0
+
1d75c0
+      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(ENOENT), 0);
1d75c0
+
1d75c0
+      return (NULL);
1d75c0
     }
1d75c0
+  }
1d75c0
+#endif /* HAVE_DNSSD || HAVE_AVAHI */
1d75c0
+
1d75c0
+  if (flags & CUPS_DEST_FLAGS_DEVICE)
1d75c0
+  {
1d75c0
+    uri = device_uri;
1d75c0
+  }
1d75c0
+  else if (printer_uri)
1d75c0
+  {
1d75c0
+    uri = printer_uri;
1d75c0
+  }
1d75c0
+  else
1d75c0
+  {
1d75c0
+    uri = _cupsCreateDest(dest->name, cupsGetOption("printer-info", dest->num_options, dest->options), NULL, device_uri, resource, resourcesize);
1d75c0
 
1d75c0
     if (uri)
1d75c0
     {
1d75c0
@@ -1160,30 +1184,24 @@ _cupsGetDestResource(
1d75c0
 
1d75c0
       uri = cupsGetOption("printer-uri-supported", dest->num_options, dest->options);
1d75c0
     }
1d75c0
-    else
1d75c0
-    {
1d75c0
-      DEBUG_puts("1_cupsGetDestResource: No printer-uri-supported found.");
1d75c0
+  }
1d75c0
 
1d75c0
-      if (resource)
1d75c0
-        *resource = '\0';
1d75c0
+  if (!uri)
1d75c0
+  {
1d75c0
+    DEBUG_puts("1_cupsGetDestResource: No printer-uri-supported or device-uri found.");
1d75c0
 
1d75c0
-      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(ENOENT), 0);
1d75c0
+    if (resource)
1d75c0
+      *resource = '\0';
1d75c0
 
1d75c0
-      return (NULL);
1d75c0
-    }
1d75c0
+    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(ENOENT), 0);
1d75c0
+
1d75c0
+    return (NULL);
1d75c0
   }
1d75c0
-  else
1d75c0
+  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)
1d75c0
   {
1d75c0
-    DEBUG_printf(("1_cupsGetDestResource: printer-uri-supported=\"%s\"", uri));
1d75c0
+    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad URI."), 1);
1d75c0
 
1d75c0
-    if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme),
1d75c0
-                        userpass, sizeof(userpass), hostname, sizeof(hostname),
1d75c0
-                        &port, resource, (int)resourcesize) < HTTP_URI_STATUS_OK)
1d75c0
-    {
1d75c0
-      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad printer-uri."), 1);
1d75c0
-
1d75c0
-      return (NULL);
1d75c0
-    }
1d75c0
+    return (NULL);
1d75c0
   }
1d75c0
 
1d75c0
   DEBUG_printf(("1_cupsGetDestResource: resource=\"%s\"", resource));
1d75c0
diff --git a/cups/testdest.c b/cups/testdest.c
1d75c0
index c5c2052..27060f6 100644
1d75c0
--- a/cups/testdest.c
1d75c0
+++ b/cups/testdest.c
1d75c0
@@ -43,9 +43,12 @@ int					/* O - Exit status */
1d75c0
 main(int  argc,				/* I - Number of command-line arguments */
1d75c0
      char *argv[])			/* I - Command-line arguments */
1d75c0
 {
1d75c0
+  int		i;			/* Looping var */
1d75c0
   http_t	*http;			/* Connection to destination */
1d75c0
   cups_dest_t	*dest = NULL;		/* Destination */
1d75c0
   cups_dinfo_t	*dinfo;			/* Destination info */
1d75c0
+  unsigned	dflags = CUPS_DEST_FLAGS_NONE;
1d75c0
+					/* Destination flags */
1d75c0
 
1d75c0
 
1d75c0
   if (argc < 2)
1d75c0
@@ -103,9 +106,17 @@ main(int  argc,				/* I - Number of command-line arguments */
1d75c0
 
1d75c0
     return (0);
1d75c0
   }
1d75c0
-  else if (!strncmp(argv[1], "ipp://", 6) || !strncmp(argv[1], "ipps://", 7))
1d75c0
-    dest = cupsGetDestWithURI(NULL, argv[1]);
1d75c0
-  else if (!strcmp(argv[1], "default"))
1d75c0
+
1d75c0
+  i = 1;
1d75c0
+  if (!strcmp(argv[i], "--device"))
1d75c0
+  {
1d75c0
+    dflags = CUPS_DEST_FLAGS_DEVICE;
1d75c0
+    i ++;
1d75c0
+  }
1d75c0
+
1d75c0
+  if (!strncmp(argv[i], "ipp://", 6) || !strncmp(argv[i], "ipps://", 7))
1d75c0
+    dest = cupsGetDestWithURI(NULL, argv[i]);
1d75c0
+  else if (!strcmp(argv[i], "default"))
1d75c0
   {
1d75c0
     dest = cupsGetNamedDest(CUPS_HTTP_DEFAULT, NULL, NULL);
1d75c0
     if (dest && dest->instance)
1d75c0
@@ -114,67 +125,70 @@ main(int  argc,				/* I - Number of command-line arguments */
1d75c0
       printf("default is \"%s\".\n", dest->name);
1d75c0
   }
1d75c0
   else
1d75c0
-    dest = cupsGetNamedDest(CUPS_HTTP_DEFAULT, argv[1], NULL);
1d75c0
+    dest = cupsGetNamedDest(CUPS_HTTP_DEFAULT, argv[i], NULL);
1d75c0
 
1d75c0
   if (!dest)
1d75c0
   {
1d75c0
-    printf("testdest: Unable to get destination \"%s\": %s\n", argv[1], cupsLastErrorString());
1d75c0
+    printf("testdest: Unable to get destination \"%s\": %s\n", argv[i], cupsLastErrorString());
1d75c0
     return (1);
1d75c0
   }
1d75c0
 
1d75c0
-  if ((http = cupsConnectDest(dest, CUPS_DEST_FLAGS_NONE, 30000, NULL, NULL, 0, NULL, NULL)) == NULL)
1d75c0
+  i ++;
1d75c0
+
1d75c0
+  if ((http = cupsConnectDest(dest, dflags, 30000, NULL, NULL, 0, NULL, NULL)) == NULL)
1d75c0
   {
1d75c0
-    printf("testdest: Unable to connect to destination \"%s\": %s\n", argv[1], cupsLastErrorString());
1d75c0
+    printf("testdest: Unable to connect to destination \"%s\": %s\n", dest->name, cupsLastErrorString());
1d75c0
     return (1);
1d75c0
   }
1d75c0
 
1d75c0
   if ((dinfo = cupsCopyDestInfo(http, dest)) == NULL)
1d75c0
   {
1d75c0
-    printf("testdest: Unable to get information for destination \"%s\": %s\n", argv[1], cupsLastErrorString());
1d75c0
+    printf("testdest: Unable to get information for destination \"%s\": %s\n", dest->name, cupsLastErrorString());
1d75c0
     return (1);
1d75c0
   }
1d75c0
 
1d75c0
-  if (argc == 2 || (!strcmp(argv[2], "supported") && argc < 6))
1d75c0
+  if (i == argc || !strcmp(argv[i], "supported"))
1d75c0
   {
1d75c0
-    if (argc > 3)
1d75c0
-      show_supported(http, dest, dinfo, argv[3], argv[4]);
1d75c0
+    i ++;
1d75c0
+
1d75c0
+    if ((i + 1) < argc)
1d75c0
+      show_supported(http, dest, dinfo, argv[i], argv[i + 1]);
1d75c0
     else if (argc > 2)
1d75c0
-      show_supported(http, dest, dinfo, argv[3], NULL);
1d75c0
+      show_supported(http, dest, dinfo, argv[i], NULL);
1d75c0
     else
1d75c0
       show_supported(http, dest, dinfo, NULL, NULL);
1d75c0
   }
1d75c0
-  else if (!strcmp(argv[2], "conflicts") && argc > 3)
1d75c0
+  else if (!strcmp(argv[i], "conflicts") && (i + 1) < argc)
1d75c0
   {
1d75c0
-    int			i,		/* Looping var */
1d75c0
-			num_options = 0;/* Number of options */
1d75c0
+    int			num_options = 0;/* Number of options */
1d75c0
     cups_option_t	*options = NULL;/* Options */
1d75c0
 
1d75c0
-    for (i = 3; i < argc; i ++)
1d75c0
+    for (i ++; i < argc; i ++)
1d75c0
       num_options = cupsParseOptions(argv[i], num_options, &options);
1d75c0
 
1d75c0
     show_conflicts(http, dest, dinfo, num_options, options);
1d75c0
   }
1d75c0
-  else if (!strcmp(argv[2], "default") && argc == 4)
1d75c0
+  else if (!strcmp(argv[i], "default") && (i + 1) < argc)
1d75c0
   {
1d75c0
-    show_default(http, dest, dinfo, argv[3]);
1d75c0
+    show_default(http, dest, dinfo, argv[i + 1]);
1d75c0
   }
1d75c0
-  else if (!strcmp(argv[2], "localize") && argc < 6)
1d75c0
+  else if (!strcmp(argv[i], "localize"))
1d75c0
   {
1d75c0
-    if (argc > 3)
1d75c0
-      localize(http, dest, dinfo, argv[3], argv[4]);
1d75c0
+    i ++;
1d75c0
+    if ((i + 1) < argc)
1d75c0
+      localize(http, dest, dinfo, argv[i], argv[i + 1]);
1d75c0
     else if (argc > 2)
1d75c0
-      localize(http, dest, dinfo, argv[3], NULL);
1d75c0
+      localize(http, dest, dinfo, argv[i], NULL);
1d75c0
     else
1d75c0
       localize(http, dest, dinfo, NULL, NULL);
1d75c0
   }
1d75c0
-  else if (!strcmp(argv[2], "media"))
1d75c0
+  else if (!strcmp(argv[i], "media"))
1d75c0
   {
1d75c0
-    int		i;			/* Looping var */
1d75c0
     const char	*name = NULL;		/* Media name, if any */
1d75c0
     unsigned	flags = CUPS_MEDIA_FLAGS_DEFAULT;
1d75c0
 					/* Media selection flags */
1d75c0
 
1d75c0
-    for (i = 3; i < argc; i ++)
1d75c0
+    for (i ++; i < argc; i ++)
1d75c0
     {
1d75c0
       if (!strcmp(argv[i], "borderless"))
1d75c0
 	flags = CUPS_MEDIA_FLAGS_BORDERLESS;
1d75c0
@@ -192,19 +206,19 @@ main(int  argc,				/* I - Number of command-line arguments */
1d75c0
 
1d75c0
     show_media(http, dest, dinfo, flags, name);
1d75c0
   }
1d75c0
-  else if (!strcmp(argv[2], "print") && argc > 3)
1d75c0
+  else if (!strcmp(argv[i], "print") && (i + 1) < argc)
1d75c0
   {
1d75c0
-    int			i,		/* Looping var */
1d75c0
-			num_options = 0;/* Number of options */
1d75c0
+    int			num_options = 0;/* Number of options */
1d75c0
     cups_option_t	*options = NULL;/* Options */
1d75c0
+    const char		*filename = argv[i + 1];
1d75c0
 
1d75c0
-    for (i = 4; i < argc; i ++)
1d75c0
+    for (i += 2; i < argc; i ++)
1d75c0
       num_options = cupsParseOptions(argv[i], num_options, &options);
1d75c0
 
1d75c0
-    print_file(http, dest, dinfo, argv[3], num_options, options);
1d75c0
+    print_file(http, dest, dinfo, filename, num_options, options);
1d75c0
   }
1d75c0
   else
1d75c0
-    usage(argv[2]);
1d75c0
+    usage(argv[i]);
1d75c0
 
1d75c0
   return (0);
1d75c0
 }
1d75c0
@@ -740,9 +754,9 @@ usage(const char *arg)			/* I - Argument for usage message */
1d75c0
     printf("testdest: Unknown option \"%s\".\n", arg);
1d75c0
 
1d75c0
   puts("Usage:");
1d75c0
-  puts("  ./testdest name [operation ...]");
1d75c0
-  puts("  ./testdest ipp://... [operation ...]");
1d75c0
-  puts("  ./testdest ipps://... [operation ...]");
1d75c0
+  puts("  ./testdest [--device] name [operation ...]");
1d75c0
+  puts("  ./testdest [--device] ipp://... [operation ...]");
1d75c0
+  puts("  ./testdest [--device] ipps://... [operation ...]");
1d75c0
   puts("  ./testdest --enum [grayscale] [color] [duplex] [staple] [small]\n"
1d75c0
        "                    [medium] [large]");
1d75c0
   puts("");
1d75c0
diff --git a/test/ippserver.c b/test/ippserver.c
1d75c0
index 38b304f..c593d3a 100644
1d75c0
--- a/test/ippserver.c
1d75c0
+++ b/test/ippserver.c
1d75c0
@@ -461,6 +461,7 @@ static AvahiClient	*DNSSDClient = NULL;
1d75c0
 #endif /* HAVE_DNSSD */
1d75c0
 
1d75c0
 static int		KeepFiles = 0,
1d75c0
+			MaxVersion = 20,
1d75c0
 			Verbosity = 0;
1d75c0
 
1d75c0
 
1d75c0
@@ -533,6 +534,23 @@ main(int  argc,				/* I - Number of command-line args */
1d75c0
               pin = 1;
1d75c0
               break;
1d75c0
 
1d75c0
+          case 'V' : /* -V max-version */
1d75c0
+	      i ++;
1d75c0
+	      if (i >= argc)
1d75c0
+	        usage(1);
1d75c0
+
1d75c0
+              if (!strcmp(argv[i], "2.2"))
1d75c0
+                MaxVersion = 22;
1d75c0
+	      else if (!strcmp(argv[i], "2.1"))
1d75c0
+                MaxVersion = 21;
1d75c0
+	      else if (!strcmp(argv[i], "2.0"))
1d75c0
+                MaxVersion = 20;
1d75c0
+	      else if (!strcmp(argv[i], "1.1"))
1d75c0
+                MaxVersion = 11;
1d75c0
+	      else
1d75c0
+	        usage(1);
1d75c0
+              break;
1d75c0
+
1d75c0
 	  case 'a' : /* -a attributes-file */
1d75c0
 	      i ++;
1d75c0
 	      if (i >= argc)
1d75c0
@@ -1324,9 +1342,10 @@ create_printer(const char *servername,	/* I - Server hostname (NULL for default)
1d75c0
   };
1d75c0
   static const char * const versions[] =/* ipp-versions-supported values */
1d75c0
   {
1d75c0
-    "1.0",
1d75c0
     "1.1",
1d75c0
-    "2.0"
1d75c0
+    "2.0",
1d75c0
+    "2.1",
1d75c0
+    "2.2"
1d75c0
   };
1d75c0
   static const char * const features[] =/* ipp-features-supported values */
1d75c0
   {
1d75c0
@@ -1738,7 +1757,12 @@ create_printer(const char *servername,	/* I - Server hostname (NULL for default)
1d75c0
 
1d75c0
   /* ipp-versions-supported */
1d75c0
   if (!ippFindAttribute(printer->attrs, "ipp-versions-supported", IPP_TAG_ZERO))
1d75c0
-    ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "ipp-versions-supported", sizeof(versions) / sizeof(versions[0]), NULL, versions);
1d75c0
+  {
1d75c0
+    int num_versions = MaxVersion == 11 ? 1 : MaxVersion == 20 ? 2 : MaxVersion == 21 ? 3 : 4;
1d75c0
+					/* Number of supported versions */
1d75c0
+
1d75c0
+    ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "ipp-versions-supported", num_versions, NULL, versions);
1d75c0
+  }
1d75c0
 
1d75c0
   /* job-account-id-default */
1d75c0
   if (!ippFindAttribute(printer->attrs, "job-account-id-default", IPP_TAG_ZERO))
1d75c0
@@ -5800,15 +5824,24 @@ process_ipp(_ipp_client_t *client)	/* I - Client */
1d75c0
     * Return an error, since we only support IPP 1.x and 2.x.
1d75c0
     */
1d75c0
 
1d75c0
-    respond_ipp(client, IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED,
1d75c0
-                "Bad request version number %d.%d.", major, minor);
1d75c0
+    respond_ipp(client, IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED, "Bad request version number %d.%d.", major, minor);
1d75c0
+  }
1d75c0
+  else if ((major * 10 + minor) > MaxVersion)
1d75c0
+  {
1d75c0
+    if (httpGetState(client->http) != HTTP_STATE_POST_SEND)
1d75c0
+      httpFlush(client->http);		/* Flush trailing (junk) data */
1d75c0
+
1d75c0
+    respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0);
1d75c0
+    return (0);
1d75c0
   }
1d75c0
   else if (ippGetRequestId(client->request) <= 0)
1d75c0
-    respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "Bad request-id %d.",
1d75c0
-                ippGetRequestId(client->request));
1d75c0
+  {
1d75c0
+    respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "Bad request-id %d.", ippGetRequestId(client->request));
1d75c0
+  }
1d75c0
   else if (!ippFirstAttribute(client->request))
1d75c0
-    respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST,
1d75c0
-                "No attributes in request.");
1d75c0
+  {
1d75c0
+    respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "No attributes in request.");
1d75c0
+  }
1d75c0
   else
1d75c0
   {
1d75c0
    /*
1d75c0
@@ -6877,8 +6910,7 @@ usage(int status)			/* O - Exit status */
1d75c0
 {
1d75c0
   if (!status)
1d75c0
   {
1d75c0
-    puts(CUPS_SVERSION " - Copyright 2010-2015 by Apple Inc. All rights "
1d75c0
-         "reserved.");
1d75c0
+    puts(CUPS_SVERSION " - Copyright (c) 2010-2018 by Apple Inc. All rights reserved.");
1d75c0
     puts("");
1d75c0
   }
1d75c0
 
1d75c0
@@ -6888,6 +6920,7 @@ usage(int status)			/* O - Exit status */
1d75c0
   puts("-2                      Supports 2-sided printing (default=1-sided)");
1d75c0
   puts("-M manufacturer         Manufacturer name (default=Test)");
1d75c0
   puts("-P                      PIN printing mode");
1d75c0
+  puts("-V max-version          Set maximum supported IPP version");
1d75c0
   puts("-a attributes-file      Load printer attributes from file");
1d75c0
   puts("-c command              Run command for every print job");
1d75c0
   printf("-d spool-directory      Spool directory "