/*
* "$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 2007-2008 by Apple Inc.
+ * 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
* 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.
* 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 */
char *dstend, const char *reserved,
const char *term, int encode);
#ifdef HAVE_DNSSD
-static void resolve_callback(DNSServiceRef sdRef,
+static void DNSSD_API resolve_callback(DNSServiceRef sdRef,
DNSServiceFlags flags,
uint32_t interfaceIndex,
DNSServiceErrorType errorCode,
* Otherwise, just copy the host string...
*/
- ptr = http_copy_encode(ptr, host, end, ":/?#[]@", NULL,
+ ptr = http_copy_encode(ptr, host, end, ":/?#[]@\\\"", NULL,
encoding & HTTP_URI_CODING_HOSTNAME);
if (!ptr)
{ 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...
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.
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
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);
}
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;
*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;
* 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)
s = _("Bad Request");
break;
case HTTP_UNAUTHORIZED :
+ case HTTP_AUTHORIZATION_CANCELED :
s = _("Unauthorized");
break;
case HTTP_FORBIDDEN :
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 :
s = _("Unknown");
#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.
*/
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 log) /* I - Log progress to stderr? */
+ int logit) /* I - Log progress to stderr? */
{
char scheme[32], /* URI components... */
userpass[256],
#endif /* DEBUG */
- DEBUG_printf(("_httpResolveURI(uri=\"%s\", resolved_uri=%p, "
- "resolved_size=" CUPS_LLFMT ")\n", uri, resolved_uri,
+ DEBUG_printf(("4_httpResolveURI(uri=\"%s\", resolved_uri=%p, "
+ "resolved_size=" CUPS_LLFMT ")", uri, resolved_uri,
CUPS_LLCAST resolved_size));
/*
sizeof(resource)) < HTTP_URI_OK)
#endif /* DEBUG */
{
- if (log)
- _cupsLangPrintf(stderr, _("Bad device URI \"%s\"!\n"), uri);
+ if (logit)
+ _cupsLangPrintFilter(stderr, "ERROR", _("Bad device-uri \"%s\"."), uri);
- DEBUG_printf(("_httpResolveURI: httpSeparateURI returned %d!\n", status));
- DEBUG_puts("_httpResolveURI: Returning NULL");
+ DEBUG_printf(("6_httpResolveURI: httpSeparateURI returned %d!", status));
+ DEBUG_puts("5_httpResolveURI: Returning NULL");
return (NULL);
}
if (strstr(hostname, "._tcp"))
{
#ifdef HAVE_DNSSD
- DNSServiceRef ref; /* DNS-SD service reference */
+# 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...
if (regtype <= hostname)
{
- DEBUG_puts("_httpResolveURI: Bad hostname, returning NULL");
+ DEBUG_puts("5_httpResolveURI: Bad hostname, returning NULL");
return (NULL);
}
- domain = regtype + strlen(regtype) - 1;
- if (domain > regtype && *domain == '.')
- *domain = '\0';
-
for (domain = strchr(regtype, '.');
domain;
domain = strchr(domain + 1, '.'))
resolved_uri[0] = '\0';
- DEBUG_printf(("_httpResolveURI: Resolving hostname=\"%s\", regtype=\"%s\", "
+ DEBUG_printf(("6_httpResolveURI: Resolving hostname=\"%s\", regtype=\"%s\", "
"domain=\"%s\"\n", hostname, regtype, domain));
- if (log)
+ if (logit)
{
fputs("STATE: +connecting-to-device\n", stderr);
- fprintf(stderr, "DEBUG: Resolving %s, regtype=%s, domain=%s...\n",
- hostname, regtype, domain);
- _cupsLangPuts(stderr, _("INFO: Looking for printer...\n"));
+ fprintf(stderr, "DEBUG: Resolving \"%s\", regtype=\"%s\", "
+ "domain=\"local.\"...\n", hostname, regtype);
}
- if (DNSServiceResolve(&ref, 0, 0, hostname, regtype, domain,
- resolve_callback,
- &uribuf) == kDNSServiceErr_NoError)
+ uri = NULL;
+
+ if (DNSServiceCreateConnection(&ref) == kDNSServiceErr_NoError)
{
- if (DNSServiceProcessResult(ref) != kDNSServiceErr_NoError &&
- resolved_uri[0])
- uri = NULL;
- else
- uri = resolved_uri;
+ 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);
}
- else
- uri = NULL;
- if (log)
- fputs("STATE: -connecting-to-device\n", stderr);
+ 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
/*
uri = NULL;
#endif /* HAVE_DNSSD */
- if (log && !uri)
- _cupsLangPuts(stderr, _("Unable to find printer!\n"));
+ if (logit && !uri)
+ _cupsLangPrintFilter(stderr, "ERROR", _("Unable to find printer."));
}
- DEBUG_printf(("_httpResolveURI: Returning \"%s\"\n", uri));
+ DEBUG_printf(("5_httpResolveURI: Returning \"%s\"", uri));
return (uri);
}
* 'resolve_callback()' - Build a device URI for the given service name.
*/
-static void
+static void DNSSD_API
resolve_callback(
DNSServiceRef sdRef, /* I - Service reference */
DNSServiceFlags flags, /* I - Results flags */
_http_uribuf_t *uribuf; /* URI buffer */
- DEBUG_printf(("resolve_callback(sdRef=%p, flags=%x, interfaceIndex=%u, "
+ DEBUG_printf(("7resolve_callback(sdRef=%p, flags=%x, interfaceIndex=%u, "
"errorCode=%d, fullName=\"%s\", hostTarget=\"%s\", port=%u, "
- "txtLen=%u, txtRecord=%p, context=%p)\n", sdRef, flags,
+ "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"))
+ if (strstr(fullName, "._ipp") || strstr(fullName, "._fax-ipp"))
scheme = "ipp";
else if (strstr(fullName, "._printer."))
scheme = "lpd";
httpAssembleURI(HTTP_URI_CODING_ALL, uribuf->buffer, uribuf->bufsize, scheme,
NULL, hostTarget, ntohs(port), rp);
- DEBUG_printf(("resolve_callback: Resolved URI is \"%s\"...\n",
+ DEBUG_printf(("8resolve_callback: Resolved URI is \"%s\"...",
uribuf->buffer));
}
#endif /* HAVE_DNSSD */