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