]> git.ipfire.org Git - thirdparty/cups.git/blame - backend/dnssd.c
Merge changes from CUPS 1.4svn-r8346.
[thirdparty/cups.git] / backend / dnssd.c
CommitLineData
7a14d768
MS
1/*
2 * "$Id$"
3 *
4 * DNS-SD discovery backend for the Common UNIX Printing System (CUPS).
5 *
bf3816c7 6 * Copyright 2008-2009 by Apple Inc.
7a14d768
MS
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Apple Inc. and are protected by Federal copyright
10 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
11 * "LICENSE" which should have been included with this file. If this
12 * file is missing or damaged, see the license at "http://www.cups.org/".
13 *
14 * This file is subject to the Apple OS-Developed Software exception.
15 *
16 * Contents:
17 *
18 * main() - Browse for printers.
19 * browse_callback() - Browse devices.
20 * browse_local_callback() - Browse local devices.
21 * compare_devices() - Compare two devices.
22 * get_device() - Create or update a device.
23 * query_callback() - Process query data.
24 * unquote() - Unquote a name string.
25 */
26
27/*
28 * Include necessary headers.
29 */
30
31#include "backend-private.h"
32#include <cups/array.h>
33#include <dns_sd.h>
34
35
36/*
37 * Device structure...
38 */
39
40typedef enum
41{
42 CUPS_DEVICE_PRINTER = 0, /* lpd://... */
43 CUPS_DEVICE_IPP, /* ipp://... */
44 CUPS_DEVICE_FAX_IPP, /* ipp://... */
45 CUPS_DEVICE_PDL_DATASTREAM, /* socket://... */
46 CUPS_DEVICE_RIOUSBPRINT /* riousbprint://... */
47} cups_devtype_t;
48
49
50typedef struct
51{
52 DNSServiceRef ref; /* Service reference for resolve */
53 char *name, /* Service name */
54 *domain, /* Domain name */
55 *fullName, /* Full name */
56 *make_and_model; /* Make and model from TXT record */
57 cups_devtype_t type; /* Device registration type */
1f0275e3
MS
58 int priority, /* Priority associated with type */
59 cups_shared, /* CUPS shared printer? */
7a14d768
MS
60 sent; /* Did we list the device? */
61} cups_device_t;
62
63
64/*
65 * Local functions...
66 */
67
68static void browse_callback(DNSServiceRef sdRef,
69 DNSServiceFlags flags,
70 uint32_t interfaceIndex,
71 DNSServiceErrorType errorCode,
72 const char *serviceName,
73 const char *regtype,
74 const char *replyDomain, void *context);
75static void browse_local_callback(DNSServiceRef sdRef,
76 DNSServiceFlags flags,
77 uint32_t interfaceIndex,
78 DNSServiceErrorType errorCode,
79 const char *serviceName,
80 const char *regtype,
81 const char *replyDomain,
82 void *context);
83static int compare_devices(cups_device_t *a, cups_device_t *b);
84static void exec_backend(char **argv);
85static cups_device_t *get_device(cups_array_t *devices,
86 const char *serviceName,
87 const char *regtype,
88 const char *replyDomain);
89static void query_callback(DNSServiceRef sdRef,
90 DNSServiceFlags flags,
91 uint32_t interfaceIndex,
92 DNSServiceErrorType errorCode,
93 const char *fullName, uint16_t rrtype,
94 uint16_t rrclass, uint16_t rdlen,
95 const void *rdata, uint32_t ttl,
96 void *context);
97static void unquote(char *dst, const char *src, size_t dstsize);
98
99
100/*
101 * 'main()' - Browse for printers.
102 */
103
104int /* O - Exit status */
105main(int argc, /* I - Number of command-line args */
106 char *argv[]) /* I - Command-line arguments */
107{
c5571a1d 108 const char *name; /* Backend name */
7a14d768
MS
109 DNSServiceRef main_ref, /* Main service reference */
110 fax_ipp_ref, /* IPP fax service reference */
111 ipp_ref, /* IPP service reference */
112 ipp_tls_ref, /* IPP w/TLS service reference */
113 local_fax_ipp_ref, /* Local IPP fax service reference */
114 local_ipp_ref, /* Local IPP service reference */
115 local_ipp_tls_ref, /* Local IPP w/TLS service reference */
116 local_printer_ref, /* Local LPD service reference */
117 pdl_datastream_ref, /* AppSocket service reference */
118 printer_ref, /* LPD service reference */
119 riousbprint_ref; /* Remote IO service reference */
120 int fd; /* Main file descriptor */
121 fd_set input; /* Input set for select() */
122 struct timeval timeout; /* Timeout for select() */
123 cups_array_t *devices; /* Device array */
124 cups_device_t *device; /* Current device */
bf3816c7 125 char uriName[1024]; /* Unquoted fullName for URI */
7a14d768
MS
126
127
128 /*
129 * Check command-line...
130 */
131
132 setbuf(stderr, NULL);
133
134 if (argc >= 6)
135 exec_backend(argv);
136 else if (argc != 1)
137 {
c5571a1d
MS
138 fprintf(stderr, "Usage: %s job user title copies options [filename(s)]\n",
139 argv[0]);
7a14d768
MS
140 return (1);
141 }
142
c5571a1d
MS
143 /*
144 * Only do discovery when run as "dnssd"...
145 */
146
147 if ((name = strrchr(argv[0], '/')) != NULL)
148 name ++;
149 else
150 name = argv[0];
151
152 if (strcmp(name, "dnssd"))
153 return (0);
154
7a14d768
MS
155 /*
156 * Create an array to track devices...
157 */
158
159 devices = cupsArrayNew((cups_array_func_t)compare_devices, NULL);
160
161 /*
162 * Browse for different kinds of printers...
163 */
164
165 if (DNSServiceCreateConnection(&main_ref) != kDNSServiceErr_NoError)
166 {
167 perror("ERROR: Unable to create service connection");
168 return (1);
169 }
170
171 fd = DNSServiceRefSockFD(main_ref);
172
173 fax_ipp_ref = main_ref;
174 DNSServiceBrowse(&fax_ipp_ref, kDNSServiceFlagsShareConnection, 0,
175 "_fax-ipp._tcp", NULL, browse_callback, devices);
176
177 ipp_ref = main_ref;
178 DNSServiceBrowse(&ipp_ref, kDNSServiceFlagsShareConnection, 0,
179 "_ipp._tcp", NULL, browse_callback, devices);
180
181 ipp_tls_ref = main_ref;
182 DNSServiceBrowse(&ipp_tls_ref, kDNSServiceFlagsShareConnection, 0,
183 "_ipp-tls._tcp", NULL, browse_callback, devices);
184
185 local_fax_ipp_ref = main_ref;
186 DNSServiceBrowse(&local_fax_ipp_ref, kDNSServiceFlagsShareConnection,
187 kDNSServiceInterfaceIndexLocalOnly,
188 "_fax-ipp._tcp", NULL, browse_local_callback, devices);
189
190 local_ipp_ref = main_ref;
191 DNSServiceBrowse(&local_ipp_ref, kDNSServiceFlagsShareConnection,
192 kDNSServiceInterfaceIndexLocalOnly,
193 "_ipp._tcp", NULL, browse_local_callback, devices);
194
195 local_ipp_tls_ref = main_ref;
196 DNSServiceBrowse(&local_ipp_tls_ref, kDNSServiceFlagsShareConnection,
197 kDNSServiceInterfaceIndexLocalOnly,
198 "_ipp-tls._tcp", NULL, browse_local_callback, devices);
199
200 local_printer_ref = main_ref;
201 DNSServiceBrowse(&local_printer_ref, kDNSServiceFlagsShareConnection,
202 kDNSServiceInterfaceIndexLocalOnly,
203 "_printer._tcp", NULL, browse_local_callback, devices);
204
205 pdl_datastream_ref = main_ref;
206 DNSServiceBrowse(&pdl_datastream_ref, kDNSServiceFlagsShareConnection, 0,
207 "_pdl-datastream._tcp", NULL, browse_callback, devices);
208
209 printer_ref = main_ref;
210 DNSServiceBrowse(&printer_ref, kDNSServiceFlagsShareConnection, 0,
211 "_printer._tcp", NULL, browse_callback, devices);
212
213 riousbprint_ref = main_ref;
214 DNSServiceBrowse(&riousbprint_ref, kDNSServiceFlagsShareConnection, 0,
215 "_riousbprint._tcp", NULL, browse_callback, devices);
216
217 /*
218 * Loop until we are killed...
219 */
220
221 for (;;)
222 {
223 FD_ZERO(&input);
224 FD_SET(fd, &input);
225
226 timeout.tv_sec = 1;
227 timeout.tv_usec = 0;
228
229 if (select(fd + 1, &input, NULL, NULL, &timeout) < 0)
230 continue;
231
232 if (FD_ISSET(fd, &input))
233 {
234 /*
235 * Process results of our browsing...
236 */
237
238 DNSServiceProcessResult(main_ref);
239 }
240 else
241 {
242 /*
243 * Announce any devices we've found...
244 */
245
58dc1933 246 DNSServiceErrorType status; /* DNS query status */
1f0275e3 247 cups_device_t *best; /* Best matching device */
7a14d768 248 char device_uri[1024]; /* Device URI */
5eb9da71 249 int count; /* Number of queries */
7a14d768
MS
250 static const char * const schemes[] =
251 { "lpd", "ipp", "ipp", "socket", "riousbprint" };
252 /* URI schemes for devices */
253
254
1f0275e3
MS
255 for (device = (cups_device_t *)cupsArrayFirst(devices),
256 best = NULL, count = 0;
7a14d768
MS
257 device;
258 device = (cups_device_t *)cupsArrayNext(devices))
259 if (!device->ref && !device->sent)
260 {
261 /*
262 * Found the device, now get the TXT record(s) for it...
263 */
264
5eb9da71
MS
265 if (count < 10)
266 {
267 device->ref = main_ref;
268
269 fprintf(stderr, "DEBUG: Querying \"%s\"...\n", device->fullName);
270
58dc1933
MS
271 status = DNSServiceQueryRecord(&(device->ref),
272 kDNSServiceFlagsShareConnection,
273 0, device->fullName,
274 kDNSServiceType_TXT,
275 kDNSServiceClass_IN, query_callback,
276 devices);
277 if (status != kDNSServiceErr_NoError)
278 {
5eb9da71 279 fputs("ERROR: Unable to query for TXT records!\n", stderr);
58dc1933
MS
280 fprintf(stderr, "DEBUG: DNSServiceQueryRecord returned %d\n",
281 status);
282 }
283 else
5eb9da71
MS
284 count ++;
285 }
7a14d768
MS
286 }
287 else if (!device->sent)
288 {
289 /*
290 * Got the TXT records, now report the device...
291 */
292
293 DNSServiceRefDeallocate(device->ref);
294 device->ref = 0;
295
1f0275e3
MS
296 if (!best)
297 best = device;
298 else if (strcasecmp(best->name, device->name) ||
299 strcasecmp(best->domain, device->domain))
300 {
bf3816c7
MS
301 unquote(uriName, best->fullName, sizeof(uriName));
302
1f0275e3 303 httpAssembleURI(HTTP_URI_CODING_ALL, device_uri, sizeof(device_uri),
bf3816c7 304 schemes[best->type], NULL, uriName, 0,
1f0275e3
MS
305 best->cups_shared ? "/cups" : "/");
306
749b1e90
MS
307 cupsBackendReport("network", device_uri, best->make_and_model,
308 best->name, NULL, NULL);
1f0275e3
MS
309 best->sent = 1;
310 best = device;
311 }
312 else if (best->priority > device->priority ||
313 (best->priority == device->priority &&
314 best->type < device->type))
315 {
316 best->sent = 1;
317 best = device;
318 }
319 else
320 device->sent = 1;
321 }
7a14d768 322
1f0275e3
MS
323 if (best)
324 {
bf3816c7
MS
325 unquote(uriName, best->fullName, sizeof(uriName));
326
1f0275e3 327 httpAssembleURI(HTTP_URI_CODING_ALL, device_uri, sizeof(device_uri),
bf3816c7 328 schemes[best->type], NULL, uriName, 0,
1f0275e3 329 best->cups_shared ? "/cups" : "/");
7a14d768 330
749b1e90
MS
331 cupsBackendReport("network", device_uri, best->make_and_model,
332 best->name, NULL, NULL);
1f0275e3
MS
333 best->sent = 1;
334 }
7a14d768
MS
335 }
336 }
337}
338
339
340/*
341 * 'browse_callback()' - Browse devices.
342 */
343
344static void
345browse_callback(
346 DNSServiceRef sdRef, /* I - Service reference */
347 DNSServiceFlags flags, /* I - Option flags */
348 uint32_t interfaceIndex, /* I - Interface number */
349 DNSServiceErrorType errorCode, /* I - Error, if any */
350 const char *serviceName, /* I - Name of service/device */
351 const char *regtype, /* I - Type of service */
352 const char *replyDomain, /* I - Service domain */
353 void *context) /* I - Devices array */
354{
355 fprintf(stderr, "DEBUG2: browse_callback(sdRef=%p, flags=%x, "
356 "interfaceIndex=%d, errorCode=%d, serviceName=\"%s\", "
357 "regtype=\"%s\", replyDomain=\"%s\", context=%p)\n",
358 sdRef, flags, interfaceIndex, errorCode,
359 serviceName ? serviceName : "(null)",
360 regtype ? regtype : "(null)",
361 replyDomain ? replyDomain : "(null)",
362 context);
363
364 /*
365 * Only process "add" data...
366 */
367
368 if (errorCode != kDNSServiceErr_NoError || !(flags & kDNSServiceFlagsAdd))
369 return;
370
371 /*
372 * Get the device...
373 */
374
375 get_device((cups_array_t *)context, serviceName, regtype, replyDomain);
376}
377
378
379/*
380 * 'browse_local_callback()' - Browse local devices.
381 */
382
383static void
384browse_local_callback(
385 DNSServiceRef sdRef, /* I - Service reference */
386 DNSServiceFlags flags, /* I - Option flags */
387 uint32_t interfaceIndex, /* I - Interface number */
388 DNSServiceErrorType errorCode, /* I - Error, if any */
389 const char *serviceName, /* I - Name of service/device */
390 const char *regtype, /* I - Type of service */
391 const char *replyDomain, /* I - Service domain */
392 void *context) /* I - Devices array */
393{
394 cups_device_t *device; /* Device */
395
396
397 fprintf(stderr, "DEBUG2: browse_local_callback(sdRef=%p, flags=%x, "
398 "interfaceIndex=%d, errorCode=%d, serviceName=\"%s\", "
399 "regtype=\"%s\", replyDomain=\"%s\", context=%p)\n",
400 sdRef, flags, interfaceIndex, errorCode,
401 serviceName ? serviceName : "(null)",
402 regtype ? regtype : "(null)",
403 replyDomain ? replyDomain : "(null)",
404 context);
405
406 /*
407 * Only process "add" data...
408 */
409
410 if (errorCode != kDNSServiceErr_NoError || !(flags & kDNSServiceFlagsAdd))
411 return;
412
413 /*
414 * Get the device...
415 */
416
417 device = get_device((cups_array_t *)context, serviceName, regtype,
418 replyDomain);
419
420 /*
421 * Hide locally-registered devices...
422 */
423
424 fprintf(stderr, "DEBUG: Hiding local printer \"%s\"...\n",
425 device->fullName);
426 device->sent = 1;
427}
428
429
430/*
431 * 'compare_devices()' - Compare two devices.
432 */
433
434static int /* O - Result of comparison */
435compare_devices(cups_device_t *a, /* I - First device */
436 cups_device_t *b) /* I - Second device */
437{
438 int result = strcmp(a->name, b->name);
439
440 if (result)
441 return (result);
442 else
443 return (strcmp(a->domain, b->domain));
444}
445
446
447/*
448 * 'exec_backend()' - Execute the backend that corresponds to the
449 * resolved service name.
450 */
451
452static void
453exec_backend(char **argv) /* I - Command-line arguments */
454{
455 const char *resolved_uri, /* Resolved device URI */
456 *cups_serverbin; /* Location of programs */
457 char scheme[1024], /* Scheme from URI */
458 *ptr, /* Pointer into scheme */
459 filename[1024]; /* Backend filename */
460
461
462 /*
463 * Resolve the device URI...
464 */
465
1f0275e3
MS
466 if ((resolved_uri = cupsBackendDeviceURI(argv)) == NULL)
467 exit(CUPS_BACKEND_FAILED);
7a14d768
MS
468
469 /*
470 * Extract the scheme from the URI...
471 */
472
473 strlcpy(scheme, resolved_uri, sizeof(scheme));
474 if ((ptr = strchr(scheme, ':')) != NULL)
475 *ptr = '\0';
476
477 /*
478 * Get the filename of the backend...
479 */
480
481 if ((cups_serverbin = getenv("CUPS_SERVERBIN")) == NULL)
482 cups_serverbin = CUPS_SERVERBIN;
483
484 snprintf(filename, sizeof(filename), "%s/backend/%s", cups_serverbin, scheme);
485
486 /*
487 * Overwrite the device URIs and run the new backend...
488 */
489
490 setenv("DEVICE_URI", resolved_uri, 1);
491
492 argv[0] = (char *)resolved_uri;
493
494 fprintf(stderr, "DEBUG: Executing backend \"%s\"...\n", filename);
495
496 execv(filename, argv);
497
498 fprintf(stderr, "ERROR: Unable to execute backend \"%s\": %s\n", filename,
499 strerror(errno));
500 exit(CUPS_BACKEND_STOP);
501}
502
503
504/*
505 * 'get_device()' - Create or update a device.
506 */
507
508static cups_device_t * /* O - Device */
509get_device(cups_array_t *devices, /* I - Device array */
510 const char *serviceName, /* I - Name of service/device */
511 const char *regtype, /* I - Type of service */
512 const char *replyDomain) /* I - Service domain */
513{
514 cups_device_t key, /* Search key */
515 *device; /* Device */
58dc1933
MS
516 char fullName[kDNSServiceMaxDomainName];
517 /* Full name for query */
7a14d768
MS
518
519
520 /*
521 * See if this is a new device...
522 */
523
524 key.name = (char *)serviceName;
525 key.domain = (char *)replyDomain;
526
527 if (!strcmp(regtype, "_ipp._tcp.") ||
528 !strcmp(regtype, "_ipp-tls._tcp."))
529 key.type = CUPS_DEVICE_IPP;
530 else if (!strcmp(regtype, "_fax-ipp._tcp."))
531 key.type = CUPS_DEVICE_FAX_IPP;
532 else if (!strcmp(regtype, "_printer._tcp."))
533 key.type = CUPS_DEVICE_PRINTER;
534 else if (!strcmp(regtype, "_pdl-datastream._tcp."))
535 key.type = CUPS_DEVICE_PDL_DATASTREAM;
536 else
537 key.type = CUPS_DEVICE_RIOUSBPRINT;
538
1f0275e3
MS
539 for (device = cupsArrayFind(devices, &key);
540 device;
541 device = cupsArrayNext(devices))
542 if (strcasecmp(device->name, key.name) ||
543 strcasecmp(device->domain, key.domain))
544 break;
545 else if (device->type == key.type)
546 return (device);
7a14d768 547
1f0275e3
MS
548 /*
549 * Yes, add the device...
550 */
7a14d768 551
1f0275e3
MS
552 fprintf(stderr, "DEBUG: Found \"%s.%s%s\"...\n", serviceName, regtype,
553 replyDomain);
7a14d768 554
1f0275e3
MS
555 device = calloc(sizeof(cups_device_t), 1);
556 device->name = strdup(serviceName);
557 device->domain = strdup(replyDomain);
558 device->type = key.type;
559 device->priority = 50;
7a14d768 560
1f0275e3 561 cupsArrayAdd(devices, device);
7a14d768
MS
562
563 /*
1f0275e3 564 * Set the "full name" of this service, which is used for queries...
7a14d768
MS
565 */
566
58dc1933 567 DNSServiceConstructFullName(fullName, serviceName, regtype, replyDomain);
7a14d768
MS
568 device->fullName = strdup(fullName);
569
570 return (device);
571}
572
573
574/*
575 * 'query_callback()' - Process query data.
576 */
577
578static void
579query_callback(
580 DNSServiceRef sdRef, /* I - Service reference */
581 DNSServiceFlags flags, /* I - Data flags */
582 uint32_t interfaceIndex, /* I - Interface */
583 DNSServiceErrorType errorCode, /* I - Error, if any */
584 const char *fullName, /* I - Full service name */
585 uint16_t rrtype, /* I - Record type */
586 uint16_t rrclass, /* I - Record class */
587 uint16_t rdlen, /* I - Length of record data */
588 const void *rdata, /* I - Record data */
589 uint32_t ttl, /* I - Time-to-live */
590 void *context) /* I - Devices array */
591{
592 cups_array_t *devices; /* Device array */
593 char name[1024], /* Service name */
594 *ptr; /* Pointer into name */
595 cups_device_t key, /* Search key */
596 *device; /* Device */
597
598
599 fprintf(stderr, "DEBUG2: query_callback(sdRef=%p, flags=%x, "
600 "interfaceIndex=%d, errorCode=%d, fullName=\"%s\", "
601 "rrtype=%u, rrclass=%u, rdlen=%u, rdata=%p, ttl=%u, "
602 "context=%p)\n",
603 sdRef, flags, interfaceIndex, errorCode,
604 fullName ? fullName : "(null)", rrtype, rrclass, rdlen, rdata, ttl,
605 context);
606
607 /*
608 * Only process "add" data...
609 */
610
611 if (errorCode != kDNSServiceErr_NoError || !(flags & kDNSServiceFlagsAdd))
612 return;
613
614 /*
615 * Lookup the service in the devices array.
616 */
617
618 devices = (cups_array_t *)context;
619 key.name = name;
620
621 unquote(name, fullName, sizeof(name));
622
623 if ((key.domain = strstr(name, "._tcp.")) != NULL)
624 key.domain += 6;
625 else
626 key.domain = (char *)"local.";
627
628 if ((ptr = strstr(name, "._")) != NULL)
629 *ptr = '\0';
630
1f0275e3
MS
631 if (strstr(fullName, "_ipp._tcp.") ||
632 strstr(fullName, "_ipp-tls._tcp."))
633 key.type = CUPS_DEVICE_IPP;
634 else if (strstr(fullName, "_fax-ipp._tcp."))
635 key.type = CUPS_DEVICE_FAX_IPP;
636 else if (strstr(fullName, "_printer._tcp."))
637 key.type = CUPS_DEVICE_PRINTER;
638 else if (strstr(fullName, "_pdl-datastream._tcp."))
639 key.type = CUPS_DEVICE_PDL_DATASTREAM;
640 else
641 key.type = CUPS_DEVICE_RIOUSBPRINT;
642
643 for (device = cupsArrayFind(devices, &key);
644 device;
645 device = cupsArrayNext(devices))
7a14d768 646 {
1f0275e3
MS
647 if (strcasecmp(device->name, key.name) ||
648 strcasecmp(device->domain, key.domain))
649 {
650 device = NULL;
651 break;
652 }
653 else if (device->type == key.type)
654 {
655 /*
656 * Found it, pull out the priority and make and model from the TXT
657 * record and save it...
658 */
7a14d768 659
1f0275e3
MS
660 const void *value; /* Pointer to value */
661 uint8_t valueLen; /* Length of value (max 255) */
662 char make_and_model[512], /* Manufacturer and model */
663 model[256], /* Model */
664 priority[256]; /* Priority */
7a14d768
MS
665
666
1f0275e3 667 value = TXTRecordGetValuePtr(rdlen, rdata, "priority", &valueLen);
7a14d768 668
1f0275e3
MS
669 if (value && valueLen)
670 {
671 memcpy(priority, value, valueLen);
672 priority[valueLen] = '\0';
673 device->priority = atoi(priority);
674 }
7a14d768 675
1f0275e3
MS
676 if ((value = TXTRecordGetValuePtr(rdlen, rdata, "usb_MFG",
677 &valueLen)) == NULL)
678 value = TXTRecordGetValuePtr(rdlen, rdata, "usb_MANUFACTURER",
679 &valueLen);
7a14d768 680
1f0275e3 681 if (value && valueLen)
5eb9da71 682 {
1f0275e3
MS
683 memcpy(make_and_model, value, valueLen);
684 make_and_model[valueLen] = '\0';
5eb9da71
MS
685 }
686 else
1f0275e3
MS
687 make_and_model[0] = '\0';
688
689 if ((value = TXTRecordGetValuePtr(rdlen, rdata, "usb_MDL",
690 &valueLen)) == NULL)
691 value = TXTRecordGetValuePtr(rdlen, rdata, "usb_MODEL", &valueLen);
692
693 if (value && valueLen)
5eb9da71
MS
694 {
695 memcpy(model, value, valueLen);
696 model[valueLen] = '\0';
697 }
1f0275e3
MS
698 else if ((value = TXTRecordGetValuePtr(rdlen, rdata, "product",
699 &valueLen)) != NULL && valueLen > 2)
7a14d768 700 {
1f0275e3
MS
701 if (((char *)value)[0] == '(')
702 {
703 /*
704 * Strip parenthesis...
705 */
706
707 memcpy(model, value + 1, valueLen - 2);
708 model[valueLen - 2] = '\0';
709 }
710 else
711 {
7a14d768
MS
712 memcpy(model, value, valueLen);
713 model[valueLen] = '\0';
1f0275e3 714 }
7a14d768 715
1f0275e3
MS
716 if (!strcasecmp(model, "GPL Ghostscript") ||
717 !strcasecmp(model, "GNU Ghostscript") ||
718 !strcasecmp(model, "ESP Ghostscript"))
719 {
720 if ((value = TXTRecordGetValuePtr(rdlen, rdata, "ty",
721 &valueLen)) != NULL)
722 {
723 memcpy(model, value, valueLen);
724 model[valueLen] = '\0';
725
726 if ((ptr = strchr(model, ',')) != NULL)
727 *ptr = '\0';
728 }
729 else
730 strcpy(model, "Unknown");
7a14d768 731 }
7a14d768 732 }
1f0275e3
MS
733 else
734 strcpy(model, "Unknown");
7a14d768 735
1f0275e3
MS
736 if (device->make_and_model)
737 free(device->make_and_model);
7a14d768 738
1f0275e3
MS
739 if (make_and_model[0])
740 {
741 strlcat(make_and_model, " ", sizeof(make_and_model));
742 strlcat(make_and_model, model, sizeof(make_and_model));
743 device->make_and_model = strdup(make_and_model);
744 }
745 else
746 device->make_and_model = strdup(model);
7a14d768 747
1f0275e3
MS
748 if ((device->type == CUPS_DEVICE_IPP ||
749 device->type == CUPS_DEVICE_PRINTER) &&
750 TXTRecordGetValuePtr(rdlen, rdata, "printer-type", &valueLen))
751 {
752 /*
753 * This is a CUPS printer!
754 */
7a14d768 755
1f0275e3 756 device->cups_shared = 1;
a0f6818e 757
1f0275e3
MS
758 if (device->type == CUPS_DEVICE_PRINTER)
759 device->sent = 1;
760 }
761
762 break;
7a14d768
MS
763 }
764 }
1f0275e3
MS
765
766 if (!device)
7a14d768
MS
767 fprintf(stderr, "DEBUG: Ignoring TXT record for \"%s\"...\n", fullName);
768}
769
770
771/*
772 * 'unquote()' - Unquote a name string.
773 */
774
775static void
776unquote(char *dst, /* I - Destination buffer */
777 const char *src, /* I - Source string */
778 size_t dstsize) /* I - Size of destination buffer */
779{
780 char *dstend = dst + dstsize - 1; /* End of destination buffer */
781
782
783 while (*src && dst < dstend)
784 {
785 if (*src == '\\')
786 {
787 src ++;
788 if (isdigit(src[0] & 255) && isdigit(src[1] & 255) &&
789 isdigit(src[2] & 255))
790 {
791 *dst++ = ((((src[0] - '0') * 10) + src[1] - '0') * 10) + src[2] - '0';
792 src += 3;
793 }
794 else
795 *dst++ = *src++;
796 }
797 else
798 *dst++ = *src ++;
799 }
800
801 *dst = '\0';
802}
803
804
805/*
806 * End of "$Id$".
807 */