]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/http-support.c
Merge changes from CUPS 1.5svn-r9374.
[thirdparty/cups.git] / cups / http-support.c
1 /*
2 * "$Id: http-support.c 7952 2008-09-17 00:56:20Z mike $"
3 *
4 * HTTP support routines for CUPS.
5 *
6 * Copyright 2007-2010 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
8 *
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
14 *
15 * This file is subject to the Apple OS-Developed Software exception.
16 *
17 * Contents:
18 *
19 * httpAssembleURI() - Assemble a uniform resource identifier from its
20 * components.
21 * httpAssembleURIf() - Assemble a uniform resource identifier from its
22 * components with a formatted resource.
23 * httpDecode64() - Base64-decode a string.
24 * httpDecode64_2() - Base64-decode a string.
25 * httpEncode64() - Base64-encode a string.
26 * httpEncode64_2() - Base64-encode a string.
27 * httpGetDateString() - Get a formatted date/time string from a time value.
28 * httpGetDateString2() - Get a formatted date/time string from a time value.
29 * httpGetDateTime() - Get a time value from a formatted date/time string.
30 * httpSeparate() - Separate a Universal Resource Identifier into its
31 * components.
32 * httpSeparate2() - Separate a Universal Resource Identifier into its
33 * components.
34 * httpSeparateURI() - Separate a Universal Resource Identifier into its
35 * components.
36 * httpStatus() - Return a short string describing a HTTP status code.
37 * _cups_hstrerror() - hstrerror() emulation function for Solaris and
38 * others...
39 * _httpDecodeURI() - Percent-decode a HTTP request URI.
40 * _httpEncodeURI() - Percent-encode a HTTP request URI.
41 * _httpResolveURI() - Resolve a DNS-SD URI.
42 * http_copy_decode() - Copy and decode a URI.
43 * http_copy_encode() - Copy and encode a URI.
44 * resolve_callback() - Build a device URI for the given service name.
45 */
46
47 /*
48 * Include necessary headers...
49 */
50
51 #include "cups-private.h"
52 #ifdef HAVE_DNSSD
53 # include <dns_sd.h>
54 # ifdef WIN32
55 # include <io.h>
56 # elif defined(HAVE_POLL)
57 # include <poll.h>
58 # else
59 # include <sys/select.h>
60 # endif /* WIN32 */
61 #endif /* HAVE_DNSSD */
62
63
64 /*
65 * Local types...
66 */
67
68 typedef struct _http_uribuf_s /* URI buffer */
69 {
70 char *buffer; /* Pointer to buffer */
71 size_t bufsize; /* Size of buffer */
72 } _http_uribuf_t;
73
74
75 /*
76 * Local globals...
77 */
78
79 static const char * const http_days[7] =
80 {
81 "Sun",
82 "Mon",
83 "Tue",
84 "Wed",
85 "Thu",
86 "Fri",
87 "Sat"
88 };
89 static const char * const http_months[12] =
90 {
91 "Jan",
92 "Feb",
93 "Mar",
94 "Apr",
95 "May",
96 "Jun",
97 "Jul",
98 "Aug",
99 "Sep",
100 "Oct",
101 "Nov",
102 "Dec"
103 };
104
105
106 /*
107 * Local functions...
108 */
109
110 static const char *http_copy_decode(char *dst, const char *src,
111 int dstsize, const char *term,
112 int decode);
113 static char *http_copy_encode(char *dst, const char *src,
114 char *dstend, const char *reserved,
115 const char *term, int encode);
116 #ifdef HAVE_DNSSD
117 static void DNSSD_API resolve_callback(DNSServiceRef sdRef,
118 DNSServiceFlags flags,
119 uint32_t interfaceIndex,
120 DNSServiceErrorType errorCode,
121 const char *fullName,
122 const char *hostTarget,
123 uint16_t port, uint16_t txtLen,
124 const unsigned char *txtRecord,
125 void *context);
126 #endif /* HAVE_DNSSD */
127
128
129 /*
130 * 'httpAssembleURI()' - Assemble a uniform resource identifier from its
131 * components.
132 *
133 * This function escapes reserved characters in the URI depending on the
134 * value of the "encoding" argument. You should use this function in
135 * place of traditional string functions whenever you need to create a
136 * URI string.
137 *
138 * @since CUPS 1.2/Mac OS X 10.5@
139 */
140
141 http_uri_status_t /* O - URI status */
142 httpAssembleURI(
143 http_uri_coding_t encoding, /* I - Encoding flags */
144 char *uri, /* I - URI buffer */
145 int urilen, /* I - Size of URI buffer */
146 const char *scheme, /* I - Scheme name */
147 const char *username, /* I - Username */
148 const char *host, /* I - Hostname or address */
149 int port, /* I - Port number */
150 const char *resource) /* I - Resource */
151 {
152 char *ptr, /* Pointer into URI buffer */
153 *end; /* End of URI buffer */
154
155
156 /*
157 * Range check input...
158 */
159
160 if (!uri || urilen < 1 || !scheme || port < 0)
161 {
162 if (uri)
163 *uri = '\0';
164
165 return (HTTP_URI_BAD_ARGUMENTS);
166 }
167
168 /*
169 * Assemble the URI starting with the scheme...
170 */
171
172 end = uri + urilen - 1;
173 ptr = http_copy_encode(uri, scheme, end, NULL, NULL, 0);
174
175 if (!ptr)
176 goto assemble_overflow;
177
178 if (!strcmp(scheme, "mailto"))
179 {
180 /*
181 * mailto: only has :, no //...
182 */
183
184 if (ptr < end)
185 *ptr++ = ':';
186 else
187 goto assemble_overflow;
188 }
189 else
190 {
191 /*
192 * Schemes other than mailto: all have //...
193 */
194
195 if ((ptr + 2) < end)
196 {
197 *ptr++ = ':';
198 *ptr++ = '/';
199 *ptr++ = '/';
200 }
201 else
202 goto assemble_overflow;
203 }
204
205 /*
206 * Next the username and hostname, if any...
207 */
208
209 if (host)
210 {
211 if (username && *username)
212 {
213 /*
214 * Add username@ first...
215 */
216
217 ptr = http_copy_encode(ptr, username, end, "/?@", NULL,
218 encoding & HTTP_URI_CODING_USERNAME);
219
220 if (!ptr)
221 goto assemble_overflow;
222
223 if (ptr < end)
224 *ptr++ = '@';
225 else
226 goto assemble_overflow;
227 }
228
229 /*
230 * Then add the hostname. Since IPv6 is a particular pain to deal
231 * with, we have several special cases to deal with. If we get
232 * an IPv6 address with brackets around it, assume it is already in
233 * URI format. Since DNS-SD service names can sometimes look like
234 * raw IPv6 addresses, we specifically look for "._tcp" in the name,
235 * too...
236 */
237
238 if (host[0] != '[' && strchr(host, ':') && !strstr(host, "._tcp"))
239 {
240 /*
241 * We have a raw IPv6 address...
242 */
243
244 if (strchr(host, '%'))
245 {
246 /*
247 * We have a link-local address, add "[v1." prefix...
248 */
249
250 if ((ptr + 4) < end)
251 {
252 *ptr++ = '[';
253 *ptr++ = 'v';
254 *ptr++ = '1';
255 *ptr++ = '.';
256 }
257 else
258 goto assemble_overflow;
259 }
260 else
261 {
262 /*
263 * We have a normal address, add "[" prefix...
264 */
265
266 if (ptr < end)
267 *ptr++ = '[';
268 else
269 goto assemble_overflow;
270 }
271
272 /*
273 * Copy the rest of the IPv6 address, and terminate with "]".
274 */
275
276 while (ptr < end && *host)
277 {
278 if (*host == '%')
279 {
280 *ptr++ = '+'; /* Convert zone separator */
281 host ++;
282 }
283 else
284 *ptr++ = *host++;
285 }
286
287 if (*host)
288 goto assemble_overflow;
289
290 if (ptr < end)
291 *ptr++ = ']';
292 else
293 goto assemble_overflow;
294 }
295 else
296 {
297 /*
298 * Otherwise, just copy the host string...
299 */
300
301 ptr = http_copy_encode(ptr, host, end, ":/?#[]@\\\"", NULL,
302 encoding & HTTP_URI_CODING_HOSTNAME);
303
304 if (!ptr)
305 goto assemble_overflow;
306 }
307
308 /*
309 * Finish things off with the port number...
310 */
311
312 if (port > 0)
313 {
314 snprintf(ptr, end - ptr + 1, ":%d", port);
315 ptr += strlen(ptr);
316
317 if (ptr >= end)
318 goto assemble_overflow;
319 }
320 }
321
322 /*
323 * Last but not least, add the resource string...
324 */
325
326 if (resource)
327 {
328 char *query; /* Pointer to query string */
329
330
331 /*
332 * Copy the resource string up to the query string if present...
333 */
334
335 query = strchr(resource, '?');
336 ptr = http_copy_encode(ptr, resource, end, NULL, "?",
337 encoding & HTTP_URI_CODING_RESOURCE);
338 if (!ptr)
339 goto assemble_overflow;
340
341 if (query)
342 {
343 /*
344 * Copy query string without encoding...
345 */
346
347 ptr = http_copy_encode(ptr, query, end, NULL, NULL,
348 encoding & HTTP_URI_CODING_QUERY);
349 if (!ptr)
350 goto assemble_overflow;
351 }
352 }
353 else if (ptr < end)
354 *ptr++ = '/';
355 else
356 goto assemble_overflow;
357
358 /*
359 * Nul-terminate the URI buffer and return with no errors...
360 */
361
362 *ptr = '\0';
363
364 return (HTTP_URI_OK);
365
366 /*
367 * Clear the URI string and return an overflow error; I don't usually
368 * like goto's, but in this case it makes sense...
369 */
370
371 assemble_overflow:
372
373 *uri = '\0';
374 return (HTTP_URI_OVERFLOW);
375 }
376
377
378 /*
379 * 'httpAssembleURIf()' - Assemble a uniform resource identifier from its
380 * components with a formatted resource.
381 *
382 * This function creates a formatted version of the resource string
383 * argument "resourcef" and escapes reserved characters in the URI
384 * depending on the value of the "encoding" argument. You should use
385 * this function in place of traditional string functions whenever
386 * you need to create a URI string.
387 *
388 * @since CUPS 1.2/Mac OS X 10.5@
389 */
390
391 http_uri_status_t /* O - URI status */
392 httpAssembleURIf(
393 http_uri_coding_t encoding, /* I - Encoding flags */
394 char *uri, /* I - URI buffer */
395 int urilen, /* I - Size of URI buffer */
396 const char *scheme, /* I - Scheme name */
397 const char *username, /* I - Username */
398 const char *host, /* I - Hostname or address */
399 int port, /* I - Port number */
400 const char *resourcef, /* I - Printf-style resource */
401 ...) /* I - Additional arguments as needed */
402 {
403 va_list ap; /* Pointer to additional arguments */
404 char resource[1024]; /* Formatted resource string */
405 int bytes; /* Bytes in formatted string */
406
407
408 /*
409 * Range check input...
410 */
411
412 if (!uri || urilen < 1 || !scheme || port < 0 || !resourcef)
413 {
414 if (uri)
415 *uri = '\0';
416
417 return (HTTP_URI_BAD_ARGUMENTS);
418 }
419
420 /*
421 * Format the resource string and assemble the URI...
422 */
423
424 va_start(ap, resourcef);
425 bytes = vsnprintf(resource, sizeof(resource), resourcef, ap);
426 va_end(ap);
427
428 if (bytes >= sizeof(resource))
429 {
430 *uri = '\0';
431 return (HTTP_URI_OVERFLOW);
432 }
433 else
434 return (httpAssembleURI(encoding, uri, urilen, scheme, username, host,
435 port, resource));
436 }
437
438
439 /*
440 * 'httpDecode64()' - Base64-decode a string.
441 *
442 * This function is deprecated. Use the httpDecode64_2() function instead
443 * which provides buffer length arguments.
444 *
445 * @deprecated@
446 */
447
448 char * /* O - Decoded string */
449 httpDecode64(char *out, /* I - String to write to */
450 const char *in) /* I - String to read from */
451 {
452 int outlen; /* Output buffer length */
453
454
455 /*
456 * Use the old maximum buffer size for binary compatibility...
457 */
458
459 outlen = 512;
460
461 return (httpDecode64_2(out, &outlen, in));
462 }
463
464
465 /*
466 * 'httpDecode64_2()' - Base64-decode a string.
467 *
468 * @since CUPS 1.1.21/Mac OS X 10.4@
469 */
470
471 char * /* O - Decoded string */
472 httpDecode64_2(char *out, /* I - String to write to */
473 int *outlen, /* IO - Size of output string */
474 const char *in) /* I - String to read from */
475 {
476 int pos, /* Bit position */
477 base64; /* Value of this character */
478 char *outptr, /* Output pointer */
479 *outend; /* End of output buffer */
480
481
482 /*
483 * Range check input...
484 */
485
486 if (!out || !outlen || *outlen < 1 || !in)
487 return (NULL);
488
489 if (!*in)
490 {
491 *out = '\0';
492 *outlen = 0;
493
494 return (out);
495 }
496
497 /*
498 * Convert from base-64 to bytes...
499 */
500
501 for (outptr = out, outend = out + *outlen - 1, pos = 0; *in != '\0'; in ++)
502 {
503 /*
504 * Decode this character into a number from 0 to 63...
505 */
506
507 if (*in >= 'A' && *in <= 'Z')
508 base64 = *in - 'A';
509 else if (*in >= 'a' && *in <= 'z')
510 base64 = *in - 'a' + 26;
511 else if (*in >= '0' && *in <= '9')
512 base64 = *in - '0' + 52;
513 else if (*in == '+')
514 base64 = 62;
515 else if (*in == '/')
516 base64 = 63;
517 else if (*in == '=')
518 break;
519 else
520 continue;
521
522 /*
523 * Store the result in the appropriate chars...
524 */
525
526 switch (pos)
527 {
528 case 0 :
529 if (outptr < outend)
530 *outptr = base64 << 2;
531 pos ++;
532 break;
533 case 1 :
534 if (outptr < outend)
535 *outptr++ |= (base64 >> 4) & 3;
536 if (outptr < outend)
537 *outptr = (base64 << 4) & 255;
538 pos ++;
539 break;
540 case 2 :
541 if (outptr < outend)
542 *outptr++ |= (base64 >> 2) & 15;
543 if (outptr < outend)
544 *outptr = (base64 << 6) & 255;
545 pos ++;
546 break;
547 case 3 :
548 if (outptr < outend)
549 *outptr++ |= base64;
550 pos = 0;
551 break;
552 }
553 }
554
555 *outptr = '\0';
556
557 /*
558 * Return the decoded string and size...
559 */
560
561 *outlen = (int)(outptr - out);
562
563 return (out);
564 }
565
566
567 /*
568 * 'httpEncode64()' - Base64-encode a string.
569 *
570 * This function is deprecated. Use the httpEncode64_2() function instead
571 * which provides buffer length arguments.
572 *
573 * @deprecated@
574 */
575
576 char * /* O - Encoded string */
577 httpEncode64(char *out, /* I - String to write to */
578 const char *in) /* I - String to read from */
579 {
580 return (httpEncode64_2(out, 512, in, (int)strlen(in)));
581 }
582
583
584 /*
585 * 'httpEncode64_2()' - Base64-encode a string.
586 *
587 * @since CUPS 1.1.21/Mac OS X 10.4@
588 */
589
590 char * /* O - Encoded string */
591 httpEncode64_2(char *out, /* I - String to write to */
592 int outlen, /* I - Size of output string */
593 const char *in, /* I - String to read from */
594 int inlen) /* I - Size of input string */
595 {
596 char *outptr, /* Output pointer */
597 *outend; /* End of output buffer */
598 static const char base64[] = /* Base64 characters... */
599 {
600 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
601 "abcdefghijklmnopqrstuvwxyz"
602 "0123456789"
603 "+/"
604 };
605
606
607 /*
608 * Range check input...
609 */
610
611 if (!out || outlen < 1 || !in)
612 return (NULL);
613
614 /*
615 * Convert bytes to base-64...
616 */
617
618 for (outptr = out, outend = out + outlen - 1; inlen > 0; in ++, inlen --)
619 {
620 /*
621 * Encode the up to 3 characters as 4 Base64 numbers...
622 */
623
624 if (outptr < outend)
625 *outptr ++ = base64[(in[0] & 255) >> 2];
626
627 if (outptr < outend)
628 {
629 if (inlen > 1)
630 *outptr ++ = base64[(((in[0] & 255) << 4) | ((in[1] & 255) >> 4)) & 63];
631 else
632 *outptr ++ = base64[((in[0] & 255) << 4) & 63];
633 }
634
635 in ++;
636 inlen --;
637 if (inlen <= 0)
638 {
639 if (outptr < outend)
640 *outptr ++ = '=';
641 if (outptr < outend)
642 *outptr ++ = '=';
643 break;
644 }
645
646 if (outptr < outend)
647 {
648 if (inlen > 1)
649 *outptr ++ = base64[(((in[0] & 255) << 2) | ((in[1] & 255) >> 6)) & 63];
650 else
651 *outptr ++ = base64[((in[0] & 255) << 2) & 63];
652 }
653
654 in ++;
655 inlen --;
656 if (inlen <= 0)
657 {
658 if (outptr < outend)
659 *outptr ++ = '=';
660 break;
661 }
662
663 if (outptr < outend)
664 *outptr ++ = base64[in[0] & 63];
665 }
666
667 *outptr = '\0';
668
669 /*
670 * Return the encoded string...
671 */
672
673 return (out);
674 }
675
676
677 /*
678 * 'httpGetDateString()' - Get a formatted date/time string from a time value.
679 *
680 * @deprecated@
681 */
682
683 const char * /* O - Date/time string */
684 httpGetDateString(time_t t) /* I - UNIX time */
685 {
686 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
687
688
689 return (httpGetDateString2(t, cg->http_date, sizeof(cg->http_date)));
690 }
691
692
693 /*
694 * 'httpGetDateString2()' - Get a formatted date/time string from a time value.
695 *
696 * @since CUPS 1.2/Mac OS X 10.5@
697 */
698
699 const char * /* O - Date/time string */
700 httpGetDateString2(time_t t, /* I - UNIX time */
701 char *s, /* I - String buffer */
702 int slen) /* I - Size of string buffer */
703 {
704 struct tm *tdate; /* UNIX date/time data */
705
706
707 tdate = gmtime(&t);
708 snprintf(s, slen, "%s, %02d %s %d %02d:%02d:%02d GMT",
709 http_days[tdate->tm_wday], tdate->tm_mday,
710 http_months[tdate->tm_mon], tdate->tm_year + 1900,
711 tdate->tm_hour, tdate->tm_min, tdate->tm_sec);
712
713 return (s);
714 }
715
716
717 /*
718 * 'httpGetDateTime()' - Get a time value from a formatted date/time string.
719 */
720
721 time_t /* O - UNIX time */
722 httpGetDateTime(const char *s) /* I - Date/time string */
723 {
724 int i; /* Looping var */
725 char mon[16]; /* Abbreviated month name */
726 int day, year; /* Day of month and year */
727 int hour, min, sec; /* Time */
728 int days; /* Number of days since 1970 */
729 static const int normal_days[] = /* Days to a month, normal years */
730 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
731 static const int leap_days[] = /* Days to a month, leap years */
732 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 };
733
734
735 DEBUG_printf(("2httpGetDateTime(s=\"%s\")", s));
736
737 /*
738 * Extract the date and time from the formatted string...
739 */
740
741 if (sscanf(s, "%*s%d%15s%d%d:%d:%d", &day, mon, &year, &hour, &min, &sec) < 6)
742 return (0);
743
744 DEBUG_printf(("4httpGetDateTime: day=%d, mon=\"%s\", year=%d, hour=%d, "
745 "min=%d, sec=%d", day, mon, year, hour, min, sec));
746
747 /*
748 * Convert the month name to a number from 0 to 11.
749 */
750
751 for (i = 0; i < 12; i ++)
752 if (!strcasecmp(mon, http_months[i]))
753 break;
754
755 if (i >= 12)
756 return (0);
757
758 DEBUG_printf(("4httpGetDateTime: i=%d", i));
759
760 /*
761 * Now convert the date and time to a UNIX time value in seconds since
762 * 1970. We can't use mktime() since the timezone may not be UTC but
763 * the date/time string *is* UTC.
764 */
765
766 if ((year & 3) == 0 && ((year % 100) != 0 || (year % 400) == 0))
767 days = leap_days[i] + day - 1;
768 else
769 days = normal_days[i] + day - 1;
770
771 DEBUG_printf(("4httpGetDateTime: days=%d", days));
772
773 days += (year - 1970) * 365 + /* 365 days per year (normally) */
774 ((year - 1) / 4 - 492) - /* + leap days */
775 ((year - 1) / 100 - 19) + /* - 100 year days */
776 ((year - 1) / 400 - 4); /* + 400 year days */
777
778 DEBUG_printf(("4httpGetDateTime: days=%d\n", days));
779
780 return (days * 86400 + hour * 3600 + min * 60 + sec);
781 }
782
783
784 /*
785 * 'httpSeparate()' - Separate a Universal Resource Identifier into its
786 * components.
787 *
788 * This function is deprecated; use the httpSeparateURI() function instead.
789 *
790 * @deprecated@
791 */
792
793 void
794 httpSeparate(const char *uri, /* I - Universal Resource Identifier */
795 char *scheme, /* O - Scheme [32] (http, https, etc.) */
796 char *username, /* O - Username [1024] */
797 char *host, /* O - Hostname [1024] */
798 int *port, /* O - Port number to use */
799 char *resource) /* O - Resource/filename [1024] */
800 {
801 httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, 32, username,
802 HTTP_MAX_URI, host, HTTP_MAX_URI, port, resource,
803 HTTP_MAX_URI);
804 }
805
806
807 /*
808 * 'httpSeparate2()' - Separate a Universal Resource Identifier into its
809 * components.
810 *
811 * This function is deprecated; use the httpSeparateURI() function instead.
812 *
813 * @since CUPS 1.1.21/Mac OS X 10.4@
814 * @deprecated@
815 */
816
817 void
818 httpSeparate2(const char *uri, /* I - Universal Resource Identifier */
819 char *scheme, /* O - Scheme (http, https, etc.) */
820 int schemelen, /* I - Size of scheme buffer */
821 char *username, /* O - Username */
822 int usernamelen, /* I - Size of username buffer */
823 char *host, /* O - Hostname */
824 int hostlen, /* I - Size of hostname buffer */
825 int *port, /* O - Port number to use */
826 char *resource, /* O - Resource/filename */
827 int resourcelen) /* I - Size of resource buffer */
828 {
829 httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, schemelen, username,
830 usernamelen, host, hostlen, port, resource, resourcelen);
831 }
832
833
834 /*
835 * 'httpSeparateURI()' - Separate a Universal Resource Identifier into its
836 * components.
837 *
838 * @since CUPS 1.2/Mac OS X 10.5@
839 */
840
841 http_uri_status_t /* O - Result of separation */
842 httpSeparateURI(
843 http_uri_coding_t decoding, /* I - Decoding flags */
844 const char *uri, /* I - Universal Resource Identifier */
845 char *scheme, /* O - Scheme (http, https, etc.) */
846 int schemelen, /* I - Size of scheme buffer */
847 char *username, /* O - Username */
848 int usernamelen, /* I - Size of username buffer */
849 char *host, /* O - Hostname */
850 int hostlen, /* I - Size of hostname buffer */
851 int *port, /* O - Port number to use */
852 char *resource, /* O - Resource/filename */
853 int resourcelen) /* I - Size of resource buffer */
854 {
855 char *ptr, /* Pointer into string... */
856 *end; /* End of string */
857 const char *sep; /* Separator character */
858 http_uri_status_t status; /* Result of separation */
859
860
861 /*
862 * Initialize everything to blank...
863 */
864
865 if (scheme && schemelen > 0)
866 *scheme = '\0';
867
868 if (username && usernamelen > 0)
869 *username = '\0';
870
871 if (host && hostlen > 0)
872 *host = '\0';
873
874 if (port)
875 *port = 0;
876
877 if (resource && resourcelen > 0)
878 *resource = '\0';
879
880 /*
881 * Range check input...
882 */
883
884 if (!uri || !port || !scheme || schemelen <= 0 || !username ||
885 usernamelen <= 0 || !host || hostlen <= 0 || !resource ||
886 resourcelen <= 0)
887 return (HTTP_URI_BAD_ARGUMENTS);
888
889 if (!*uri)
890 return (HTTP_URI_BAD_URI);
891
892 /*
893 * Grab the scheme portion of the URI...
894 */
895
896 status = HTTP_URI_OK;
897
898 if (!strncmp(uri, "//", 2))
899 {
900 /*
901 * Workaround for HP IPP client bug...
902 */
903
904 strlcpy(scheme, "ipp", schemelen);
905 status = HTTP_URI_MISSING_SCHEME;
906 }
907 else if (*uri == '/')
908 {
909 /*
910 * Filename...
911 */
912
913 strlcpy(scheme, "file", schemelen);
914 status = HTTP_URI_MISSING_SCHEME;
915 }
916 else
917 {
918 /*
919 * Standard URI with scheme...
920 */
921
922 for (ptr = scheme, end = scheme + schemelen - 1;
923 *uri && *uri != ':' && ptr < end;)
924 if (strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
925 "abcdefghijklmnopqrstuvwxyz"
926 "0123456789-+.", *uri) != NULL)
927 *ptr++ = *uri++;
928 else
929 break;
930
931 *ptr = '\0';
932
933 if (*uri != ':')
934 {
935 *scheme = '\0';
936 return (HTTP_URI_BAD_SCHEME);
937 }
938
939 uri ++;
940 }
941
942 /*
943 * Set the default port number...
944 */
945
946 if (!strcmp(scheme, "http"))
947 *port = 80;
948 else if (!strcmp(scheme, "https"))
949 *port = 443;
950 else if (!strcmp(scheme, "ipp") || !strcmp(scheme, "ipps"))
951 *port = 631;
952 else if (!strcasecmp(scheme, "lpd"))
953 *port = 515;
954 else if (!strcmp(scheme, "socket")) /* Not yet registered with IANA... */
955 *port = 9100;
956 else if (strcmp(scheme, "file") && strcmp(scheme, "mailto"))
957 status = HTTP_URI_UNKNOWN_SCHEME;
958
959 /*
960 * Now see if we have a hostname...
961 */
962
963 if (!strncmp(uri, "//", 2))
964 {
965 /*
966 * Yes, extract it...
967 */
968
969 uri += 2;
970
971 /*
972 * Grab the username, if any...
973 */
974
975 if ((sep = strpbrk(uri, "@/")) != NULL && *sep == '@')
976 {
977 /*
978 * Get a username:password combo...
979 */
980
981 uri = http_copy_decode(username, uri, usernamelen, "@",
982 decoding & HTTP_URI_CODING_USERNAME);
983
984 if (!uri)
985 {
986 *username = '\0';
987 return (HTTP_URI_BAD_USERNAME);
988 }
989
990 uri ++;
991 }
992
993 /*
994 * Then the hostname/IP address...
995 */
996
997 if (*uri == '[')
998 {
999 /*
1000 * Grab IPv6 address...
1001 */
1002
1003 uri ++;
1004 if (!strncmp(uri, "v1.", 3))
1005 uri += 3; /* Skip IPvN leader... */
1006
1007 uri = http_copy_decode(host, uri, hostlen, "]",
1008 decoding & HTTP_URI_CODING_HOSTNAME);
1009
1010 if (!uri)
1011 {
1012 *host = '\0';
1013 return (HTTP_URI_BAD_HOSTNAME);
1014 }
1015
1016 /*
1017 * Validate value...
1018 */
1019
1020 if (*uri != ']')
1021 {
1022 *host = '\0';
1023 return (HTTP_URI_BAD_HOSTNAME);
1024 }
1025
1026 uri ++;
1027
1028 for (ptr = host; *ptr; ptr ++)
1029 if (*ptr == '+')
1030 {
1031 /*
1032 * Convert zone separator to % and stop here...
1033 */
1034
1035 *ptr = '%';
1036 break;
1037 }
1038 else if (*ptr != ':' && *ptr != '.' && !isxdigit(*ptr & 255))
1039 {
1040 *host = '\0';
1041 return (HTTP_URI_BAD_HOSTNAME);
1042 }
1043 }
1044 else
1045 {
1046 /*
1047 * Validate the hostname or IPv4 address first...
1048 */
1049
1050 for (ptr = (char *)uri; *ptr; ptr ++)
1051 if (strchr(":?/", *ptr))
1052 break;
1053 else if (!strchr("abcdefghijklmnopqrstuvwxyz"
1054 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1055 "0123456789"
1056 "-._~"
1057 "%"
1058 "!$&'()*+,;=\\", *ptr))
1059 {
1060 *host = '\0';
1061 return (HTTP_URI_BAD_HOSTNAME);
1062 }
1063
1064 /*
1065 * Then copy the hostname or IPv4 address to the buffer...
1066 */
1067
1068 uri = http_copy_decode(host, uri, hostlen, ":?/",
1069 decoding & HTTP_URI_CODING_HOSTNAME);
1070
1071 if (!uri)
1072 {
1073 *host = '\0';
1074 return (HTTP_URI_BAD_HOSTNAME);
1075 }
1076 }
1077
1078 /*
1079 * Validate hostname for file scheme - only empty and localhost are
1080 * acceptable.
1081 */
1082
1083 if (!strcmp(scheme, "file") && strcmp(host, "localhost") && host[0])
1084 {
1085 *host = '\0';
1086 return (HTTP_URI_BAD_HOSTNAME);
1087 }
1088
1089 /*
1090 * See if we have a port number...
1091 */
1092
1093 if (*uri == ':')
1094 {
1095 /*
1096 * Yes, collect the port number...
1097 */
1098
1099 if (!isdigit(uri[1] & 255))
1100 {
1101 *port = 0;
1102 return (HTTP_URI_BAD_PORT);
1103 }
1104
1105 *port = strtol(uri + 1, (char **)&uri, 10);
1106
1107 if (*uri != '/' && *uri)
1108 {
1109 *port = 0;
1110 return (HTTP_URI_BAD_PORT);
1111 }
1112 }
1113 }
1114
1115 /*
1116 * The remaining portion is the resource string...
1117 */
1118
1119 if (*uri == '?' || !*uri)
1120 {
1121 /*
1122 * Hostname but no path...
1123 */
1124
1125 status = HTTP_URI_MISSING_RESOURCE;
1126 *resource = '/';
1127
1128 /*
1129 * Copy any query string...
1130 */
1131
1132 if (*uri == '?')
1133 uri = http_copy_decode(resource + 1, uri, resourcelen - 1, NULL,
1134 decoding & HTTP_URI_CODING_QUERY);
1135 else
1136 resource[1] = '\0';
1137 }
1138 else
1139 {
1140 uri = http_copy_decode(resource, uri, resourcelen, "?",
1141 decoding & HTTP_URI_CODING_RESOURCE);
1142
1143 if (uri && *uri == '?')
1144 {
1145 /*
1146 * Concatenate any query string...
1147 */
1148
1149 char *resptr = resource + strlen(resource);
1150
1151 uri = http_copy_decode(resptr, uri, resourcelen - (int)(resptr - resource),
1152 NULL, decoding & HTTP_URI_CODING_QUERY);
1153 }
1154 }
1155
1156 if (!uri)
1157 {
1158 *resource = '\0';
1159 return (HTTP_URI_BAD_RESOURCE);
1160 }
1161
1162 /*
1163 * Return the URI separation status...
1164 */
1165
1166 return (status);
1167 }
1168
1169
1170 /*
1171 * 'httpStatus()' - Return a short string describing a HTTP status code.
1172 *
1173 * The returned string is localized to the current POSIX locale and is based
1174 * on the status strings defined in RFC 2616.
1175 */
1176
1177 const char * /* O - Localized status string */
1178 httpStatus(http_status_t status) /* I - HTTP status code */
1179 {
1180 const char *s; /* Status string */
1181 _cups_globals_t *cg = _cupsGlobals(); /* Global data */
1182
1183
1184 if (!cg->lang_default)
1185 cg->lang_default = cupsLangDefault();
1186
1187 switch (status)
1188 {
1189 case HTTP_CONTINUE :
1190 s = _("Continue");
1191 break;
1192 case HTTP_SWITCHING_PROTOCOLS :
1193 s = _("Switching Protocols");
1194 break;
1195 case HTTP_OK :
1196 s = _("OK");
1197 break;
1198 case HTTP_CREATED :
1199 s = _("Created");
1200 break;
1201 case HTTP_ACCEPTED :
1202 s = _("Accepted");
1203 break;
1204 case HTTP_NO_CONTENT :
1205 s = _("No Content");
1206 break;
1207 case HTTP_MOVED_PERMANENTLY :
1208 s = _("Moved Permanently");
1209 break;
1210 case HTTP_SEE_OTHER :
1211 s = _("See Other");
1212 break;
1213 case HTTP_NOT_MODIFIED :
1214 s = _("Not Modified");
1215 break;
1216 case HTTP_BAD_REQUEST :
1217 s = _("Bad Request");
1218 break;
1219 case HTTP_UNAUTHORIZED :
1220 case HTTP_AUTHORIZATION_CANCELED :
1221 s = _("Unauthorized");
1222 break;
1223 case HTTP_FORBIDDEN :
1224 s = _("Forbidden");
1225 break;
1226 case HTTP_NOT_FOUND :
1227 s = _("Not Found");
1228 break;
1229 case HTTP_REQUEST_TOO_LARGE :
1230 s = _("Request Entity Too Large");
1231 break;
1232 case HTTP_URI_TOO_LONG :
1233 s = _("URI Too Long");
1234 break;
1235 case HTTP_UPGRADE_REQUIRED :
1236 s = _("Upgrade Required");
1237 break;
1238 case HTTP_NOT_IMPLEMENTED :
1239 s = _("Not Implemented");
1240 break;
1241 case HTTP_NOT_SUPPORTED :
1242 s = _("Not Supported");
1243 break;
1244 case HTTP_EXPECTATION_FAILED :
1245 s = _("Expectation Failed");
1246 break;
1247 case HTTP_SERVICE_UNAVAILABLE :
1248 s = _("Service Unavailable");
1249 break;
1250 case HTTP_SERVER_ERROR :
1251 s = _("Internal Server Error");
1252 break;
1253 case HTTP_PKI_ERROR :
1254 s = _("SSL/TLS Negotiation Error");
1255 break;
1256
1257 default :
1258 s = _("Unknown");
1259 break;
1260 }
1261
1262 return (_cupsLangString(cg->lang_default, s));
1263 }
1264
1265
1266 #ifndef HAVE_HSTRERROR
1267 /*
1268 * '_cups_hstrerror()' - hstrerror() emulation function for Solaris and others...
1269 */
1270
1271 const char * /* O - Error string */
1272 _cups_hstrerror(int error) /* I - Error number */
1273 {
1274 static const char * const errors[] = /* Error strings */
1275 {
1276 "OK",
1277 "Host not found.",
1278 "Try again.",
1279 "Unrecoverable lookup error.",
1280 "No data associated with name."
1281 };
1282
1283
1284 if (error < 0 || error > 4)
1285 return ("Unknown hostname lookup error.");
1286 else
1287 return (errors[error]);
1288 }
1289 #endif /* !HAVE_HSTRERROR */
1290
1291
1292 /*
1293 * '_httpDecodeURI()' - Percent-decode a HTTP request URI.
1294 */
1295
1296 char * /* O - Decoded URI or NULL on error */
1297 _httpDecodeURI(char *dst, /* I - Destination buffer */
1298 const char *src, /* I - Source URI */
1299 size_t dstsize) /* I - Size of destination buffer */
1300 {
1301 if (http_copy_decode(dst, src, (int)dstsize, NULL, 1))
1302 return (dst);
1303 else
1304 return (NULL);
1305 }
1306
1307
1308 /*
1309 * '_httpEncodeURI()' - Percent-encode a HTTP request URI.
1310 */
1311
1312 char * /* O - Encoded URI */
1313 _httpEncodeURI(char *dst, /* I - Destination buffer */
1314 const char *src, /* I - Source URI */
1315 size_t dstsize) /* I - Size of destination buffer */
1316 {
1317 http_copy_encode(dst, src, dst + dstsize - 1, NULL, NULL, 1);
1318 return (dst);
1319 }
1320
1321
1322 /*
1323 * '_httpResolveURI()' - Resolve a DNS-SD URI.
1324 */
1325
1326 const char * /* O - Resolved URI */
1327 _httpResolveURI(
1328 const char *uri, /* I - DNS-SD URI */
1329 char *resolved_uri, /* I - Buffer for resolved URI */
1330 size_t resolved_size, /* I - Size of URI buffer */
1331 int logit) /* I - Log progress to stderr? */
1332 {
1333 char scheme[32], /* URI components... */
1334 userpass[256],
1335 hostname[1024],
1336 resource[1024];
1337 int port;
1338 #ifdef DEBUG
1339 http_uri_status_t status; /* URI decode status */
1340 #endif /* DEBUG */
1341
1342
1343 DEBUG_printf(("4_httpResolveURI(uri=\"%s\", resolved_uri=%p, "
1344 "resolved_size=" CUPS_LLFMT ")", uri, resolved_uri,
1345 CUPS_LLCAST resolved_size));
1346
1347 /*
1348 * Get the device URI...
1349 */
1350
1351 #ifdef DEBUG
1352 if ((status = httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme,
1353 sizeof(scheme), userpass, sizeof(userpass),
1354 hostname, sizeof(hostname), &port, resource,
1355 sizeof(resource))) < HTTP_URI_OK)
1356 #else
1357 if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme,
1358 sizeof(scheme), userpass, sizeof(userpass),
1359 hostname, sizeof(hostname), &port, resource,
1360 sizeof(resource)) < HTTP_URI_OK)
1361 #endif /* DEBUG */
1362 {
1363 if (logit)
1364 _cupsLangPrintf(stderr, _("Bad device URI \"%s\"\n"), uri);
1365
1366 DEBUG_printf(("6_httpResolveURI: httpSeparateURI returned %d!", status));
1367 DEBUG_puts("5_httpResolveURI: Returning NULL");
1368 return (NULL);
1369 }
1370
1371 /*
1372 * Resolve it as needed...
1373 */
1374
1375 if (strstr(hostname, "._tcp"))
1376 {
1377 #ifdef HAVE_DNSSD
1378 # ifdef WIN32
1379 # pragma comment(lib, "dnssd.lib")
1380 # endif /* WIN32 */
1381 DNSServiceRef ref, /* DNS-SD master service reference */
1382 domainref, /* DNS-SD service reference for domain */
1383 localref; /* DNS-SD service reference for .local */
1384 int domainsent = 0, /* Send the domain resolve? */
1385 offline = 0; /* offline-report state set? */
1386 char *regtype, /* Pointer to type in hostname */
1387 *domain; /* Pointer to domain in hostname */
1388 _http_uribuf_t uribuf; /* URI buffer */
1389 #ifdef HAVE_POLL
1390 struct pollfd polldata; /* Polling data */
1391 #else /* select() */
1392 fd_set input_set; /* Input set for select() */
1393 struct timeval stimeout; /* Timeout value for select() */
1394 #endif /* HAVE_POLL */
1395
1396 if (logit)
1397 fprintf(stderr, "DEBUG: Resolving \"%s\"...\n", hostname);
1398
1399 /*
1400 * Separate the hostname into service name, registration type, and domain...
1401 */
1402
1403 for (regtype = strstr(hostname, "._tcp") - 2;
1404 regtype > hostname;
1405 regtype --)
1406 if (regtype[0] == '.' && regtype[1] == '_')
1407 {
1408 /*
1409 * Found ._servicetype in front of ._tcp...
1410 */
1411
1412 *regtype++ = '\0';
1413 break;
1414 }
1415
1416 if (regtype <= hostname)
1417 {
1418 DEBUG_puts("5_httpResolveURI: Bad hostname, returning NULL");
1419 return (NULL);
1420 }
1421
1422 for (domain = strchr(regtype, '.');
1423 domain;
1424 domain = strchr(domain + 1, '.'))
1425 if (domain[1] != '_')
1426 break;
1427
1428 if (domain)
1429 *domain++ = '\0';
1430
1431 uribuf.buffer = resolved_uri;
1432 uribuf.bufsize = resolved_size;
1433
1434 resolved_uri[0] = '\0';
1435
1436 DEBUG_printf(("6_httpResolveURI: Resolving hostname=\"%s\", regtype=\"%s\", "
1437 "domain=\"%s\"\n", hostname, regtype, domain));
1438 if (logit)
1439 {
1440 fputs("STATE: +connecting-to-device\n", stderr);
1441 fprintf(stderr, "DEBUG: Resolving \"%s\", regtype=\"%s\", "
1442 "domain=\"local.\"...\n", hostname, regtype);
1443 }
1444
1445 uri = NULL;
1446
1447 if (DNSServiceCreateConnection(&ref) == kDNSServiceErr_NoError)
1448 {
1449 localref = ref;
1450 if (DNSServiceResolve(&localref, kDNSServiceFlagsShareConnection, 0,
1451 hostname, regtype, "local.", resolve_callback,
1452 &uribuf) == kDNSServiceErr_NoError)
1453 {
1454 int fds; /* Number of ready descriptors */
1455 time_t timeout, /* Poll timeout */
1456 start_time = time(NULL);/* Start time */
1457
1458 for (;;)
1459 {
1460 if (logit)
1461 _cupsLangPuts(stderr, _("INFO: Looking for printer...\n"));
1462
1463 /*
1464 * For the first minute, wakeup every 2 seconds to emit a
1465 * "looking for printer" message...
1466 */
1467
1468 timeout = (time(NULL) < (start_time + 60)) ? 2000 : -1;
1469
1470 #ifdef HAVE_POLL
1471 polldata.fd = DNSServiceRefSockFD(ref);
1472 polldata.events = POLLIN;
1473
1474 fds = poll(&polldata, 1, timeout);
1475
1476 #else /* select() */
1477 FD_ZERO(&input_set);
1478 FD_SET(DNSServiceRefSockFD(ref), &input_set);
1479
1480 stimeout.tv_sec = ((int)timeout) / 1000;
1481 stimeout.tv_usec = ((int)(timeout) * 1000) % 1000000;
1482
1483 fds = select(DNSServiceRefSockFD(ref)+1, &input_set, NULL, NULL,
1484 timeout < 0.0 ? NULL : &stimeout);
1485 #endif /* HAVE_POLL */
1486
1487 if (fds < 0)
1488 {
1489 if (errno != EINTR && errno != EAGAIN)
1490 {
1491 DEBUG_printf(("5_httpResolveURI: poll error: %s", strerror(errno)));
1492 break;
1493 }
1494 }
1495 else if (fds == 0)
1496 {
1497 /*
1498 * Wait 2 seconds for a response to the local resolve; if nothing
1499 * comes in, do an additional domain resolution...
1500 */
1501
1502 if (domainsent == 0 && strcasecmp(domain, "local."))
1503 {
1504 if (logit)
1505 fprintf(stderr,
1506 "DEBUG: Resolving \"%s\", regtype=\"%s\", "
1507 "domain=\"%s\"...\n", hostname, regtype, domain);
1508
1509 domainref = ref;
1510 if (DNSServiceResolve(&domainref, kDNSServiceFlagsShareConnection, 0,
1511 hostname, regtype, domain, resolve_callback,
1512 &uribuf) == kDNSServiceErr_NoError)
1513 domainsent = 1;
1514 }
1515
1516 /*
1517 * If it hasn't resolved within 5 seconds set the offline-report
1518 * printer-state-reason...
1519 */
1520
1521 if (logit && offline == 0 && time(NULL) > (start_time + 5))
1522 {
1523 fputs("STATE: +offline-report\n", stderr);
1524 offline = 1;
1525 }
1526 }
1527 else
1528 {
1529 if (DNSServiceProcessResult(ref) == kDNSServiceErr_NoError)
1530 {
1531 uri = resolved_uri;
1532 break;
1533 }
1534 }
1535 }
1536
1537 if (domainsent)
1538 DNSServiceRefDeallocate(domainref);
1539
1540 DNSServiceRefDeallocate(localref);
1541 }
1542
1543 DNSServiceRefDeallocate(ref);
1544 }
1545
1546 if (logit)
1547 {
1548 if (uri)
1549 fprintf(stderr, "DEBUG: Resolved as \"%s\"...\n", uri);
1550 else
1551 fputs("DEBUG: Unable to resolve URI\n", stderr);
1552
1553 fputs("STATE: -connecting-to-device,offline-report\n", stderr);
1554 }
1555
1556 #else
1557 /*
1558 * No DNS-SD support...
1559 */
1560
1561 uri = NULL;
1562 #endif /* HAVE_DNSSD */
1563
1564 if (logit && !uri)
1565 _cupsLangPuts(stderr, _("Unable to find printer\n"));
1566 }
1567
1568 DEBUG_printf(("5_httpResolveURI: Returning \"%s\"", uri));
1569
1570 return (uri);
1571 }
1572
1573
1574 /*
1575 * 'http_copy_decode()' - Copy and decode a URI.
1576 */
1577
1578 static const char * /* O - New source pointer or NULL on error */
1579 http_copy_decode(char *dst, /* O - Destination buffer */
1580 const char *src, /* I - Source pointer */
1581 int dstsize, /* I - Destination size */
1582 const char *term, /* I - Terminating characters */
1583 int decode) /* I - Decode %-encoded values */
1584 {
1585 char *ptr, /* Pointer into buffer */
1586 *end; /* End of buffer */
1587 int quoted; /* Quoted character */
1588
1589
1590 /*
1591 * Copy the src to the destination until we hit a terminating character
1592 * or the end of the string.
1593 */
1594
1595 for (ptr = dst, end = dst + dstsize - 1;
1596 *src && (!term || !strchr(term, *src));
1597 src ++)
1598 if (ptr < end)
1599 {
1600 if (*src == '%' && decode)
1601 {
1602 if (isxdigit(src[1] & 255) && isxdigit(src[2] & 255))
1603 {
1604 /*
1605 * Grab a hex-encoded character...
1606 */
1607
1608 src ++;
1609 if (isalpha(*src))
1610 quoted = (tolower(*src) - 'a' + 10) << 4;
1611 else
1612 quoted = (*src - '0') << 4;
1613
1614 src ++;
1615 if (isalpha(*src))
1616 quoted |= tolower(*src) - 'a' + 10;
1617 else
1618 quoted |= *src - '0';
1619
1620 *ptr++ = quoted;
1621 }
1622 else
1623 {
1624 /*
1625 * Bad hex-encoded character...
1626 */
1627
1628 *ptr = '\0';
1629 return (NULL);
1630 }
1631 }
1632 else
1633 *ptr++ = *src;
1634 }
1635
1636 *ptr = '\0';
1637
1638 return (src);
1639 }
1640
1641
1642 /*
1643 * 'http_copy_encode()' - Copy and encode a URI.
1644 */
1645
1646 static char * /* O - End of current URI */
1647 http_copy_encode(char *dst, /* O - Destination buffer */
1648 const char *src, /* I - Source pointer */
1649 char *dstend, /* I - End of destination buffer */
1650 const char *reserved, /* I - Extra reserved characters */
1651 const char *term, /* I - Terminating characters */
1652 int encode) /* I - %-encode reserved chars? */
1653 {
1654 static const char hex[] = "0123456789ABCDEF";
1655
1656
1657 while (*src && dst < dstend)
1658 {
1659 if (term && *src == *term)
1660 return (dst);
1661
1662 if (encode && (*src == '%' || *src <= ' ' || *src & 128 ||
1663 (reserved && strchr(reserved, *src))))
1664 {
1665 /*
1666 * Hex encode reserved characters...
1667 */
1668
1669 if ((dst + 2) >= dstend)
1670 break;
1671
1672 *dst++ = '%';
1673 *dst++ = hex[(*src >> 4) & 15];
1674 *dst++ = hex[*src & 15];
1675
1676 src ++;
1677 }
1678 else
1679 *dst++ = *src++;
1680 }
1681
1682 *dst = '\0';
1683
1684 if (*src)
1685 return (NULL);
1686 else
1687 return (dst);
1688 }
1689
1690
1691 #ifdef HAVE_DNSSD
1692 /*
1693 * 'resolve_callback()' - Build a device URI for the given service name.
1694 */
1695
1696 static void DNSSD_API
1697 resolve_callback(
1698 DNSServiceRef sdRef, /* I - Service reference */
1699 DNSServiceFlags flags, /* I - Results flags */
1700 uint32_t interfaceIndex, /* I - Interface number */
1701 DNSServiceErrorType errorCode, /* I - Error, if any */
1702 const char *fullName, /* I - Full service name */
1703 const char *hostTarget, /* I - Hostname */
1704 uint16_t port, /* I - Port number */
1705 uint16_t txtLen, /* I - Length of TXT record */
1706 const unsigned char *txtRecord, /* I - TXT record data */
1707 void *context) /* I - Pointer to URI buffer */
1708 {
1709 const char *scheme; /* URI scheme */
1710 char rp[257]; /* Remote printer */
1711 const void *value; /* Value from TXT record */
1712 uint8_t valueLen; /* Length of value */
1713 _http_uribuf_t *uribuf; /* URI buffer */
1714
1715
1716 DEBUG_printf(("7resolve_callback(sdRef=%p, flags=%x, interfaceIndex=%u, "
1717 "errorCode=%d, fullName=\"%s\", hostTarget=\"%s\", port=%u, "
1718 "txtLen=%u, txtRecord=%p, context=%p)", sdRef, flags,
1719 interfaceIndex, errorCode, fullName, hostTarget, port, txtLen,
1720 txtRecord, context));
1721
1722 /*
1723 * Figure out the scheme from the full name...
1724 */
1725
1726 if (strstr(fullName, "._ipp") || strstr(fullName, "._fax-ipp"))
1727 scheme = "ipp";
1728 else if (strstr(fullName, "._printer."))
1729 scheme = "lpd";
1730 else if (strstr(fullName, "._pdl-datastream."))
1731 scheme = "socket";
1732 else
1733 scheme = "riousbprint";
1734
1735 /*
1736 * Extract the "remote printer" key from the TXT record...
1737 */
1738
1739 if ((value = TXTRecordGetValuePtr(txtLen, txtRecord, "rp",
1740 &valueLen)) != NULL)
1741 {
1742 /*
1743 * Convert to resource by concatenating with a leading "/"...
1744 */
1745
1746 rp[0] = '/';
1747 memcpy(rp + 1, value, valueLen);
1748 rp[valueLen + 1] = '\0';
1749 }
1750 else
1751 rp[0] = '\0';
1752
1753 /*
1754 * Assemble the final device URI...
1755 */
1756
1757 uribuf = (_http_uribuf_t *)context;
1758
1759 httpAssembleURI(HTTP_URI_CODING_ALL, uribuf->buffer, uribuf->bufsize, scheme,
1760 NULL, hostTarget, ntohs(port), rp);
1761
1762 DEBUG_printf(("8resolve_callback: Resolved URI is \"%s\"...",
1763 uribuf->buffer));
1764 }
1765 #endif /* HAVE_DNSSD */
1766
1767
1768 /*
1769 * End of "$Id: http-support.c 7952 2008-09-17 00:56:20Z mike $".
1770 */