]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - cups/http-support.c
License change: Apache License, Version 2.0.
[thirdparty/cups.git] / cups / http-support.c
index 24664d3c9e4fc2cda768f34265d6cf6a07dd548c..95135e0493f92cd67957a2424dbdd78a9acef72b 100644 (file)
@@ -1,53 +1,10 @@
 /*
- * "$Id$"
+ * HTTP support routines for CUPS.
  *
- *   HTTP support routines for CUPS.
+ * Copyright 2007-2017 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
- *   Copyright 2007-2013 by Apple Inc.
- *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
- *
- *   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
- *   file is missing or damaged, see the license at "http://www.cups.org/".
- *
- *   This file is subject to the Apple OS-Developed Software exception.
- *
- * Contents:
- *
- *   httpAssembleURI()   - Assemble a uniform resource identifier from its
- *                         components.
- *   httpAssembleURIf()   - Assemble a uniform resource identifier from its
- *                         components with a formatted resource.
- *   httpAssembleUUID()   - Assemble a name-based UUID URN conforming to RFC
- *                          4122.
- *   httpDecode64()      - Base64-decode a string.
- *   httpDecode64_2()    - Base64-decode a string.
- *   httpEncode64()      - Base64-encode a string.
- *   httpEncode64_2()    - Base64-encode a string.
- *   httpGetDateString()  - Get a formatted date/time string from a time value.
- *   httpGetDateString2() - Get a formatted date/time string from a time value.
- *   httpGetDateTime()   - Get a time value from a formatted date/time string.
- *   httpSeparate()      - Separate a Universal Resource Identifier into its
- *                         components.
- *   httpSeparate2()     - Separate a Universal Resource Identifier into its
- *                         components.
- *   httpSeparateURI()   - Separate a Universal Resource Identifier into its
- *                         components.
- *   httpStatus()        - Return a short string describing a HTTP status
- *                         code.
- *   _cups_hstrerror()   - hstrerror() emulation function for Solaris and
- *                         others.
- *   _httpDecodeURI()    - Percent-decode a HTTP request URI.
- *   _httpEncodeURI()    - Percent-encode a HTTP request URI.
- *   _httpResolveURI()   - Resolve a DNS-SD URI.
- *   http_client_cb()    - Client callback for resolving URI.
- *   http_copy_decode()   - Copy and decode a URI.
- *   http_copy_encode()   - Copy and encode a URI.
- *   http_poll_cb()       - Wait for input on the specified file descriptors.
- *   http_resolve_cb()   - Build a device URI for the given service name.
- *   http_resolve_cb()   - Build a device URI for the given service name.
+ * Licensed under Apache License v2.0.  See the file "LICENSE" for more information.
  */
 
 /*
@@ -84,6 +41,7 @@ typedef struct _http_uribuf_s         /* URI buffer */
   size_t               bufsize;        /* Size of buffer */
   int                  options;        /* Options passed to _httpResolveURI */
   const char           *resource;      /* Resource from URI */
+  const char           *uuid;          /* UUID from URI */
 } _http_uribuf_t;
 
 
@@ -91,7 +49,7 @@ typedef struct _http_uribuf_s         /* URI buffer */
  * Local globals...
  */
 
-static const char * const http_days[7] =
+static const char * const http_days[7] =/* Days of the week */
                        {
                          "Sun",
                          "Mon",
@@ -102,7 +60,7 @@ static const char * const http_days[7] =
                          "Sat"
                        };
 static const char * const http_months[12] =
