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