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