]> git.ipfire.org Git - people/arne_f/ipfire-3.x.git/blame - cups/patches/cups-avahi.patch
Move all packages to root.
[people/arne_f/ipfire-3.x.git] / cups / patches / cups-avahi.patch
CommitLineData
f92713d3
SS
1diff -up cups-1.4.5/backend/dnssd.c.avahi cups-1.4.5/backend/dnssd.c
2--- cups-1.4.5/backend/dnssd.c.avahi 2010-12-24 13:11:33.760461375 +0000
3+++ cups-1.4.5/backend/dnssd.c 2010-12-24 13:11:38.325341226 +0000
4@@ -15,14 +15,21 @@
5 *
6 * Contents:
7 *
8+ * next_txt_record() - Get next TXT record from a cups_txt_records_t.
9+ * parse_txt_record_pair() - Read key/value pair in cups_txt_records_t.
10 * main() - Browse for printers.
11 * browse_callback() - Browse devices.
12 * browse_local_callback() - Browse local devices.
13 * compare_devices() - Compare two devices.
14 * exec_backend() - Execute the backend that corresponds to the
15 * resolved service name.
16+ * device_type() - Get DNS-SD type enumeration from string.
17 * get_device() - Create or update a device.
18 * query_callback() - Process query data.
19+ * avahi_client_callback() - Avahi client callback function.
20+ * avahi_query_callback() - Avahi query callback function.
21+ * avahi_browse_callback() - Avahi browse callback function.
22+ * find_device() - Find a device from its name and domain.
23 * sigterm_handler() - Handle termination signals...
24 * unquote() - Unquote a name string.
25 */
26@@ -33,7 +40,18 @@
27
28 #include "backend-private.h"
29 #include <cups/array.h>
30-#include <dns_sd.h>
31+#ifdef HAVE_DNSSD
32+# include <dns_sd.h>
33+#endif /* HAVE_DNSSD */
34+#ifdef HAVE_AVAHI
35+# include <avahi-client/client.h>
36+# include <avahi-client/lookup.h>
37+# include <avahi-common/simple-watch.h>
38+# include <avahi-common/domain.h>
39+# include <avahi-common/error.h>
40+# include <avahi-common/malloc.h>
41+#define kDNSServiceMaxDomainName AVAHI_DOMAIN_NAME_MAX
42+#endif /* HAVE_AVAHI */
43
44
45 /*
46@@ -52,7 +70,12 @@ typedef enum
47
48 typedef struct
49 {
50+#ifdef HAVE_DNSSD
51 DNSServiceRef ref; /* Service reference for resolve */
52+#endif /* HAVE_DNSSD */
53+#ifdef HAVE_AVAHI
54+ int resolved; /* Did we resolve the device? */
55+#endif /* HAVE_AVAHI */
56 char *name, /* Service name */
57 *domain, /* Domain name */
58 *fullName, /* Full name */
59@@ -64,6 +87,20 @@ typedef struct
60 sent; /* Did we list the device? */
61 } cups_device_t;
62
63+typedef struct
64+{
65+ char key[256];
66+ char value[256];
67+
68+#ifdef HAVE_DNSSD
69+ const uint8_t *data;
70+ const uint8_t *datanext;
71+ const uint8_t *dataend;
72+#else /* HAVE_AVAHI */
73+ AvahiStringList *txt;
74+#endif /* HAVE_DNSSD */
75+} cups_txt_records_t;
76+
77
78 /*
79 * Local globals...
80@@ -77,6 +114,7 @@ static int job_canceled = 0;
81 * Local functions...
82 */
83
84+#ifdef HAVE_DNSSD
85 static void browse_callback(DNSServiceRef sdRef,
86 DNSServiceFlags flags,
87 uint32_t interfaceIndex,
88@@ -92,12 +130,6 @@ static void browse_local_callback(DNSSe
89 const char *regtype,
90 const char *replyDomain,
91 void *context);
92-static int compare_devices(cups_device_t *a, cups_device_t *b);
93-static void exec_backend(char **argv);
94-static cups_device_t *get_device(cups_array_t *devices,
95- const char *serviceName,
96- const char *regtype,
97- const char *replyDomain);
98 static void query_callback(DNSServiceRef sdRef,
99 DNSServiceFlags flags,
100 uint32_t interfaceIndex,
101@@ -106,9 +138,118 @@ static void query_callback(DNSServiceRe
102 uint16_t rrclass, uint16_t rdlen,
103 const void *rdata, uint32_t ttl,
104 void *context);
105+#endif /* HAVE_DNSSD */
106+#ifdef HAVE_AVAHI
107+static void avahi_client_callback (AvahiClient *client,
108+ AvahiClientState state,
109+ void *context);
110+static void avahi_browse_callback (AvahiServiceBrowser *browser,
111+ AvahiIfIndex interface,
112+ AvahiProtocol protocol,
113+ AvahiBrowserEvent event,
114+ const char *serviceName,
115+ const char *regtype,
116+ const char *replyDomain,
117+ AvahiLookupResultFlags flags,
118+ void *context);
119+#endif /* HAVE_AVAHI */
120+
121+static cups_device_t * find_device (cups_array_t *devices,
122+ cups_txt_records_t *txt,
123+ cups_device_t *dkey);
124+static int compare_devices(cups_device_t *a, cups_device_t *b);
125+static void exec_backend(char **argv);
126+static cups_device_t *get_device(cups_array_t *devices,
127+ const char *serviceName,
128+ const char *regtype,
129+ const char *replyDomain);
130 static void sigterm_handler(int sig);
131 static void unquote(char *dst, const char *src, size_t dstsize);
132
133+#ifdef HAVE_AVAHI
134+static AvahiSimplePoll *simple_poll = NULL;
135+static int avahi_got_callback;
136+#endif /* HAVE_AVAHI */
137+
138+
139+/*
140+ * 'next_txt_record()' - Get next TXT record from a cups_txt_records_t.
141+ */
142+
143+static cups_txt_records_t *
144+next_txt_record (cups_txt_records_t *txt)
145+{
146+#ifdef HAVE_DNSSD
147+ txt->data = txt->datanext;
148+#else /* HAVE_AVAHI */
149+ txt->txt = avahi_string_list_get_next (txt->txt);
150+ if (txt->txt == NULL)
151+ return NULL;
152+#endif /* HAVE_DNSSD */
153+
154+ return txt;
155+}
156+
157+
158+/*
159+ * 'parse_txt_record_pair()' - Read key/value pair in cups_txt_records_t.
160+ */
161+
162+static int
163+parse_txt_record_pair (cups_txt_records_t *txt)
164+{
165+#ifdef HAVE_DNSSD
166+ uint8_t datalen;
167+ uint8_t *data = txt->data;
168+ char *ptr;
169+
170+ /*
171+ * Read a key/value pair starting with an 8-bit length. Since the
172+ * length is 8 bits and the size of the key/value buffers is 256, we
173+ * don't need to check for overflow...
174+ */
175+
176+ datalen = *data++;
177+ if (!datalen || (data + datalen) >= txt->dataend)
178+ return NULL;
179+ txt->datanext = data + datalen;
180+
181+ for (ptr = txt->key; data < txt->datanext && *data != '='; data ++)
182+ *ptr++ = *data;
183+ *ptr = '\0';
184+
185+ if (data < txt->datanext && *data == '=')
186+ {
187+ data++;
188+
189+ if (data < datanext)
190+ memcpy (txt->value, data, txt->datanext - data);
191+ value[txt->datanext - data] = '\0';
192+ }
193+ else
194+ return 1;
195+#else /* HAVE_AVAHI */
196+ char *key, *value;
197+ size_t len;
198+ avahi_string_list_get_pair (txt->txt, &key, &value, &len);
199+ if (len > sizeof (txt->value) - 1)
200+ len = sizeof (txt->value) - 1;
201+
202+ memcpy (txt->value, value, len);
203+ txt->value[len] = '\0';
204+ len = strlen (key);
205+ if (len > sizeof (txt->key) - 1)
206+ len = sizeof (txt->key) - 1;
207+
208+ memcpy (txt->key, key, len);
209+ txt->key[len] = '\0';
210+ avahi_free (key);
211+ avahi_free (value);
212+#endif /* HAVE_AVAHI */
213+
214+ return 0;
215+}
216+
217
218 /*
219 * 'main()' - Browse for printers.
220@@ -119,6 +260,13 @@ main(int argc, /* I - Number of comm
221 char *argv[]) /* I - Command-line arguments */
222 {
223 const char *name; /* Backend name */
224+ cups_array_t *devices; /* Device array */
225+ cups_device_t *device; /* Current device */
226+ char uriName[1024]; /* Unquoted fullName for URI */
227+#ifdef HAVE_DNSSD
228+ int fd; /* Main file descriptor */
229+ fd_set input; /* Input set for select() */
230+ struct timeval timeout; /* Timeout for select() */
231 DNSServiceRef main_ref, /* Main service reference */
232 fax_ipp_ref, /* IPP fax service reference */
233 ipp_ref, /* IPP service reference */
234@@ -130,12 +278,11 @@ main(int argc, /* I - Number of comm
235 pdl_datastream_ref, /* AppSocket service reference */
236 printer_ref, /* LPD service reference */
237 riousbprint_ref; /* Remote IO service reference */
238- int fd; /* Main file descriptor */
239- fd_set input; /* Input set for select() */
240- struct timeval timeout; /* Timeout for select() */
241- cups_array_t *devices; /* Device array */
242- cups_device_t *device; /* Current device */
243- char uriName[1024]; /* Unquoted fullName for URI */
244+#endif /* HAVE_DNSSD */
245+#ifdef HAVE_AVAHI
246+ AvahiClient *client;
247+ int error;
248+#endif /* HAVE_AVAHI */
249 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
250 struct sigaction action; /* Actions for POSIX signals */
251 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
252@@ -194,6 +341,49 @@ main(int argc, /* I - Number of comm
253 * Browse for different kinds of printers...
254 */
255
256+#ifdef HAVE_AVAHI
257+ if ((simple_poll = avahi_simple_poll_new ()) == NULL)
258+ {
259+ perror ("ERROR: Unable to create avahi simple poll object");
260+ return (1);
261+ }
262+
263+ client = avahi_client_new (avahi_simple_poll_get (simple_poll),
264+ 0, avahi_client_callback, NULL, &error);
265+ if (!client)
266+ {
267+ perror ("ERROR: Unable to create avahi client");
268+ return (1);
269+ }
270+
271+ avahi_service_browser_new (client, AVAHI_IF_UNSPEC,
272+ AVAHI_PROTO_UNSPEC,
273+ "_fax-ipp._tcp", NULL, 0,
274+ avahi_browse_callback, devices);
275+ avahi_service_browser_new (client, AVAHI_IF_UNSPEC,
276+ AVAHI_PROTO_UNSPEC,
277+ "_ipp._tcp", NULL, 0,
278+ avahi_browse_callback, devices);
279+ avahi_service_browser_new (client, AVAHI_IF_UNSPEC,
280+ AVAHI_PROTO_UNSPEC,
281+ "_ipp-tls._tcp", NULL, 0,
282+ avahi_browse_callback, devices);
283+ avahi_service_browser_new (client, AVAHI_IF_UNSPEC,
284+ AVAHI_PROTO_UNSPEC,
285+ "_pdl-datastream._tcp",
286+ NULL, 0,
287+ avahi_browse_callback,
288+ devices);
289+ avahi_service_browser_new (client, AVAHI_IF_UNSPEC,
290+ AVAHI_PROTO_UNSPEC,
291+ "_printer._tcp", NULL, 0,
292+ avahi_browse_callback, devices);
293+ avahi_service_browser_new (client, AVAHI_IF_UNSPEC,
294+ AVAHI_PROTO_UNSPEC,
295+ "_riousbprint._tcp", NULL, 0,
296+ avahi_browse_callback, devices);
297+#endif /* HAVE_AVAHI */
298+#ifdef HAVE_DNSSD
299 if (DNSServiceCreateConnection(&main_ref) != kDNSServiceErr_NoError)
300 {
301 perror("ERROR: Unable to create service connection");
302@@ -245,6 +435,7 @@ main(int argc, /* I - Number of comm
303 riousbprint_ref = main_ref;
304 DNSServiceBrowse(&riousbprint_ref, kDNSServiceFlagsShareConnection, 0,
305 "_riousbprint._tcp", NULL, browse_callback, devices);
306+#endif /* HAVE_DNSSD */
307
308 /*
309 * Loop until we are killed...
310@@ -252,6 +443,9 @@ main(int argc, /* I - Number of comm
311
312 while (!job_canceled)
313 {
314+ int announce = 0;
315+
316+#ifdef HAVE_DNSSD
317 FD_ZERO(&input);
318 FD_SET(fd, &input);
319
320@@ -271,11 +465,35 @@ main(int argc, /* I - Number of comm
321 }
322 else
323 {
324+ announce = 1;
325+ }
326+#else /* HAVE_AVAHI */
327+ int r;
328+ avahi_got_callback = 0;
329+ r = avahi_simple_poll_iterate (simple_poll, 1);
330+ if (r != 0 && r != EINTR)
331+ {
332+ /*
333+ * We've been told to exit the loop. Perhaps the connection to
334+ * avahi failed.
335+ */
336+
337+ break;
338+ }
339+
340+ if (avahi_got_callback)
341+ announce = 1;
342+#endif /* HAVE_DNSSD */
343+
344+ if (announce)
345+ {
346 /*
347 * Announce any devices we've found...
348 */
349
350+#ifdef HAVE_DNSSD
351 DNSServiceErrorType status; /* DNS query status */
352+#endif /* HAVE_DNSSD */
353 cups_device_t *best; /* Best matching device */
354 char device_uri[1024]; /* Device URI */
355 int count; /* Number of queries */
356@@ -285,6 +503,7 @@ main(int argc, /* I - Number of comm
357 best = NULL, count = 0;
358 device;
359 device = (cups_device_t *)cupsArrayNext(devices))
360+#ifdef HAVE_DNSSD
361 if (!device->ref && !device->sent)
362 {
363 /*
364@@ -313,14 +532,23 @@ main(int argc, /* I - Number of comm
365 count ++;
366 }
367 }
368- else if (!device->sent)
369+ else
370+#endif /* HAVE_DNSSD */
371+#ifdef HAVE_AVAHI
372+ if (!device->resolved)
373+ continue;
374+ else
375+#endif /* HAVE_AVAHI */
376+ if (!device->sent)
377 {
378+#ifdef HAVE_DNSSD
379 /*
380 * Got the TXT records, now report the device...
381 */
382
383 DNSServiceRefDeallocate(device->ref);
384 device->ref = 0;
385+#endif /* HAVE_DNSSD */
386
387 if (!best)
388 best = device;
389@@ -368,6 +596,7 @@ main(int argc, /* I - Number of comm
390 }
391
392
393+#ifdef HAVE_DNSSD
394 /*
395 * 'browse_callback()' - Browse devices.
396 */
397@@ -456,6 +685,7 @@ browse_local_callback(
398 device->fullName);
399 device->sent = 1;
400 }
401+#endif /* HAVE_DNSSD */
402
403
404 /*
405@@ -530,6 +760,37 @@ exec_backend(char **argv) /* I - Comman
406
407
408 /*
409+ * 'device_type()' - Get DNS-SD type enumeration from string.
410+ */
411+
412+static int
413+device_type (const char *regtype)
414+{
415+#ifdef HAVE_AVAHI
416+ if (!strcmp(regtype, "_ipp._tcp") ||
417+ !strcmp(regtype, "_ipp-tls._tcp"))
418+ return (CUPS_DEVICE_IPP);
419+ else if (!strcmp(regtype, "_fax-ipp._tcp"))
420+ return (CUPS_DEVICE_FAX_IPP);
421+ else if (!strcmp(regtype, "_printer._tcp"))
422+ return (CUPS_DEVICE_PDL_DATASTREAM);
423+#else
424+ if (!strcmp(regtype, "_ipp._tcp.") ||
425+ !strcmp(regtype, "_ipp-tls._tcp."))
426+ return (CUPS_DEVICE_IPP);
427+ else if (!strcmp(regtype, "_fax-ipp._tcp."))
428+ return (CUPS_DEVICE_FAX_IPP);
429+ else if (!strcmp(regtype, "_printer._tcp."))
430+ return (CUPS_DEVICE_PRINTER);
431+ else if (!strcmp(regtype, "_pdl-datastream._tcp."))
432+ return (CUPS_DEVICE_PDL_DATASTREAM);
433+#endif /* HAVE_AVAHI */
434+
435+ return (CUPS_DEVICE_RIOUSBPRINT);
436+}
437+
438+
439+/*
440 * 'get_device()' - Create or update a device.
441 */
442
443@@ -550,18 +811,7 @@ get_device(cups_array_t *devices, /* I -
444 */
445
446 key.name = (char *)serviceName;
447-
448- if (!strcmp(regtype, "_ipp._tcp.") ||
449- !strcmp(regtype, "_ipp-tls._tcp."))
450- key.type = CUPS_DEVICE_IPP;
451- else if (!strcmp(regtype, "_fax-ipp._tcp."))
452- key.type = CUPS_DEVICE_FAX_IPP;
453- else if (!strcmp(regtype, "_printer._tcp."))
454- key.type = CUPS_DEVICE_PRINTER;
455- else if (!strcmp(regtype, "_pdl-datastream._tcp."))
456- key.type = CUPS_DEVICE_PDL_DATASTREAM;
457- else
458- key.type = CUPS_DEVICE_RIOUSBPRINT;
459+ key.type = device_type (regtype);
460
461 for (device = cupsArrayFind(devices, &key);
462 device;
463@@ -581,8 +831,14 @@ get_device(cups_array_t *devices, /* I -
464 free(device->domain);
465 device->domain = strdup(replyDomain);
466
467+#ifdef HAVE_DNSSD
468 DNSServiceConstructFullName(fullName, device->name, regtype,
469 replyDomain);
470+#else /* HAVE_AVAHI */
471+ avahi_service_name_join (fullName, kDNSServiceMaxDomainName,
472+ serviceName, regtype, replyDomain);
473+#endif /* HAVE_DNSSD */
474+
475 free(device->fullName);
476 device->fullName = strdup(fullName);
477 }
478@@ -602,6 +858,9 @@ get_device(cups_array_t *devices, /* I -
479 device->domain = strdup(replyDomain);
480 device->type = key.type;
481 device->priority = 50;
482+#ifdef HAVE_AVAHI
483+ device->resolved = 0;
484+#endif /* HAVE_AVAHI */
485
486 cupsArrayAdd(devices, device);
487
488@@ -609,13 +868,20 @@ get_device(cups_array_t *devices, /* I -
489 * Set the "full name" of this service, which is used for queries...
490 */
491
492+#ifdef HAVE_DNSSD
493 DNSServiceConstructFullName(fullName, serviceName, regtype, replyDomain);
494+#else /* HAVE_AVAHI */
495+ avahi_service_name_join (fullName, kDNSServiceMaxDomainName,
496+ serviceName, regtype, replyDomain);
497+#endif /* HAVE_DNSSD */
498+
499 device->fullName = strdup(fullName);
500
501 return (device);
502 }
503
504
505+#ifdef HAVE_DNSSD
506 /*
507 * 'query_callback()' - Process query data.
508 */
509@@ -639,7 +905,7 @@ query_callback(
510 *ptr; /* Pointer into string */
511 cups_device_t dkey, /* Search key */
512 *device; /* Device */
513-
514+ cups_txt_records_t txt;
515
516 fprintf(stderr, "DEBUG2: query_callback(sdRef=%p, flags=%x, "
517 "interfaceIndex=%d, errorCode=%d, fullName=\"%s\", "
518@@ -673,84 +939,232 @@ query_callback(
519 if ((ptr = strstr(name, "._")) != NULL)
520 *ptr = '\0';
521
522- if (strstr(fullName, "_ipp._tcp.") ||
523- strstr(fullName, "_ipp-tls._tcp."))
524- dkey.type = CUPS_DEVICE_IPP;
525- else if (strstr(fullName, "_fax-ipp._tcp."))
526- dkey.type = CUPS_DEVICE_FAX_IPP;
527- else if (strstr(fullName, "_printer._tcp."))
528- dkey.type = CUPS_DEVICE_PRINTER;
529- else if (strstr(fullName, "_pdl-datastream._tcp."))
530- dkey.type = CUPS_DEVICE_PDL_DATASTREAM;
531+ dkey.type = device_type (fullName);
532+
533+ txt.data = rdata;
534+ txt.dataend = rdata + rdlen;
535+ device = find_device ((cups_array_t *) context, &txt, &dkey);
536+ if (!device)
537+ fprintf(stderr, "DEBUG: Ignoring TXT record for \"%s\"...\n", fullName);
538+}
539+#endif /* HAVE_DNSSD */
540+
541+
542+#ifdef HAVE_AVAHI
543+/*
544+ * 'avahi_client_callback()' - Avahi client callback function.
545+ */
546+
547+static void
548+avahi_client_callback(AvahiClient *client,
549+ AvahiClientState state,
550+ void *context)
551+{
552+ /*
553+ * If the connection drops, quit.
554+ */
555+
556+ if (state == AVAHI_CLIENT_FAILURE)
557+ {
558+ fprintf (stderr, "ERROR: Avahi connection failed\n");
559+ avahi_simple_poll_quit (simple_poll);
560+ }
561+}
562+
563+
564+/*
565+ * 'avahi_query_callback()' - Avahi query callback function.
566+ */
567+
568+static void
569+avahi_query_callback(AvahiServiceResolver *resolver,
570+ AvahiIfIndex interface,
571+ AvahiProtocol protocol,
572+ AvahiResolverEvent event,
573+ const char *name,
574+ const char *type,
575+ const char *domain,
576+ const char *host_name,
577+ const AvahiAddress *address,
578+ uint16_t port,
579+ AvahiStringList *txt,
580+ AvahiLookupResultFlags flags,
581+ void *context)
582+{
583+ AvahiClient *client;
584+ cups_device_t key,
585+ *device;
586+ char uqname[1024],
587+ *ptr;
588+ cups_txt_records_t txtr;
589+
590+ client = avahi_service_resolver_get_client (resolver);
591+ if (event != AVAHI_RESOLVER_FOUND)
592+ {
593+ if (event == AVAHI_RESOLVER_FAILURE)
594+ {
595+ fprintf (stderr, "ERROR: %s\n",
596+ avahi_strerror (avahi_client_errno (client)));
597+ }
598+
599+ avahi_service_resolver_free (resolver);
600+ return;
601+ }
602+
603+ /*
604+ * Set search key for device.
605+ */
606+
607+ key.name = uqname;
608+ unquote (uqname, name, sizeof (uqname));
609+ if ((ptr = strstr(name, "._")) != NULL)
610+ *ptr = '\0';
611+
612+ key.domain = (char *) domain;
613+ key.type = device_type (type);
614+
615+ /*
616+ * Find the device and the the TXT information.
617+ */
618+
619+ txtr.txt = txt;
620+ device = find_device ((cups_array_t *) context, &txtr, &key);
621+ if (device)
622+ {
623+ /*
624+ * Let the main loop know to announce the device.
625+ */
626+
627+ device->resolved = 1;
628+ avahi_got_callback = 1;
629+ }
630 else
631- dkey.type = CUPS_DEVICE_RIOUSBPRINT;
632+ fprintf (stderr, "DEBUG: Ignoring TXT record for \"%s\"...\n", name);
633+
634+ avahi_service_resolver_free (resolver);
635+}
636+
637+
638+/*
639+ * 'avahi_browse_callback()' - Avahi browse callback function.
640+ */
641+
642+static void
643+avahi_browse_callback(AvahiServiceBrowser *browser,
644+ AvahiIfIndex interface,
645+ AvahiProtocol protocol,
646+ AvahiBrowserEvent event,
647+ const char *name,
648+ const char *type,
649+ const char *domain,
650+ AvahiLookupResultFlags flags,
651+ void *context)
652+{
653+ AvahiClient *client = avahi_service_browser_get_client (browser);
654
655- for (device = cupsArrayFind(devices, &dkey);
656+ switch (event)
657+ {
658+ case AVAHI_BROWSER_FAILURE:
659+ fprintf (stderr, "ERROR: %s\n",
660+ avahi_strerror (avahi_client_errno (client)));
661+ avahi_simple_poll_quit (simple_poll);
662+ return;
663+
664+ case AVAHI_BROWSER_NEW:
665+ /*
666+ * This object is new on the network.
667+ */
668+
669+ if (flags & AVAHI_LOOKUP_RESULT_LOCAL)
670+ {
671+ /*
672+ * This comes from the local machine so ignore it.
673+ */
674+
675+ fprintf (stderr, "DEBUG: ignoring local service %s\n", name);
676+ }
677+ else
678+ {
679+ /*
680+ * Create a device entry for it if it doesn't yet exist.
681+ */
682+
683+ get_device ((cups_array_t *)context, name, type, domain);
684+
685+ /*
686+ * Now look for a TXT entry.
687+ */
688+
689+ if (avahi_service_resolver_new (client, interface, protocol,
690+ name, type, domain,
691+ AVAHI_PROTO_UNSPEC, 0,
692+ avahi_query_callback, context) == NULL)
693+ {
694+ fprintf (stderr, "ERROR: failed to resolve service %s: %s\n",
695+ name, avahi_strerror (avahi_client_errno (client)));
696+ }
697+ }
698+
699+ break;
700+
701+ case AVAHI_BROWSER_REMOVE:
702+ case AVAHI_BROWSER_ALL_FOR_NOW:
703+ case AVAHI_BROWSER_CACHE_EXHAUSTED:
704+ break;
705+ }
706+}
707+#endif /* HAVE_AVAHI */
708+
709+
710+/*
711+ * 'find_device()' - Find a device from its name and domain.
712+ */
713+
714+static cups_device_t *
715+find_device (cups_array_t *devices,
716+ cups_txt_records_t *txt,
717+ cups_device_t *dkey)
718+{
719+ cups_device_t *device;
720+ char *ptr;
721+
722+ for (device = cupsArrayFind(devices, dkey);
723 device;
724 device = cupsArrayNext(devices))
725 {
726- if (strcasecmp(device->name, dkey.name) ||
727- strcasecmp(device->domain, dkey.domain))
728+ if (strcasecmp(device->name, dkey->name) ||
729+ strcasecmp(device->domain, dkey->domain))
730 {
731 device = NULL;
732 break;
733 }
734- else if (device->type == dkey.type)
735+ else if (device->type == dkey->type)
736 {
737 /*
738 * Found it, pull out the priority and make and model from the TXT
739 * record and save it...
740 */
741
742- const uint8_t *data, /* Pointer into data */
743- *datanext, /* Next key/value pair */
744- *dataend; /* End of entire TXT record */
745- uint8_t datalen; /* Length of current key/value pair */
746- char key[256], /* Key string */
747- value[256], /* Value string */
748- make_and_model[512],
749+ char make_and_model[512],
750 /* Manufacturer and model */
751 model[256], /* Model */
752- device_id[2048];/* 1284 device ID */
753-
754+ device_id[2048]; /* 1284 device ID */
755
756 device_id[0] = '\0';
757 make_and_model[0] = '\0';
758
759 strcpy(model, "Unknown");
760
761- for (data = rdata, dataend = data + rdlen;
762- data < dataend;
763- data = datanext)
764+ for (;;)
765 {
766- /*
767- * Read a key/value pair starting with an 8-bit length. Since the
768- * length is 8 bits and the size of the key/value buffers is 256, we
769- * don't need to check for overflow...
770- */
771-
772- datalen = *data++;
773-
774- if (!datalen || (data + datalen) >= dataend)
775- break;
776+ char *key;
777+ char *value;
778
779- datanext = data + datalen;
780-
781- for (ptr = key; data < datanext && *data != '='; data ++)
782- *ptr++ = *data;
783- *ptr = '\0';
784-
785- if (data < datanext && *data == '=')
786- {
787- data ++;
788-
789- if (data < datanext)
790- memcpy(value, data, datanext - data);
791- value[datanext - data] = '\0';
792- }
793- else
794- continue;
795+ if (parse_txt_record_pair (txt))
796+ goto next;
797
798+ key = txt->key;
799+ value = txt->value;
800 if (!strncasecmp(key, "usb_", 4))
801 {
802 /*
803@@ -805,6 +1219,10 @@ query_callback(
804 if (device->type == CUPS_DEVICE_PRINTER)
805 device->sent = 1;
806 }
807+
808+ next:
809+ if (next_txt_record (txt) == NULL)
810+ break;
811 }
812
813 if (device->device_id)
814@@ -861,11 +1279,9 @@ query_callback(
815 }
816 }
817
818- if (!device)
819- fprintf(stderr, "DEBUG: Ignoring TXT record for \"%s\"...\n", fullName);
820+ return device;
821 }
822
823-
824 /*
825 * 'sigterm_handler()' - Handle termination signals...
826 */
827diff -up cups-1.4.5/config.h.in.avahi cups-1.4.5/config.h.in
828--- cups-1.4.5/config.h.in.avahi 2010-08-13 05:11:46.000000000 +0100
829+++ cups-1.4.5/config.h.in 2010-12-24 13:11:38.327341170 +0000
830@@ -344,6 +344,13 @@
831
832
833 /*
834+ * Do we have Avahi for DNS Service Discovery?
835+ */
836+
837+#undef HAVE_AVAHI
838+
839+
840+/*
841 * Do we have <sys/ioctl.h>?
842 */
843
844diff -up cups-1.4.5/config-scripts/cups-dnssd.m4.avahi cups-1.4.5/config-scripts/cups-dnssd.m4
845--- cups-1.4.5/config-scripts/cups-dnssd.m4.avahi 2009-08-28 23:54:34.000000000 +0100
846+++ cups-1.4.5/config-scripts/cups-dnssd.m4 2010-12-24 13:11:38.326341199 +0000
847@@ -27,6 +27,21 @@ AC_ARG_WITH(dnssd-includes, [ --with-dn
848 DNSSDLIBS=""
849 DNSSD_BACKEND=""
850
851+AC_ARG_ENABLE(avahi, [ --enable-avahi turn on DNS Service Discovery support, default=no],
852+ [if test x$enable_avahi = xyes; then
853+ AC_MSG_CHECKING(for Avahi)
854+ if $PKGCONFIG --exists avahi-client; then
855+ AC_MSG_RESULT(yes)
856+ CFLAGS="$CFLAGS `$PKGCONFIG --cflags avahi-client`"
857+ DNSSDLIBS="`$PKGCONFIG --libs avahi-client`"
858+ DNSSD_BACKEND="dnssd"
859+ AC_DEFINE(HAVE_AVAHI)
860+ enable_dnssd=no
861+ else
862+ AC_MSG_RESULT(no)
863+ fi
864+ fi])
865+
866 if test x$enable_dnssd != xno; then
867 AC_CHECK_HEADER(dns_sd.h, [
868 case "$uname" in
869diff -up cups-1.4.5/cups/http-support.c.avahi cups-1.4.5/cups/http-support.c
870--- cups-1.4.5/cups/http-support.c.avahi 2010-10-01 23:40:38.000000000 +0100
871+++ cups-1.4.5/cups/http-support.c 2010-12-24 13:11:38.330341093 +0000
872@@ -41,6 +41,10 @@
873 * http_copy_decode() - Copy and decode a URI.
874 * http_copy_encode() - Copy and encode a URI.
875 * resolve_callback() - Build a device URI for the given service name.
876+ * avahi_resolve_uri_client_cb()
877+ * - Avahi client callback for resolving URI.
878+ * avahi_resolve_uri_resolver_cb()
879+ * - Avahi resolver callback for resolving URI.
880 */
881
882 /*
883@@ -55,6 +59,11 @@
884 # include <dns_sd.h>
885 # include <poll.h>
886 #endif /* HAVE_DNSSD */
887+#ifdef HAVE_AVAHI
888+# include <avahi-client/client.h>
889+# include <avahi-client/lookup.h>
890+# include <avahi-common/simple-watch.h>
891+#endif /* HAVE_AVAHI */
892
893
894 /*
895@@ -121,6 +130,24 @@ static void resolve_callback(DNSService
896 void *context);
897 #endif /* HAVE_DNSSD */
898
899+#ifdef HAVE_AVAHI
900+static void avahi_resolve_uri_client_cb(AvahiClient *client,
901+ AvahiClientState state,
902+ void *simple_poll);
903+static void avahi_resolve_uri_resolver_cb(AvahiServiceResolver *resolver,
904+ AvahiIfIndex interface,
905+ AvahiProtocol protocol,
906+ AvahiResolverEvent event,
907+ const char *name,
908+ const char *type,
909+ const char *domain,
910+ const char *host_name,
911+ const AvahiAddress *address,
912+ uint16_t port,
913+ AvahiStringList *txt,
914+ AvahiLookupResultFlags flags,
915+ void *context);
916+#endif /* HAVE_AVAHI */
917
918 /*
919 * 'httpAssembleURI()' - Assemble a uniform resource identifier from its
920@@ -1351,6 +1378,9 @@ _httpResolveURI(
921
922 if (strstr(hostname, "._tcp"))
923 {
924+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
925+ char *regtype, /* Pointer to type in hostname */
926+ *domain; /* Pointer to domain in hostname */
927 #ifdef HAVE_DNSSD
928 DNSServiceRef ref, /* DNS-SD master service reference */
929 domainref, /* DNS-SD service reference for domain */
930@@ -1361,6 +1391,16 @@ _httpResolveURI(
931 *domain; /* Pointer to domain in hostname */
932 _http_uribuf_t uribuf; /* URI buffer */
933 struct pollfd polldata; /* Polling data */
934+#else /* HAVE_AVAHI */
935+ AvahiSimplePoll *simple_poll;
936+ AvahiClient *client;
937+ int error;
938+ struct
939+ {
940+ AvahiSimplePoll *poll;
941+ _http_uribuf_t uribuf;
942+ } user_data;
943+#endif /* HAVE_DNSSD */
944
945
946 if (logit)
947@@ -1398,8 +1438,13 @@ _httpResolveURI(
948 if (domain)
949 *domain++ = '\0';
950
951+#ifdef HAVE_DNSSD
952 uribuf.buffer = resolved_uri;
953 uribuf.bufsize = resolved_size;
954+#else
955+ user_data.uribuf.buffer = resolved_uri;
956+ user_data.uribuf.bufsize = resolved_size;
957+#endif
958
959 resolved_uri[0] = '\0';
960
961@@ -1414,6 +1459,7 @@ _httpResolveURI(
962
963 uri = NULL;
964
965+#ifdef HAVE_DNSSD
966 if (DNSServiceCreateConnection(&ref) == kDNSServiceErr_NoError)
967 {
968 localref = ref;
969@@ -1500,6 +1546,36 @@ _httpResolveURI(
970
971 DNSServiceRefDeallocate(ref);
972 }
973+#else /* HAVE_AVAHI */
974+ if ((simple_poll = avahi_simple_poll_new ()) != NULL)
975+ {
976+ if ((client = avahi_client_new (avahi_simple_poll_get (simple_poll),
977+ 0, avahi_resolve_uri_client_cb,
978+ &simple_poll, &error)) != NULL)
979+ {
980+ user_data.poll = simple_poll;
981+ if (avahi_service_resolver_new (client, AVAHI_IF_UNSPEC,
982+ AVAHI_PROTO_UNSPEC, hostname,
983+ regtype, domain, AVAHI_PROTO_UNSPEC, 0,
984+ avahi_resolve_uri_resolver_cb,
985+ &user_data) != NULL)
986+ {
987+ avahi_simple_poll_loop (simple_poll);
988+
989+ /*
990+ * Collect the result.
991+ */
992+
993+ if (resolved_uri[0])
994+ uri = resolved_uri;
995+ }
996+
997+ avahi_client_free (client);
998+ }
999+
1000+ avahi_simple_poll_free (simple_poll);
1001+ }
1002+#endif /* HAVE_DNSSD */
1003
1004 if (logit)
1005 {
1006@@ -1511,13 +1587,13 @@ _httpResolveURI(
1007 fputs("STATE: -connecting-to-device,offline-report\n", stderr);
1008 }
1009
1010-#else
1011+#else /* HAVE_DNSSD || HAVE_AVAHI */
1012 /*
1013 * No DNS-SD support...
1014 */
1015
1016 uri = NULL;
1017-#endif /* HAVE_DNSSD */
1018+#endif /* HAVE_DNSSD || HAVE_AVAHI */
1019
1020 if (logit && !uri)
1021 _cupsLangPuts(stderr, _("Unable to find printer!\n"));
1022@@ -1723,6 +1799,116 @@ resolve_callback(
1023 #endif /* HAVE_DNSSD */
1024
1025
1026+#ifdef HAVE_AVAHI
1027+/*
1028+ * 'avahi_resolve_uri_client_cb()' - Avahi client callback for resolving URI.
1029+ */
1030+
1031+static void
1032+avahi_resolve_uri_client_cb (AvahiClient *client,
1033+ AvahiClientState state,
1034+ void *simple_poll)
1035+{
1036+ DEBUG_printf(("avahi_resolve_uri_client_callback(client=%p, state=%d, "
1037+ "simple_poll=%p)\n", client, state, simple_poll));
1038+
1039+ /*
1040+ * If the connection drops, quit.
1041+ */
1042+
1043+ if (state == AVAHI_CLIENT_FAILURE)
1044+ avahi_simple_poll_quit (simple_poll);
1045+}
1046+
1047+
1048+/*
1049+ * 'avahi_resolve_uri_resolver_cb()' - Avahi resolver callback for resolving
1050+ * URI.
1051+ */
1052+
1053+static void
1054+avahi_resolve_uri_resolver_cb (AvahiServiceResolver *resolver,
1055+ AvahiIfIndex interface,
1056+ AvahiProtocol protocol,
1057+ AvahiResolverEvent event,
1058+ const char *name,
1059+ const char *type,
1060+ const char *domain,
1061+ const char *host_name,
1062+ const AvahiAddress *address,
1063+ uint16_t port,
1064+ AvahiStringList *txt,
1065+ AvahiLookupResultFlags flags,
1066+ void *context)
1067+{
1068+ const char *scheme; /* URI scheme */
1069+ char rp[256]; /* Remote printer */
1070+ AvahiStringList *pair;
1071+ char *value;
1072+ size_t valueLen = 0;
1073+ char addr[AVAHI_ADDRESS_STR_MAX];
1074+ struct
1075+ {
1076+ AvahiSimplePoll *poll;
1077+ _http_uribuf_t uribuf;
1078+ } *poll_uribuf = context;
1079+
1080+ DEBUG_printf(("avahi_resolve_uri_resolver_callback(resolver=%p, "
1081+ "interface=%d, protocol=%d, event=%d, name=\"%s\", "
1082+ "type=\"%s\", domain=\"%s\", host_name=\"%s\", address=%p, "
1083+ "port=%d, txt=%p, flags=%d, context=%p)\n",
1084+ resolver, interface, protocol, event, name, type, domain,
1085+ host_name, address, port, txt, flags, context));
1086+
1087+ if (event != AVAHI_RESOLVER_FOUND)
1088+ {
1089+ avahi_service_resolver_free (resolver);
1090+ avahi_simple_poll_quit (poll_uribuf->poll);
1091+ return;
1092+ }
1093+
1094+ /*
1095+ * Figure out the scheme from the full name...
1096+ */
1097+
1098+ if (strstr(type, "_ipp."))
1099+ scheme = "ipp";
1100+ else if (strstr(type, "_printer."))
1101+ scheme = "lpd";
1102+ else if (strstr(type, "_pdl-datastream."))
1103+ scheme = "socket";
1104+ else
1105+ scheme = "riousbprint";
1106+
1107+ /*
1108+ * Extract the "remote printer key from the TXT record...
1109+ */
1110+
1111+ if ((pair = avahi_string_list_find (txt, "rp")) != NULL)
1112+ {
1113+ avahi_string_list_get_pair (pair, NULL, &value, &valueLen);
1114+ rp[0] = '/';
1115+ memcpy (rp + 1, value, valueLen);
1116+ rp[valueLen + 1] = '\0';
1117+ }
1118+ else
1119+ rp[0] = '\0';
1120+
1121+ /*
1122+ * Assemble the final device URI...
1123+ */
1124+
1125+ avahi_address_snprint (addr, AVAHI_ADDRESS_STR_MAX, address);
1126+ httpAssembleURI(HTTP_URI_CODING_ALL, poll_uribuf->uribuf.buffer,
1127+ poll_uribuf->uribuf.bufsize, scheme, NULL,
1128+ addr, port, rp);
1129+ DEBUG_printf(("avahi_resolve_uri_resolver_callback: Resolved URI is \"%s\"\n",
1130+ poll_uribuf->uribuf.buffer));
1131+ avahi_simple_poll_quit (poll_uribuf->poll);
1132+}
1133+#endif /* HAVE_AVAHI */
1134+
1135+
1136 /*
1137 * End of "$Id: http-support.c 9322 2010-10-01 22:40:38Z mike $".
1138 */
1139diff -up cups-1.4.5/scheduler/avahi.c.avahi cups-1.4.5/scheduler/avahi.c
1140--- cups-1.4.5/scheduler/avahi.c.avahi 2010-12-24 13:11:38.333341014 +0000
1141+++ cups-1.4.5/scheduler/avahi.c 2010-12-24 13:11:38.333341014 +0000
1142@@ -0,0 +1,441 @@
1143+/*
1144+ * "$Id$"
1145+ *
1146+ * Avahi poll implementation for the CUPS scheduler.
1147+ *
1148+ * Copyright (C) 2010 Red Hat, Inc.
1149+ * Authors:
1150+ * Tim Waugh <twaugh@redhat.com>
1151+ *
1152+ * Distribution and use rights are outlined in the file "LICENSE.txt"
1153+ * "LICENSE" which should have been included with this file. If this
1154+ * file is missing or damaged, see the license at "http://www.cups.org/".
1155+ *
1156+ * Contents:
1157+ *
1158+ * watch_read_cb - Read callback for file descriptor
1159+ * watch_write_cb - Write callback for file descriptor
1160+ * watched_fd_add_select() - Call cupsdAddSelect() as needed
1161+ * watch_new() - Create a new file descriptor watch
1162+ * watch_free() - Free a file descriptor watch
1163+ * watch_update() - Update watched events for a file descriptor
1164+ * watch_get_events() - Get events that happened for a file descriptor
1165+ * timeout_cb() - Run a timed Avahi callback
1166+ * timeout_new() - Set a wakeup time
1167+ * timeout_update() - Update the expiration time for a timeout
1168+ * timeout_free() - Free a timeout
1169+ * compare_watched_fds() - Compare watched file descriptors for array sorting
1170+ * compare_timeouts() - Compare timeouts for array sorting
1171+ * avahi_cups_poll_new() - Create a new Avahi main loop object for CUPS
1172+ * avahi_cups_poll_free() - Free an Avahi main loop object for CUPS
1173+ * avahi_cups_poll_get() - Get the abstract poll API structure
1174+ */
1175+
1176+#include <config.h>
1177+
1178+#ifdef HAVE_AVAHI /* Applies to entire file... */
1179+
1180+/*
1181+ * Include necessary headers...
1182+ */
1183+
1184+#include "cupsd.h"
1185+
1186+#if defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO)
1187+# include <malloc.h>
1188+#endif /* HAVE_MALLOC_H && HAVE_MALLINFO */
1189+
1190+#ifdef HAVE_AVAHI
1191+# include <avahi-common/timeval.h>
1192+#endif /* HAVE_AVAHI */
1193+
1194+
1195+typedef struct
1196+{
1197+ AvahiCupsPoll *cups_poll;
1198+
1199+ int fd;
1200+ AvahiWatchEvent occurred;
1201+ cups_array_t *watches;
1202+} cupsd_watched_fd_t;
1203+
1204+struct AvahiWatch
1205+{
1206+ cupsd_watched_fd_t *watched_fd;
1207+
1208+ AvahiWatchEvent events;
1209+ AvahiWatchCallback callback;
1210+ void *userdata;
1211+};
1212+
1213+struct AvahiTimeout
1214+{
1215+ AvahiCupsPoll *cups_poll;
1216+ AvahiTimeoutCallback callback;
1217+ void *userdata;
1218+ cupsd_timeout_t *cupsd_timeout;
1219+};
1220+
1221+/*
1222+ * Local functions...
1223+ */
1224+
1225+static AvahiWatch * watch_new(const AvahiPoll *api,
1226+ int fd,
1227+ AvahiWatchEvent events,
1228+ AvahiWatchCallback callback,
1229+ void *userdata);
1230+static void watch_free(AvahiWatch *watch);
1231+static void watch_update(AvahiWatch *watch,
1232+ AvahiWatchEvent events);
1233+static AvahiWatchEvent watch_get_events(AvahiWatch *watch);
1234+static int compare_watches(AvahiWatch *p0,
1235+ AvahiWatch *p1);
1236+
1237+
1238+/*
1239+ * 'watch_read_cb' - Read callback for file descriptor
1240+ */
1241+
1242+static void
1243+watch_read_cb (void *userdata)
1244+{
1245+ AvahiWatch *watch;
1246+ cupsd_watched_fd_t *watched_fd = userdata;
1247+ watched_fd->occurred |= AVAHI_WATCH_IN;
1248+ for (watch = (AvahiWatch *)cupsArrayFirst(watched_fd->watches);
1249+ watch;
1250+ watch = (AvahiWatch *)cupsArrayNext(watched_fd->watches)) {
1251+ if (watch->events & watched_fd->occurred) {
1252+ (watch->callback) (watch, watched_fd->fd,
1253+ AVAHI_WATCH_IN, watch->userdata);
1254+ watched_fd->occurred &= ~AVAHI_WATCH_IN;
1255+ break;
1256+ }
1257+ }
1258+}
1259+
1260+
1261+/*
1262+ * 'watch_write_cb' - Write callback for file descriptor
1263+ */
1264+
1265+static void
1266+watch_write_cb (void *userdata)
1267+{
1268+ AvahiWatch *watch;
1269+ cupsd_watched_fd_t *watched_fd = userdata;
1270+ watched_fd->occurred |= AVAHI_WATCH_OUT;
1271+ for (watch = (AvahiWatch *)cupsArrayFirst(watched_fd->watches);
1272+ watch;
1273+ watch = (AvahiWatch *)cupsArrayNext(watched_fd->watches)) {
1274+ if (watch->events & watched_fd->occurred) {
1275+ (watch->callback) (watch, watched_fd->fd,
1276+ AVAHI_WATCH_OUT, watch->userdata);
1277+ watched_fd->occurred &= ~AVAHI_WATCH_OUT;
1278+ break;
1279+ }
1280+ }
1281+}
1282+
1283+
1284+/*
1285+ * 'watched_fd_add_select' - Call cupsdAddSelect() as needed
1286+ */
1287+
1288+static int /* O - Watches? */
1289+watched_fd_add_select (cupsd_watched_fd_t *watched_fd)
1290+{
1291+ AvahiWatch *watch;
1292+ cupsd_selfunc_t read_cb = NULL, write_cb = NULL;
1293+
1294+ for (watch = (AvahiWatch *)cupsArrayFirst(watched_fd->watches);
1295+ watch;
1296+ watch = (AvahiWatch *)cupsArrayNext(watched_fd->watches)) {
1297+ if (watch->events & (AVAHI_WATCH_IN |
1298+ AVAHI_WATCH_ERR |
1299+ AVAHI_WATCH_HUP)) {
1300+ read_cb = (cupsd_selfunc_t)watch_read_cb;
1301+ if (write_cb != NULL)
1302+ break;
1303+ }
1304+
1305+ if (watch->events & AVAHI_WATCH_OUT) {
1306+ write_cb = (cupsd_selfunc_t)watch_write_cb;
1307+ if (read_cb != NULL)
1308+ break;
1309+ }
1310+ }
1311+
1312+ if (read_cb || write_cb)
1313+ cupsdAddSelect (watched_fd->fd, read_cb, write_cb, watched_fd);
1314+ else
1315+ cupsdRemoveSelect (watched_fd->fd);
1316+
1317+ return (read_cb || write_cb);
1318+}
1319+
1320+/*
1321+ * 'watch_new' - Create a new file descriptor watch
1322+ */
1323+
1324+static AvahiWatch *
1325+watch_new (const AvahiPoll *api,
1326+ int fd,
1327+ AvahiWatchEvent events,
1328+ AvahiWatchCallback callback,
1329+ void *userdata)
1330+{
1331+ cupsd_watched_fd_t key, *watched_fd;
1332+ AvahiCupsPoll *cups_poll = api->userdata;
1333+ AvahiWatch *watch = malloc(sizeof(AvahiWatch));
1334+ if (watch == NULL)
1335+ return (NULL);
1336+
1337+ watch->events = events;
1338+ watch->callback = callback;
1339+ watch->userdata = userdata;
1340+
1341+ key.fd = fd;
1342+ watched_fd = cupsArrayFind (cups_poll->watched_fds, &key);
1343+ if (watched_fd == NULL) {
1344+ watched_fd = malloc(sizeof(cupsd_watched_fd_t));
1345+ if (watched_fd == NULL)
1346+ return (NULL);
1347+
1348+ watched_fd->fd = fd;
1349+ watched_fd->occurred = 0;
1350+ watched_fd->watches = cupsArrayNew ((cups_array_func_t)compare_watches,
1351+ NULL);
1352+ }
1353+
1354+ cupsArrayAdd(watched_fd->watches, watch);
1355+ watched_fd_add_select (watched_fd);
1356+ return (watch);
1357+}
1358+
1359+
1360+/*
1361+ * 'watch_free' - Free a file descriptor watch
1362+ */
1363+
1364+static void
1365+watch_free (AvahiWatch *watch)
1366+{
1367+ cupsd_watched_fd_t *watched_fd = watch->watched_fd;
1368+ AvahiCupsPoll *cups_poll = watched_fd->cups_poll;
1369+
1370+ cupsArrayRemove (watched_fd->watches, watch);
1371+ free (watch);
1372+
1373+ if (!watched_fd_add_select (watched_fd)) {
1374+ /* No more watches */
1375+ cupsArrayRemove (cups_poll->watched_fds, watched_fd);
1376+ free (watched_fd);
1377+ }
1378+}
1379+
1380+
1381+/*
1382+ * 'watch_update' - Update watched events for a file descriptor
1383+ */
1384+
1385+static void
1386+watch_update (AvahiWatch *watch,
1387+ AvahiWatchEvent events)
1388+{
1389+ watch->events = events;
1390+ watched_fd_add_select (watch->watched_fd);
1391+}
1392+
1393+
1394+/*
1395+ * 'watch_get_events' - Get events that happened for a file descriptor
1396+ */
1397+
1398+static AvahiWatchEvent
1399+watch_get_events (AvahiWatch *watch)
1400+{
1401+ return (watch->watched_fd->occurred);
1402+}
1403+
1404+
1405+/*
1406+ * 'compare_watches' - Compare watches for array sorting
1407+ */
1408+
1409+static int
1410+compare_watches (AvahiWatch *p0,
1411+ AvahiWatch *p1)
1412+{
1413+ if (p0->watched_fd->fd < p1->watched_fd->fd)
1414+ return (-1);
1415+
1416+ return ((p0->watched_fd->fd == p1->watched_fd->fd) ? 0 : 1);
1417+}
1418+
1419+
1420+/*
1421+ * 'timeout_cb()' - Run a timed Avahi callback
1422+ */
1423+
1424+static void
1425+timeout_cb (cupsd_timeout_t *cupsd_timeout, void *userdata)
1426+{
1427+ AvahiTimeout *timeout = userdata;
1428+ (timeout->callback) (timeout, timeout->userdata);
1429+}
1430+
1431+
1432+/*
1433+ * 'timeout_new' - Set a wakeup time
1434+ */
1435+
1436+static AvahiTimeout *
1437+timeout_new (const AvahiPoll *api,
1438+ const struct timeval *tv,
1439+ AvahiTimeoutCallback callback,
1440+ void *userdata)
1441+{
1442+ AvahiTimeout *timeout;
1443+ AvahiCupsPoll *cups_poll = api->userdata;
1444+
1445+ timeout = malloc(sizeof(AvahiTimeout));
1446+ if (timeout == NULL)
1447+ return (NULL);
1448+
1449+ timeout->cups_poll = cups_poll;
1450+ timeout->callback = callback;
1451+ timeout->userdata = userdata;
1452+ timeout->cupsd_timeout = cupsdAddTimeout (tv,
1453+ (cupsd_timeoutfunc_t)timeout_cb,
1454+ timeout);
1455+ cupsArrayAdd (cups_poll->timeouts, timeout);
1456+ return (timeout);
1457+}
1458+
1459+
1460+/*
1461+ * 'timeout_update' - Update the expiration time for a timeout
1462+ */
1463+
1464+static void
1465+timeout_update (AvahiTimeout *timeout,
1466+ const struct timeval *tv)
1467+{
1468+ cupsdUpdateTimeout (timeout->cupsd_timeout, tv);
1469+}
1470+
1471+
1472+/*
1473+ * ' timeout_free' - Free a timeout
1474+ */
1475+
1476+static void
1477+timeout_free (AvahiTimeout *timeout)
1478+{
1479+ cupsArrayRemove (timeout->cups_poll->timeouts, timeout);
1480+ cupsdRemoveTimeout (timeout->cupsd_timeout);
1481+ free (timeout);
1482+}
1483+
1484+
1485+/*
1486+ * 'compare_watched_fds' - Compare watched file descriptors for array sorting
1487+ */
1488+static int
1489+compare_watched_fds(cupsd_watched_fd_t *p0,
1490+ cupsd_watched_fd_t *p1)
1491+{
1492+ if (p0->fd != p1->fd)
1493+ return (p0->fd < p1->fd ? -1 : 1);
1494+
1495+ if (p0 == p1)
1496+ return (0);
1497+
1498+ return (p0 < p1 ? -1 : 1);
1499+}
1500+
1501+
1502+/*
1503+ * 'compare_timeouts' - Compare timeouts for array sorting
1504+ */
1505+static int
1506+compare_timeouts(AvahiTimeout *p0,
1507+ AvahiTimeout *p1)
1508+{
1509+ /*
1510+ * Just compare pointers to make it a stable sort.
1511+ */
1512+
1513+ if (p0->cupsd_timeout < p1->cupsd_timeout)
1514+ return (-1);
1515+ return ((p0->cupsd_timeout == p1->cupsd_timeout) ? 0 : 1);
1516+}
1517+
1518+
1519+/*
1520+ * 'avahi_cups_poll_new' - Create a new Avahi main loop object for CUPS
1521+ */
1522+
1523+AvahiCupsPoll *
1524+avahi_cups_poll_new (void)
1525+{
1526+ AvahiCupsPoll *cups_poll = malloc(sizeof(AvahiCupsPoll));
1527+ if (cups_poll == NULL)
1528+ return (NULL);
1529+
1530+ cups_poll->watched_fds = cupsArrayNew ((cups_array_func_t)compare_watched_fds,
1531+ NULL);
1532+ cups_poll->timeouts = cupsArrayNew ((cups_array_func_t)compare_timeouts,
1533+ NULL);
1534+
1535+ cups_poll->api.userdata = cups_poll;
1536+ cups_poll->api.watch_new = watch_new;
1537+ cups_poll->api.watch_free = watch_free;
1538+ cups_poll->api.watch_update = watch_update;
1539+ cups_poll->api.watch_get_events = watch_get_events;
1540+
1541+ cups_poll->api.timeout_new = timeout_new;
1542+ cups_poll->api.timeout_update = timeout_update;
1543+ cups_poll->api.timeout_free = timeout_free;
1544+
1545+ return (cups_poll);
1546+}
1547+
1548+
1549+/*
1550+ * 'avahi_cups_poll_free' - Free an Avahi main loop object for CUPS
1551+ */
1552+void
1553+avahi_cups_poll_free (AvahiCupsPoll *cups_poll)
1554+{
1555+ cupsd_watched_fd_t *watched_fd;
1556+
1557+ for (watched_fd = (cupsd_watched_fd_t*)cupsArrayFirst(cups_poll->watched_fds);
1558+ watched_fd;
1559+ watched_fd = (cupsd_watched_fd_t*)cupsArrayNext(cups_poll->watched_fds)){
1560+ cupsArrayClear (watched_fd->watches);
1561+ }
1562+
1563+ cupsArrayClear (cups_poll->watched_fds);
1564+ cupsArrayClear (cups_poll->timeouts);
1565+}
1566+
1567+
1568+/*
1569+ * 'avahi_cups_poll_get' - Get the abstract poll API structure
1570+ */
1571+
1572+const AvahiPoll *
1573+avahi_cups_poll_get (AvahiCupsPoll *cups_poll)
1574+{
1575+ return (&cups_poll->api);
1576+}
1577+
1578+
1579+#endif /* HAVE_AVAHI ... from top of file */
1580+
1581+/*
1582+ * End of "$Id$".
1583+ */
1584diff -up cups-1.4.5/scheduler/avahi.h.avahi cups-1.4.5/scheduler/avahi.h
1585--- cups-1.4.5/scheduler/avahi.h.avahi 2010-12-24 13:11:38.334340988 +0000
1586+++ cups-1.4.5/scheduler/avahi.h 2010-12-24 13:11:38.334340988 +0000
1587@@ -0,0 +1,49 @@
1588+/*
1589+ * "$Id$"
1590+ *
1591+ * Avahi poll implementation for the CUPS scheduler.
1592+ *
1593+ * Copyright (C) 2010 Red Hat, Inc.
1594+ * Authors:
1595+ * Tim Waugh <twaugh@redhat.com>
1596+ *
1597+ * Distribution and use rights are outlined in the file "LICENSE.txt"
1598+ * which should have been included with this file. If this file is
1599+ * file is missing or damaged, see the license at "http://www.cups.org/".
1600+ */
1601+
1602+#include <config.h>
1603+
1604+#ifdef HAVE_AVAHI
1605+# include <avahi-client/client.h>
1606+# include <avahi-client/publish.h>
1607+#endif /* HAVE_AVAHI */
1608+
1609+#ifdef HAVE_AUTHORIZATION_H
1610+# include <Security/Authorization.h>
1611+#endif /* HAVE_AUTHORIZATION_H */
1612+
1613+
1614+#ifdef HAVE_AVAHI
1615+typedef struct
1616+{
1617+ AvahiPoll api;
1618+ cups_array_t *watched_fds;
1619+ cups_array_t *timeouts;
1620+} AvahiCupsPoll;
1621+#endif /* HAVE_AVAHI */
1622+
1623+/*
1624+ * Prototypes...
1625+ */
1626+
1627+#ifdef HAVE_AVAHI
1628+extern AvahiCupsPoll * avahi_cups_poll_new(void);
1629+extern void avahi_cups_poll_free(AvahiCupsPoll *cups_poll);
1630+extern const AvahiPoll *avahi_cups_poll_get(AvahiCupsPoll *cups_poll);
1631+#endif /* HAVE_AVAHI */
1632+
1633+
1634+/*
1635+ * End of "$Id$".
1636+ */
1637diff -up cups-1.4.5/scheduler/cupsd.h.avahi cups-1.4.5/scheduler/cupsd.h
1638--- cups-1.4.5/scheduler/cupsd.h.avahi 2010-09-21 23:34:57.000000000 +0100
1639+++ cups-1.4.5/scheduler/cupsd.h 2010-12-24 13:11:38.335340961 +0000
1640@@ -147,6 +147,15 @@ extern const char *cups_hstrerror(int);
1641
1642 typedef void (*cupsd_selfunc_t)(void *data);
1643
1644+#ifdef HAVE_AVAHI
1645+/*
1646+ * Timeout callback function type...
1647+ */
1648+
1649+typedef struct _cupsd_timeout_s cupsd_timeout_t;
1650+typedef void (*cupsd_timeoutfunc_t)(cupsd_timeout_t *timeout, void *data);
1651+#endif /* HAVE_AVAHI */
1652+
1653
1654 /*
1655 * Globals...
1656@@ -188,6 +197,9 @@ VAR PSQUpdateQuotaProcPtr PSQUpdateQuota
1657 /* Apple PrintService quota function */
1658 #endif /* __APPLE__ && HAVE_DLFCN_H */
1659
1660+#ifdef HAVE_AVAHI
1661+VAR cups_array_t *Timeouts; /* Timed callbacks for main loop */
1662+#endif /* HAVE_AVAHI */
1663
1664
1665
1666@@ -240,6 +252,18 @@ extern void cupsdRemoveSelect(int fd);
1667 extern void cupsdStartSelect(void);
1668 extern void cupsdStopSelect(void);
1669
1670+#ifdef HAVE_AVAHI
1671+extern void cupsdInitTimeouts(void);
1672+extern cupsd_timeout_t *cupsdAddTimeout (const struct timeval *tv,
1673+ cupsd_timeoutfunc_t cb,
1674+ void *data);
1675+extern cupsd_timeout_t *cupsdNextTimeout (long *delay);
1676+extern void cupsdRunTimeout (cupsd_timeout_t *timeout);
1677+extern void cupsdUpdateTimeout (cupsd_timeout_t *timeout,
1678+ const struct timeval *tv);
1679+extern void cupsdRemoveTimeout (cupsd_timeout_t *timeout);
1680+#endif /* HAVE_AVAHI */
1681+
1682 extern int cupsdRemoveFile(const char *filename);
1683
1684
1685diff -up cups-1.4.5/scheduler/dirsvc.c.avahi cups-1.4.5/scheduler/dirsvc.c
1686--- cups-1.4.5/scheduler/dirsvc.c.avahi 2010-12-24 13:11:33.679463507 +0000
1687+++ cups-1.4.5/scheduler/dirsvc.c 2010-12-24 13:11:38.343340751 +0000
1688@@ -99,6 +99,13 @@
1689 #endif /* HAVE_DNSSD */
1690
1691
1692+#ifdef HAVE_DNSSD
1693+typedef char *cupsd_txt_record_t;
1694+#endif /* HAVE_DNSSD */
1695+#ifdef HAVE_AVAHI
1696+typedef AvahiStringList *cupsd_txt_record_t;
1697+#endif /* HAVE_AVAHI */
1698+
1699 /*
1700 * Local functions...
1701 */
1702@@ -159,15 +166,20 @@ static void update_polling(void);
1703 static void update_smb(int onoff);
1704
1705
1706+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
1707+static cupsd_txt_record_t dnssdBuildTxtRecord(int *txt_len, cupsd_printer_t *p,
1708+ int for_lpd);
1709+static void dnssdDeregisterPrinter(cupsd_printer_t *p);
1710+static int dnssdComparePrinters(cupsd_printer_t *a, cupsd_printer_t *b);
1711+static void dnssdRegisterPrinter(cupsd_printer_t *p);
1712+static void dnssdStop(void);
1713+#endif /* defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */
1714+
1715 #ifdef HAVE_DNSSD
1716 # ifdef HAVE_COREFOUNDATION
1717 static void dnssdAddAlias(const void *key, const void *value,
1718 void *context);
1719 # endif /* HAVE_COREFOUNDATION */
1720-static char *dnssdBuildTxtRecord(int *txt_len, cupsd_printer_t *p,
1721- int for_lpd);
1722-static int dnssdComparePrinters(cupsd_printer_t *a, cupsd_printer_t *b);
1723-static void dnssdDeregisterPrinter(cupsd_printer_t *p);
1724 static char *dnssdPackTxtRecord(int *txt_len, char *keyvalue[][2],
1725 int count);
1726 static void dnssdRegisterCallback(DNSServiceRef sdRef,
1727@@ -175,11 +187,20 @@ static void dnssdRegisterCallback(DNSSer
1728 DNSServiceErrorType errorCode,
1729 const char *name, const char *regtype,
1730 const char *domain, void *context);
1731-static void dnssdRegisterPrinter(cupsd_printer_t *p);
1732-static void dnssdStop(void);
1733 static void dnssdUpdate(void);
1734 #endif /* HAVE_DNSSD */
1735
1736+#ifdef HAVE_AVAHI
1737+static AvahiStringList *avahiPackTxtRecord(char *keyvalue[][2],
1738+ int count);
1739+static void avahi_entry_group_cb (AvahiEntryGroup *group,
1740+ AvahiEntryGroupState state,
1741+ void *userdata);
1742+static void avahi_client_cb (AvahiClient *client,
1743+ AvahiClientState state,
1744+ void *userdata);
1745+#endif /* HAVE_AVAHI */
1746+
1747 #ifdef HAVE_LDAP
1748 static const char * const ldap_attrs[] =/* CUPS LDAP attributes */
1749 {
1750@@ -283,10 +304,10 @@ cupsdDeregisterPrinter(
1751 ldap_dereg_printer(p);
1752 #endif /* HAVE_LDAP */
1753
1754-#ifdef HAVE_DNSSD
1755- if (removeit && (BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDRef)
1756+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
1757+ if (removeit && (BrowseLocalProtocols & BROWSE_DNSSD))
1758 dnssdDeregisterPrinter(p);
1759-#endif /* HAVE_DNSSD */
1760+#endif /* defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */
1761 }
1762
1763
1764@@ -694,10 +715,10 @@ cupsdRegisterPrinter(cupsd_printer_t *p)
1765 slpRegisterPrinter(p); */
1766 #endif /* HAVE_LIBSLP */
1767
1768-#ifdef HAVE_DNSSD
1769- if ((BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDRef)
1770+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
1771+ if ((BrowseLocalProtocols & BROWSE_DNSSD))
1772 dnssdRegisterPrinter(p);
1773-#endif /* HAVE_DNSSD */
1774+#endif /* defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */
1775 }
1776
1777
1778@@ -1535,13 +1556,16 @@ cupsdStartBrowsing(void)
1779 else
1780 BrowseSocket = -1;
1781
1782-#ifdef HAVE_DNSSD
1783+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
1784 if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_DNSSD)
1785 {
1786+#ifdef HAVE_DNSSD
1787 DNSServiceErrorType error; /* Error from service creation */
1788+#endif /* HAVE_DNSSD */
1789 cupsd_listener_t *lis; /* Current listening socket */
1790
1791
1792+#ifdef HAVE_DNSSD
1793 /*
1794 * First create a "master" connection for all registrations...
1795 */
1796@@ -1566,6 +1590,7 @@ cupsdStartBrowsing(void)
1797 fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
1798
1799 cupsdAddSelect(fd, (cupsd_selfunc_t)dnssdUpdate, NULL, NULL);
1800+#endif /* HAVE_DNSSD */
1801
1802 /*
1803 * Then get the port we use for registrations. If we are not listening
1804@@ -1607,9 +1632,20 @@ cupsdStartBrowsing(void)
1805 */
1806
1807 cupsdUpdateDNSSDName();
1808+#ifdef HAVE_DNSSD
1809 }
1810- }
1811 #endif /* HAVE_DNSSD */
1812+ }
1813+#endif /* defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */
1814+
1815+#ifdef HAVE_AVAHI
1816+ if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_DNSSD)
1817+ {
1818+ AvahiCupsPollHandle = avahi_cups_poll_new ();
1819+ avahi_client_new (avahi_cups_poll_get (AvahiCupsPollHandle),
1820+ 0, avahi_client_cb, NULL, NULL);
1821+ }
1822+#endif /* HAVE_AVAHI */
1823
1824 #ifdef HAVE_LIBSLP
1825 if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP)
1826@@ -1835,10 +1871,10 @@ cupsdStopBrowsing(void)
1827 BrowseSocket = -1;
1828 }
1829
1830-#ifdef HAVE_DNSSD
1831- if ((BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDRef)
1832+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
1833+ if ((BrowseLocalProtocols & BROWSE_DNSSD))
1834 dnssdStop();
1835-#endif /* HAVE_DNSSD */
1836+#endif /* defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */
1837
1838 #ifdef HAVE_LIBSLP
1839 if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP) &&
1840@@ -1903,7 +1939,7 @@ cupsdStopPolling(void)
1841 }
1842
1843
1844-#ifdef HAVE_DNSSD
1845+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
1846 /*
1847 * 'cupsdUpdateDNSSDName()' - Update the computer name we use for browsing...
1848 */
1849@@ -1911,7 +1947,12 @@ cupsdStopPolling(void)
1850 void
1851 cupsdUpdateDNSSDName(void)
1852 {
1853+#ifdef HAVE_DNSSD
1854 DNSServiceErrorType error; /* Error from service creation */
1855+#endif /* HAVE_DNSSD */
1856+#ifdef HAVE_AVAHI
1857+ int ret; /* Error from service creation */
1858+#endif /* HAVE_AVAHI */
1859 char webif[1024]; /* Web interface share name */
1860 #ifdef HAVE_COREFOUNDATION_H
1861 SCDynamicStoreRef sc; /* Context for dynamic store */
1862@@ -2043,6 +2084,7 @@ cupsdUpdateDNSSDName(void)
1863 else
1864 strlcpy(webif, "CUPS Web Interface", sizeof(webif));
1865
1866+#ifdef HAVE_DNSSD
1867 if (WebIFRef)
1868 DNSServiceRefDeallocate(WebIFRef);
1869
1870@@ -2055,6 +2097,42 @@ cupsdUpdateDNSSDName(void)
1871 NULL)) != kDNSServiceErr_NoError)
1872 cupsdLogMessage(CUPSD_LOG_ERROR,
1873 "DNS-SD web interface registration failed: %d", error);
1874+#endif /* HAVE_DNSSD */
1875+
1876+#ifdef HAVE_AVAHI
1877+ if (!AvahiCupsClient)
1878+ /*
1879+ * Client not yet running.
1880+ */
1881+ return;
1882+
1883+ if (AvahiWebIFGroup)
1884+ avahi_entry_group_reset (AvahiWebIFGroup);
1885+ else
1886+ AvahiWebIFGroup = avahi_entry_group_new (AvahiCupsClient,
1887+ avahi_entry_group_cb,
1888+ NULL);
1889+
1890+ if (AvahiWebIFGroup)
1891+ {
1892+ ret = avahi_entry_group_add_service (AvahiWebIFGroup,
1893+ AVAHI_IF_UNSPEC,
1894+ AVAHI_PROTO_UNSPEC,
1895+ 0, /* flags */
1896+ webif, /* name */
1897+ "_http._tcp", /* type */
1898+ NULL, /* domain */
1899+ NULL, /* host */
1900+ htons(DNSSDPort), /* port */
1901+ "path=/", NULL);
1902+ if (ret == 0)
1903+ ret = avahi_entry_group_commit (AvahiWebIFGroup);
1904+
1905+ if (ret != 0)
1906+ cupsdLogMessage (CUPSD_LOG_ERROR,
1907+ "Avahi web interface registration failed: %d", ret);
1908+ }
1909+#endif /* HAVE_AVAHI */
1910 }
1911 }
1912 #endif /* HAVE_DNSSD */
1913@@ -2300,162 +2378,7 @@ dequote(char *d, /* I - Destinat
1914 }
1915
1916
1917-#ifdef HAVE_DNSSD
1918-# ifdef HAVE_COREFOUNDATION
1919-/*
1920- * 'dnssdAddAlias()' - Add a DNS-SD alias name.
1921- */
1922-
1923-static void
1924-dnssdAddAlias(const void *key, /* I - Key */
1925- const void *value, /* I - Value (domain) */
1926- void *context) /* I - Unused */
1927-{
1928- char valueStr[1024], /* Domain string */
1929- hostname[1024]; /* Complete hostname */
1930-
1931-
1932- (void)context;
1933-
1934- if (CFGetTypeID((CFStringRef)value) == CFStringGetTypeID() &&
1935- CFStringGetCString((CFStringRef)value, valueStr, sizeof(valueStr),
1936- kCFStringEncodingUTF8))
1937- {
1938- snprintf(hostname, sizeof(hostname), "%s.%s", DNSSDHostName, valueStr);
1939- if (!DNSSDAlias)
1940- DNSSDAlias = cupsArrayNew(NULL, NULL);
1941-
1942- cupsdAddAlias(DNSSDAlias, hostname);
1943- cupsdLogMessage(CUPSD_LOG_DEBUG, "Added Back to My Mac ServerAlias %s",
1944- hostname);
1945- }
1946- else
1947- cupsdLogMessage(CUPSD_LOG_ERROR,
1948- "Bad Back to My Mac domain in dynamic store!");
1949-}
1950-# endif /* HAVE_COREFOUNDATION */
1951-
1952-
1953-/*
1954- * 'dnssdBuildTxtRecord()' - Build a TXT record from printer info.
1955- */
1956-
1957-static char * /* O - TXT record */
1958-dnssdBuildTxtRecord(
1959- int *txt_len, /* O - TXT record length */
1960- cupsd_printer_t *p, /* I - Printer information */
1961- int for_lpd) /* I - 1 = LPD, 0 = IPP */
1962-{
1963- int i; /* Looping var */
1964- char adminurl_str[256], /* URL for th admin page */
1965- type_str[32], /* Type to string buffer */
1966- state_str[32], /* State to string buffer */
1967- rp_str[1024], /* Queue name string buffer */
1968- air_str[1024], /* auth-info-required string buffer */
1969- *keyvalue[32][2]; /* Table of key/value pairs */
1970-
1971-
1972- /*
1973- * Load up the key value pairs...
1974- */
1975-
1976- i = 0;
1977-
1978- keyvalue[i ][0] = "txtvers";
1979- keyvalue[i++][1] = "1";
1980-
1981- keyvalue[i ][0] = "qtotal";
1982- keyvalue[i++][1] = "1";
1983-
1984- keyvalue[i ][0] = "rp";
1985- keyvalue[i++][1] = rp_str;
1986- if (for_lpd)
1987- strlcpy(rp_str, p->name, sizeof(rp_str));
1988- else
1989- snprintf(rp_str, sizeof(rp_str), "%s/%s",
1990- (p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers", p->name);
1991-
1992- keyvalue[i ][0] = "ty";
1993- keyvalue[i++][1] = p->make_model ? p->make_model : "Unknown";
1994-
1995- httpAssembleURIf(HTTP_URI_CODING_ALL, adminurl_str, sizeof(adminurl_str),
1996- "http", NULL, DNSSDHostName, DNSSDPort, "/%s/%s",
1997- (p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers",
1998- p->name);
1999- keyvalue[i ][0] = "adminurl";
2000- keyvalue[i++][1] = adminurl_str;
2001-
2002- keyvalue[i ][0] = "note";
2003- keyvalue[i++][1] = p->location ? p->location : "";
2004-
2005- keyvalue[i ][0] = "priority";
2006- keyvalue[i++][1] = for_lpd ? "100" : "0";
2007-
2008- keyvalue[i ][0] = "product";
2009- keyvalue[i++][1] = p->product ? p->product : "Unknown";
2010-
2011- snprintf(type_str, sizeof(type_str), "0x%X", p->type | CUPS_PRINTER_REMOTE);
2012- snprintf(state_str, sizeof(state_str), "%d", p->state);
2013-
2014- keyvalue[i ][0] = "printer-state";
2015- keyvalue[i++][1] = state_str;
2016-
2017- keyvalue[i ][0] = "printer-type";
2018- keyvalue[i++][1] = type_str;
2019-
2020- keyvalue[i ][0] = "Transparent";
2021- keyvalue[i++][1] = "T";
2022-
2023- keyvalue[i ][0] = "Binary";
2024- keyvalue[i++][1] = "T";
2025-
2026- keyvalue[i ][0] = "Fax";
2027- keyvalue[i++][1] = (p->type & CUPS_PRINTER_FAX) ? "T" : "F";
2028-
2029- keyvalue[i ][0] = "Color";
2030- keyvalue[i++][1] = (p->type & CUPS_PRINTER_COLOR) ? "T" : "F";
2031-
2032- keyvalue[i ][0] = "Duplex";
2033- keyvalue[i++][1] = (p->type & CUPS_PRINTER_DUPLEX) ? "T" : "F";
2034-
2035- keyvalue[i ][0] = "Staple";
2036- keyvalue[i++][1] = (p->type & CUPS_PRINTER_STAPLE) ? "T" : "F";
2037-
2038- keyvalue[i ][0] = "Copies";
2039- keyvalue[i++][1] = (p->type & CUPS_PRINTER_COPIES) ? "T" : "F";
2040-
2041- keyvalue[i ][0] = "Collate";
2042- keyvalue[i++][1] = (p->type & CUPS_PRINTER_COLLATE) ? "T" : "F";
2043-
2044- keyvalue[i ][0] = "Punch";
2045- keyvalue[i++][1] = (p->type & CUPS_PRINTER_PUNCH) ? "T" : "F";
2046-
2047- keyvalue[i ][0] = "Bind";
2048- keyvalue[i++][1] = (p->type & CUPS_PRINTER_BIND) ? "T" : "F";
2049-
2050- keyvalue[i ][0] = "Sort";
2051- keyvalue[i++][1] = (p->type & CUPS_PRINTER_SORT) ? "T" : "F";
2052-
2053- keyvalue[i ][0] = "Scan";
2054- keyvalue[i++][1] = (p->type & CUPS_PRINTER_MFP) ? "T" : "F";
2055-
2056- keyvalue[i ][0] = "pdl";
2057- keyvalue[i++][1] = p->pdl ? p->pdl : "application/postscript";
2058-
2059- if (get_auth_info_required(p, air_str, sizeof(air_str)))
2060- {
2061- keyvalue[i ][0] = "air";
2062- keyvalue[i++][1] = air_str;
2063- }
2064-
2065- /*
2066- * Then pack them into a proper txt record...
2067- */
2068-
2069- return (dnssdPackTxtRecord(txt_len, keyvalue, i));
2070-}
2071-
2072-
2073+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
2074 /*
2075 * 'dnssdComparePrinters()' - Compare the registered names of two printers.
2076 */
2077@@ -2479,6 +2402,10 @@ dnssdDeregisterPrinter(
2078 {
2079 cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdDeregisterPrinter(%s)", p->name);
2080
2081+#ifdef HAVE_DNSSD
2082+ if (!DNSSDRef)
2083+ return;
2084+
2085 /*
2086 * Closing the socket deregisters the service
2087 */
2088@@ -2514,6 +2441,23 @@ dnssdDeregisterPrinter(
2089 free(p->printer_txt);
2090 p->printer_txt = NULL;
2091 }
2092+#endif /* HAVE_DNSSD */
2093+#ifdef HAVE_AVAHI
2094+ if (p->avahi_group)
2095+ {
2096+ avahi_entry_group_reset (p->avahi_group);
2097+ avahi_entry_group_free (p->avahi_group);
2098+ p->avahi_group = NULL;
2099+
2100+ if (p->ipp_txt)
2101+ avahi_string_list_free (p->ipp_txt);
2102+
2103+ if (p->printer_txt)
2104+ avahi_string_list_free (p->printer_txt);
2105+
2106+ p->ipp_txt = p->printer_txt = NULL;
2107+ }
2108+#endif /* HAVE_AVAHI */
2109
2110 /*
2111 * Remove the printer from the array of DNS-SD printers, then clear the
2112@@ -2526,140 +2470,53 @@ dnssdDeregisterPrinter(
2113
2114
2115 /*
2116- * 'dnssdPackTxtRecord()' - Pack an array of key/value pairs into the
2117- * TXT record format.
2118+ * 'dnssdRegisterPrinter()' - Start sending broadcast information for a printer
2119+ * or update the broadcast contents.
2120 */
2121
2122-static char * /* O - TXT record */
2123-dnssdPackTxtRecord(int *txt_len, /* O - TXT record length */
2124- char *keyvalue[][2], /* I - Table of key value pairs */
2125- int count) /* I - Items in table */
2126+static void
2127+dnssdRegisterPrinter(cupsd_printer_t *p)/* I - Printer */
2128 {
2129- int i; /* Looping var */
2130- int length; /* Length of TXT record */
2131- int length2; /* Length of value */
2132- char *txtRecord; /* TXT record buffer */
2133- char *cursor; /* Looping pointer */
2134+#ifdef HAVE_DNSSD
2135+ DNSServiceErrorType se; /* dnssd errors */
2136+ char *ipp_txt, /* IPP TXT record buffer */
2137+ *printer_txt, /* LPD TXT record buffer */
2138+ *nameptr; /* Pointer into name */
2139+ int ipp_len, /* IPP TXT record length */
2140+ printer_len; /* LPD TXT record length */
2141+#endif /* HAVE_DNSSD */
2142+#ifdef HAVE_AVAHI
2143+ int ret; /* Error code */
2144+ AvahiStringList *ipp_txt, /* IPP TXT record list */
2145+ *printer_txt; /* LPD TXT record buffer */
2146+#endif /* HAVE_AVAHI */
2147+ char name[1024]; /* Service name */
2148+ const char *regtype; /* Registration type */
2149
2150
2151- /*
2152- * Calculate the buffer size
2153- */
2154+#ifdef HAVE_DNSSD
2155+ if (!DNSSDRef)
2156+ return;
2157
2158- for (length = i = 0; i < count; i++)
2159- length += 1 + strlen(keyvalue[i][0]) +
2160- (keyvalue[i][1] ? 1 + strlen(keyvalue[i][1]) : 0);
2161+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterPrinter(%s) %s", p->name,
2162+ !p->ipp_ref ? "new" : "update");
2163+
2164+#endif /* HAVE_DNSSD */
2165+#ifdef HAVE_AVAHI
2166+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterPrinter(%s) %s", p->name,
2167+ !p->avahi_group ? "new" : "update");
2168+#endif /* HAVE_AVAHI */
2169
2170 /*
2171- * Allocate and fill it
2172+ * If per-printer sharing was just disabled make sure we're not
2173+ * registered before returning.
2174 */
2175
2176- txtRecord = malloc(length);
2177- if (txtRecord)
2178+ if (!p->shared)
2179 {
2180- *txt_len = length;
2181-
2182- for (cursor = txtRecord, i = 0; i < count; i++)
2183- {
2184- /*
2185- * Drop in the p-string style length byte followed by the data
2186- */
2187-
2188- length = strlen(keyvalue[i][0]);
2189- length2 = keyvalue[i][1] ? 1 + strlen(keyvalue[i][1]) : 0;
2190-
2191- *cursor++ = (unsigned char)(length + length2);
2192-
2193- memcpy(cursor, keyvalue[i][0], length);
2194- cursor += length;
2195-
2196- if (length2)
2197- {
2198- length2 --;
2199- *cursor++ = '=';
2200- memcpy(cursor, keyvalue[i][1], length2);
2201- cursor += length2;
2202- }
2203- }
2204- }
2205-
2206- return (txtRecord);
2207-}
2208-
2209-
2210-/*
2211- * 'dnssdRegisterCallback()' - DNSServiceRegister callback.
2212- */
2213-
2214-static void
2215-dnssdRegisterCallback(
2216- DNSServiceRef sdRef, /* I - DNS Service reference */
2217- DNSServiceFlags flags, /* I - Reserved for future use */
2218- DNSServiceErrorType errorCode, /* I - Error code */
2219- const char *name, /* I - Service name */
2220- const char *regtype, /* I - Service type */
2221- const char *domain, /* I - Domain. ".local" for now */
2222- void *context) /* I - User-defined context */
2223-{
2224- cupsd_printer_t *p = (cupsd_printer_t *)context;
2225- /* Current printer */
2226-
2227-
2228- cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterCallback(%s, %s) for %s (%s)",
2229- name, regtype, p ? p->name : "Web Interface",
2230- p ? (p->reg_name ? p->reg_name : "(null)") : "NA");
2231-
2232- if (errorCode)
2233- {
2234- cupsdLogMessage(CUPSD_LOG_ERROR,
2235- "DNSServiceRegister failed with error %d", (int)errorCode);
2236- return;
2237- }
2238- else if (p && (!p->reg_name || strcasecmp(name, p->reg_name)))
2239- {
2240- cupsdLogMessage(CUPSD_LOG_INFO, "Using service name \"%s\" for \"%s\"",
2241- name, p->name);
2242-
2243- cupsArrayRemove(DNSSDPrinters, p);
2244- cupsdSetString(&p->reg_name, name);
2245- cupsArrayAdd(DNSSDPrinters, p);
2246-
2247- LastEvent |= CUPSD_EVENT_PRINTER_MODIFIED;
2248- }
2249-}
2250-
2251-
2252-/*
2253- * 'dnssdRegisterPrinter()' - Start sending broadcast information for a printer
2254- * or update the broadcast contents.
2255- */
2256-
2257-static void
2258-dnssdRegisterPrinter(cupsd_printer_t *p)/* I - Printer */
2259-{
2260- DNSServiceErrorType se; /* dnssd errors */
2261- char *ipp_txt, /* IPP TXT record buffer */
2262- *printer_txt, /* LPD TXT record buffer */
2263- name[1024], /* Service name */
2264- *nameptr; /* Pointer into name */
2265- int ipp_len, /* IPP TXT record length */
2266- printer_len; /* LPD TXT record length */
2267- const char *regtype; /* Registration type */
2268-
2269-
2270- cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterPrinter(%s) %s", p->name,
2271- !p->ipp_ref ? "new" : "update");
2272-
2273- /*
2274- * If per-printer sharing was just disabled make sure we're not
2275- * registered before returning.
2276- */
2277-
2278- if (!p->shared)
2279- {
2280- dnssdDeregisterPrinter(p);
2281- return;
2282- }
2283+ dnssdDeregisterPrinter(p);
2284+ return;
2285+ }
2286
2287 /*
2288 * The registered name takes the form of "<printer-info> @ <computer name>"...
2289@@ -2694,6 +2551,7 @@ dnssdRegisterPrinter(cupsd_printer_t *p)
2290 * Register IPP and (optionally) LPD...
2291 */
2292
2293+#ifdef HAVE_DNSSD
2294 ipp_len = 0; /* anti-compiler-warning-code */
2295 ipp_txt = dnssdBuildTxtRecord(&ipp_len, p, 0);
2296
2297@@ -2860,6 +2718,140 @@ dnssdRegisterPrinter(cupsd_printer_t *p)
2298 if (printer_txt)
2299 free(printer_txt);
2300 }
2301+#endif /* HAVE_DNSSD */
2302+#ifdef HAVE_AVAHI
2303+ if (!AvahiCupsClient)
2304+ /*
2305+ * Client not running yet. The client callback will call us again later.
2306+ */
2307+ return;
2308+
2309+ ipp_txt = dnssdBuildTxtRecord(NULL, p, 0);
2310+ printer_txt = dnssdBuildTxtRecord(NULL, p, 1);
2311+ regtype = (p->type & CUPS_PRINTER_FAX) ? "_fax-ipp._tcp" : "_ipp._tcp";
2312+
2313+ if (p->avahi_group && p->ipp_txt && ipp_txt &&
2314+ !avahi_string_list_equal (p->ipp_txt, ipp_txt))
2315+ {
2316+ /*
2317+ * Update the existing registration...
2318+ */
2319+
2320+ avahi_string_list_free (p->ipp_txt);
2321+
2322+ if (p->printer_txt)
2323+ avahi_string_list_free (p->printer_txt);
2324+
2325+ ret = avahi_entry_group_update_service_txt_strlst (p->avahi_group,
2326+ AVAHI_IF_UNSPEC,
2327+ AVAHI_PROTO_UNSPEC,
2328+ 0, name, regtype, NULL,
2329+ ipp_txt);
2330+ if (ret < 0)
2331+ goto update_failed;
2332+
2333+ p->ipp_txt = ipp_txt;
2334+ ipp_txt = NULL;
2335+
2336+ if (BrowseLocalProtocols & BROWSE_LPD)
2337+ {
2338+ ret = avahi_entry_group_update_service_txt_strlst (p->avahi_group,
2339+ AVAHI_IF_UNSPEC,
2340+ AVAHI_PROTO_UNSPEC,
2341+ 0, name,
2342+ "_printer._tcp", NULL,
2343+ printer_txt);
2344+
2345+ if (ret < 0)
2346+ goto update_failed;
2347+
2348+ p->printer_txt = printer_txt;
2349+ printer_txt = NULL;
2350+ }
2351+
2352+ ret = avahi_entry_group_commit (p->avahi_group);
2353+ if (ret < 0)
2354+ {
2355+ update_failed:
2356+ cupsdLogMessage (CUPSD_LOG_ERROR,
2357+ "Failed to update TXT record for %s: %d",
2358+ name, ret);
2359+ avahi_entry_group_reset (p->avahi_group);
2360+ avahi_entry_group_free (p->avahi_group);
2361+ p->avahi_group = NULL;
2362+ ipp_txt = p->ipp_txt;
2363+ p->ipp_txt = NULL;
2364+ }
2365+ }
2366+
2367+ if (!p->avahi_group)
2368+ {
2369+ /*
2370+ * Initial registration. Use the _fax subtype for fax queues...
2371+ */
2372+
2373+ p->avahi_group = avahi_entry_group_new (AvahiCupsClient,
2374+ avahi_entry_group_cb,
2375+ p);
2376+
2377+ cupsdLogMessage(CUPSD_LOG_DEBUG,
2378+ "Registering Avahi printer %s with name \"%s\" and "
2379+ "type \"%s\"", p->name, name, regtype);
2380+
2381+ ret = avahi_entry_group_add_service_strlst (p->avahi_group,
2382+ AVAHI_IF_UNSPEC,
2383+ AVAHI_PROTO_UNSPEC,
2384+ 0, name, regtype, NULL, NULL,
2385+ htons(DNSSDPort),
2386+ ipp_txt);
2387+ if (ret < 0)
2388+ goto add_failed;
2389+
2390+ p->ipp_txt = ipp_txt;
2391+ ipp_txt = NULL;
2392+
2393+ if (BrowseLocalProtocols & BROWSE_LPD)
2394+ {
2395+ cupsdLogMessage(CUPSD_LOG_DEBUG,
2396+ "Registering Avahi printer %s with name \"%s\" and "
2397+ "type \"_printer._tcp\"", p->name, name);
2398+
2399+ ret = avahi_entry_group_add_service_strlst (p->avahi_group,
2400+ AVAHI_IF_UNSPEC,
2401+ AVAHI_PROTO_UNSPEC,
2402+ 0, name,
2403+ "_printer._tcp", NULL, NULL,
2404+ htons(515),
2405+ printer_txt);
2406+ if (ret < 0)
2407+ goto add_failed;
2408+
2409+ p->printer_txt = printer_txt;
2410+ printer_txt = NULL;
2411+ }
2412+
2413+ ret = avahi_entry_group_commit (p->avahi_group);
2414+
2415+ if (ret < 0)
2416+ {
2417+ add_failed:
2418+ cupsdLogMessage (CUPSD_LOG_ERROR,
2419+ "Failed to add Avahi entry for %s: %d",
2420+ name, ret);
2421+ avahi_entry_group_reset (p->avahi_group);
2422+ avahi_entry_group_free (p->avahi_group);
2423+ p->avahi_group = NULL;
2424+ ipp_txt = p->ipp_txt;
2425+ p->ipp_txt = NULL;
2426+ }
2427+ }
2428+
2429+ if (ipp_txt)
2430+ avahi_string_list_free (ipp_txt);
2431+
2432+ if (printer_txt)
2433+ avahi_string_list_free (printer_txt);
2434+#endif /* HAVE_AVAHI */
2435 }
2436
2437
2438@@ -2872,6 +2864,10 @@ dnssdStop(void)
2439 {
2440 cupsd_printer_t *p; /* Current printer */
2441
2442+#ifdef HAVE_DNSSD
2443+ if (!DNSSDRef)
2444+ return;
2445+#endif /* HAVE_DNSSD */
2446
2447 /*
2448 * De-register the individual printers
2449@@ -2882,6 +2878,7 @@ dnssdStop(void)
2450 p = (cupsd_printer_t *)cupsArrayNext(Printers))
2451 dnssdDeregisterPrinter(p);
2452
2453+#ifdef HAVE_DNSSD
2454 /*
2455 * Shutdown the rest of the service refs...
2456 */
2457@@ -2902,6 +2899,7 @@ dnssdStop(void)
2458
2459 DNSServiceRefDeallocate(DNSSDRef);
2460 DNSSDRef = NULL;
2461+#endif /* HAVE_DNSSD */
2462
2463 cupsArrayDelete(DNSSDPrinters);
2464 DNSSDPrinters = NULL;
2465@@ -2911,6 +2909,272 @@ dnssdStop(void)
2466
2467
2468 /*
2469+ * 'dnssdBuildTxtRecord()' - Build a TXT record from printer info.
2470+ */
2471+
2472+static cupsd_txt_record_t /* O - TXT record */
2473+dnssdBuildTxtRecord(
2474+ int *txt_len, /* O - TXT record length */
2475+ cupsd_printer_t *p, /* I - Printer information */
2476+ int for_lpd) /* I - 1 = LPD, 0 = IPP */
2477+{
2478+ int i; /* Looping var */
2479+ char adminurl_str[256], /* URL for th admin page */
2480+ type_str[32], /* Type to string buffer */
2481+ state_str[32], /* State to string buffer */
2482+ rp_str[1024], /* Queue name string buffer */
2483+ air_str[1024], /* auth-info-required string buffer */
2484+ *keyvalue[32][2]; /* Table of key/value pairs */
2485+
2486+
2487+ /*
2488+ * Load up the key value pairs...
2489+ */
2490+
2491+ i = 0;
2492+
2493+ keyvalue[i ][0] = "txtvers";
2494+ keyvalue[i++][1] = "1";
2495+
2496+ keyvalue[i ][0] = "qtotal";
2497+ keyvalue[i++][1] = "1";
2498+
2499+ keyvalue[i ][0] = "rp";
2500+ keyvalue[i++][1] = rp_str;
2501+ if (for_lpd)
2502+ strlcpy(rp_str, p->name, sizeof(rp_str));
2503+ else
2504+ snprintf(rp_str, sizeof(rp_str), "%s/%s",
2505+ (p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers", p->name);
2506+
2507+ keyvalue[i ][0] = "ty";
2508+ keyvalue[i++][1] = p->make_model ? p->make_model : "Unknown";
2509+
2510+ httpAssembleURIf(HTTP_URI_CODING_ALL, adminurl_str, sizeof(adminurl_str),
2511+ "http", NULL, DNSSDHostName, DNSSDPort, "/%s/%s",
2512+ (p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers",
2513+ p->name);
2514+ keyvalue[i ][0] = "adminurl";
2515+ keyvalue[i++][1] = adminurl_str;
2516+
2517+ keyvalue[i ][0] = "note";
2518+ keyvalue[i++][1] = p->location ? p->location : "";
2519+
2520+ keyvalue[i ][0] = "priority";
2521+ keyvalue[i++][1] = for_lpd ? "100" : "0";
2522+
2523+ keyvalue[i ][0] = "product";
2524+ keyvalue[i++][1] = p->product ? p->product : "Unknown";
2525+
2526+ snprintf(type_str, sizeof(type_str), "0x%X", p->type | CUPS_PRINTER_REMOTE);
2527+ snprintf(state_str, sizeof(state_str), "%d", p->state);
2528+
2529+ keyvalue[i ][0] = "printer-state";
2530+ keyvalue[i++][1] = state_str;
2531+
2532+ keyvalue[i ][0] = "printer-type";
2533+ keyvalue[i++][1] = type_str;
2534+
2535+ keyvalue[i ][0] = "Transparent";
2536+ keyvalue[i++][1] = "T";
2537+
2538+ keyvalue[i ][0] = "Binary";
2539+ keyvalue[i++][1] = "T";
2540+
2541+ keyvalue[i ][0] = "Fax";
2542+ keyvalue[i++][1] = (p->type & CUPS_PRINTER_FAX) ? "T" : "F";
2543+
2544+ keyvalue[i ][0] = "Color";
2545+ keyvalue[i++][1] = (p->type & CUPS_PRINTER_COLOR) ? "T" : "F";
2546+
2547+ keyvalue[i ][0] = "Duplex";
2548+ keyvalue[i++][1] = (p->type & CUPS_PRINTER_DUPLEX) ? "T" : "F";
2549+
2550+ keyvalue[i ][0] = "Staple";
2551+ keyvalue[i++][1] = (p->type & CUPS_PRINTER_STAPLE) ? "T" : "F";
2552+
2553+ keyvalue[i ][0] = "Copies";
2554+ keyvalue[i++][1] = (p->type & CUPS_PRINTER_COPIES) ? "T" : "F";
2555+
2556+ keyvalue[i ][0] = "Collate";
2557+ keyvalue[i++][1] = (p->type & CUPS_PRINTER_COLLATE) ? "T" : "F";
2558+
2559+ keyvalue[i ][0] = "Punch";
2560+ keyvalue[i++][1] = (p->type & CUPS_PRINTER_PUNCH) ? "T" : "F";
2561+
2562+ keyvalue[i ][0] = "Bind";
2563+ keyvalue[i++][1] = (p->type & CUPS_PRINTER_BIND) ? "T" : "F";
2564+
2565+ keyvalue[i ][0] = "Sort";
2566+ keyvalue[i++][1] = (p->type & CUPS_PRINTER_SORT) ? "T" : "F";
2567+
2568+ keyvalue[i ][0] = "Scan";
2569+ keyvalue[i++][1] = (p->type & CUPS_PRINTER_MFP) ? "T" : "F";
2570+
2571+ keyvalue[i ][0] = "pdl";
2572+ keyvalue[i++][1] = p->pdl ? p->pdl : "application/postscript";
2573+
2574+ if (get_auth_info_required(p, air_str, sizeof(air_str)))
2575+ {
2576+ keyvalue[i ][0] = "air";
2577+ keyvalue[i++][1] = air_str;
2578+ }
2579+
2580+ /*
2581+ * Then pack them into a proper txt record...
2582+ */
2583+
2584+#ifdef HAVE_DNSSD
2585+ return (dnssdPackTxtRecord(txt_len, keyvalue, i));
2586+#endif /* HAVE_DNSSD */
2587+#ifdef HAVE_AVAHI
2588+ return (avahiPackTxtRecord(keyvalue, i));
2589+#endif /* HAVE_AVAHI */
2590+}
2591+#endif /* defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */
2592+
2593+
2594+#ifdef HAVE_DNSSD
2595+# ifdef HAVE_COREFOUNDATION
2596+/*
2597+ * 'dnssdAddAlias()' - Add a DNS-SD alias name.
2598+ */
2599+
2600+static void
2601+dnssdAddAlias(const void *key, /* I - Key */
2602+ const void *value, /* I - Value (domain) */
2603+ void *context) /* I - Unused */
2604+{
2605+ char valueStr[1024], /* Domain string */
2606+ hostname[1024]; /* Complete hostname */
2607+
2608+
2609+ (void)context;
2610+
2611+ if (CFGetTypeID((CFStringRef)value) == CFStringGetTypeID() &&
2612+ CFStringGetCString((CFStringRef)value, valueStr, sizeof(valueStr),
2613+ kCFStringEncodingUTF8))
2614+ {
2615+ snprintf(hostname, sizeof(hostname), "%s.%s", DNSSDHostName, valueStr);
2616+ if (!DNSSDAlias)
2617+ DNSSDAlias = cupsArrayNew(NULL, NULL);
2618+
2619+ cupsdAddAlias(DNSSDAlias, hostname);
2620+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Added Back to My Mac ServerAlias %s",
2621+ hostname);
2622+ }
2623+ else
2624+ cupsdLogMessage(CUPSD_LOG_ERROR,
2625+ "Bad Back to My Mac domain in dynamic store!");
2626+}
2627+# endif /* HAVE_COREFOUNDATION */
2628+
2629+
2630+/*
2631+ * 'dnssdPackTxtRecord()' - Pack an array of key/value pairs into the
2632+ * TXT record format.
2633+ */
2634+
2635+static char * /* O - TXT record */
2636+dnssdPackTxtRecord(int *txt_len, /* O - TXT record length */
2637+ char *keyvalue[][2], /* I - Table of key value pairs */
2638+ int count) /* I - Items in table */
2639+{
2640+ int i; /* Looping var */
2641+ int length; /* Length of TXT record */
2642+ int length2; /* Length of value */
2643+ char *txtRecord; /* TXT record buffer */
2644+ char *cursor; /* Looping pointer */
2645+
2646+
2647+ /*
2648+ * Calculate the buffer size
2649+ */
2650+
2651+ for (length = i = 0; i < count; i++)
2652+ length += 1 + strlen(keyvalue[i][0]) +
2653+ (keyvalue[i][1] ? 1 + strlen(keyvalue[i][1]) : 0);
2654+
2655+ /*
2656+ * Allocate and fill it
2657+ */
2658+
2659+ txtRecord = malloc(length);
2660+ if (txtRecord)
2661+ {
2662+ *txt_len = length;
2663+
2664+ for (cursor = txtRecord, i = 0; i < count; i++)
2665+ {
2666+ /*
2667+ * Drop in the p-string style length byte followed by the data
2668+ */
2669+
2670+ length = strlen(keyvalue[i][0]);
2671+ length2 = keyvalue[i][1] ? 1 + strlen(keyvalue[i][1]) : 0;
2672+
2673+ *cursor++ = (unsigned char)(length + length2);
2674+
2675+ memcpy(cursor, keyvalue[i][0], length);
2676+ cursor += length;
2677+
2678+ if (length2)
2679+ {
2680+ length2 --;
2681+ *cursor++ = '=';
2682+ memcpy(cursor, keyvalue[i][1], length2);
2683+ cursor += length2;
2684+ }
2685+ }
2686+ }
2687+
2688+ return (txtRecord);
2689+}
2690+
2691+
2692+/*
2693+ * 'dnssdRegisterCallback()' - DNSServiceRegister callback.
2694+ */
2695+
2696+static void
2697+dnssdRegisterCallback(
2698+ DNSServiceRef sdRef, /* I - DNS Service reference */
2699+ DNSServiceFlags flags, /* I - Reserved for future use */
2700+ DNSServiceErrorType errorCode, /* I - Error code */
2701+ const char *name, /* I - Service name */
2702+ const char *regtype, /* I - Service type */
2703+ const char *domain, /* I - Domain. ".local" for now */
2704+ void *context) /* I - User-defined context */
2705+{
2706+ cupsd_printer_t *p = (cupsd_printer_t *)context;
2707+ /* Current printer */
2708+
2709+
2710+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterCallback(%s, %s) for %s (%s)",
2711+ name, regtype, p ? p->name : "Web Interface",
2712+ p ? (p->reg_name ? p->reg_name : "(null)") : "NA");
2713+
2714+ if (errorCode)
2715+ {
2716+ cupsdLogMessage(CUPSD_LOG_ERROR,
2717+ "DNSServiceRegister failed with error %d", (int)errorCode);
2718+ return;
2719+ }
2720+ else if (p && (!p->reg_name || strcasecmp(name, p->reg_name)))
2721+ {
2722+ cupsdLogMessage(CUPSD_LOG_INFO, "Using service name \"%s\" for \"%s\"",
2723+ name, p->name);
2724+
2725+ cupsArrayRemove(DNSSDPrinters, p);
2726+ cupsdSetString(&p->reg_name, name);
2727+ cupsArrayAdd(DNSSDPrinters, p);
2728+
2729+ LastEvent |= CUPSD_EVENT_PRINTER_MODIFIED;
2730+ }
2731+}
2732+
2733+
2734+/*
2735 * 'dnssdUpdate()' - Handle DNS-SD queries.
2736 */
2737
2738@@ -2931,6 +3195,126 @@ dnssdUpdate(void)
2739 #endif /* HAVE_DNSSD */
2740
2741
2742+#ifdef HAVE_AVAHI
2743+/*
2744+ * 'avahiPackTxtRecord()' - Pack an array of key/value pairs into an
2745+ * AvahiStringList.
2746+ */
2747+
2748+static AvahiStringList * /* O - new string list */
2749+avahiPackTxtRecord(char *keyvalue[][2], /* I - Table of key value pairs */
2750+ int count) /* I - Items in table */
2751+{
2752+ AvahiStringList *strlst = NULL;
2753+ char **elements;
2754+ size_t len;
2755+ int i;
2756+
2757+ elements = malloc ((1 + count) * sizeof (char *));
2758+ if (!elements)
2759+ goto cleanup;
2760+
2761+ for (i = 0; i < count; i++)
2762+ {
2763+ len = (1 + strlen (keyvalue[i][0]) +
2764+ (keyvalue[i][1] ? 1 + strlen (keyvalue[i][1]) : 1));
2765+ elements[i] = malloc (len * sizeof (char));
2766+ if (!elements[i])
2767+ goto cleanup;
2768+
2769+ snprintf (elements[i], len, "%s=%s", keyvalue[i][0], keyvalue[i][1]);
2770+ }
2771+
2772+ strlst = avahi_string_list_new_from_array ((const char **) elements, count);
2773+
2774+cleanup:
2775+ while (--i >= 0)
2776+ free (elements[i]);
2777+
2778+ free (elements);
2779+ return (strlst);
2780+}
2781+
2782+
2783+/*
2784+ * 'avahi_entry_group_cb()' - Avahi entry group callback function.
2785+ */
2786+static void
2787+avahi_entry_group_cb (AvahiEntryGroup *group,
2788+ AvahiEntryGroupState state,
2789+ void *userdata)
2790+{
2791+ char *name;
2792+
2793+ if (userdata)
2794+ name = ((cupsd_printer_t *) userdata)->reg_name;
2795+ else
2796+ name = "CUPS web interface";
2797+
2798+ switch (state)
2799+ {
2800+ case AVAHI_ENTRY_GROUP_UNCOMMITED:
2801+ case AVAHI_ENTRY_GROUP_REGISTERING:
2802+ break;
2803+
2804+ case AVAHI_ENTRY_GROUP_ESTABLISHED:
2805+ cupsdLogMessage (CUPSD_LOG_DEBUG,
2806+ "Avahi entry group established for %s", name);
2807+ break;
2808+
2809+ default:
2810+ cupsdLogMessage (CUPSD_LOG_DEBUG,
2811+ "Avahi entry group %s has state %d",
2812+ name, state);
2813+ break;
2814+ }
2815+}
2816+
2817+/*
2818+ * 'avahi_client_cb()' - Avahi client callback function.
2819+ */
2820+static void
2821+avahi_client_cb (AvahiClient *client,
2822+ AvahiClientState state,
2823+ void *userdata)
2824+{
2825+ cupsd_printer_t *printer;
2826+ switch (state)
2827+ {
2828+ case AVAHI_CLIENT_S_RUNNING:
2829+ /*
2830+ * Avahi client started successfully.
2831+ */
2832+ AvahiCupsClient = client;
2833+ cupsdLogMessage (CUPSD_LOG_DEBUG, "Avahi client started");
2834+
2835+ cupsdUpdateDNSSDName ();
2836+
2837+ for (printer = (cupsd_printer_t *)cupsArrayFirst(DNSSDPrinters);
2838+ printer;
2839+ printer = (cupsd_printer_t *)cupsArrayNext(DNSSDPrinters))
2840+ {
2841+ if (!printer->avahi_group)
2842+ dnssdRegisterPrinter (printer);
2843+ }
2844+
2845+ break;
2846+
2847+ case AVAHI_CLIENT_CONNECTING:
2848+ cupsdLogMessage (CUPSD_LOG_DEBUG, "Avahi client connecting");
2849+ break;
2850+
2851+ case AVAHI_CLIENT_FAILURE:
2852+ cupsdLogMessage (CUPSD_LOG_ERROR, "Avahi client failed");
2853+ break;
2854+
2855+ default:
2856+ cupsdLogMessage (CUPSD_LOG_DEBUG, "Avahi client state: %d", state);
2857+ }
2858+}
2859+#endif /* HAVE_AVAHI */
2860+
2861+
2862 /*
2863 * 'get_auth_info_required()' - Get the auth-info-required value to advertise.
2864 */
2865diff -up cups-1.4.5/scheduler/dirsvc.h.avahi cups-1.4.5/scheduler/dirsvc.h
2866--- cups-1.4.5/scheduler/dirsvc.h.avahi 2009-05-14 18:54:37.000000000 +0100
2867+++ cups-1.4.5/scheduler/dirsvc.h 2010-12-24 13:11:38.344340724 +0000
2868@@ -32,6 +32,10 @@
2869 # endif /* HAVE_LDAP_SSL_H */
2870 #endif /* HAVE_LDAP */
2871
2872+#ifdef HAVE_AVAHI
2873+# include <avahi-client/publish.h>
2874+#endif /* HAVE_AVAHI */
2875+
2876 /*
2877 * Browse protocols...
2878 */
2879@@ -132,17 +136,20 @@ VAR int PollPipe VALUE(0);
2880 VAR cupsd_statbuf_t *PollStatusBuffer VALUE(NULL);
2881 /* Status buffer for pollers */
2882
2883-#ifdef HAVE_DNSSD
2884+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
2885+VAR int DNSSDPort VALUE(0);
2886+ /* Port number to register */
2887 VAR char *DNSSDComputerName VALUE(NULL),
2888 /* Computer/server name */
2889 *DNSSDHostName VALUE(NULL);
2890 /* Hostname */
2891-VAR cups_array_t *DNSSDAlias VALUE(NULL);
2892- /* List of dynamic ServerAlias's */
2893-VAR int DNSSDPort VALUE(0);
2894- /* Port number to register */
2895 VAR cups_array_t *DNSSDPrinters VALUE(NULL);
2896 /* Printers we have registered */
2897+#endif /* HAVE_DNSSD || HAVE_AVAHI */
2898+
2899+#ifdef HAVE_DNSSD
2900+VAR cups_array_t *DNSSDAlias VALUE(NULL);
2901+ /* List of dynamic ServerAlias's */
2902 VAR DNSServiceRef DNSSDRef VALUE(NULL),
2903 /* Master DNS-SD service reference */
2904 WebIFRef VALUE(NULL),
2905@@ -151,6 +158,15 @@ VAR DNSServiceRef DNSSDRef VALUE(NULL),
2906 /* Remote printer browse reference */
2907 #endif /* HAVE_DNSSD */
2908
2909+#ifdef HAVE_AVAHI
2910+VAR AvahiCupsPoll *AvahiCupsPollHandle VALUE(NULL);
2911+ /* AvahiCupsPoll object */
2912+VAR AvahiClient *AvahiCupsClient VALUE(NULL);
2913+ /* AvahiClient object */
2914+VAR AvahiEntryGroup *AvahiWebIFGroup VALUE(NULL);
2915+ /* Web interface entry group */
2916+#endif /* HAVE_AVAHI */
2917+
2918 #ifdef HAVE_LIBSLP
2919 VAR SLPHandle BrowseSLPHandle VALUE(NULL);
2920 /* SLP API handle */
2921@@ -198,9 +214,9 @@ extern void cupsdStartBrowsing(void);
2922 extern void cupsdStartPolling(void);
2923 extern void cupsdStopBrowsing(void);
2924 extern void cupsdStopPolling(void);
2925-#ifdef HAVE_DNSSD
2926+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
2927 extern void cupsdUpdateDNSSDName(void);
2928-#endif /* HAVE_DNSSD */
2929+#endif /* defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */
2930 #ifdef HAVE_LDAP
2931 extern void cupsdUpdateLDAPBrowse(void);
2932 #endif /* HAVE_LDAP */
2933diff -up cups-1.4.5/scheduler/main.c.avahi cups-1.4.5/scheduler/main.c
2934--- cups-1.4.5/scheduler/main.c.avahi 2010-12-24 13:11:33.633464718 +0000
2935+++ cups-1.4.5/scheduler/main.c 2010-12-24 13:11:38.348340619 +0000
2936@@ -161,6 +161,10 @@ main(int argc, /* I - Number of comm
2937 int launchd_idle_exit;
2938 /* Idle exit on select timeout? */
2939 #endif /* HAVE_LAUNCHD */
2940+#ifdef HAVE_AVAHI
2941+ cupsd_timeout_t *tmo; /* Next scheduled timed callback */
2942+ long tmo_delay; /* Time before it must be called */
2943+#endif /* HAVE_AVAHI */
2944
2945
2946 #ifdef HAVE_GETEUID
2947@@ -561,6 +565,14 @@ main(int argc, /* I - Number of comm
2948
2949 httpInitialize();
2950
2951+#ifdef HAVE_AVAHI
2952+ /*
2953+ * Initialize timed callback structures.
2954+ */
2955+
2956+ cupsdInitTimeouts();
2957+#endif /* HAVE_AVAHI */
2958+
2959 cupsdStartServer();
2960
2961 /*
2962@@ -900,6 +912,16 @@ main(int argc, /* I - Number of comm
2963 }
2964 #endif /* __APPLE__ */
2965
2966+#ifdef HAVE_AVAHI
2967+ /*
2968+ * If a timed callback is due, run it.
2969+ */
2970+
2971+ tmo = cupsdNextTimeout (&tmo_delay);
2972+ if (tmo && tmo_delay == 0)
2973+ cupsdRunTimeout (tmo);
2974+#endif /* HAVE_AVAHI */
2975+
2976 #ifndef __APPLE__
2977 /*
2978 * Update the network interfaces once a minute...
2979@@ -1925,6 +1947,10 @@ select_timeout(int fds) /* I - Number
2980 cupsd_job_t *job; /* Job information */
2981 cupsd_subscription_t *sub; /* Subscription information */
2982 const char *why; /* Debugging aid */
2983+#ifdef HAVE_AVAHI
2984+ cupsd_timeout_t *tmo; /* Timed callback */
2985+ long tmo_delay; /* Seconds before calling it */
2986+#endif /* HAVE_AVAHI */
2987
2988
2989 /*
2990@@ -1967,6 +1993,19 @@ select_timeout(int fds) /* I - Number
2991 }
2992 #endif /* __APPLE__ */
2993
2994+#ifdef HAVE_AVAHI
2995+ /*
2996+ * See if there are any scheduled timed callbacks to run.
2997+ */
2998+
2999+ tmo = cupsdNextTimeout (&tmo_delay);
3000+ if (tmo)
3001+ {
3002+ timeout = tmo_delay;
3003+ why = "run a timed callback";
3004+ }
3005+#endif /* HAVE_AVAHI */
3006+
3007 /*
3008 * Check whether we are accepting new connections...
3009 */
3010diff -up cups-1.4.5/scheduler/Makefile.avahi cups-1.4.5/scheduler/Makefile
3011--- cups-1.4.5/scheduler/Makefile.avahi 2010-12-24 13:11:33.739461928 +0000
3012+++ cups-1.4.5/scheduler/Makefile 2010-12-24 13:11:38.332341040 +0000
3013@@ -17,6 +17,7 @@ include ../Makedefs
3014
3015 CUPSDOBJS = \
3016 auth.o \
3017+ avahi.o \
3018 banners.o \
3019 cert.o \
3020 classes.o \
3021@@ -39,7 +40,8 @@ CUPSDOBJS = \
3022 server.o \
3023 statbuf.o \
3024 subscriptions.o \
3025- sysman.o
3026+ sysman.o \
3027+ timeout.o
3028 LIBOBJS = \
3029 filter.o \
3030 mime.o \
3031diff -up cups-1.4.5/scheduler/printers.c.avahi cups-1.4.5/scheduler/printers.c
3032--- cups-1.4.5/scheduler/printers.c.avahi 2010-12-24 13:11:33.784460744 +0000
3033+++ cups-1.4.5/scheduler/printers.c 2010-12-24 13:11:38.356340409 +0000
3034@@ -929,10 +929,10 @@ cupsdDeletePrinter(
3035 cupsdClearString(&p->alert);
3036 cupsdClearString(&p->alert_description);
3037
3038-#ifdef HAVE_DNSSD
3039+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
3040 cupsdClearString(&p->product);
3041 cupsdClearString(&p->pdl);
3042-#endif /* HAVE_DNSSD */
3043+#endif /* defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */
3044
3045 cupsArrayDelete(p->filetypes);
3046
3047@@ -1301,9 +1301,9 @@ cupsdLoadAllPrinters(void)
3048 {
3049 if (value)
3050 {
3051-#ifdef HAVE_DNSSD
3052+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
3053 p->product = _cupsStrAlloc(value);
3054-#endif /* HAVE_DNSSD */
3055+#endif /* defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */
3056 }
3057 else
3058 cupsdLogMessage(CUPSD_LOG_ERROR,
3059@@ -1717,10 +1717,10 @@ cupsdSaveAllPrinters(void)
3060
3061 cupsFilePrintf(fp, "Type %d\n", printer->type);
3062
3063-#ifdef HAVE_DNSSD
3064+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
3065 if (printer->product)
3066 cupsFilePutConf(fp, "Product", printer->product);
3067-#endif /* HAVE_DNSSD */
3068+#endif /* defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */
3069
3070 for (ptr = (char *)cupsArrayFirst(printer->filters);
3071 ptr;
3072@@ -3860,7 +3860,7 @@ add_printer_formats(cupsd_printer_t *p)
3073 attr->values[i].string.text = _cupsStrAlloc(mimetype);
3074 }
3075
3076-#ifdef HAVE_DNSSD
3077+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
3078 {
3079 char pdl[1024]; /* Buffer to build pdl list */
3080 mime_filter_t *filter; /* MIME filter looping var */
3081@@ -3914,7 +3914,7 @@ add_printer_formats(cupsd_printer_t *p)
3082
3083 cupsdSetString(&p->pdl, pdl);
3084 }
3085-#endif /* HAVE_DNSSD */
3086+#endif /* defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */
3087 }
3088
3089
3090@@ -4951,9 +4951,9 @@ load_ppd(cupsd_printer_t *p) /* I - Pri
3091 attr->values[i].string.text = _cupsStrAlloc("bcp");
3092 }
3093
3094-#ifdef HAVE_DNSSD
3095+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
3096 cupsdSetString(&p->product, ppd->product);
3097-#endif /* HAVE_DNSSD */
3098+#endif /* defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */
3099
3100 if (ppdFindAttr(ppd, "APRemoteQueueID", NULL))
3101 p->type |= CUPS_PRINTER_REMOTE;
3102diff -up cups-1.4.5/scheduler/printers.h.avahi cups-1.4.5/scheduler/printers.h
3103--- cups-1.4.5/scheduler/printers.h.avahi 2010-03-30 23:07:33.000000000 +0100
3104+++ cups-1.4.5/scheduler/printers.h 2010-12-24 13:11:38.357340382 +0000
3105@@ -16,6 +16,9 @@
3106 #ifdef HAVE_DNSSD
3107 # include <dns_sd.h>
3108 #endif /* HAVE_DNSSD */
3109+#ifdef HAVE_AVAHI
3110+# include "avahi.h"
3111+#endif /* HAVE_AVAHI */
3112 #include <cups/pwg-private.h>
3113
3114
3115@@ -99,17 +102,24 @@ typedef struct cupsd_printer_s
3116 char *recoverable; /* com.apple.print.recoverable-message */
3117 _pwg_t *pwg; /* PWG<->PPD mapping data */
3118
3119+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
3120+ char *reg_name; /* Name used for service registration */
3121+ char *product, /* PPD Product string */
3122+ *pdl; /* pdl value for TXT record */
3123+#endif /* defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */
3124 #ifdef HAVE_DNSSD
3125- char *reg_name, /* Name used for service registration */
3126- *product, /* PPD Product string */
3127- *pdl, /* pdl value for TXT record */
3128- *ipp_txt, /* IPP TXT record contents */
3129+ char *ipp_txt, /* IPP TXT record contents */
3130 *printer_txt; /* LPD TXT record contents */
3131 int ipp_len, /* IPP TXT record length */
3132 printer_len; /* LPD TXT record length */
3133 DNSServiceRef ipp_ref, /* Reference for _ipp._tcp,_cups */
3134 printer_ref; /* Reference for _printer._tcp */
3135 #endif /* HAVE_DNSSD */
3136+#ifdef HAVE_AVAHI
3137+ AvahiStringList *ipp_txt, /* IPP TXT record */
3138+ *printer_txt; /* LPD TXT record */
3139+ AvahiEntryGroup *avahi_group; /* Avahi entry group */
3140+#endif /* HAVE_AVAHI */
3141 } cupsd_printer_t;
3142
3143
3144diff -up cups-1.4.5/scheduler/timeout.c.avahi cups-1.4.5/scheduler/timeout.c
3145--- cups-1.4.5/scheduler/timeout.c.avahi 2010-12-24 13:11:38.358340356 +0000
3146+++ cups-1.4.5/scheduler/timeout.c 2010-12-24 13:11:38.358340356 +0000
3147@@ -0,0 +1,191 @@
3148+/*
3149+ * "$Id$"
3150+ *
3151+ * Timeout functions for the Common UNIX Printing System (CUPS).
3152+ *
3153+ * Copyright (C) 2010 Red Hat, Inc.
3154+ * Authors:
3155+ * Tim Waugh <twaugh@redhat.com>
3156+ *
3157+ * Distribution and use rights are outlined in the file "LICENSE.txt"
3158+ * which should have been included with this file. If this file is
3159+ * file is missing or damaged, see the license at "http://www.cups.org/".
3160+ *
3161+ * Contents:
3162+ *
3163+ * cupsdInitTimeouts() - Initialise timeout structure.
3164+ * cupsdAddTimeout() - Add a timed callback.
3165+ * cupsdNextTimeout() - Find the next enabled timed callback.
3166+ * cupsdUpdateTimeout() - Adjust the time of a timed callback or disable it.
3167+ * cupsdRemoveTimeout() - Discard a timed callback.
3168+ * compare_timeouts() - Compare timed callbacks for array sorting.
3169+ */
3170+
3171+#include <config.h>
3172+
3173+#ifdef HAVE_AVAHI /* Applies to entire file... */
3174+
3175+/*
3176+ * Include necessary headers...
3177+ */
3178+
3179+#include "cupsd.h"
3180+
3181+#if defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO)
3182+# include <malloc.h>
3183+#endif /* HAVE_MALLOC_H && HAVE_MALLINFO */
3184+
3185+#ifdef HAVE_AVAHI
3186+# include <avahi-common/timeval.h>
3187+#endif /* HAVE_AVAHI */
3188+
3189+
3190+struct _cupsd_timeout_s
3191+{
3192+ struct timeval when;
3193+ int enabled;
3194+ cupsd_timeoutfunc_t callback;
3195+ void *data;
3196+};
3197+
3198+/*
3199+ * Local functions...
3200+ */
3201+
3202+/*
3203+ * 'compare_timeouts()' - Compare timed callbacks for array sorting.
3204+ */
3205+
3206+static int
3207+compare_timeouts (cupsd_timeout_t *p0, cupsd_timeout_t *p1)
3208+{
3209+ if (!p0->enabled || !p1->enabled)
3210+ {
3211+ if (!p0->enabled && !p1->enabled)
3212+ return (0);
3213+
3214+ return (p0->enabled ? -1 : 1);
3215+ }
3216+
3217+ return (avahi_timeval_compare (&p0->when, &p1->when));
3218+}
3219+
3220+
3221+/*
3222+ * 'cupsdInitTimeouts()' - Initialise timeout structures.
3223+ */
3224+
3225+void
3226+cupsdInitTimeouts(void)
3227+{
3228+ Timeouts = cupsArrayNew ((cups_array_func_t)compare_timeouts, NULL);
3229+}
3230+
3231+
3232+/*
3233+ * 'cupsdAddTimeout()' - Add a timed callback.
3234+ */
3235+
3236+cupsd_timeout_t * /* O - Timeout handle */
3237+cupsdAddTimeout(const struct timeval *tv, /* I - Absolute time */
3238+ cupsd_timeoutfunc_t cb, /* I - Callback function */
3239+ void *data) /* I - User data */
3240+{
3241+ cupsd_timeout_t *timeout;
3242+
3243+ timeout = malloc (sizeof(cupsd_timeout_t));
3244+ if (timeout != NULL)
3245+ {
3246+ timeout->enabled = (tv != NULL);
3247+ if (tv)
3248+ {
3249+ timeout->when.tv_sec = tv->tv_sec;
3250+ timeout->when.tv_usec = tv->tv_usec;
3251+ }
3252+
3253+ timeout->callback = cb;
3254+ timeout->data = data;
3255+ cupsArrayAdd (Timeouts, timeout);
3256+ }
3257+
3258+ return timeout;
3259+}
3260+
3261+
3262+/*
3263+ * 'cupsdNextTimeout()' - Find the next enabled timed callback.
3264+ */
3265+
3266+cupsd_timeout_t * /* O - Next enabled timeout or NULL */
3267+cupsdNextTimeout(long *delay) /* O - Seconds before scheduled */
3268+{
3269+ cupsd_timeout_t *first = cupsArrayFirst (Timeouts);
3270+ struct timeval curtime;
3271+
3272+ if (first && !first->enabled)
3273+ first = NULL;
3274+
3275+ if (first && delay)
3276+ {
3277+ gettimeofday (&curtime, NULL);
3278+ if (avahi_timeval_compare (&curtime, &first->when) > 0)
3279+ {
3280+ *delay = 0;
3281+ } else {
3282+ *delay = 1 + first->when.tv_sec - curtime.tv_sec;
3283+ if (first->when.tv_usec < curtime.tv_usec)
3284+ (*delay)--;
3285+ }
3286+ }
3287+
3288+ return (first);
3289+}
3290+
3291+
3292+/*
3293+ * 'cupsdRunTimeout()' - Run a timed callback.
3294+ */
3295+
3296+void
3297+cupsdRunTimeout(cupsd_timeout_t *timeout) /* I - Timeout */
3298+{
3299+ timeout->enabled = 0;
3300+ timeout->callback (timeout, timeout->data);
3301+}
3302+
3303+/*
3304+ * 'cupsdUpdateTimeout()' - Adjust the time of a timed callback or disable it.
3305+ */
3306+
3307+void
3308+cupsdUpdateTimeout(cupsd_timeout_t *timeout, /* I - Timeout */
3309+ const struct timeval *tv) /* I - Absolute time or NULL */
3310+{
3311+ cupsArrayRemove (Timeouts, timeout);
3312+ timeout->enabled = (tv != NULL);
3313+ if (tv)
3314+ {
3315+ timeout->when.tv_sec = tv->tv_sec;
3316+ timeout->when.tv_usec = tv->tv_usec;
3317+ }
3318+ cupsArrayAdd (Timeouts, timeout);
3319+}
3320+
3321+
3322+/*
3323+ * 'cupsdRemoveTimeout()' - Discard a timed callback.
3324+ */
3325+
3326+void
3327+cupsdRemoveTimeout(cupsd_timeout_t *timeout) /* I - Timeout */
3328+{
3329+ cupsArrayRemove (Timeouts, timeout);
3330+ free (timeout);
3331+}
3332+
3333+
3334+#endif /* HAVE_AVAHI ... from top of file */
3335+
3336+/*
3337+ * End of "$Id$".
3338+ */