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