-                       {
+                       {               /* Months of the year */
                          "Jan",
                          "Feb",
                          "Mar",
@@ -116,6 +74,26 @@ static const char * const http_months[12] =
                          "Nov",
                          "Dec"
                        };
+static const char * const http_states[] =
+                       {               /* HTTP state strings */
+                         "HTTP_STATE_ERROR",
+                         "HTTP_STATE_WAITING",
+                         "HTTP_STATE_OPTIONS",
+                         "HTTP_STATE_GET",
+                         "HTTP_STATE_GET_SEND",
+                         "HTTP_STATE_HEAD",
+                         "HTTP_STATE_POST",
+                         "HTTP_STATE_POST_RECV",
+                         "HTTP_STATE_POST_SEND",
+                         "HTTP_STATE_PUT",
+                         "HTTP_STATE_PUT_RECV",
+                         "HTTP_STATE_DELETE",
+                         "HTTP_STATE_TRACE",
+                         "HTTP_STATE_CONNECT",
+                         "HTTP_STATE_STATUS",
+                         "HTTP_STATE_UNKNOWN_METHOD",
+                         "HTTP_STATE_UNKNOWN_VERSION"
+                       };
 
 
 /*
@@ -166,7 +144,7 @@ static void http_resolve_cb(AvahiServiceResolver *resolver,
  * place of traditional string functions whenever you need to create a
  * URI string.
  *
- * @since CUPS 1.2/OS X 10.5@
+ * @since CUPS 1.2/macOS 10.5@
  */
 
 http_uri_status_t                      /* O - URI status */
@@ -206,10 +184,10 @@ httpAssembleURI(
   if (!ptr)
     goto assemble_overflow;
 
-  if (!strcmp(scheme, "mailto"))
+  if (!strcmp(scheme, "geo") || !strcmp(scheme, "mailto") || !strcmp(scheme, "tel"))
   {
    /*
-    * mailto: only has :, no //...
+    * geo:, mailto:, and tel: only have :, no //...
     */
 
     if (ptr < end)
@@ -220,7 +198,7 @@ httpAssembleURI(
   else
   {
    /*
-    * Schemes other than mailto: all have //...
+    * Schemes other than geo:, mailto:, and tel: typically have //...
     */
 
     if ((ptr + 2) < end)
@@ -372,7 +350,7 @@ httpAssembleURI(
 
     if (port > 0)
     {
-      snprintf(ptr, end - ptr + 1, ":%d", port);
+      snprintf(ptr, (size_t)(end - ptr + 1), ":%d", port);
       ptr += strlen(ptr);
 
       if (ptr >= end)
@@ -446,7 +424,7 @@ httpAssembleURI(
  * this function in place of traditional string functions whenever
  * you need to create a URI string.
  *
- * @since CUPS 1.2/OS X 10.5@
+ * @since CUPS 1.2/macOS 10.5@
  */
 
 http_uri_status_t                      /* O - URI status */
@@ -486,7 +464,7 @@ httpAssembleURIf(
   bytes = vsnprintf(resource, sizeof(resource), resourcef, ap);
   va_end(ap);
 
-  if (bytes >= sizeof(resource))
+  if ((size_t)bytes >= sizeof(resource))
   {
     *uri = '\0';
     return (HTTP_URI_STATUS_OVERFLOW);
@@ -506,7 +484,7 @@ httpAssembleURIf(
  *
  * The buffer needs to be at least 46 bytes in size.
  *
- * @since CUPS 1.7@
+ * @since CUPS 1.7/macOS 10.9@
  */
 
 char *                                 /* I - UUID string */
@@ -518,7 +496,6 @@ httpAssembleUUID(const char *server,        /* I - Server name */
                 size_t     bufsize)    /* I - Size of buffer */
 {
   char                 data[1024];     /* Source string for MD5 */
-  _cups_md5_state_t    md5state;       /* MD5 state */
   unsigned char                md5sum[16];     /* MD5 digest/sum */
 
 
@@ -533,9 +510,7 @@ httpAssembleUUID(const char *server,        /* I - Server name */
            port, name ? name : server, number,
           (unsigned)CUPS_RAND() & 0xffff, (unsigned)CUPS_RAND() & 0xffff);
 
-  _cupsMD5Init(&md5state);
-  _cupsMD5Append(&md5state, (unsigned char *)data, strlen(data));
-  _cupsMD5Finish(&md5state, md5sum);
+  cupsHashData("md5", (unsigned char *)data, strlen(data), md5sum, sizeof(md5sum));
 
  /*
   * Generate the UUID from the MD5...
@@ -552,13 +527,6 @@ httpAssembleUUID(const char *server,       /* I - Server name */
   return (buffer);
 }
 
-/* For OS X 10.8 and earlier */
-char *_httpAssembleUUID(const char *server, int port, const char *name,
-                       int number, char *buffer, size_t bufsize)
-{
-  return (httpAssembleUUID(server, port, name, number, buffer, bufsize));
-}
-
 
 /*
  * 'httpDecode64()' - Base64-decode a string.
@@ -566,7 +534,7 @@ char *_httpAssembleUUID(const char *server, int port, const char *name,
  * This function is deprecated. Use the httpDecode64_2() function instead
  * which provides buffer length arguments.
  *
- * @deprecated@
+ * @deprecated@ @exclude all@
  */
 
 char *                                 /* O - Decoded string */
@@ -589,7 +557,11 @@ httpDecode64(char       *out,              /* I - String to write to */
 /*
  * 'httpDecode64_2()' - Base64-decode a string.
  *
- * @since CUPS 1.1.21/OS X 10.4@
+ * The caller must initialize "outlen" to the maximum size of the decoded
+ * string before calling @code httpDecode64_2@.  On return "outlen" contains the
+ * decoded length of the string.
+ *
+ * @since CUPS 1.1.21/macOS 10.4@
  */
 
 char *                                 /* O  - Decoded string */
@@ -597,10 +569,10 @@ httpDecode64_2(char       *out,           /* I  - String to write to */
               int        *outlen,      /* IO - Size of output string */
                const char *in)         /* I  - String to read from */
 {
-  int  pos,                            /* Bit position */
-       base64;                         /* Value of this character */
-  char *outptr,                        /* Output pointer */
-       *outend;                        /* End of output buffer */
+  int          pos;                    /* Bit position */
+  unsigned     base64;                 /* Value of this character */
+  char         *outptr,                /* Output pointer */
+               *outend;                /* End of output buffer */
 
 
  /*
@@ -629,11 +601,11 @@ httpDecode64_2(char       *out,           /* I  - String to write to */
     */
 
     if (*in >= 'A' && *in <= 'Z')
-      base64 = *in - 'A';
+      base64 = (unsigned)(*in - 'A');
     else if (*in >= 'a' && *in <= 'z')
-      base64 = *in - 'a' + 26;
+      base64 = (unsigned)(*in - 'a' + 26);
     else if (*in >= '0' && *in <= '9')
-      base64 = *in - '0' + 52;
+      base64 = (unsigned)(*in - '0' + 52);
     else if (*in == '+')
       base64 = 62;
     else if (*in == '/')
@@ -651,26 +623,26 @@ httpDecode64_2(char       *out,           /* I  - String to write to */
     {
       case 0 :
           if (outptr < outend)
-            *outptr = base64 << 2;
+            *outptr = (char)(base64 << 2);
          pos ++;
          break;
       case 1 :
           if (outptr < outend)
-            *outptr++ |= (base64 >> 4) & 3;
+            *outptr++ |= (char)((base64 >> 4) & 3);
           if (outptr < outend)
-           *outptr = (base64 << 4) & 255;
+           *outptr = (char)((base64 << 4) & 255);
          pos ++;
          break;
       case 2 :
           if (outptr < outend)
-            *outptr++ |= (base64 >> 2) & 15;
+            *outptr++ |= (char)((base64 >> 2) & 15);
           if (outptr < outend)
-           *outptr = (base64 << 6) & 255;
+           *outptr = (char)((base64 << 6) & 255);
          pos ++;
          break;
       case 3 :
           if (outptr < outend)
-            *outptr++ |= base64;
+            *outptr++ |= (char)base64;
          pos = 0;
          break;
     }
@@ -694,7 +666,7 @@ httpDecode64_2(char       *out,             /* I  - String to write to */
  * This function is deprecated. Use the httpEncode64_2() function instead
  * which provides buffer length arguments.
  *
- * @deprecated@
+ * @deprecated@ @exclude all@
  */
 
 char *                                 /* O - Encoded string */
@@ -708,12 +680,12 @@ httpEncode64(char       *out,             /* I - String to write to */
 /*
  * 'httpEncode64_2()' - Base64-encode a string.
  *
- * @since CUPS 1.1.21/OS X 10.4@
+ * @since CUPS 1.1.21/macOS 10.4@
  */
 
 char *                                 /* O - Encoded string */
 httpEncode64_2(char       *out,                /* I - String to write to */
-              int        outlen,       /* I - Size of output string */
+              int        outlen,       /* I - Maximum size of output string */
                const char *in,         /* I - String to read from */
               int        inlen)        /* I - Size of input string */
 {
@@ -801,11 +773,11 @@ httpEncode64_2(char       *out,           /* I - String to write to */
 /*
  * 'httpGetDateString()' - Get a formatted date/time string from a time value.
  *
- * @deprecated@
+ * @deprecated@ @exclude all@
  */
 
 const char *                           /* O - Date/time string */
-httpGetDateString(time_t t)            /* I - UNIX time */
+httpGetDateString(time_t t)            /* I - Time in seconds */
 {
   _cups_globals_t *cg = _cupsGlobals();        /* Pointer to library globals */
 
@@ -817,11 +789,11 @@ httpGetDateString(time_t t)               /* I - UNIX time */
 /*
  * 'httpGetDateString2()' - Get a formatted date/time string from a time value.
  *
- * @since CUPS 1.2/OS X 10.5@
+ * @since CUPS 1.2/macOS 10.5@
  */
 
 const char *                           /* O - Date/time string */
-httpGetDateString2(time_t t,           /* I - UNIX time */
+httpGetDateString2(time_t t,           /* I - Time in seconds */
                    char   *s,          /* I - String buffer */
                   int    slen)         /* I - Size of string buffer */
 {
@@ -830,10 +802,7 @@ httpGetDateString2(time_t t,               /* I - UNIX time */
 
   tdate = gmtime(&t);
   if (tdate)
-    snprintf(s, slen, "%s, %02d %s %d %02d:%02d:%02d GMT",
-            http_days[tdate->tm_wday], tdate->tm_mday,
-            http_months[tdate->tm_mon], tdate->tm_year + 1900,
-            tdate->tm_hour, tdate->tm_min, tdate->tm_sec);
+    snprintf(s, (size_t)slen, "%s, %02d %s %d %02d:%02d:%02d GMT", http_days[tdate->tm_wday], tdate->tm_mday, http_months[tdate->tm_mon], tdate->tm_year + 1900, tdate->tm_hour, tdate->tm_min, tdate->tm_sec);
   else
     s[0] = '\0';
 
@@ -845,7 +814,7 @@ httpGetDateString2(time_t t,                /* I - UNIX time */
  * 'httpGetDateTime()' - Get a time value from a formatted date/time string.
  */
 
-time_t                                 /* O - UNIX time */
+time_t                                 /* O - Time in seconds */
 httpGetDateTime(const char *s)         /* I - Date/time string */
 {
   int          i;                      /* Looping var */
@@ -914,7 +883,7 @@ httpGetDateTime(const char *s)              /* I - Date/time string */
  *
  * This function is deprecated; use the httpSeparateURI() function instead.
  *
- * @deprecated@
+ * @deprecated@ @exclude all@
  */
 
 void
@@ -937,8 +906,8 @@ httpSeparate(const char *uri,               /* I - Universal Resource Identifier */
  *
  * This function is deprecated; use the httpSeparateURI() function instead.
  *
- * @since CUPS 1.1.21/OS X 10.4@
- * @deprecated@
+ * @since CUPS 1.1.21/macOS 10.4@
+ * @deprecated@ @exclude all@
  */
 
 void
@@ -962,7 +931,7 @@ httpSeparate2(const char *uri,              /* I - Universal Resource Identifier */
  * 'httpSeparateURI()' - Separate a Universal Resource Identifier into its
  *                       components.
  *
- * @since CUPS 1.2/OS X 10.5@
+ * @since CUPS 1.2/macOS 10.5@
  */
 
 http_uri_status_t                      /* O - Result of separation */
@@ -1028,7 +997,7 @@ httpSeparateURI(
     * Workaround for HP IPP client bug...
     */
 
-    strlcpy(scheme, "ipp", schemelen);
+    strlcpy(scheme, "ipp", (size_t)schemelen);
     status = HTTP_URI_STATUS_MISSING_SCHEME;
   }
   else if (*uri == '/')
@@ -1037,7 +1006,7 @@ httpSeparateURI(
     * Filename...
     */
 
-    strlcpy(scheme, "file", schemelen);
+    strlcpy(scheme, "file", (size_t)schemelen);
     status = HTTP_URI_STATUS_MISSING_SCHEME;
   }
   else
@@ -1080,7 +1049,7 @@ httpSeparateURI(
     *port = 515;
   else if (!strcmp(scheme, "socket"))  /* Not yet registered with IANA... */
     *port = 9100;
-  else if (strcmp(scheme, "file") && strcmp(scheme, "mailto"))
+  else if (strcmp(scheme, "file") && strcmp(scheme, "mailto") && strcmp(scheme, "tel"))
     status = HTTP_URI_STATUS_UNKNOWN_SCHEME;
 
  /*
@@ -1255,7 +1224,13 @@ httpSeparateURI(
         return (HTTP_URI_STATUS_BAD_PORT);
       }
 
-      *port = strtol(uri + 1, (char **)&uri, 10);
+      *port = (int)strtol(uri + 1, (char **)&uri, 10);
+
+      if (*port <= 0 || *port > 65535)
+      {
+        *port = 0;
+        return (HTTP_URI_STATUS_BAD_PORT);
+      }
 
       if (*uri != '/' && *uri)
       {
@@ -1322,22 +1297,34 @@ httpSeparateURI(
 
 
 /*
- * 'httpStatus()' - Return a short string describing a HTTP status code.
+ * 'httpStateString()' - Return the string describing a HTTP state value.
  *
- * The returned string is localized to the current POSIX locale and is based
- * on the status strings defined in RFC 2616.
+ * @since CUPS 2.0/OS 10.10@
+ */
+
+const char *                           /* O - State string */
+httpStateString(http_state_t state)    /* I - HTTP state value */
+{
+  if (state < HTTP_STATE_ERROR || state > HTTP_STATE_UNKNOWN_VERSION)
+    return ("HTTP_STATE_???");
+  else
+    return (http_states[state - HTTP_STATE_ERROR]);
+}
+
+
+/*
+ * '_httpStatus()' - Return the localized string describing a HTTP status code.
+ *
+ * The returned string is localized using the passed message catalog.
  */
 
 const char *                           /* O - Localized status string */
-httpStatus(http_status_t status)       /* I - HTTP status code */
+_httpStatus(cups_lang_t   *lang,       /* I - Language */
+            http_status_t status)      /* I - HTTP status code */
 {
   const char   *s;                     /* Status string */
-  _cups_globals_t *cg = _cupsGlobals();        /* Global data */
 
 
-  if (!cg->lang_default)
-    cg->lang_default = cupsLangDefault();
-
   switch (status)
   {
     case HTTP_STATUS_ERROR :
@@ -1419,6 +1406,90 @@ httpStatus(http_status_t status) /* I - HTTP status code */
        break;
   }
 
+  return (_cupsLangString(lang, s));
+}
+
+
+/*
+ * 'httpStatus()' - Return a short string describing a HTTP status code.
+ *
+ * The returned string is localized to the current POSIX locale and is based
+ * on the status strings defined in RFC 7231.
+ */
+
+const char *                           /* O - Localized status string */
+httpStatus(http_status_t status)       /* I - HTTP status code */
+{
+  _cups_globals_t *cg = _cupsGlobals();        /* Global data */
+
+
+  if (!cg->lang_default)
+    cg->lang_default = cupsLangDefault();
+
+  return (_httpStatus(cg->lang_default, status));
+}
+
+/*
+ * 'httpURIStatusString()' - Return a string describing a URI status code.
+ *
+ * @since CUPS 2.0/OS 10.10@
+ */
+
+const char *                           /* O - Localized status string */
+httpURIStatusString(
+    http_uri_status_t status)          /* I - URI status code */
+{
+  const char   *s;                     /* Status string */
+  _cups_globals_t *cg = _cupsGlobals();        /* Global data */
+
+
+  if (!cg->lang_default)
+    cg->lang_default = cupsLangDefault();
+
+  switch (status)
+  {
+    case HTTP_URI_STATUS_OVERFLOW :
+       s = _("URI too large");
+       break;
+    case HTTP_URI_STATUS_BAD_ARGUMENTS :
+       s = _("Bad arguments to function");
+       break;
+    case HTTP_URI_STATUS_BAD_RESOURCE :
+       s = _("Bad resource in URI");
+       break;
+    case HTTP_URI_STATUS_BAD_PORT :
+       s = _("Bad port number in URI");
+       break;
+    case HTTP_URI_STATUS_BAD_HOSTNAME :
+       s = _("Bad hostname/address in URI");
+       break;
+    case HTTP_URI_STATUS_BAD_USERNAME :
+       s = _("Bad username in URI");
+       break;
+    case HTTP_URI_STATUS_BAD_SCHEME :
+       s = _("Bad scheme in URI");
+       break;
+    case HTTP_URI_STATUS_BAD_URI :
+       s = _("Bad/empty URI");
+       break;
+    case HTTP_URI_STATUS_OK :
+       s = _("OK");
+       break;
+    case HTTP_URI_STATUS_MISSING_SCHEME :
+       s = _("Missing scheme in URI");
+       break;
+    case HTTP_URI_STATUS_UNKNOWN_SCHEME :
+       s = _("Unknown scheme in URI");
+       break;
+    case HTTP_URI_STATUS_MISSING_RESOURCE :
+       s = _("Missing resource in URI");
+       break;
+
+    default:
+        s = _("Unknown");
+       break;
+  }
+
   return (_cupsLangString(cg->lang_default, s));
 }
 
@@ -1502,9 +1573,7 @@ _httpResolveURI(
 #endif /* DEBUG */
 
 
-  DEBUG_printf(("4_httpResolveURI(uri=\"%s\", resolved_uri=%p, "
-                "resolved_size=" CUPS_LLFMT ")", uri, resolved_uri,
-               CUPS_LLCAST resolved_size));
+  DEBUG_printf(("_httpResolveURI(uri=\"%s\", resolved_uri=%p, resolved_size=" CUPS_LLFMT ", options=0x%x, cb=%p, context=%p)", uri, (void *)resolved_uri, CUPS_LLCAST resolved_size, options, (void *)cb, context));
 
  /*
   * Get the device URI...
@@ -1525,8 +1594,8 @@ _httpResolveURI(
     if (options & _HTTP_RESOLVE_STDERR)
       _cupsLangPrintFilter(stderr, "ERROR", _("Bad device-uri \"%s\"."), uri);
 
-    DEBUG_printf(("6_httpResolveURI: httpSeparateURI returned %d!", status));
-    DEBUG_puts("5_httpResolveURI: Returning NULL");
+    DEBUG_printf(("2_httpResolveURI: httpSeparateURI returned %d!", status));
+    DEBUG_puts("2_httpResolveURI: Returning NULL");
     return (NULL);
   }
 
@@ -1538,7 +1607,9 @@ _httpResolveURI(
   {
 #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
     char               *regtype,       /* Pointer to type in hostname */
-                       *domain;        /* Pointer to domain in hostname */
+                       *domain,        /* Pointer to domain in hostname */
+                       *uuid,          /* Pointer to UUID in URI */
+                       *uuidend;       /* Pointer to end of UUID in URI */
     _http_uribuf_t     uribuf;         /* URI buffer */
     int                        offline = 0;    /* offline-report state set? */
 #  ifdef HAVE_DNSSD
@@ -1546,9 +1617,11 @@ _httpResolveURI(
 #      pragma comment(lib, "dnssd.lib")
 #    endif /* WIN32 */
     DNSServiceRef      ref,            /* DNS-SD master service reference */
-                       domainref,      /* DNS-SD service reference for domain */
+                       domainref = NULL,/* DNS-SD service reference for domain */
+                       ippref = NULL,  /* DNS-SD service reference for network IPP */
+                       ippsref = NULL, /* DNS-SD service reference for network IPPS */
                        localref;       /* DNS-SD service reference for .local */
-    int                        domainsent = 0; /* Send the domain resolve? */
+    int                        extrasent = 0;  /* Send the domain/IPP/IPPS resolves? */
 #    ifdef HAVE_POLL
     struct pollfd      polldata;       /* Polling data */
 #    else /* select() */
@@ -1582,7 +1655,7 @@ _httpResolveURI(
 
     if (regtype <= hostname)
     {
-      DEBUG_puts("5_httpResolveURI: Bad hostname, returning NULL");
+      DEBUG_puts("2_httpResolveURI: Bad hostname, returning NULL");
       return (NULL);
     }
 
@@ -1595,14 +1668,23 @@ _httpResolveURI(
     if (domain)
       *domain++ = '\0';
 
+    if ((uuid = strstr(resource, "?uuid=")) != NULL)
+    {
+      *uuid = '\0';
+      uuid  += 6;
+      if ((uuidend = strchr(uuid, '&')) != NULL)
+        *uuidend = '\0';
+    }
+
+    resolved_uri[0] = '\0';
+
     uribuf.buffer   = resolved_uri;
     uribuf.bufsize  = resolved_size;
     uribuf.options  = options;
     uribuf.resource = resource;
+    uribuf.uuid     = uuid;
 
-    resolved_uri[0] = '\0';
-
-    DEBUG_printf(("6_httpResolveURI: Resolving hostname=\"%s\", regtype=\"%s\", "
+    DEBUG_printf(("2_httpResolveURI: Resolving hostname=\"%s\", regtype=\"%s\", "
                   "domain=\"%s\"\n", hostname, regtype, domain));
     if (options & _HTTP_RESOLVE_STDERR)
     {
@@ -1616,7 +1698,7 @@ _httpResolveURI(
 #  ifdef HAVE_DNSSD
     if (DNSServiceCreateConnection(&ref) == kDNSServiceErr_NoError)
     {
-      int myinterface = kDNSServiceInterfaceIndexAny;
+      uint32_t myinterface = kDNSServiceInterfaceIndexAny;
                                        /* Lookup on any interface */
 
       if (!strcmp(scheme, "ippusb"))
@@ -1641,7 +1723,7 @@ _httpResolveURI(
 
          if (cb && !(*cb)(context))
          {
-           DEBUG_puts("5_httpResolveURI: callback returned 0 (stop)");
+           DEBUG_puts("2_httpResolveURI: callback returned 0 (stop)");
            break;
          }
 
@@ -1656,7 +1738,7 @@ _httpResolveURI(
          polldata.fd     = DNSServiceRefSockFD(ref);
          polldata.events = POLLIN;
 
-         fds = poll(&polldata, 1, 1000 * timeout);
+         fds = poll(&polldata, 1, (int)(1000 * timeout));
 
 #    else /* select() */
          FD_ZERO(&input_set);
@@ -1677,7 +1759,7 @@ _httpResolveURI(
          {
            if (errno != EINTR && errno != EAGAIN)
            {
-             DEBUG_printf(("5_httpResolveURI: poll error: %s", strerror(errno)));
+             DEBUG_printf(("2_httpResolveURI: poll error: %s", strerror(errno)));
              break;
            }
          }
@@ -1688,7 +1770,7 @@ _httpResolveURI(
            * comes in, do an additional domain resolution...
            */
 
-           if (domainsent == 0 && domain && _cups_strcasecmp(domain, "local."))
+           if (extrasent == 0 && domain && _cups_strcasecmp(domain, "local."))
            {
              if (options & _HTTP_RESOLVE_STDERR)
                fprintf(stderr,
@@ -1702,7 +1784,33 @@ _httpResolveURI(
                                    myinterface, hostname, regtype, domain,
                                    http_resolve_cb,
                                    &uribuf) == kDNSServiceErr_NoError)
-               domainsent = 1;
+               extrasent = 1;
+           }
+           else if (extrasent == 0 && !strcmp(scheme, "ippusb"))
+           {
+             if (options & _HTTP_RESOLVE_STDERR)
+               fprintf(stderr, "DEBUG: Resolving \"%s\", regtype=\"_ipps._tcp\", domain=\"local.\"...\n", hostname);
+
+             ippsref = ref;
+             if (DNSServiceResolve(&ippsref,
+                                   kDNSServiceFlagsShareConnection,
+                                   kDNSServiceInterfaceIndexAny, hostname,
+                                   "_ipps._tcp", domain, http_resolve_cb,
+                                   &uribuf) == kDNSServiceErr_NoError)
+               extrasent = 1;
+           }
+           else if (extrasent == 1 && !strcmp(scheme, "ippusb"))
+           {
+             if (options & _HTTP_RESOLVE_STDERR)
+               fprintf(stderr, "DEBUG: Resolving \"%s\", regtype=\"_ipp._tcp\", domain=\"local.\"...\n", hostname);
+
+             ippref = ref;
+             if (DNSServiceResolve(&ippref,
+                                   kDNSServiceFlagsShareConnection,
+                                   kDNSServiceInterfaceIndexAny, hostname,
+                                   "_ipp._tcp", domain, http_resolve_cb,
+                                   &uribuf) == kDNSServiceErr_NoError)
+               extrasent = 2;
            }
 
           /*
@@ -1719,7 +1827,8 @@ _httpResolveURI(
          }
          else
          {
-           if (DNSServiceProcessResult(ref) == kDNSServiceErr_NoError)
+           if (DNSServiceProcessResult(ref) == kDNSServiceErr_NoError &&
+               resolved_uri[0])
            {
              uri = resolved_uri;
              break;
@@ -1727,8 +1836,15 @@ _httpResolveURI(
          }
        }
 
-       if (domainsent)
-         DNSServiceRefDeallocate(domainref);
+       if (extrasent)
+       {
+         if (domainref)
+           DNSServiceRefDeallocate(domainref);
+         if (ippref)
+           DNSServiceRefDeallocate(ippref);
+         if (ippsref)
+           DNSServiceRefDeallocate(ippsref);
+       }
 
        DNSServiceRefDeallocate(localref);
       }
@@ -1839,7 +1955,7 @@ _httpResolveURI(
     uri = resolved_uri;
   }
 
-  DEBUG_printf(("5_httpResolveURI: Returning \"%s\"", uri));
+  DEBUG_printf(("2_httpResolveURI: Returning \"%s\"", uri));
 
   return (uri);
 }
@@ -1920,7 +2036,7 @@ http_copy_decode(char       *dst, /* O - Destination buffer */
          else
            quoted |= *src - '0';
 
-          *ptr++ = quoted;
+          *ptr++ = (char)quoted;
        }
        else
        {
@@ -2026,11 +2142,32 @@ http_resolve_cb(
   uint8_t              valueLen;       /* Length of value */
 
 
-  DEBUG_printf(("7http_resolve_cb(sdRef=%p, flags=%x, interfaceIndex=%u, "
-               "errorCode=%d, fullName=\"%s\", hostTarget=\"%s\", port=%u, "
-               "txtLen=%u, txtRecord=%p, context=%p)", sdRef, flags,
-               interfaceIndex, errorCode, fullName, hostTarget, port, txtLen,
-               txtRecord, context));
+  DEBUG_printf(("4http_resolve_cb(sdRef=%p, flags=%x, interfaceIndex=%u, errorCode=%d, fullName=\"%s\", hostTarget=\"%s\", port=%u, txtLen=%u, txtRecord=%p, context=%p)", (void *)sdRef, flags, interfaceIndex, errorCode, fullName, hostTarget, port, txtLen, (void *)txtRecord, context));
+
+ /*
+  * If we have a UUID, compare it...
+  */
+
+  if (uribuf->uuid &&
+      (value = TXTRecordGetValuePtr(txtLen, txtRecord, "UUID",
+                                    &valueLen)) != NULL)
+  {
+    char       uuid[256];              /* UUID value */
+
+    memcpy(uuid, value, valueLen);
+    uuid[valueLen] = '\0';
+
+    if (_cups_strcasecmp(uuid, uribuf->uuid))
+    {
+      if (uribuf->options & _HTTP_RESOLVE_STDERR)
+       fprintf(stderr, "DEBUG: Found UUID %s, looking for %s.", uuid,
+               uribuf->uuid);
+
+      DEBUG_printf(("5http_resolve_cb: Found UUID %s, looking for %s.", uuid,
+                    uribuf->uuid));
+      return;
+    }
+  }
 
  /*
   * Figure out the scheme from the full name...
@@ -2056,7 +2193,8 @@ http_resolve_cb(
   */
 
   if ((uribuf->options & _HTTP_RESOLVE_FAXOUT) &&
-      (!strcmp(scheme, "ipp") || !strcmp(scheme, "ipps")))
+      (!strcmp(scheme, "ipp") || !strcmp(scheme, "ipps")) &&
+      !TXTRecordGetValuePtr(txtLen, txtRecord, "printer-type", &valueLen))
   {
     reskey     = "rfo";
     resdefault = "/ipp/faxout";
@@ -2115,20 +2253,18 @@ http_resolve_cb(
     http_addrlist_t    *addrlist,      /* List of addresses */
                        *addr;          /* Current address */
 
-    DEBUG_printf(("8http_resolve_cb: Looking up \"%s\".", hostTarget));
+    DEBUG_printf(("5http_resolve_cb: Looking up \"%s\".", hostTarget));
 
     snprintf(fqdn, sizeof(fqdn), "%d", ntohs(port));
     if ((addrlist = httpAddrGetList(hostTarget, AF_UNSPEC, fqdn)) != NULL)
     {
       for (addr = addrlist; addr; addr = addr->next)
       {
-        int error = getnameinfo(&(addr->addr.addr),
-                               httpAddrLength(&(addr->addr)),
-                               fqdn, sizeof(fqdn), NULL, 0, NI_NAMEREQD);
+        int error = getnameinfo(&(addr->addr.addr), (socklen_t)httpAddrLength(&(addr->addr)), fqdn, sizeof(fqdn), NULL, 0, NI_NAMEREQD);
 
         if (!error)
        {
-         DEBUG_printf(("8http_resolve_cb: Found \"%s\".", fqdn));
+         DEBUG_printf(("5http_resolve_cb: Found \"%s\".", fqdn));
 
          if ((hostptr = fqdn + strlen(fqdn) - 6) <= fqdn ||
              _cups_strcasecmp(hostptr, ".local"))
@@ -2139,7 +2275,7 @@ http_resolve_cb(
        }
 #ifdef DEBUG
        else
-         DEBUG_printf(("8http_resolve_cb: \"%s\" did not resolve: %d",
+         DEBUG_printf(("5http_resolve_cb: \"%s\" did not resolve: %d",
                        httpAddrString(&(addr->addr), fqdn, sizeof(fqdn)),
                        error));
 #endif /* DEBUG */
@@ -2155,14 +2291,11 @@ http_resolve_cb(
 
   if ((!strcmp(scheme, "ipp") || !strcmp(scheme, "ipps")) &&
       !strcmp(uribuf->resource, "/cups"))
-    httpAssembleURIf(HTTP_URI_CODING_ALL, uribuf->buffer, uribuf->bufsize,
-                     scheme, NULL, hostTarget, ntohs(port), "%s?snmp=false",
-                     resource);
+    httpAssembleURIf(HTTP_URI_CODING_ALL, uribuf->buffer, (int)uribuf->bufsize, scheme, NULL, hostTarget, ntohs(port), "%s?snmp=false", resource);
   else
-    httpAssembleURI(HTTP_URI_CODING_ALL, uribuf->buffer, uribuf->bufsize,
-                    scheme, NULL, hostTarget, ntohs(port), resource);
+    httpAssembleURI(HTTP_URI_CODING_ALL, uribuf->buffer, (int)uribuf->bufsize, scheme, NULL, hostTarget, ntohs(port), resource);
 
-  DEBUG_printf(("8http_resolve_cb: Resolved URI is \"%s\"...", uribuf->buffer));
+  DEBUG_printf(("5http_resolve_cb: Resolved URI is \"%s\"...", uribuf->buffer));
 }
 
 #elif defined(HAVE_AVAHI)
@@ -2172,6 +2305,8 @@ http_resolve_cb(
  * Note: This function is needed because avahi_simple_poll_iterate is broken
  *       and always uses a timeout of 0 (!) milliseconds.
  *       (Avahi Ticket #364)
+ *
+ * @private@
  */
 
 static int                             /* O - Number of file descriptors matching */
@@ -2221,7 +2356,7 @@ http_resolve_cb(
   size_t               valueLen = 0;   /* Length of "rp" key */
 
 
-  DEBUG_printf(("7http_resolve_cb(resolver=%p, "
+  DEBUG_printf(("4http_resolve_cb(resolver=%p, "
                "interface=%d, protocol=%d, event=%d, name=\"%s\", "
                "type=\"%s\", domain=\"%s\", hostTarget=\"%s\", address=%p, "
                "port=%d, txt=%p, flags=%d, context=%p)",
@@ -2235,6 +2370,31 @@ http_resolve_cb(
     return;
   }
 
+ /*
+  * If we have a UUID, compare it...
+  */
+
+  if (uribuf->uuid && (pair = avahi_string_list_find(txt, "UUID")) != NULL)
+  {
+    char       uuid[256];              /* UUID value */
+
+    avahi_string_list_get_pair(pair, NULL, &value, &valueLen);
+
+    memcpy(uuid, value, valueLen);
+    uuid[valueLen] = '\0';
+
+    if (_cups_strcasecmp(uuid, uribuf->uuid))
+    {
+      if (uribuf->options & _HTTP_RESOLVE_STDERR)
+       fprintf(stderr, "DEBUG: Found UUID %s, looking for %s.", uuid,
+               uribuf->uuid);
+
+      DEBUG_printf(("5http_resolve_cb: Found UUID %s, looking for %s.", uuid,
+                    uribuf->uuid));
+      return;
+    }
+  }
+
  /*
   * Figure out the scheme from the full name...
   */
@@ -2272,7 +2432,8 @@ http_resolve_cb(
   */
 
   if ((uribuf->options & _HTTP_RESOLVE_FAXOUT) &&
-      (!strcmp(scheme, "ipp") || !strcmp(scheme, "ipps")))
+      (!strcmp(scheme, "ipp") || !strcmp(scheme, "ipps")) &&
+      !avahi_string_list_find(txt, "printer-type"))
   {
     reskey     = "rfo";
     resdefault = "/ipp/faxout";
@@ -2332,20 +2493,18 @@ http_resolve_cb(
     http_addrlist_t    *addrlist,      /* List of addresses */
                        *addr;          /* Current address */
 
-    DEBUG_printf(("8http_resolve_cb: Looking up \"%s\".", hostTarget));
+    DEBUG_printf(("5http_resolve_cb: Looking up \"%s\".", hostTarget));
 
     snprintf(fqdn, sizeof(fqdn), "%d", ntohs(port));
     if ((addrlist = httpAddrGetList(hostTarget, AF_UNSPEC, fqdn)) != NULL)
     {
       for (addr = addrlist; addr; addr = addr->next)
       {
-        int error = getnameinfo(&(addr->addr.addr),
-                               httpAddrLength(&(addr->addr)),
-                               fqdn, sizeof(fqdn), NULL, 0, NI_NAMEREQD);
+        int error = getnameinfo(&(addr->addr.addr), (socklen_t)httpAddrLength(&(addr->addr)), fqdn, sizeof(fqdn), NULL, 0, NI_NAMEREQD);
 
         if (!error)
        {
-         DEBUG_printf(("8http_resolve_cb: Found \"%s\".", fqdn));
+         DEBUG_printf(("5http_resolve_cb: Found \"%s\".", fqdn));
 
          if ((hostptr = fqdn + strlen(fqdn) - 6) <= fqdn ||
              _cups_strcasecmp(hostptr, ".local"))
@@ -2356,7 +2515,7 @@ http_resolve_cb(
        }
 #ifdef DEBUG
        else
-         DEBUG_printf(("8http_resolve_cb: \"%s\" did not resolve: %d",
+         DEBUG_printf(("5http_resolve_cb: \"%s\" did not resolve: %d",
                        httpAddrString(&(addr->addr), fqdn, sizeof(fqdn)),
                        error));
 #endif /* DEBUG */
@@ -2370,15 +2529,10 @@ http_resolve_cb(
   * Assemble the final device URI using the resolved hostname...
   */
 
-  httpAssembleURI(HTTP_URI_CODING_ALL, uribuf->buffer, uribuf->bufsize, scheme,
+  httpAssembleURI(HTTP_URI_CODING_ALL, uribuf->buffer, (int)uribuf->bufsize, scheme,
                   NULL, hostTarget, port, resource);
-  DEBUG_printf(("8http_resolve_cb: Resolved URI is \"%s\".", uribuf->buffer));
+  DEBUG_printf(("5http_resolve_cb: Resolved URI is \"%s\".", uribuf->buffer));
 
   avahi_simple_poll_quit(uribuf->poll);
 }
 #endif /* HAVE_DNSSD */
-
-
-/*
- * End of "$Id$".
- */