]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - cups/http-support.c
Merge changes from CUPS 1.5svn-r9641
[thirdparty/cups.git] / cups / http-support.c
index 72bd4bde28240c7834d3bbb730a59c115d7ad3c8..1d73f7d4887e8767cbfbb71ff56508a103a682aa 100644 (file)
@@ -1,25 +1,16 @@
 /*
- * "$Id: http-support.c 5360 2006-03-30 17:02:17Z mike $"
+ * "$Id: http-support.c 7952 2008-09-17 00:56:20Z mike $"
  *
- *   HTTP support routines for the Common UNIX Printing System (CUPS) scheduler.
+ *   HTTP support routines for CUPS.
  *
- *   Copyright 1997-2006 by Easy Software Products, all rights reserved.
+ *   Copyright 2007-2011 by Apple Inc.
+ *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  *   These coded instructions, statements, and computer programs are the
- *   property of Easy Software Products 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 please contact Easy Software Products
- *   at:
- *
- *       Attn: CUPS Licensing Information
- *       Easy Software Products
- *       44141 Airport View Drive, Suite 204
- *       Hollywood, Maryland 20636 USA
- *
- *       Voice: (301) 373-9600
- *       EMail: cups-info@cups.org
- *         WWW: http://www.cups.org
+ *   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.
  *
  *   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_copy_decode()   - Copy and decode a URI.
  *   http_copy_encode()   - Copy and encode a URI.
+ *   resolve_callback()   - Build a device URI for the given service name.
  */
 
 /*
  * Include necessary headers...
  */
 
-#include "debug.h"
-#include "globals.h"
-#include <stdlib.h>
+#include "cups-private.h"
+#ifdef HAVE_DNSSD
+#  include <dns_sd.h>
+#  ifdef WIN32
+#    include <io.h>
+#  elif defined(HAVE_POLL)
+#    include <poll.h>
+#  else
+#    include <sys/select.h>
+#  endif /* WIN32 */
+#endif /* HAVE_DNSSD */
+
+
+/*
+ * Local types...
+ */
+
+typedef struct _http_uribuf_s          /* URI buffer */
+{
+  char         *buffer;                /* Pointer to buffer */
+  size_t       bufsize;                /* Size of buffer */
+} _http_uribuf_t;
 
 
 /*
@@ -64,7 +78,8 @@
 
 static const char * const http_days[7] =
                        {
-                         "Sun",                          "Mon",
+                         "Sun",
+                         "Mon",
                          "Tue",
                          "Wed",
                          "Thu",
@@ -98,6 +113,17 @@ static const char   *http_copy_decode(char *dst, const char *src,
 static char            *http_copy_encode(char *dst, const char *src,
                                          char *dstend, const char *reserved,
                                          const char *term, int encode);
+#ifdef HAVE_DNSSD
+static void DNSSD_API  resolve_callback(DNSServiceRef sdRef,
+                                        DNSServiceFlags flags,
+                                        uint32_t interfaceIndex,
+                                        DNSServiceErrorType errorCode,
+                                        const char *fullName,
+                                        const char *hostTarget,
+                                        uint16_t port, uint16_t txtLen,
+                                        const unsigned char *txtRecord,
+                                        void *context);
+#endif /* HAVE_DNSSD */
 
 
 /*
@@ -109,7 +135,7 @@ static char         *http_copy_encode(char *dst, const char *src,
  * place of traditional string functions whenever you need to create a
  * URI string.
  *
- * @since CUPS 1.2@
+ * @since CUPS 1.2/Mac OS X 10.5@
  */
 
 http_uri_status_t                      /* O - URI status */
