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