@@ -149,7 +175,7 @@ httpAssembleURI(
   if (!ptr)
     goto assemble_overflow;
 
-  if (!strcmp(scheme, "mailto:"))
+  if (!strcmp(scheme, "mailto"))
   {
    /*
     * mailto: only has :, no //...
@@ -202,15 +228,17 @@ httpAssembleURI(
 
    /*
     * Then add the hostname.  Since IPv6 is a particular pain to deal
-    * with, we have several special cases to deal with...  If we get
+    * with, we have several special cases to deal with.  If we get
     * an IPv6 address with brackets around it, assume it is already in
-    * URI format...
+    * URI format.  Since DNS-SD service names can sometimes look like
+    * raw IPv6 addresses, we specifically look for "._tcp" in the name,
+    * too...
     */
 
-    if (host[0] != '[' && strchr(host, ':'))
+    if (host[0] != '[' && strchr(host, ':') && !strstr(host, "._tcp"))
     {
      /*
-      * We have an IPv6 address...
+      * We have a raw IPv6 address...
       */
 
       if (strchr(host, '%'))
@@ -270,7 +298,7 @@ httpAssembleURI(
       * Otherwise, just copy the host string...
       */
 
-      ptr = http_copy_encode(ptr, host, end, NULL, NULL,
+      ptr = http_copy_encode(ptr, host, end, ":/?#[]@\\\"", NULL,
                              encoding & HTTP_URI_CODING_HOSTNAME);
 
       if (!ptr)
@@ -357,7 +385,7 @@ httpAssembleURI(
  * this function in place of traditional string functions whenever
  * you need to create a URI string.
  *
- * @since CUPS 1.2@
+ * @since CUPS 1.2/Mac OS X 10.5@
  */
 
 http_uri_status_t                      /* O - URI status */
@@ -437,7 +465,7 @@ httpDecode64(char       *out,               /* I - String to write to */
 /*
  * 'httpDecode64_2()' - Base64-decode a string.
  *
- * @since CUPS 1.1.21@
+ * @since CUPS 1.1.21/Mac OS X 10.4@
  */
 
 char *                                 /* O  - Decoded string */
@@ -549,14 +577,14 @@ char *                                    /* O - Encoded string */
 httpEncode64(char       *out,          /* I - String to write to */
              const char *in)           /* I - String to read from */
 {
-  return (httpEncode64_2(out, 512, in, strlen(in)));
+  return (httpEncode64_2(out, 512, in, (int)strlen(in)));
 }
 
 
 /*
  * 'httpEncode64_2()' - Base64-encode a string.
  *
- * @since CUPS 1.1.21@
+ * @since CUPS 1.1.21/Mac OS X 10.4@
  */
 
 char *                                 /* O - Encoded string */
@@ -595,8 +623,14 @@ httpEncode64_2(char       *out,            /* I - String to write to */
 
     if (outptr < outend)
       *outptr ++ = base64[(in[0] & 255) >> 2];
+
     if (outptr < outend)
-      *outptr ++ = base64[(((in[0] & 255) << 4) | ((in[1] & 255) >> 4)) & 63];
+    {
+      if (inlen > 1)
+        *outptr ++ = base64[(((in[0] & 255) << 4) | ((in[1] & 255) >> 4)) & 63];
+      else
+        *outptr ++ = base64[((in[0] & 255) << 4) & 63];
+    }
 
     in ++;
     inlen --;
@@ -610,7 +644,12 @@ httpEncode64_2(char       *out,            /* I - String to write to */
     }
 
     if (outptr < outend)
-      *outptr ++ = base64[(((in[0] & 255) << 2) | ((in[1] & 255) >> 6)) & 63];
+    {
+      if (inlen > 1)
+        *outptr ++ = base64[(((in[0] & 255) << 2) | ((in[1] & 255) >> 6)) & 63];
+      else
+        *outptr ++ = base64[((in[0] & 255) << 2) & 63];
+    }
 
     in ++;
     inlen --;
@@ -654,7 +693,7 @@ httpGetDateString(time_t t)         /* I - UNIX time */
 /*
  * 'httpGetDateString2()' - Get a formatted date/time string from a time value.
  *
- * @since CUPS 1.2@
+ * @since CUPS 1.2/Mac OS X 10.5@
  */
 
 const char *                           /* O - Date/time string */
@@ -693,7 +732,7 @@ httpGetDateTime(const char *s)              /* I - Date/time string */
                { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 };
 
 
-  DEBUG_printf(("httpGetDateTime(s=\"%s\")\n", s));
+  DEBUG_printf(("2httpGetDateTime(s=\"%s\")", s));
 
  /*
   * Extract the date and time from the formatted string...
@@ -702,8 +741,8 @@ httpGetDateTime(const char *s)              /* I - Date/time string */
   if (sscanf(s, "%*s%d%15s%d%d:%d:%d", &day, mon, &year, &hour, &min, &sec) < 6)
     return (0);
 
-  DEBUG_printf(("    day=%d, mon=\"%s\", year=%d, hour=%d, min=%d, sec=%d\n",
-                day, mon, year, hour, min, sec));
+  DEBUG_printf(("4httpGetDateTime: day=%d, mon=\"%s\", year=%d, hour=%d, "
+                "min=%d, sec=%d", day, mon, year, hour, min, sec));
 
  /*
   * Convert the month name to a number from 0 to 11.
@@ -716,7 +755,7 @@ httpGetDateTime(const char *s)              /* I - Date/time string */
   if (i >= 12)
     return (0);
 
-  DEBUG_printf(("    i=%d\n", i));
+  DEBUG_printf(("4httpGetDateTime: i=%d", i));
 
  /*
   * Now convert the date and time to a UNIX time value in seconds since
@@ -729,14 +768,14 @@ httpGetDateTime(const char *s)            /* I - Date/time string */
   else
     days = normal_days[i] + day - 1;
 
-  DEBUG_printf(("    days=%d\n", days));
+  DEBUG_printf(("4httpGetDateTime: days=%d", days));
 
   days += (year - 1970) * 365 +                /* 365 days per year (normally) */
           ((year - 1) / 4 - 492) -     /* + leap days */
          ((year - 1) / 100 - 19) +     /* - 100 year days */
           ((year - 1) / 400 - 4);      /* + 400 year days */
 
-  DEBUG_printf(("    days=%d\n", days));
+  DEBUG_printf(("4httpGetDateTime: days=%d\n", days));
 
   return (days * 86400 + hour * 3600 + min * 60 + sec);
 }
@@ -771,7 +810,7 @@ httpSeparate(const char *uri,               /* I - Universal Resource Identifier */
  *
  * This function is deprecated; use the httpSeparateURI() function instead.
  *
- * @since CUPS 1.1.21@
+ * @since CUPS 1.1.21/Mac OS X 10.4@
  * @deprecated@
  */
 
@@ -796,7 +835,7 @@ httpSeparate2(const char *uri,              /* I - Universal Resource Identifier */
  * 'httpSeparateURI()' - Separate a Universal Resource Identifier into its
  *                       components.
  *
- * @since CUPS 1.2@
+ * @since CUPS 1.2/Mac OS X 10.5@
  */
 
 http_uri_status_t                      /* O - Result of separation */
@@ -882,7 +921,9 @@ httpSeparateURI(
 
     for (ptr = scheme, end = scheme + schemelen - 1;
          *uri && *uri != ':' && ptr < end;)
-      if (isalnum(*uri & 255) || *uri == '-' || *uri == '+' || *uri == '.')
+      if (strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+                 "abcdefghijklmnopqrstuvwxyz"
+                "0123456789-+.", *uri) != NULL)
         *ptr++ = *uri++;
       else
         break;
@@ -906,7 +947,7 @@ httpSeparateURI(
     *port = 80;
   else if (!strcmp(scheme, "https"))
     *port = 443;
-  else if (!strcmp(scheme, "ipp"))
+  else if (!strcmp(scheme, "ipp") || !strcmp(scheme, "ipps"))
     *port = 631;
   else if (!strcasecmp(scheme, "lpd"))
     *port = 515;
@@ -1014,7 +1055,7 @@ httpSeparateURI(
                         "0123456789"
                         "-._~"
                         "%"
-                        "!$&'()*+,;=", *ptr))
+                        "!$&'()*+,;=\\", *ptr))
        {
          *host = '\0';
          return (HTTP_URI_BAD_HOSTNAME);
@@ -1055,6 +1096,12 @@ httpSeparateURI(
       * Yes, collect the port number...
       */
 
+      if (!isdigit(uri[1] & 255))
+      {
+        *port = 0;
+        return (HTTP_URI_BAD_PORT);
+      }
+
       *port = strtol(uri + 1, (char **)&uri, 10);
 
       if (*uri != '/' && *uri)
@@ -1101,7 +1148,7 @@ httpSeparateURI(
 
       char *resptr = resource + strlen(resource);
 
-      uri = http_copy_decode(resptr, uri, resourcelen - (resptr - resource),
+      uri = http_copy_decode(resptr, uri, resourcelen - (int)(resptr - resource),
                              NULL, decoding & HTTP_URI_CODING_QUERY);
     }
   }
@@ -1122,55 +1169,100 @@ httpSeparateURI(
 
 /*
  * '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 2616.
  */
 
-const char *                           /* O - String or NULL */
+const char *                           /* O - Localized status string */
 httpStatus(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_CONTINUE :
-        return ("Continue");
+        s = _("Continue");
+       break;
     case HTTP_SWITCHING_PROTOCOLS :
-        return ("Switching Protocols");
+        s = _("Switching Protocols");
+       break;
     case HTTP_OK :
-        return ("OK");
+        s = _("OK");
+       break;
     case HTTP_CREATED :
-        return ("Created");
+        s = _("Created");
+       break;
     case HTTP_ACCEPTED :
-        return ("Accepted");
+        s = _("Accepted");
+       break;
     case HTTP_NO_CONTENT :
-        return ("No Content");
+        s = _("No Content");
+       break;
     case HTTP_MOVED_PERMANENTLY :
-        return ("Moved Permanently");
+        s = _("Moved Permanently");
+       break;
     case HTTP_SEE_OTHER :
-        return ("See Other");
+        s = _("See Other");
+       break;
     case HTTP_NOT_MODIFIED :
-        return ("Not Modified");
+        s = _("Not Modified");
+       break;
     case HTTP_BAD_REQUEST :
-        return ("Bad Request");
+        s = _("Bad Request");
+       break;
     case HTTP_UNAUTHORIZED :
-        return ("Unauthorized");
+    case HTTP_AUTHORIZATION_CANCELED :
+        s = _("Unauthorized");
+       break;
     case HTTP_FORBIDDEN :
-        return ("Forbidden");
+        s = _("Forbidden");
+       break;
     case HTTP_NOT_FOUND :
-        return ("Not Found");
+        s = _("Not Found");
+       break;
     case HTTP_REQUEST_TOO_LARGE :
-        return ("Request Entity Too Large");
+        s = _("Request Entity Too Large");
+       break;
     case HTTP_URI_TOO_LONG :
-        return ("URI Too Long");
+        s = _("URI Too Long");
+       break;
     case HTTP_UPGRADE_REQUIRED :
-        return ("Upgrade Required");
+        s = _("Upgrade Required");
+       break;
     case HTTP_NOT_IMPLEMENTED :
-        return ("Not Implemented");
+        s = _("Not Implemented");
+       break;
     case HTTP_NOT_SUPPORTED :
-        return ("Not Supported");
+        s = _("Not Supported");
+       break;
     case HTTP_EXPECTATION_FAILED :
-        return ("Expectation Failed");
+        s = _("Expectation Failed");
+       break;
+    case HTTP_SERVICE_UNAVAILABLE :
+        s = _("Service Unavailable");
+       break;
+    case HTTP_SERVER_ERROR :
+        s = _("Internal Server Error");
+       break;
+    case HTTP_PKI_ERROR :
+        s = _("SSL/TLS Negotiation Error");
+       break;
+    case HTTP_WEBIF_DISABLED :
+        s = _("Web Interface is Disabled");
+       break;
 
     default :
-        return ("Unknown");
+        s = _("Unknown");
+       break;
   }
+
+  return (_cupsLangString(cg->lang_default, s));
 }
 
 
@@ -1200,6 +1292,288 @@ _cups_hstrerror(int error)              /* I - Error number */
 #endif /* !HAVE_HSTRERROR */
 
 
+/*
+ * '_httpDecodeURI()' - Percent-decode a HTTP request URI.
+ */
+
+char *                                 /* O - Decoded URI or NULL on error */
+_httpDecodeURI(char       *dst,                /* I - Destination buffer */
+               const char *src,                /* I - Source URI */
+              size_t     dstsize)      /* I - Size of destination buffer */
+{
+  if (http_copy_decode(dst, src, (int)dstsize, NULL, 1))
+    return (dst);
+  else
+    return (NULL);
+}
+
+
+/*
+ * '_httpEncodeURI()' - Percent-encode a HTTP request URI.
+ */
+
+char *                                 /* O - Encoded URI */
+_httpEncodeURI(char       *dst,                /* I - Destination buffer */
+               const char *src,                /* I - Source URI */
+              size_t     dstsize)      /* I - Size of destination buffer */
+{
+  http_copy_encode(dst, src, dst + dstsize - 1, NULL, NULL, 1);
+  return (dst);
+}
+
+
+/*
+ * '_httpResolveURI()' - Resolve a DNS-SD URI.
+ */
+
+const char *                           /* O - Resolved URI */
+_httpResolveURI(
+    const char *uri,                   /* I - DNS-SD URI */
+    char       *resolved_uri,          /* I - Buffer for resolved URI */
+    size_t     resolved_size,          /* I - Size of URI buffer */
+    int        logit)                  /* I - Log progress to stderr? */
+{
+  char                 scheme[32],     /* URI components... */
+                       userpass[256],
+                       hostname[1024],
+                       resource[1024];
+  int                  port;
+#ifdef DEBUG
+  http_uri_status_t    status;         /* URI decode status */
+#endif /* DEBUG */
+
+
+  DEBUG_printf(("4_httpResolveURI(uri=\"%s\", resolved_uri=%p, "
+                "resolved_size=" CUPS_LLFMT ")", uri, resolved_uri,
+               CUPS_LLCAST resolved_size));
+
+ /*
+  * Get the device URI...
+  */
+
+#ifdef DEBUG
+  if ((status = httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme,
+                                sizeof(scheme), userpass, sizeof(userpass),
+                               hostname, sizeof(hostname), &port, resource,
+                               sizeof(resource))) < HTTP_URI_OK)
+#else
+  if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme,
+                     sizeof(scheme), userpass, sizeof(userpass),
+                     hostname, sizeof(hostname), &port, resource,
+                     sizeof(resource)) < HTTP_URI_OK)
+#endif /* DEBUG */
+  {
+    if (logit)
+      _cupsLangPrintFilter(stderr, "ERROR", _("Bad device-uri \"%s\"."), uri);
+
+    DEBUG_printf(("6_httpResolveURI: httpSeparateURI returned %d!", status));
+    DEBUG_puts("5_httpResolveURI: Returning NULL");
+    return (NULL);
+  }
+
+ /*
+  * Resolve it as needed...
+  */
+
+  if (strstr(hostname, "._tcp"))
+  {
+#ifdef HAVE_DNSSD
+#  ifdef WIN32
+#    pragma comment(lib, "dnssd.lib")
+#  endif /* WIN32 */
+    DNSServiceRef      ref,            /* DNS-SD master service reference */
+                       domainref,      /* DNS-SD service reference for domain */
+                       localref;       /* DNS-SD service reference for .local */
+    int                        domainsent = 0, /* Send the domain resolve? */
+                       offline = 0;    /* offline-report state set? */
+    char               *regtype,       /* Pointer to type in hostname */
+                       *domain;        /* Pointer to domain in hostname */
+    _http_uribuf_t     uribuf;         /* URI buffer */
+#ifdef HAVE_POLL
+    struct pollfd      polldata;       /* Polling data */
+#else /* select() */
+    fd_set             input_set;      /* Input set for select() */
+    struct timeval     stimeout;       /* Timeout value for select() */
+#endif /* HAVE_POLL */
+
+    if (logit)
+      fprintf(stderr, "DEBUG: Resolving \"%s\"...\n", hostname);
+
+   /*
+    * Separate the hostname into service name, registration type, and domain...
+    */
+
+    for (regtype = strstr(hostname, "._tcp") - 2;
+         regtype > hostname;
+        regtype --)
+      if (regtype[0] == '.' && regtype[1] == '_')
+      {
+       /*
+        * Found ._servicetype in front of ._tcp...
+       */
+
+        *regtype++ = '\0';
+       break;
+      }
+
+    if (regtype <= hostname)
+    {
+      DEBUG_puts("5_httpResolveURI: Bad hostname, returning NULL");
+      return (NULL);
+    }
+
+    for (domain = strchr(regtype, '.');
+         domain;
+        domain = strchr(domain + 1, '.'))
+      if (domain[1] != '_')
+        break;
+
+    if (domain)
+      *domain++ = '\0';
+
+    uribuf.buffer  = resolved_uri;
+    uribuf.bufsize = resolved_size;
+
+    resolved_uri[0] = '\0';
+
+    DEBUG_printf(("6_httpResolveURI: Resolving hostname=\"%s\", regtype=\"%s\", "
+                  "domain=\"%s\"\n", hostname, regtype, domain));
+    if (logit)
+    {
+      fputs("STATE: +connecting-to-device\n", stderr);
+      fprintf(stderr, "DEBUG: Resolving \"%s\", regtype=\"%s\", "
+                      "domain=\"local.\"...\n", hostname, regtype);
+    }
+
+    uri = NULL;
+
+    if (DNSServiceCreateConnection(&ref) == kDNSServiceErr_NoError)
+    {
+      localref = ref;
+      if (DNSServiceResolve(&localref, kDNSServiceFlagsShareConnection, 0,
+                           hostname, regtype, "local.", resolve_callback,
+                           &uribuf) == kDNSServiceErr_NoError)
+      {
+       int     fds;                    /* Number of ready descriptors */
+       time_t  timeout,                /* Poll timeout */
+               start_time = time(NULL);/* Start time */
+
+       for (;;)
+       {
+         if (logit)
+           _cupsLangPrintFilter(stderr, "INFO", _("Looking for printer."));
+
+        /*
+         * For the first minute, wakeup every 2 seconds to emit a
+         * "looking for printer" message...
+         */
+
+         timeout = (time(NULL) < (start_time + 60)) ? 2000 : -1;
+
+#ifdef HAVE_POLL
+         polldata.fd     = DNSServiceRefSockFD(ref);
+         polldata.events = POLLIN;
+
+         fds = poll(&polldata, 1, timeout);
+
+#else /* select() */
+         FD_ZERO(&input_set);
+         FD_SET(DNSServiceRefSockFD(ref), &input_set);
+
+         stimeout.tv_sec  = ((int)timeout) / 1000;
+         stimeout.tv_usec = ((int)(timeout) * 1000) % 1000000;
+
+         fds = select(DNSServiceRefSockFD(ref)+1, &input_set, NULL, NULL, 
+                      timeout < 0.0 ? NULL : &stimeout); 
+#endif /* HAVE_POLL */
+
+         if (fds < 0)
+         {
+           if (errno != EINTR && errno != EAGAIN)
+           {
+             DEBUG_printf(("5_httpResolveURI: poll error: %s", strerror(errno)));
+             break;
+           }
+         }
+         else if (fds == 0)
+         {
+          /*
+           * Wait 2 seconds for a response to the local resolve; if nothing
+           * comes in, do an additional domain resolution...
+           */
+
+           if (domainsent == 0 && strcasecmp(domain, "local."))
+           {
+             if (logit)
+               fprintf(stderr,
+                       "DEBUG: Resolving \"%s\", regtype=\"%s\", "
+                       "domain=\"%s\"...\n", hostname, regtype, domain);
+  
+             domainref = ref;
+             if (DNSServiceResolve(&domainref, kDNSServiceFlagsShareConnection, 0,
+                                   hostname, regtype, domain, resolve_callback,
+                                   &uribuf) == kDNSServiceErr_NoError)
+               domainsent = 1;
+           }
+
+          /*
+           * If it hasn't resolved within 5 seconds set the offline-report
+           * printer-state-reason...
+           */
+
+           if (logit && offline == 0 && time(NULL) > (start_time + 5))
+           {
+             fputs("STATE: +offline-report\n", stderr);
+             offline = 1;
+           }
+         }
+         else
+         {
+           if (DNSServiceProcessResult(ref) == kDNSServiceErr_NoError)
+           {
+             uri = resolved_uri;
+             break;
+           }
+         }
+       }
+
+       if (domainsent)
+         DNSServiceRefDeallocate(domainref);
+
+       DNSServiceRefDeallocate(localref);
+      }
+
+      DNSServiceRefDeallocate(ref);
+    }
+
+    if (logit)
+    {
+      if (uri)
+        fprintf(stderr, "DEBUG: Resolved as \"%s\"...\n", uri);
+      else
+        fputs("DEBUG: Unable to resolve URI\n", stderr);
+
+      fputs("STATE: -connecting-to-device,offline-report\n", stderr);
+    }
+
+#else
+   /*
+    * No DNS-SD support...
+    */
+
+    uri = NULL;
+#endif /* HAVE_DNSSD */
+
+    if (logit && !uri)
+      _cupsLangPrintFilter(stderr, "ERROR", _("Unable to find printer."));
+  }
+
+  DEBUG_printf(("5_httpResolveURI: Returning \"%s\"", uri));
+
+  return (uri);
+}
+
+
 /*
  * 'http_copy_decode()' - Copy and decode a URI.
  */
@@ -1280,7 +1654,7 @@ http_copy_encode(char       *dst, /* O - Destination buffer */
                 const char *term,      /* I - Terminating characters */
                 int        encode)     /* I - %-encode reserved chars? */
 {
-  static const char *hex = "0123456789ABCDEF";
+  static const char hex[] = "0123456789ABCDEF";
 
 
   while (*src && dst < dstend)
@@ -1308,6 +1682,8 @@ http_copy_encode(char       *dst, /* O - Destination buffer */
       *dst++ = *src++;
   }
 
+  *dst = '\0';
+
   if (*src)
     return (NULL);
   else
@@ -1315,6 +1691,83 @@ http_copy_encode(char       *dst,        /* O - Destination buffer */
 }
 
 
+#ifdef HAVE_DNSSD
+/*
+ * 'resolve_callback()' - Build a device URI for the given service name.
+ */
+
+static void DNSSD_API
+resolve_callback(
+    DNSServiceRef       sdRef,         /* I - Service reference */
+    DNSServiceFlags     flags,         /* I - Results flags */
+    uint32_t            interfaceIndex,        /* I - Interface number */
+    DNSServiceErrorType errorCode,     /* I - Error, if any */
+    const char          *fullName,     /* I - Full service name */
+    const char          *hostTarget,   /* I - Hostname */
+    uint16_t            port,          /* I - Port number */
+    uint16_t            txtLen,                /* I - Length of TXT record */
+    const unsigned char *txtRecord,    /* I - TXT record data */
+    void                *context)      /* I - Pointer to URI buffer */
+{
+  const char           *scheme;        /* URI scheme */
+  char                 rp[257];        /* Remote printer */
+  const void           *value;         /* Value from TXT record */
+  uint8_t              valueLen;       /* Length of value */
+  _http_uribuf_t       *uribuf;        /* URI buffer */
+
+
+  DEBUG_printf(("7resolve_callback(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));
+
+ /*
+  * Figure out the scheme from the full name...
+  */
+
+  if (strstr(fullName, "._ipp") || strstr(fullName, "._fax-ipp"))
+    scheme = "ipp";
+  else if (strstr(fullName, "._printer."))
+    scheme = "lpd";
+  else if (strstr(fullName, "._pdl-datastream."))
+    scheme = "socket";
+  else
+    scheme = "riousbprint";
+
+ /*
+  * Extract the "remote printer" key from the TXT record...
+  */
+
+  if ((value = TXTRecordGetValuePtr(txtLen, txtRecord, "rp",
+                                    &valueLen)) != NULL)
+  {
+   /*
+    * Convert to resource by concatenating with a leading "/"...
+    */
+
+    rp[0] = '/';
+    memcpy(rp + 1, value, valueLen);
+    rp[valueLen + 1] = '\0';
+  }
+  else
+    rp[0] = '\0';
+
+ /*
+  * Assemble the final device URI...
+  */
+
+  uribuf = (_http_uribuf_t *)context;
+
+  httpAssembleURI(HTTP_URI_CODING_ALL, uribuf->buffer, uribuf->bufsize, scheme,
+                  NULL, hostTarget, ntohs(port), rp);
+
+  DEBUG_printf(("8resolve_callback: Resolved URI is \"%s\"...",
+                uribuf->buffer));
+}
+#endif /* HAVE_DNSSD */
+
+
 /*
- * End of "$Id: http-support.c 5360 2006-03-30 17:02:17Z mike $".
+ * End of "$Id: http-support.c 7952 2008-09-17 00:56:20Z mike $".
  */