xref: /aosp_15_r20/external/libcups/backend/dnssd.c (revision 5e7646d21f1134fb0638875d812ef646c12ab91e)
1*5e7646d2SAndroid Build Coastguard Worker /*
2*5e7646d2SAndroid Build Coastguard Worker  * DNS-SD discovery backend for CUPS.
3*5e7646d2SAndroid Build Coastguard Worker  *
4*5e7646d2SAndroid Build Coastguard Worker  * Copyright © 2008-2018 by Apple Inc.
5*5e7646d2SAndroid Build Coastguard Worker  *
6*5e7646d2SAndroid Build Coastguard Worker  * Licensed under Apache License v2.0.  See the file "LICENSE" for more
7*5e7646d2SAndroid Build Coastguard Worker  * information.
8*5e7646d2SAndroid Build Coastguard Worker  */
9*5e7646d2SAndroid Build Coastguard Worker 
10*5e7646d2SAndroid Build Coastguard Worker /*
11*5e7646d2SAndroid Build Coastguard Worker  * Include necessary headers.
12*5e7646d2SAndroid Build Coastguard Worker  */
13*5e7646d2SAndroid Build Coastguard Worker 
14*5e7646d2SAndroid Build Coastguard Worker #include "backend-private.h"
15*5e7646d2SAndroid Build Coastguard Worker #include <cups/array.h>
16*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_DNSSD
17*5e7646d2SAndroid Build Coastguard Worker #  include <dns_sd.h>
18*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_DNSSD */
19*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_AVAHI
20*5e7646d2SAndroid Build Coastguard Worker #  include <avahi-client/client.h>
21*5e7646d2SAndroid Build Coastguard Worker #  include <avahi-client/lookup.h>
22*5e7646d2SAndroid Build Coastguard Worker #  include <avahi-common/simple-watch.h>
23*5e7646d2SAndroid Build Coastguard Worker #  include <avahi-common/domain.h>
24*5e7646d2SAndroid Build Coastguard Worker #  include <avahi-common/error.h>
25*5e7646d2SAndroid Build Coastguard Worker #  include <avahi-common/malloc.h>
26*5e7646d2SAndroid Build Coastguard Worker #define kDNSServiceMaxDomainName AVAHI_DOMAIN_NAME_MAX
27*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_AVAHI */
28*5e7646d2SAndroid Build Coastguard Worker 
29*5e7646d2SAndroid Build Coastguard Worker 
30*5e7646d2SAndroid Build Coastguard Worker /*
31*5e7646d2SAndroid Build Coastguard Worker  * Device structure...
32*5e7646d2SAndroid Build Coastguard Worker  */
33*5e7646d2SAndroid Build Coastguard Worker 
34*5e7646d2SAndroid Build Coastguard Worker typedef enum
35*5e7646d2SAndroid Build Coastguard Worker {
36*5e7646d2SAndroid Build Coastguard Worker   CUPS_DEVICE_PRINTER = 0,		/* lpd://... */
37*5e7646d2SAndroid Build Coastguard Worker   CUPS_DEVICE_IPPS,			/* ipps://... */
38*5e7646d2SAndroid Build Coastguard Worker   CUPS_DEVICE_IPP,			/* ipp://... */
39*5e7646d2SAndroid Build Coastguard Worker   CUPS_DEVICE_FAX_IPP,			/* ipp://... */
40*5e7646d2SAndroid Build Coastguard Worker   CUPS_DEVICE_PDL_DATASTREAM,		/* socket://... */
41*5e7646d2SAndroid Build Coastguard Worker   CUPS_DEVICE_RIOUSBPRINT		/* riousbprint://... */
42*5e7646d2SAndroid Build Coastguard Worker } cups_devtype_t;
43*5e7646d2SAndroid Build Coastguard Worker 
44*5e7646d2SAndroid Build Coastguard Worker 
45*5e7646d2SAndroid Build Coastguard Worker typedef struct
46*5e7646d2SAndroid Build Coastguard Worker {
47*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_DNSSD
48*5e7646d2SAndroid Build Coastguard Worker   DNSServiceRef	ref;			/* Service reference for query */
49*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_DNSSD */
50*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_AVAHI
51*5e7646d2SAndroid Build Coastguard Worker   AvahiRecordBrowser *ref;		/* Browser for query */
52*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_AVAHI */
53*5e7646d2SAndroid Build Coastguard Worker   char		*name,			/* Service name */
54*5e7646d2SAndroid Build Coastguard Worker 		*domain,		/* Domain name */
55*5e7646d2SAndroid Build Coastguard Worker 		*fullName,		/* Full name */
56*5e7646d2SAndroid Build Coastguard Worker 		*make_and_model,	/* Make and model from TXT record */
57*5e7646d2SAndroid Build Coastguard Worker 		*device_id,		/* 1284 device ID from TXT record */
58*5e7646d2SAndroid Build Coastguard Worker 		*uuid;			/* UUID from TXT record */
59*5e7646d2SAndroid Build Coastguard Worker   cups_devtype_t type;			/* Device registration type */
60*5e7646d2SAndroid Build Coastguard Worker   int		priority,		/* Priority associated with type */
61*5e7646d2SAndroid Build Coastguard Worker 		cups_shared,		/* CUPS shared printer? */
62*5e7646d2SAndroid Build Coastguard Worker 		sent;			/* Did we list the device? */
63*5e7646d2SAndroid Build Coastguard Worker } cups_device_t;
64*5e7646d2SAndroid Build Coastguard Worker 
65*5e7646d2SAndroid Build Coastguard Worker 
66*5e7646d2SAndroid Build Coastguard Worker /*
67*5e7646d2SAndroid Build Coastguard Worker  * Local globals...
68*5e7646d2SAndroid Build Coastguard Worker  */
69*5e7646d2SAndroid Build Coastguard Worker 
70*5e7646d2SAndroid Build Coastguard Worker static int		job_canceled = 0;
71*5e7646d2SAndroid Build Coastguard Worker 					/* Set to 1 on SIGTERM */
72*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_AVAHI
73*5e7646d2SAndroid Build Coastguard Worker static AvahiSimplePoll	*simple_poll = NULL;
74*5e7646d2SAndroid Build Coastguard Worker 					/* Poll information */
75*5e7646d2SAndroid Build Coastguard Worker static int		got_data = 0;	/* Got data from poll? */
76*5e7646d2SAndroid Build Coastguard Worker static int		browsers = 0;	/* Number of running browsers */
77*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_AVAHI */
78*5e7646d2SAndroid Build Coastguard Worker 
79*5e7646d2SAndroid Build Coastguard Worker 
80*5e7646d2SAndroid Build Coastguard Worker /*
81*5e7646d2SAndroid Build Coastguard Worker  * Local functions...
82*5e7646d2SAndroid Build Coastguard Worker  */
83*5e7646d2SAndroid Build Coastguard Worker 
84*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_DNSSD
85*5e7646d2SAndroid Build Coastguard Worker static void		browse_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *serviceName, const char *regtype, const char *replyDomain, void *context) _CUPS_NONNULL(1,5,6,7,8);
86*5e7646d2SAndroid Build Coastguard Worker static void		browse_local_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *serviceName, const char *regtype, const char *replyDomain, void *context) _CUPS_NONNULL(1,5,6,7,8);
87*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_DNSSD */
88*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_AVAHI
89*5e7646d2SAndroid Build Coastguard Worker static void		browse_callback(AvahiServiceBrowser *browser,
90*5e7646d2SAndroid Build Coastguard Worker 					AvahiIfIndex interface,
91*5e7646d2SAndroid Build Coastguard Worker 					AvahiProtocol protocol,
92*5e7646d2SAndroid Build Coastguard Worker 					AvahiBrowserEvent event,
93*5e7646d2SAndroid Build Coastguard Worker 					const char *serviceName,
94*5e7646d2SAndroid Build Coastguard Worker 					const char *regtype,
95*5e7646d2SAndroid Build Coastguard Worker 					const char *replyDomain,
96*5e7646d2SAndroid Build Coastguard Worker 					AvahiLookupResultFlags flags,
97*5e7646d2SAndroid Build Coastguard Worker 					void *context);
98*5e7646d2SAndroid Build Coastguard Worker static void		client_callback(AvahiClient *client,
99*5e7646d2SAndroid Build Coastguard Worker 					AvahiClientState state,
100*5e7646d2SAndroid Build Coastguard Worker 					void *context);
101*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_AVAHI */
102*5e7646d2SAndroid Build Coastguard Worker 
103*5e7646d2SAndroid Build Coastguard Worker static int		compare_devices(cups_device_t *a, cups_device_t *b);
104*5e7646d2SAndroid Build Coastguard Worker static void		exec_backend(char **argv) _CUPS_NORETURN;
105*5e7646d2SAndroid Build Coastguard Worker static cups_device_t	*get_device(cups_array_t *devices, const char *serviceName, const char *regtype, const char *replyDomain) _CUPS_NONNULL(1,2,3,4);
106*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_DNSSD
107*5e7646d2SAndroid Build Coastguard Worker static void		query_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *fullName, uint16_t rrtype, uint16_t rrclass, uint16_t rdlen, const void *rdata, uint32_t ttl, void *context) _CUPS_NONNULL(1,5,9,11);
108*5e7646d2SAndroid Build Coastguard Worker #elif defined(HAVE_AVAHI)
109*5e7646d2SAndroid Build Coastguard Worker static int		poll_callback(struct pollfd *pollfds,
110*5e7646d2SAndroid Build Coastguard Worker 			              unsigned int num_pollfds, int timeout,
111*5e7646d2SAndroid Build Coastguard Worker 			              void *context);
112*5e7646d2SAndroid Build Coastguard Worker static void		query_callback(AvahiRecordBrowser *browser,
113*5e7646d2SAndroid Build Coastguard Worker 				       AvahiIfIndex interface,
114*5e7646d2SAndroid Build Coastguard Worker 				       AvahiProtocol protocol,
115*5e7646d2SAndroid Build Coastguard Worker 				       AvahiBrowserEvent event,
116*5e7646d2SAndroid Build Coastguard Worker 				       const char *name, uint16_t rrclass,
117*5e7646d2SAndroid Build Coastguard Worker 				       uint16_t rrtype, const void *rdata,
118*5e7646d2SAndroid Build Coastguard Worker 				       size_t rdlen,
119*5e7646d2SAndroid Build Coastguard Worker 				       AvahiLookupResultFlags flags,
120*5e7646d2SAndroid Build Coastguard Worker 				       void *context);
121*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_DNSSD */
122*5e7646d2SAndroid Build Coastguard Worker static void		sigterm_handler(int sig);
123*5e7646d2SAndroid Build Coastguard Worker static void		unquote(char *dst, const char *src, size_t dstsize) _CUPS_NONNULL(1,2);
124*5e7646d2SAndroid Build Coastguard Worker 
125*5e7646d2SAndroid Build Coastguard Worker 
126*5e7646d2SAndroid Build Coastguard Worker /*
127*5e7646d2SAndroid Build Coastguard Worker  * 'main()' - Browse for printers.
128*5e7646d2SAndroid Build Coastguard Worker  */
129*5e7646d2SAndroid Build Coastguard Worker 
130*5e7646d2SAndroid Build Coastguard Worker int					/* O - Exit status */
main(int argc,char * argv[])131*5e7646d2SAndroid Build Coastguard Worker main(int  argc,				/* I - Number of command-line args */
132*5e7646d2SAndroid Build Coastguard Worker      char *argv[])			/* I - Command-line arguments */
133*5e7646d2SAndroid Build Coastguard Worker {
134*5e7646d2SAndroid Build Coastguard Worker   const char	*name;			/* Backend name */
135*5e7646d2SAndroid Build Coastguard Worker   cups_array_t	*devices;		/* Device array */
136*5e7646d2SAndroid Build Coastguard Worker   cups_device_t	*device;		/* Current device */
137*5e7646d2SAndroid Build Coastguard Worker   char		uriName[1024];		/* Unquoted fullName for URI */
138*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_DNSSD
139*5e7646d2SAndroid Build Coastguard Worker   int		fd;			/* Main file descriptor */
140*5e7646d2SAndroid Build Coastguard Worker   fd_set	input;			/* Input set for select() */
141*5e7646d2SAndroid Build Coastguard Worker   struct timeval timeout;		/* Timeout for select() */
142*5e7646d2SAndroid Build Coastguard Worker   DNSServiceRef	main_ref,		/* Main service reference */
143*5e7646d2SAndroid Build Coastguard Worker 		fax_ipp_ref,		/* IPP fax service reference */
144*5e7646d2SAndroid Build Coastguard Worker 		ipp_ref,		/* IPP service reference */
145*5e7646d2SAndroid Build Coastguard Worker 		ipp_tls_ref,		/* IPP w/TLS service reference */
146*5e7646d2SAndroid Build Coastguard Worker 		ipps_ref,		/* IPP service reference */
147*5e7646d2SAndroid Build Coastguard Worker 		local_fax_ipp_ref,	/* Local IPP fax service reference */
148*5e7646d2SAndroid Build Coastguard Worker 		local_ipp_ref,		/* Local IPP service reference */
149*5e7646d2SAndroid Build Coastguard Worker 		local_ipp_tls_ref,	/* Local IPP w/TLS service reference */
150*5e7646d2SAndroid Build Coastguard Worker 		local_ipps_ref,		/* Local IPP service reference */
151*5e7646d2SAndroid Build Coastguard Worker 		local_printer_ref,	/* Local LPD service reference */
152*5e7646d2SAndroid Build Coastguard Worker 		pdl_datastream_ref,	/* AppSocket service reference */
153*5e7646d2SAndroid Build Coastguard Worker 		printer_ref,		/* LPD service reference */
154*5e7646d2SAndroid Build Coastguard Worker 		riousbprint_ref;	/* Remote IO service reference */
155*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_DNSSD */
156*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_AVAHI
157*5e7646d2SAndroid Build Coastguard Worker   AvahiClient	*client;		/* Client information */
158*5e7646d2SAndroid Build Coastguard Worker   int		error;			/* Error code, if any */
159*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_AVAHI */
160*5e7646d2SAndroid Build Coastguard Worker #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
161*5e7646d2SAndroid Build Coastguard Worker   struct sigaction action;		/* Actions for POSIX signals */
162*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
163*5e7646d2SAndroid Build Coastguard Worker 
164*5e7646d2SAndroid Build Coastguard Worker 
165*5e7646d2SAndroid Build Coastguard Worker  /*
166*5e7646d2SAndroid Build Coastguard Worker   * Don't buffer stderr, and catch SIGTERM...
167*5e7646d2SAndroid Build Coastguard Worker   */
168*5e7646d2SAndroid Build Coastguard Worker 
169*5e7646d2SAndroid Build Coastguard Worker   setbuf(stderr, NULL);
170*5e7646d2SAndroid Build Coastguard Worker 
171*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
172*5e7646d2SAndroid Build Coastguard Worker   sigset(SIGTERM, sigterm_handler);
173*5e7646d2SAndroid Build Coastguard Worker #elif defined(HAVE_SIGACTION)
174*5e7646d2SAndroid Build Coastguard Worker   memset(&action, 0, sizeof(action));
175*5e7646d2SAndroid Build Coastguard Worker 
176*5e7646d2SAndroid Build Coastguard Worker   sigemptyset(&action.sa_mask);
177*5e7646d2SAndroid Build Coastguard Worker   action.sa_handler = sigterm_handler;
178*5e7646d2SAndroid Build Coastguard Worker   sigaction(SIGTERM, &action, NULL);
179*5e7646d2SAndroid Build Coastguard Worker #else
180*5e7646d2SAndroid Build Coastguard Worker   signal(SIGTERM, sigterm_handler);
181*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_SIGSET */
182*5e7646d2SAndroid Build Coastguard Worker 
183*5e7646d2SAndroid Build Coastguard Worker  /*
184*5e7646d2SAndroid Build Coastguard Worker   * Check command-line...
185*5e7646d2SAndroid Build Coastguard Worker   */
186*5e7646d2SAndroid Build Coastguard Worker 
187*5e7646d2SAndroid Build Coastguard Worker   if (argc >= 6)
188*5e7646d2SAndroid Build Coastguard Worker     exec_backend(argv);
189*5e7646d2SAndroid Build Coastguard Worker   else if (argc != 1)
190*5e7646d2SAndroid Build Coastguard Worker   {
191*5e7646d2SAndroid Build Coastguard Worker     _cupsLangPrintf(stderr,
192*5e7646d2SAndroid Build Coastguard Worker                     _("Usage: %s job-id user title copies options [file]"),
193*5e7646d2SAndroid Build Coastguard Worker 		    argv[0]);
194*5e7646d2SAndroid Build Coastguard Worker     return (1);
195*5e7646d2SAndroid Build Coastguard Worker   }
196*5e7646d2SAndroid Build Coastguard Worker 
197*5e7646d2SAndroid Build Coastguard Worker  /*
198*5e7646d2SAndroid Build Coastguard Worker   * Only do discovery when run as "dnssd"...
199*5e7646d2SAndroid Build Coastguard Worker   */
200*5e7646d2SAndroid Build Coastguard Worker 
201*5e7646d2SAndroid Build Coastguard Worker   if ((name = strrchr(argv[0], '/')) != NULL)
202*5e7646d2SAndroid Build Coastguard Worker     name ++;
203*5e7646d2SAndroid Build Coastguard Worker   else
204*5e7646d2SAndroid Build Coastguard Worker     name = argv[0];
205*5e7646d2SAndroid Build Coastguard Worker 
206*5e7646d2SAndroid Build Coastguard Worker   if (strcmp(name, "dnssd"))
207*5e7646d2SAndroid Build Coastguard Worker     return (0);
208*5e7646d2SAndroid Build Coastguard Worker 
209*5e7646d2SAndroid Build Coastguard Worker  /*
210*5e7646d2SAndroid Build Coastguard Worker   * Create an array to track devices...
211*5e7646d2SAndroid Build Coastguard Worker   */
212*5e7646d2SAndroid Build Coastguard Worker 
213*5e7646d2SAndroid Build Coastguard Worker   devices = cupsArrayNew((cups_array_func_t)compare_devices, NULL);
214*5e7646d2SAndroid Build Coastguard Worker 
215*5e7646d2SAndroid Build Coastguard Worker  /*
216*5e7646d2SAndroid Build Coastguard Worker   * Browse for different kinds of printers...
217*5e7646d2SAndroid Build Coastguard Worker   */
218*5e7646d2SAndroid Build Coastguard Worker 
219*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_DNSSD
220*5e7646d2SAndroid Build Coastguard Worker   if (DNSServiceCreateConnection(&main_ref) != kDNSServiceErr_NoError)
221*5e7646d2SAndroid Build Coastguard Worker   {
222*5e7646d2SAndroid Build Coastguard Worker     perror("ERROR: Unable to create service connection");
223*5e7646d2SAndroid Build Coastguard Worker     return (1);
224*5e7646d2SAndroid Build Coastguard Worker   }
225*5e7646d2SAndroid Build Coastguard Worker 
226*5e7646d2SAndroid Build Coastguard Worker   fd = DNSServiceRefSockFD(main_ref);
227*5e7646d2SAndroid Build Coastguard Worker 
228*5e7646d2SAndroid Build Coastguard Worker   fax_ipp_ref = main_ref;
229*5e7646d2SAndroid Build Coastguard Worker   DNSServiceBrowse(&fax_ipp_ref, kDNSServiceFlagsShareConnection, 0,
230*5e7646d2SAndroid Build Coastguard Worker                    "_fax-ipp._tcp", NULL, browse_callback, devices);
231*5e7646d2SAndroid Build Coastguard Worker 
232*5e7646d2SAndroid Build Coastguard Worker   ipp_ref = main_ref;
233*5e7646d2SAndroid Build Coastguard Worker   DNSServiceBrowse(&ipp_ref, kDNSServiceFlagsShareConnection, 0,
234*5e7646d2SAndroid Build Coastguard Worker                    "_ipp._tcp", NULL, browse_callback, devices);
235*5e7646d2SAndroid Build Coastguard Worker 
236*5e7646d2SAndroid Build Coastguard Worker   ipp_tls_ref = main_ref;
237*5e7646d2SAndroid Build Coastguard Worker   DNSServiceBrowse(&ipp_tls_ref, kDNSServiceFlagsShareConnection, 0,
238*5e7646d2SAndroid Build Coastguard Worker                    "_ipp-tls._tcp", NULL, browse_callback, devices);
239*5e7646d2SAndroid Build Coastguard Worker 
240*5e7646d2SAndroid Build Coastguard Worker   ipps_ref = main_ref;
241*5e7646d2SAndroid Build Coastguard Worker   DNSServiceBrowse(&ipps_ref, kDNSServiceFlagsShareConnection, 0,
242*5e7646d2SAndroid Build Coastguard Worker                    "_ipps._tcp", NULL, browse_callback, devices);
243*5e7646d2SAndroid Build Coastguard Worker 
244*5e7646d2SAndroid Build Coastguard Worker   local_fax_ipp_ref = main_ref;
245*5e7646d2SAndroid Build Coastguard Worker   DNSServiceBrowse(&local_fax_ipp_ref, kDNSServiceFlagsShareConnection,
246*5e7646d2SAndroid Build Coastguard Worker                    kDNSServiceInterfaceIndexLocalOnly,
247*5e7646d2SAndroid Build Coastguard Worker 		   "_fax-ipp._tcp", NULL, browse_local_callback, devices);
248*5e7646d2SAndroid Build Coastguard Worker 
249*5e7646d2SAndroid Build Coastguard Worker   local_ipp_ref = main_ref;
250*5e7646d2SAndroid Build Coastguard Worker   DNSServiceBrowse(&local_ipp_ref, kDNSServiceFlagsShareConnection,
251*5e7646d2SAndroid Build Coastguard Worker                    kDNSServiceInterfaceIndexLocalOnly,
252*5e7646d2SAndroid Build Coastguard Worker 		   "_ipp._tcp", NULL, browse_local_callback, devices);
253*5e7646d2SAndroid Build Coastguard Worker 
254*5e7646d2SAndroid Build Coastguard Worker   local_ipp_tls_ref = main_ref;
255*5e7646d2SAndroid Build Coastguard Worker   DNSServiceBrowse(&local_ipp_tls_ref, kDNSServiceFlagsShareConnection,
256*5e7646d2SAndroid Build Coastguard Worker                    kDNSServiceInterfaceIndexLocalOnly,
257*5e7646d2SAndroid Build Coastguard Worker                    "_ipp-tls._tcp", NULL, browse_local_callback, devices);
258*5e7646d2SAndroid Build Coastguard Worker 
259*5e7646d2SAndroid Build Coastguard Worker   local_ipps_ref = main_ref;
260*5e7646d2SAndroid Build Coastguard Worker   DNSServiceBrowse(&local_ipps_ref, kDNSServiceFlagsShareConnection,
261*5e7646d2SAndroid Build Coastguard Worker                    kDNSServiceInterfaceIndexLocalOnly,
262*5e7646d2SAndroid Build Coastguard Worker 		   "_ipps._tcp", NULL, browse_local_callback, devices);
263*5e7646d2SAndroid Build Coastguard Worker 
264*5e7646d2SAndroid Build Coastguard Worker   local_printer_ref = main_ref;
265*5e7646d2SAndroid Build Coastguard Worker   DNSServiceBrowse(&local_printer_ref, kDNSServiceFlagsShareConnection,
266*5e7646d2SAndroid Build Coastguard Worker                    kDNSServiceInterfaceIndexLocalOnly,
267*5e7646d2SAndroid Build Coastguard Worker                    "_printer._tcp", NULL, browse_local_callback, devices);
268*5e7646d2SAndroid Build Coastguard Worker 
269*5e7646d2SAndroid Build Coastguard Worker   pdl_datastream_ref = main_ref;
270*5e7646d2SAndroid Build Coastguard Worker   DNSServiceBrowse(&pdl_datastream_ref, kDNSServiceFlagsShareConnection, 0,
271*5e7646d2SAndroid Build Coastguard Worker                    "_pdl-datastream._tcp", NULL, browse_callback, devices);
272*5e7646d2SAndroid Build Coastguard Worker 
273*5e7646d2SAndroid Build Coastguard Worker   printer_ref = main_ref;
274*5e7646d2SAndroid Build Coastguard Worker   DNSServiceBrowse(&printer_ref, kDNSServiceFlagsShareConnection, 0,
275*5e7646d2SAndroid Build Coastguard Worker                    "_printer._tcp", NULL, browse_callback, devices);
276*5e7646d2SAndroid Build Coastguard Worker 
277*5e7646d2SAndroid Build Coastguard Worker   riousbprint_ref = main_ref;
278*5e7646d2SAndroid Build Coastguard Worker   DNSServiceBrowse(&riousbprint_ref, kDNSServiceFlagsShareConnection, 0,
279*5e7646d2SAndroid Build Coastguard Worker                    "_riousbprint._tcp", NULL, browse_callback, devices);
280*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_DNSSD */
281*5e7646d2SAndroid Build Coastguard Worker 
282*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_AVAHI
283*5e7646d2SAndroid Build Coastguard Worker   if ((simple_poll = avahi_simple_poll_new()) == NULL)
284*5e7646d2SAndroid Build Coastguard Worker   {
285*5e7646d2SAndroid Build Coastguard Worker     fputs("DEBUG: Unable to create Avahi simple poll object.\n", stderr);
286*5e7646d2SAndroid Build Coastguard Worker     return (0);
287*5e7646d2SAndroid Build Coastguard Worker   }
288*5e7646d2SAndroid Build Coastguard Worker 
289*5e7646d2SAndroid Build Coastguard Worker   avahi_simple_poll_set_func(simple_poll, poll_callback, NULL);
290*5e7646d2SAndroid Build Coastguard Worker 
291*5e7646d2SAndroid Build Coastguard Worker   client = avahi_client_new(avahi_simple_poll_get(simple_poll),
292*5e7646d2SAndroid Build Coastguard Worker 			    0, client_callback, simple_poll, &error);
293*5e7646d2SAndroid Build Coastguard Worker   if (!client)
294*5e7646d2SAndroid Build Coastguard Worker   {
295*5e7646d2SAndroid Build Coastguard Worker     fputs("DEBUG: Unable to create Avahi client.\n", stderr);
296*5e7646d2SAndroid Build Coastguard Worker     return (0);
297*5e7646d2SAndroid Build Coastguard Worker   }
298*5e7646d2SAndroid Build Coastguard Worker 
299*5e7646d2SAndroid Build Coastguard Worker   browsers = 6;
300*5e7646d2SAndroid Build Coastguard Worker   avahi_service_browser_new(client, AVAHI_IF_UNSPEC,
301*5e7646d2SAndroid Build Coastguard Worker 			    AVAHI_PROTO_UNSPEC,
302*5e7646d2SAndroid Build Coastguard Worker 			    "_fax-ipp._tcp", NULL, 0,
303*5e7646d2SAndroid Build Coastguard Worker 			    browse_callback, devices);
304*5e7646d2SAndroid Build Coastguard Worker   avahi_service_browser_new(client, AVAHI_IF_UNSPEC,
305*5e7646d2SAndroid Build Coastguard Worker 			    AVAHI_PROTO_UNSPEC,
306*5e7646d2SAndroid Build Coastguard Worker 			    "_ipp._tcp", NULL, 0,
307*5e7646d2SAndroid Build Coastguard Worker 			    browse_callback, devices);
308*5e7646d2SAndroid Build Coastguard Worker   avahi_service_browser_new(client, AVAHI_IF_UNSPEC,
309*5e7646d2SAndroid Build Coastguard Worker 			    AVAHI_PROTO_UNSPEC,
310*5e7646d2SAndroid Build Coastguard Worker 			    "_ipp-tls._tcp", NULL, 0,
311*5e7646d2SAndroid Build Coastguard Worker 			    browse_callback, devices);
312*5e7646d2SAndroid Build Coastguard Worker   avahi_service_browser_new(client, AVAHI_IF_UNSPEC,
313*5e7646d2SAndroid Build Coastguard Worker 			    AVAHI_PROTO_UNSPEC,
314*5e7646d2SAndroid Build Coastguard Worker 			    "_ipps._tcp", NULL, 0,
315*5e7646d2SAndroid Build Coastguard Worker 			    browse_callback, devices);
316*5e7646d2SAndroid Build Coastguard Worker   avahi_service_browser_new(client, AVAHI_IF_UNSPEC,
317*5e7646d2SAndroid Build Coastguard Worker 			    AVAHI_PROTO_UNSPEC,
318*5e7646d2SAndroid Build Coastguard Worker 			    "_pdl-datastream._tcp",
319*5e7646d2SAndroid Build Coastguard Worker 			    NULL, 0,
320*5e7646d2SAndroid Build Coastguard Worker 			    browse_callback,
321*5e7646d2SAndroid Build Coastguard Worker 			    devices);
322*5e7646d2SAndroid Build Coastguard Worker   avahi_service_browser_new(client, AVAHI_IF_UNSPEC,
323*5e7646d2SAndroid Build Coastguard Worker 			    AVAHI_PROTO_UNSPEC,
324*5e7646d2SAndroid Build Coastguard Worker 			    "_printer._tcp", NULL, 0,
325*5e7646d2SAndroid Build Coastguard Worker 			    browse_callback, devices);
326*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_AVAHI */
327*5e7646d2SAndroid Build Coastguard Worker 
328*5e7646d2SAndroid Build Coastguard Worker  /*
329*5e7646d2SAndroid Build Coastguard Worker   * Loop until we are killed...
330*5e7646d2SAndroid Build Coastguard Worker   */
331*5e7646d2SAndroid Build Coastguard Worker 
332*5e7646d2SAndroid Build Coastguard Worker   while (!job_canceled)
333*5e7646d2SAndroid Build Coastguard Worker   {
334*5e7646d2SAndroid Build Coastguard Worker     int announce = 0;			/* Announce printers? */
335*5e7646d2SAndroid Build Coastguard Worker 
336*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_DNSSD
337*5e7646d2SAndroid Build Coastguard Worker     FD_ZERO(&input);
338*5e7646d2SAndroid Build Coastguard Worker     FD_SET(fd, &input);
339*5e7646d2SAndroid Build Coastguard Worker 
340*5e7646d2SAndroid Build Coastguard Worker     timeout.tv_sec  = 0;
341*5e7646d2SAndroid Build Coastguard Worker     timeout.tv_usec = 500000;
342*5e7646d2SAndroid Build Coastguard Worker 
343*5e7646d2SAndroid Build Coastguard Worker     if (select(fd + 1, &input, NULL, NULL, &timeout) < 0)
344*5e7646d2SAndroid Build Coastguard Worker       continue;
345*5e7646d2SAndroid Build Coastguard Worker 
346*5e7646d2SAndroid Build Coastguard Worker     if (FD_ISSET(fd, &input))
347*5e7646d2SAndroid Build Coastguard Worker     {
348*5e7646d2SAndroid Build Coastguard Worker      /*
349*5e7646d2SAndroid Build Coastguard Worker       * Process results of our browsing...
350*5e7646d2SAndroid Build Coastguard Worker       */
351*5e7646d2SAndroid Build Coastguard Worker 
352*5e7646d2SAndroid Build Coastguard Worker       DNSServiceProcessResult(main_ref);
353*5e7646d2SAndroid Build Coastguard Worker     }
354*5e7646d2SAndroid Build Coastguard Worker     else
355*5e7646d2SAndroid Build Coastguard Worker       announce = 1;
356*5e7646d2SAndroid Build Coastguard Worker 
357*5e7646d2SAndroid Build Coastguard Worker #elif defined(HAVE_AVAHI)
358*5e7646d2SAndroid Build Coastguard Worker     got_data = 0;
359*5e7646d2SAndroid Build Coastguard Worker 
360*5e7646d2SAndroid Build Coastguard Worker     if ((error = avahi_simple_poll_iterate(simple_poll, 500)) > 0)
361*5e7646d2SAndroid Build Coastguard Worker     {
362*5e7646d2SAndroid Build Coastguard Worker      /*
363*5e7646d2SAndroid Build Coastguard Worker       * We've been told to exit the loop.  Perhaps the connection to
364*5e7646d2SAndroid Build Coastguard Worker       * Avahi failed.
365*5e7646d2SAndroid Build Coastguard Worker       */
366*5e7646d2SAndroid Build Coastguard Worker 
367*5e7646d2SAndroid Build Coastguard Worker       break;
368*5e7646d2SAndroid Build Coastguard Worker     }
369*5e7646d2SAndroid Build Coastguard Worker 
370*5e7646d2SAndroid Build Coastguard Worker     if (!got_data)
371*5e7646d2SAndroid Build Coastguard Worker       announce = 1;
372*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_DNSSD */
373*5e7646d2SAndroid Build Coastguard Worker 
374*5e7646d2SAndroid Build Coastguard Worker /*    fprintf(stderr, "DEBUG: announce=%d\n", announce);*/
375*5e7646d2SAndroid Build Coastguard Worker 
376*5e7646d2SAndroid Build Coastguard Worker     if (announce)
377*5e7646d2SAndroid Build Coastguard Worker     {
378*5e7646d2SAndroid Build Coastguard Worker      /*
379*5e7646d2SAndroid Build Coastguard Worker       * Announce any devices we've found...
380*5e7646d2SAndroid Build Coastguard Worker       */
381*5e7646d2SAndroid Build Coastguard Worker 
382*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_DNSSD
383*5e7646d2SAndroid Build Coastguard Worker       DNSServiceErrorType status;	/* DNS query status */
384*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_DNSSD */
385*5e7646d2SAndroid Build Coastguard Worker       cups_device_t *best;		/* Best matching device */
386*5e7646d2SAndroid Build Coastguard Worker       char	device_uri[1024];	/* Device URI */
387*5e7646d2SAndroid Build Coastguard Worker       int	count;			/* Number of queries */
388*5e7646d2SAndroid Build Coastguard Worker       int	sent;			/* Number of sent */
389*5e7646d2SAndroid Build Coastguard Worker 
390*5e7646d2SAndroid Build Coastguard Worker       for (device = (cups_device_t *)cupsArrayFirst(devices),
391*5e7646d2SAndroid Build Coastguard Worker                best = NULL, count = 0, sent = 0;
392*5e7646d2SAndroid Build Coastguard Worker            device;
393*5e7646d2SAndroid Build Coastguard Worker 	   device = (cups_device_t *)cupsArrayNext(devices))
394*5e7646d2SAndroid Build Coastguard Worker       {
395*5e7646d2SAndroid Build Coastguard Worker         if (device->sent)
396*5e7646d2SAndroid Build Coastguard Worker 	  sent ++;
397*5e7646d2SAndroid Build Coastguard Worker 
398*5e7646d2SAndroid Build Coastguard Worker         if (device->ref)
399*5e7646d2SAndroid Build Coastguard Worker 	  count ++;
400*5e7646d2SAndroid Build Coastguard Worker 
401*5e7646d2SAndroid Build Coastguard Worker         if (!device->ref && !device->sent)
402*5e7646d2SAndroid Build Coastguard Worker 	{
403*5e7646d2SAndroid Build Coastguard Worker 	 /*
404*5e7646d2SAndroid Build Coastguard Worker 	  * Found the device, now get the TXT record(s) for it...
405*5e7646d2SAndroid Build Coastguard Worker 	  */
406*5e7646d2SAndroid Build Coastguard Worker 
407*5e7646d2SAndroid Build Coastguard Worker           if (count < 50)
408*5e7646d2SAndroid Build Coastguard Worker 	  {
409*5e7646d2SAndroid Build Coastguard Worker 	    fprintf(stderr, "DEBUG: Querying \"%s\"...\n", device->fullName);
410*5e7646d2SAndroid Build Coastguard Worker 
411*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_DNSSD
412*5e7646d2SAndroid Build Coastguard Worker 	    device->ref = main_ref;
413*5e7646d2SAndroid Build Coastguard Worker 
414*5e7646d2SAndroid Build Coastguard Worker 	    status = DNSServiceQueryRecord(&(device->ref),
415*5e7646d2SAndroid Build Coastguard Worker 				           kDNSServiceFlagsShareConnection,
416*5e7646d2SAndroid Build Coastguard Worker 				           0, device->fullName,
417*5e7646d2SAndroid Build Coastguard Worker 					   kDNSServiceType_TXT,
418*5e7646d2SAndroid Build Coastguard Worker 				           kDNSServiceClass_IN, query_callback,
419*5e7646d2SAndroid Build Coastguard Worker 				           device);
420*5e7646d2SAndroid Build Coastguard Worker             if (status != kDNSServiceErr_NoError)
421*5e7646d2SAndroid Build Coastguard Worker 	      fprintf(stderr,
422*5e7646d2SAndroid Build Coastguard Worker 	              "ERROR: Unable to query \"%s\" for TXT records: %d\n",
423*5e7646d2SAndroid Build Coastguard Worker 	              device->fullName, status);
424*5e7646d2SAndroid Build Coastguard Worker 	              			/* Users never see this */
425*5e7646d2SAndroid Build Coastguard Worker 	    else
426*5e7646d2SAndroid Build Coastguard Worker 	      count ++;
427*5e7646d2SAndroid Build Coastguard Worker 
428*5e7646d2SAndroid Build Coastguard Worker #else
429*5e7646d2SAndroid Build Coastguard Worker 	    if ((device->ref = avahi_record_browser_new(client, AVAHI_IF_UNSPEC,
430*5e7646d2SAndroid Build Coastguard Worker 	                                                AVAHI_PROTO_UNSPEC,
431*5e7646d2SAndroid Build Coastguard Worker 	                                                device->fullName,
432*5e7646d2SAndroid Build Coastguard Worker 	                                                AVAHI_DNS_CLASS_IN,
433*5e7646d2SAndroid Build Coastguard Worker 	                                                AVAHI_DNS_TYPE_TXT,
434*5e7646d2SAndroid Build Coastguard Worker 	                                                0,
435*5e7646d2SAndroid Build Coastguard Worker 				                        query_callback,
436*5e7646d2SAndroid Build Coastguard Worker 				                        device)) == NULL)
437*5e7646d2SAndroid Build Coastguard Worker 	      fprintf(stderr,
438*5e7646d2SAndroid Build Coastguard Worker 	              "ERROR: Unable to query \"%s\" for TXT records: %s\n",
439*5e7646d2SAndroid Build Coastguard Worker 	              device->fullName,
440*5e7646d2SAndroid Build Coastguard Worker 	              avahi_strerror(avahi_client_errno(client)));
441*5e7646d2SAndroid Build Coastguard Worker 	              			/* Users never see this */
442*5e7646d2SAndroid Build Coastguard Worker 	    else
443*5e7646d2SAndroid Build Coastguard Worker 	      count ++;
444*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_AVAHI */
445*5e7646d2SAndroid Build Coastguard Worker           }
446*5e7646d2SAndroid Build Coastguard Worker 	}
447*5e7646d2SAndroid Build Coastguard Worker 	else if (!device->sent)
448*5e7646d2SAndroid Build Coastguard Worker 	{
449*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_DNSSD
450*5e7646d2SAndroid Build Coastguard Worker 	 /*
451*5e7646d2SAndroid Build Coastguard Worker 	  * Got the TXT records, now report the device...
452*5e7646d2SAndroid Build Coastguard Worker 	  */
453*5e7646d2SAndroid Build Coastguard Worker 
454*5e7646d2SAndroid Build Coastguard Worker 	  DNSServiceRefDeallocate(device->ref);
455*5e7646d2SAndroid Build Coastguard Worker #else
456*5e7646d2SAndroid Build Coastguard Worker           avahi_record_browser_free(device->ref);
457*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_DNSSD */
458*5e7646d2SAndroid Build Coastguard Worker 
459*5e7646d2SAndroid Build Coastguard Worker 	  device->ref = NULL;
460*5e7646d2SAndroid Build Coastguard Worker 
461*5e7646d2SAndroid Build Coastguard Worker           if (!best)
462*5e7646d2SAndroid Build Coastguard Worker 	    best = device;
463*5e7646d2SAndroid Build Coastguard Worker 	  else if (_cups_strcasecmp(best->name, device->name) ||
464*5e7646d2SAndroid Build Coastguard Worker 	           _cups_strcasecmp(best->domain, device->domain))
465*5e7646d2SAndroid Build Coastguard Worker           {
466*5e7646d2SAndroid Build Coastguard Worker 	    unquote(uriName, best->fullName, sizeof(uriName));
467*5e7646d2SAndroid Build Coastguard Worker 
468*5e7646d2SAndroid Build Coastguard Worker             if (best->uuid)
469*5e7646d2SAndroid Build Coastguard Worker 	      httpAssembleURIf(HTTP_URI_CODING_ALL, device_uri,
470*5e7646d2SAndroid Build Coastguard Worker 	                       sizeof(device_uri), "dnssd", NULL, uriName, 0,
471*5e7646d2SAndroid Build Coastguard Worker 			       best->cups_shared ? "/cups?uuid=%s" : "/?uuid=%s",
472*5e7646d2SAndroid Build Coastguard Worker 			       best->uuid);
473*5e7646d2SAndroid Build Coastguard Worker 	    else
474*5e7646d2SAndroid Build Coastguard Worker 	      httpAssembleURI(HTTP_URI_CODING_ALL, device_uri,
475*5e7646d2SAndroid Build Coastguard Worker 	                      sizeof(device_uri), "dnssd", NULL, uriName, 0,
476*5e7646d2SAndroid Build Coastguard Worker 			      best->cups_shared ? "/cups" : "/");
477*5e7646d2SAndroid Build Coastguard Worker 
478*5e7646d2SAndroid Build Coastguard Worker 	    cupsBackendReport("network", device_uri, best->make_and_model,
479*5e7646d2SAndroid Build Coastguard Worker 	                      best->name, best->device_id, NULL);
480*5e7646d2SAndroid Build Coastguard Worker 	    best->sent = 1;
481*5e7646d2SAndroid Build Coastguard Worker 	    best       = device;
482*5e7646d2SAndroid Build Coastguard Worker 
483*5e7646d2SAndroid Build Coastguard Worker 	    sent ++;
484*5e7646d2SAndroid Build Coastguard Worker 	  }
485*5e7646d2SAndroid Build Coastguard Worker 	  else if (best->priority > device->priority ||
486*5e7646d2SAndroid Build Coastguard Worker 	           (best->priority == device->priority &&
487*5e7646d2SAndroid Build Coastguard Worker 		    best->type < device->type))
488*5e7646d2SAndroid Build Coastguard Worker           {
489*5e7646d2SAndroid Build Coastguard Worker 	    best->sent = 1;
490*5e7646d2SAndroid Build Coastguard Worker 	    best       = device;
491*5e7646d2SAndroid Build Coastguard Worker 
492*5e7646d2SAndroid Build Coastguard Worker 	    sent ++;
493*5e7646d2SAndroid Build Coastguard Worker 	  }
494*5e7646d2SAndroid Build Coastguard Worker 	  else
495*5e7646d2SAndroid Build Coastguard Worker 	  {
496*5e7646d2SAndroid Build Coastguard Worker 	    device->sent = 1;
497*5e7646d2SAndroid Build Coastguard Worker 
498*5e7646d2SAndroid Build Coastguard Worker 	    sent ++;
499*5e7646d2SAndroid Build Coastguard Worker 	  }
500*5e7646d2SAndroid Build Coastguard Worker         }
501*5e7646d2SAndroid Build Coastguard Worker       }
502*5e7646d2SAndroid Build Coastguard Worker 
503*5e7646d2SAndroid Build Coastguard Worker       if (best)
504*5e7646d2SAndroid Build Coastguard Worker       {
505*5e7646d2SAndroid Build Coastguard Worker 	unquote(uriName, best->fullName, sizeof(uriName));
506*5e7646d2SAndroid Build Coastguard Worker 
507*5e7646d2SAndroid Build Coastguard Worker 	if (best->uuid)
508*5e7646d2SAndroid Build Coastguard Worker 	  httpAssembleURIf(HTTP_URI_CODING_ALL, device_uri,
509*5e7646d2SAndroid Build Coastguard Worker 			   sizeof(device_uri), "dnssd", NULL, uriName, 0,
510*5e7646d2SAndroid Build Coastguard Worker 			   best->cups_shared ? "/cups?uuid=%s" : "/?uuid=%s",
511*5e7646d2SAndroid Build Coastguard Worker 			   best->uuid);
512*5e7646d2SAndroid Build Coastguard Worker 	else
513*5e7646d2SAndroid Build Coastguard Worker 	  httpAssembleURI(HTTP_URI_CODING_ALL, device_uri,
514*5e7646d2SAndroid Build Coastguard Worker 			  sizeof(device_uri), "dnssd", NULL, uriName, 0,
515*5e7646d2SAndroid Build Coastguard Worker 			  best->cups_shared ? "/cups" : "/");
516*5e7646d2SAndroid Build Coastguard Worker 
517*5e7646d2SAndroid Build Coastguard Worker 	cupsBackendReport("network", device_uri, best->make_and_model,
518*5e7646d2SAndroid Build Coastguard Worker 			  best->name, best->device_id, NULL);
519*5e7646d2SAndroid Build Coastguard Worker 	best->sent = 1;
520*5e7646d2SAndroid Build Coastguard Worker 	sent ++;
521*5e7646d2SAndroid Build Coastguard Worker       }
522*5e7646d2SAndroid Build Coastguard Worker 
523*5e7646d2SAndroid Build Coastguard Worker       fprintf(stderr, "DEBUG: sent=%d, count=%d\n", sent, count);
524*5e7646d2SAndroid Build Coastguard Worker 
525*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_AVAHI
526*5e7646d2SAndroid Build Coastguard Worker       if (sent == cupsArrayCount(devices) && browsers == 0)
527*5e7646d2SAndroid Build Coastguard Worker #else
528*5e7646d2SAndroid Build Coastguard Worker       if (sent == cupsArrayCount(devices))
529*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_AVAHI */
530*5e7646d2SAndroid Build Coastguard Worker 	break;
531*5e7646d2SAndroid Build Coastguard Worker     }
532*5e7646d2SAndroid Build Coastguard Worker   }
533*5e7646d2SAndroid Build Coastguard Worker 
534*5e7646d2SAndroid Build Coastguard Worker   return (CUPS_BACKEND_OK);
535*5e7646d2SAndroid Build Coastguard Worker }
536*5e7646d2SAndroid Build Coastguard Worker 
537*5e7646d2SAndroid Build Coastguard Worker 
538*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_DNSSD
539*5e7646d2SAndroid Build Coastguard Worker /*
540*5e7646d2SAndroid Build Coastguard Worker  * 'browse_callback()' - Browse devices.
541*5e7646d2SAndroid Build Coastguard Worker  */
542*5e7646d2SAndroid Build Coastguard Worker 
543*5e7646d2SAndroid Build Coastguard Worker static void
browse_callback(DNSServiceRef sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,DNSServiceErrorType errorCode,const char * serviceName,const char * regtype,const char * replyDomain,void * context)544*5e7646d2SAndroid Build Coastguard Worker browse_callback(
545*5e7646d2SAndroid Build Coastguard Worker     DNSServiceRef       sdRef,		/* I - Service reference */
546*5e7646d2SAndroid Build Coastguard Worker     DNSServiceFlags     flags,		/* I - Option flags */
547*5e7646d2SAndroid Build Coastguard Worker     uint32_t            interfaceIndex,	/* I - Interface number */
548*5e7646d2SAndroid Build Coastguard Worker     DNSServiceErrorType errorCode,	/* I - Error, if any */
549*5e7646d2SAndroid Build Coastguard Worker     const char          *serviceName,	/* I - Name of service/device */
550*5e7646d2SAndroid Build Coastguard Worker     const char          *regtype,	/* I - Type of service */
551*5e7646d2SAndroid Build Coastguard Worker     const char          *replyDomain,	/* I - Service domain */
552*5e7646d2SAndroid Build Coastguard Worker     void                *context)	/* I - Devices array */
553*5e7646d2SAndroid Build Coastguard Worker {
554*5e7646d2SAndroid Build Coastguard Worker   fprintf(stderr, "DEBUG2: browse_callback(sdRef=%p, flags=%x, "
555*5e7646d2SAndroid Build Coastguard Worker                   "interfaceIndex=%d, errorCode=%d, serviceName=\"%s\", "
556*5e7646d2SAndroid Build Coastguard Worker 		  "regtype=\"%s\", replyDomain=\"%s\", context=%p)\n",
557*5e7646d2SAndroid Build Coastguard Worker           sdRef, flags, interfaceIndex, errorCode,
558*5e7646d2SAndroid Build Coastguard Worker 	  serviceName, regtype, replyDomain, context);
559*5e7646d2SAndroid Build Coastguard Worker 
560*5e7646d2SAndroid Build Coastguard Worker  /*
561*5e7646d2SAndroid Build Coastguard Worker   * Only process "add" data...
562*5e7646d2SAndroid Build Coastguard Worker   */
563*5e7646d2SAndroid Build Coastguard Worker 
564*5e7646d2SAndroid Build Coastguard Worker   if (errorCode != kDNSServiceErr_NoError || !(flags & kDNSServiceFlagsAdd))
565*5e7646d2SAndroid Build Coastguard Worker     return;
566*5e7646d2SAndroid Build Coastguard Worker 
567*5e7646d2SAndroid Build Coastguard Worker  /*
568*5e7646d2SAndroid Build Coastguard Worker   * Get the device...
569*5e7646d2SAndroid Build Coastguard Worker   */
570*5e7646d2SAndroid Build Coastguard Worker 
571*5e7646d2SAndroid Build Coastguard Worker   get_device((cups_array_t *)context, serviceName, regtype, replyDomain);
572*5e7646d2SAndroid Build Coastguard Worker }
573*5e7646d2SAndroid Build Coastguard Worker 
574*5e7646d2SAndroid Build Coastguard Worker 
575*5e7646d2SAndroid Build Coastguard Worker /*
576*5e7646d2SAndroid Build Coastguard Worker  * 'browse_local_callback()' - Browse local devices.
577*5e7646d2SAndroid Build Coastguard Worker  */
578*5e7646d2SAndroid Build Coastguard Worker 
579*5e7646d2SAndroid Build Coastguard Worker static void
browse_local_callback(DNSServiceRef sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,DNSServiceErrorType errorCode,const char * serviceName,const char * regtype,const char * replyDomain,void * context)580*5e7646d2SAndroid Build Coastguard Worker browse_local_callback(
581*5e7646d2SAndroid Build Coastguard Worker     DNSServiceRef       sdRef,		/* I - Service reference */
582*5e7646d2SAndroid Build Coastguard Worker     DNSServiceFlags     flags,		/* I - Option flags */
583*5e7646d2SAndroid Build Coastguard Worker     uint32_t            interfaceIndex,	/* I - Interface number */
584*5e7646d2SAndroid Build Coastguard Worker     DNSServiceErrorType errorCode,	/* I - Error, if any */
585*5e7646d2SAndroid Build Coastguard Worker     const char          *serviceName,	/* I - Name of service/device */
586*5e7646d2SAndroid Build Coastguard Worker     const char          *regtype,	/* I - Type of service */
587*5e7646d2SAndroid Build Coastguard Worker     const char          *replyDomain,	/* I - Service domain */
588*5e7646d2SAndroid Build Coastguard Worker     void                *context)	/* I - Devices array */
589*5e7646d2SAndroid Build Coastguard Worker {
590*5e7646d2SAndroid Build Coastguard Worker   cups_device_t	*device;		/* Device */
591*5e7646d2SAndroid Build Coastguard Worker 
592*5e7646d2SAndroid Build Coastguard Worker 
593*5e7646d2SAndroid Build Coastguard Worker   fprintf(stderr, "DEBUG2: browse_local_callback(sdRef=%p, flags=%x, "
594*5e7646d2SAndroid Build Coastguard Worker                   "interfaceIndex=%d, errorCode=%d, serviceName=\"%s\", "
595*5e7646d2SAndroid Build Coastguard Worker 		  "regtype=\"%s\", replyDomain=\"%s\", context=%p)\n",
596*5e7646d2SAndroid Build Coastguard Worker           sdRef, flags, interfaceIndex, errorCode,
597*5e7646d2SAndroid Build Coastguard Worker 	  serviceName, regtype, replyDomain, context);
598*5e7646d2SAndroid Build Coastguard Worker 
599*5e7646d2SAndroid Build Coastguard Worker  /*
600*5e7646d2SAndroid Build Coastguard Worker   * Only process "add" data...
601*5e7646d2SAndroid Build Coastguard Worker   */
602*5e7646d2SAndroid Build Coastguard Worker 
603*5e7646d2SAndroid Build Coastguard Worker   if (errorCode != kDNSServiceErr_NoError || !(flags & kDNSServiceFlagsAdd))
604*5e7646d2SAndroid Build Coastguard Worker     return;
605*5e7646d2SAndroid Build Coastguard Worker 
606*5e7646d2SAndroid Build Coastguard Worker  /*
607*5e7646d2SAndroid Build Coastguard Worker   * Get the device...
608*5e7646d2SAndroid Build Coastguard Worker   */
609*5e7646d2SAndroid Build Coastguard Worker 
610*5e7646d2SAndroid Build Coastguard Worker   device = get_device((cups_array_t *)context, serviceName, regtype,
611*5e7646d2SAndroid Build Coastguard Worker                       replyDomain);
612*5e7646d2SAndroid Build Coastguard Worker 
613*5e7646d2SAndroid Build Coastguard Worker  /*
614*5e7646d2SAndroid Build Coastguard Worker   * Hide locally-registered devices...
615*5e7646d2SAndroid Build Coastguard Worker   */
616*5e7646d2SAndroid Build Coastguard Worker 
617*5e7646d2SAndroid Build Coastguard Worker   fprintf(stderr, "DEBUG: Hiding local printer \"%s\"...\n",
618*5e7646d2SAndroid Build Coastguard Worker 	  device->fullName);
619*5e7646d2SAndroid Build Coastguard Worker   device->sent = 1;
620*5e7646d2SAndroid Build Coastguard Worker }
621*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_DNSSD */
622*5e7646d2SAndroid Build Coastguard Worker 
623*5e7646d2SAndroid Build Coastguard Worker 
624*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_AVAHI
625*5e7646d2SAndroid Build Coastguard Worker /*
626*5e7646d2SAndroid Build Coastguard Worker  * 'browse_callback()' - Browse devices.
627*5e7646d2SAndroid Build Coastguard Worker  */
628*5e7646d2SAndroid Build Coastguard Worker 
629*5e7646d2SAndroid Build Coastguard Worker static void
browse_callback(AvahiServiceBrowser * browser,AvahiIfIndex interface,AvahiProtocol protocol,AvahiBrowserEvent event,const char * name,const char * type,const char * domain,AvahiLookupResultFlags flags,void * context)630*5e7646d2SAndroid Build Coastguard Worker browse_callback(
631*5e7646d2SAndroid Build Coastguard Worker     AvahiServiceBrowser    *browser,	/* I - Browser */
632*5e7646d2SAndroid Build Coastguard Worker     AvahiIfIndex           interface,	/* I - Interface index (unused) */
633*5e7646d2SAndroid Build Coastguard Worker     AvahiProtocol          protocol,	/* I - Network protocol (unused) */
634*5e7646d2SAndroid Build Coastguard Worker     AvahiBrowserEvent      event,	/* I - What happened */
635*5e7646d2SAndroid Build Coastguard Worker     const char             *name,	/* I - Service name */
636*5e7646d2SAndroid Build Coastguard Worker     const char             *type,	/* I - Registration type */
637*5e7646d2SAndroid Build Coastguard Worker     const char             *domain,	/* I - Domain */
638*5e7646d2SAndroid Build Coastguard Worker     AvahiLookupResultFlags flags,	/* I - Flags */
639*5e7646d2SAndroid Build Coastguard Worker     void                   *context)	/* I - Devices array */
640*5e7646d2SAndroid Build Coastguard Worker {
641*5e7646d2SAndroid Build Coastguard Worker   AvahiClient *client = avahi_service_browser_get_client(browser);
642*5e7646d2SAndroid Build Coastguard Worker 					/* Client information */
643*5e7646d2SAndroid Build Coastguard Worker 
644*5e7646d2SAndroid Build Coastguard Worker 
645*5e7646d2SAndroid Build Coastguard Worker   (void)interface;
646*5e7646d2SAndroid Build Coastguard Worker   (void)protocol;
647*5e7646d2SAndroid Build Coastguard Worker   (void)context;
648*5e7646d2SAndroid Build Coastguard Worker 
649*5e7646d2SAndroid Build Coastguard Worker   switch (event)
650*5e7646d2SAndroid Build Coastguard Worker   {
651*5e7646d2SAndroid Build Coastguard Worker     case AVAHI_BROWSER_FAILURE:
652*5e7646d2SAndroid Build Coastguard Worker 	fprintf(stderr, "DEBUG: browse_callback: %s\n",
653*5e7646d2SAndroid Build Coastguard Worker 		avahi_strerror(avahi_client_errno(client)));
654*5e7646d2SAndroid Build Coastguard Worker 	avahi_simple_poll_quit(simple_poll);
655*5e7646d2SAndroid Build Coastguard Worker 	break;
656*5e7646d2SAndroid Build Coastguard Worker 
657*5e7646d2SAndroid Build Coastguard Worker     case AVAHI_BROWSER_NEW:
658*5e7646d2SAndroid Build Coastguard Worker        /*
659*5e7646d2SAndroid Build Coastguard Worker 	* This object is new on the network.
660*5e7646d2SAndroid Build Coastguard Worker 	*/
661*5e7646d2SAndroid Build Coastguard Worker 
662*5e7646d2SAndroid Build Coastguard Worker 	if (flags & AVAHI_LOOKUP_RESULT_LOCAL)
663*5e7646d2SAndroid Build Coastguard Worker 	{
664*5e7646d2SAndroid Build Coastguard Worker 	 /*
665*5e7646d2SAndroid Build Coastguard Worker 	  * This comes from the local machine so ignore it.
666*5e7646d2SAndroid Build Coastguard Worker 	  */
667*5e7646d2SAndroid Build Coastguard Worker 
668*5e7646d2SAndroid Build Coastguard Worker 	  fprintf(stderr, "DEBUG: Ignoring local service %s.\n", name);
669*5e7646d2SAndroid Build Coastguard Worker 	}
670*5e7646d2SAndroid Build Coastguard Worker 	else
671*5e7646d2SAndroid Build Coastguard Worker 	{
672*5e7646d2SAndroid Build Coastguard Worker 	 /*
673*5e7646d2SAndroid Build Coastguard Worker 	  * Create a device entry for it if it doesn't yet exist.
674*5e7646d2SAndroid Build Coastguard Worker 	  */
675*5e7646d2SAndroid Build Coastguard Worker 
676*5e7646d2SAndroid Build Coastguard Worker 	  get_device((cups_array_t *)context, name, type, domain);
677*5e7646d2SAndroid Build Coastguard Worker 	}
678*5e7646d2SAndroid Build Coastguard Worker 	break;
679*5e7646d2SAndroid Build Coastguard Worker 
680*5e7646d2SAndroid Build Coastguard Worker     case AVAHI_BROWSER_REMOVE:
681*5e7646d2SAndroid Build Coastguard Worker     case AVAHI_BROWSER_CACHE_EXHAUSTED:
682*5e7646d2SAndroid Build Coastguard Worker         break;
683*5e7646d2SAndroid Build Coastguard Worker 
684*5e7646d2SAndroid Build Coastguard Worker     case AVAHI_BROWSER_ALL_FOR_NOW:
685*5e7646d2SAndroid Build Coastguard Worker 	browsers--;
686*5e7646d2SAndroid Build Coastguard Worker 	break;
687*5e7646d2SAndroid Build Coastguard Worker   }
688*5e7646d2SAndroid Build Coastguard Worker }
689*5e7646d2SAndroid Build Coastguard Worker 
690*5e7646d2SAndroid Build Coastguard Worker 
691*5e7646d2SAndroid Build Coastguard Worker /*
692*5e7646d2SAndroid Build Coastguard Worker  * 'client_callback()' - Avahi client callback function.
693*5e7646d2SAndroid Build Coastguard Worker  */
694*5e7646d2SAndroid Build Coastguard Worker 
695*5e7646d2SAndroid Build Coastguard Worker static void
client_callback(AvahiClient * client,AvahiClientState state,void * context)696*5e7646d2SAndroid Build Coastguard Worker client_callback(
697*5e7646d2SAndroid Build Coastguard Worker     AvahiClient      *client,		/* I - Client information (unused) */
698*5e7646d2SAndroid Build Coastguard Worker     AvahiClientState state,		/* I - Current state */
699*5e7646d2SAndroid Build Coastguard Worker     void             *context)		/* I - User data (unused) */
700*5e7646d2SAndroid Build Coastguard Worker {
701*5e7646d2SAndroid Build Coastguard Worker   (void)client;
702*5e7646d2SAndroid Build Coastguard Worker   (void)context;
703*5e7646d2SAndroid Build Coastguard Worker 
704*5e7646d2SAndroid Build Coastguard Worker  /*
705*5e7646d2SAndroid Build Coastguard Worker   * If the connection drops, quit.
706*5e7646d2SAndroid Build Coastguard Worker   */
707*5e7646d2SAndroid Build Coastguard Worker 
708*5e7646d2SAndroid Build Coastguard Worker   if (state == AVAHI_CLIENT_FAILURE)
709*5e7646d2SAndroid Build Coastguard Worker   {
710*5e7646d2SAndroid Build Coastguard Worker     fputs("DEBUG: Avahi connection failed.\n", stderr);
711*5e7646d2SAndroid Build Coastguard Worker     avahi_simple_poll_quit(simple_poll);
712*5e7646d2SAndroid Build Coastguard Worker   }
713*5e7646d2SAndroid Build Coastguard Worker }
714*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_AVAHI */
715*5e7646d2SAndroid Build Coastguard Worker 
716*5e7646d2SAndroid Build Coastguard Worker 
717*5e7646d2SAndroid Build Coastguard Worker /*
718*5e7646d2SAndroid Build Coastguard Worker  * 'compare_devices()' - Compare two devices.
719*5e7646d2SAndroid Build Coastguard Worker  */
720*5e7646d2SAndroid Build Coastguard Worker 
721*5e7646d2SAndroid Build Coastguard Worker static int				/* O - Result of comparison */
compare_devices(cups_device_t * a,cups_device_t * b)722*5e7646d2SAndroid Build Coastguard Worker compare_devices(cups_device_t *a,	/* I - First device */
723*5e7646d2SAndroid Build Coastguard Worker                 cups_device_t *b)	/* I - Second device */
724*5e7646d2SAndroid Build Coastguard Worker {
725*5e7646d2SAndroid Build Coastguard Worker   return (strcmp(a->name, b->name));
726*5e7646d2SAndroid Build Coastguard Worker }
727*5e7646d2SAndroid Build Coastguard Worker 
728*5e7646d2SAndroid Build Coastguard Worker 
729*5e7646d2SAndroid Build Coastguard Worker /*
730*5e7646d2SAndroid Build Coastguard Worker  * 'exec_backend()' - Execute the backend that corresponds to the
731*5e7646d2SAndroid Build Coastguard Worker  *                    resolved service name.
732*5e7646d2SAndroid Build Coastguard Worker  */
733*5e7646d2SAndroid Build Coastguard Worker 
734*5e7646d2SAndroid Build Coastguard Worker static void
exec_backend(char ** argv)735*5e7646d2SAndroid Build Coastguard Worker exec_backend(char **argv)		/* I - Command-line arguments */
736*5e7646d2SAndroid Build Coastguard Worker {
737*5e7646d2SAndroid Build Coastguard Worker   const char	*resolved_uri,		/* Resolved device URI */
738*5e7646d2SAndroid Build Coastguard Worker 		*cups_serverbin;	/* Location of programs */
739*5e7646d2SAndroid Build Coastguard Worker   char		scheme[1024],		/* Scheme from URI */
740*5e7646d2SAndroid Build Coastguard Worker 		*ptr,			/* Pointer into scheme */
741*5e7646d2SAndroid Build Coastguard Worker 		filename[1024];		/* Backend filename */
742*5e7646d2SAndroid Build Coastguard Worker 
743*5e7646d2SAndroid Build Coastguard Worker 
744*5e7646d2SAndroid Build Coastguard Worker  /*
745*5e7646d2SAndroid Build Coastguard Worker   * Resolve the device URI...
746*5e7646d2SAndroid Build Coastguard Worker   */
747*5e7646d2SAndroid Build Coastguard Worker 
748*5e7646d2SAndroid Build Coastguard Worker   job_canceled = -1;
749*5e7646d2SAndroid Build Coastguard Worker 
750*5e7646d2SAndroid Build Coastguard Worker   while ((resolved_uri = cupsBackendDeviceURI(argv)) == NULL)
751*5e7646d2SAndroid Build Coastguard Worker   {
752*5e7646d2SAndroid Build Coastguard Worker     _cupsLangPrintFilter(stderr, "INFO", _("Unable to locate printer."));
753*5e7646d2SAndroid Build Coastguard Worker     sleep(10);
754*5e7646d2SAndroid Build Coastguard Worker 
755*5e7646d2SAndroid Build Coastguard Worker     if (getenv("CLASS") != NULL)
756*5e7646d2SAndroid Build Coastguard Worker       exit(CUPS_BACKEND_FAILED);
757*5e7646d2SAndroid Build Coastguard Worker   }
758*5e7646d2SAndroid Build Coastguard Worker 
759*5e7646d2SAndroid Build Coastguard Worker  /*
760*5e7646d2SAndroid Build Coastguard Worker   * Extract the scheme from the URI...
761*5e7646d2SAndroid Build Coastguard Worker   */
762*5e7646d2SAndroid Build Coastguard Worker 
763*5e7646d2SAndroid Build Coastguard Worker   strlcpy(scheme, resolved_uri, sizeof(scheme));
764*5e7646d2SAndroid Build Coastguard Worker   if ((ptr = strchr(scheme, ':')) != NULL)
765*5e7646d2SAndroid Build Coastguard Worker     *ptr = '\0';
766*5e7646d2SAndroid Build Coastguard Worker 
767*5e7646d2SAndroid Build Coastguard Worker  /*
768*5e7646d2SAndroid Build Coastguard Worker   * Get the filename of the backend...
769*5e7646d2SAndroid Build Coastguard Worker   */
770*5e7646d2SAndroid Build Coastguard Worker 
771*5e7646d2SAndroid Build Coastguard Worker   if ((cups_serverbin = getenv("CUPS_SERVERBIN")) == NULL)
772*5e7646d2SAndroid Build Coastguard Worker     cups_serverbin = CUPS_SERVERBIN;
773*5e7646d2SAndroid Build Coastguard Worker 
774*5e7646d2SAndroid Build Coastguard Worker   snprintf(filename, sizeof(filename), "%s/backend/%s", cups_serverbin, scheme);
775*5e7646d2SAndroid Build Coastguard Worker 
776*5e7646d2SAndroid Build Coastguard Worker  /*
777*5e7646d2SAndroid Build Coastguard Worker   * Overwrite the device URI and run the new backend...
778*5e7646d2SAndroid Build Coastguard Worker   */
779*5e7646d2SAndroid Build Coastguard Worker 
780*5e7646d2SAndroid Build Coastguard Worker   setenv("DEVICE_URI", resolved_uri, 1);
781*5e7646d2SAndroid Build Coastguard Worker 
782*5e7646d2SAndroid Build Coastguard Worker   argv[0] = (char *)resolved_uri;
783*5e7646d2SAndroid Build Coastguard Worker 
784*5e7646d2SAndroid Build Coastguard Worker   fprintf(stderr, "DEBUG: Executing backend \"%s\"...\n", filename);
785*5e7646d2SAndroid Build Coastguard Worker 
786*5e7646d2SAndroid Build Coastguard Worker   execv(filename, argv);
787*5e7646d2SAndroid Build Coastguard Worker 
788*5e7646d2SAndroid Build Coastguard Worker   fprintf(stderr, "ERROR: Unable to execute backend \"%s\": %s\n", filename,
789*5e7646d2SAndroid Build Coastguard Worker           strerror(errno));
790*5e7646d2SAndroid Build Coastguard Worker   exit(CUPS_BACKEND_STOP);
791*5e7646d2SAndroid Build Coastguard Worker }
792*5e7646d2SAndroid Build Coastguard Worker 
793*5e7646d2SAndroid Build Coastguard Worker 
794*5e7646d2SAndroid Build Coastguard Worker /*
795*5e7646d2SAndroid Build Coastguard Worker  * 'device_type()' - Get DNS-SD type enumeration from string.
796*5e7646d2SAndroid Build Coastguard Worker  */
797*5e7646d2SAndroid Build Coastguard Worker 
798*5e7646d2SAndroid Build Coastguard Worker static cups_devtype_t			/* O - Device type */
device_type(const char * regtype)799*5e7646d2SAndroid Build Coastguard Worker device_type(const char *regtype)	/* I - Service registration type */
800*5e7646d2SAndroid Build Coastguard Worker {
801*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_AVAHI
802*5e7646d2SAndroid Build Coastguard Worker   if (!strcmp(regtype, "_ipp._tcp"))
803*5e7646d2SAndroid Build Coastguard Worker     return (CUPS_DEVICE_IPP);
804*5e7646d2SAndroid Build Coastguard Worker   else if (!strcmp(regtype, "_ipps._tcp") ||
805*5e7646d2SAndroid Build Coastguard Worker 	   !strcmp(regtype, "_ipp-tls._tcp"))
806*5e7646d2SAndroid Build Coastguard Worker     return (CUPS_DEVICE_IPPS);
807*5e7646d2SAndroid Build Coastguard Worker   else if (!strcmp(regtype, "_fax-ipp._tcp"))
808*5e7646d2SAndroid Build Coastguard Worker     return (CUPS_DEVICE_FAX_IPP);
809*5e7646d2SAndroid Build Coastguard Worker   else if (!strcmp(regtype, "_printer._tcp"))
810*5e7646d2SAndroid Build Coastguard Worker     return (CUPS_DEVICE_PDL_DATASTREAM);
811*5e7646d2SAndroid Build Coastguard Worker #else
812*5e7646d2SAndroid Build Coastguard Worker   if (!strcmp(regtype, "_ipp._tcp."))
813*5e7646d2SAndroid Build Coastguard Worker     return (CUPS_DEVICE_IPP);
814*5e7646d2SAndroid Build Coastguard Worker   else if (!strcmp(regtype, "_ipps._tcp.") ||
815*5e7646d2SAndroid Build Coastguard Worker 	   !strcmp(regtype, "_ipp-tls._tcp."))
816*5e7646d2SAndroid Build Coastguard Worker     return (CUPS_DEVICE_IPPS);
817*5e7646d2SAndroid Build Coastguard Worker   else if (!strcmp(regtype, "_fax-ipp._tcp."))
818*5e7646d2SAndroid Build Coastguard Worker     return (CUPS_DEVICE_FAX_IPP);
819*5e7646d2SAndroid Build Coastguard Worker   else if (!strcmp(regtype, "_printer._tcp."))
820*5e7646d2SAndroid Build Coastguard Worker     return (CUPS_DEVICE_PRINTER);
821*5e7646d2SAndroid Build Coastguard Worker   else if (!strcmp(regtype, "_pdl-datastream._tcp."))
822*5e7646d2SAndroid Build Coastguard Worker     return (CUPS_DEVICE_PDL_DATASTREAM);
823*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_AVAHI */
824*5e7646d2SAndroid Build Coastguard Worker 
825*5e7646d2SAndroid Build Coastguard Worker   return (CUPS_DEVICE_RIOUSBPRINT);
826*5e7646d2SAndroid Build Coastguard Worker }
827*5e7646d2SAndroid Build Coastguard Worker 
828*5e7646d2SAndroid Build Coastguard Worker 
829*5e7646d2SAndroid Build Coastguard Worker /*
830*5e7646d2SAndroid Build Coastguard Worker  * 'get_device()' - Create or update a device.
831*5e7646d2SAndroid Build Coastguard Worker  */
832*5e7646d2SAndroid Build Coastguard Worker 
833*5e7646d2SAndroid Build Coastguard Worker static cups_device_t *			/* O - Device */
get_device(cups_array_t * devices,const char * serviceName,const char * regtype,const char * replyDomain)834*5e7646d2SAndroid Build Coastguard Worker get_device(cups_array_t *devices,	/* I - Device array */
835*5e7646d2SAndroid Build Coastguard Worker            const char   *serviceName,	/* I - Name of service/device */
836*5e7646d2SAndroid Build Coastguard Worker            const char   *regtype,	/* I - Type of service */
837*5e7646d2SAndroid Build Coastguard Worker            const char   *replyDomain)	/* I - Service domain */
838*5e7646d2SAndroid Build Coastguard Worker {
839*5e7646d2SAndroid Build Coastguard Worker   cups_device_t	key,			/* Search key */
840*5e7646d2SAndroid Build Coastguard Worker 		*device;		/* Device */
841*5e7646d2SAndroid Build Coastguard Worker   char		fullName[kDNSServiceMaxDomainName];
842*5e7646d2SAndroid Build Coastguard Worker 					/* Full name for query */
843*5e7646d2SAndroid Build Coastguard Worker 
844*5e7646d2SAndroid Build Coastguard Worker 
845*5e7646d2SAndroid Build Coastguard Worker  /*
846*5e7646d2SAndroid Build Coastguard Worker   * See if this is a new device...
847*5e7646d2SAndroid Build Coastguard Worker   */
848*5e7646d2SAndroid Build Coastguard Worker 
849*5e7646d2SAndroid Build Coastguard Worker   key.name = (char *)serviceName;
850*5e7646d2SAndroid Build Coastguard Worker   key.type = device_type(regtype);
851*5e7646d2SAndroid Build Coastguard Worker 
852*5e7646d2SAndroid Build Coastguard Worker   for (device = cupsArrayFind(devices, &key);
853*5e7646d2SAndroid Build Coastguard Worker        device;
854*5e7646d2SAndroid Build Coastguard Worker        device = cupsArrayNext(devices))
855*5e7646d2SAndroid Build Coastguard Worker     if (_cups_strcasecmp(device->name, key.name))
856*5e7646d2SAndroid Build Coastguard Worker       break;
857*5e7646d2SAndroid Build Coastguard Worker     else if (device->type == key.type)
858*5e7646d2SAndroid Build Coastguard Worker     {
859*5e7646d2SAndroid Build Coastguard Worker       if (!_cups_strcasecmp(device->domain, "local.") &&
860*5e7646d2SAndroid Build Coastguard Worker           _cups_strcasecmp(device->domain, replyDomain))
861*5e7646d2SAndroid Build Coastguard Worker       {
862*5e7646d2SAndroid Build Coastguard Worker        /*
863*5e7646d2SAndroid Build Coastguard Worker         * Update the .local listing to use the "global" domain name instead.
864*5e7646d2SAndroid Build Coastguard Worker 	* The backend will try local lookups first, then the global domain name.
865*5e7646d2SAndroid Build Coastguard Worker 	*/
866*5e7646d2SAndroid Build Coastguard Worker 
867*5e7646d2SAndroid Build Coastguard Worker         free(device->domain);
868*5e7646d2SAndroid Build Coastguard Worker 	device->domain = strdup(replyDomain);
869*5e7646d2SAndroid Build Coastguard Worker 
870*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_DNSSD
871*5e7646d2SAndroid Build Coastguard Worker 	DNSServiceConstructFullName(fullName, device->name, regtype,
872*5e7646d2SAndroid Build Coastguard Worker 	                            replyDomain);
873*5e7646d2SAndroid Build Coastguard Worker #else /* HAVE_AVAHI */
874*5e7646d2SAndroid Build Coastguard Worker 	avahi_service_name_join(fullName, kDNSServiceMaxDomainName,
875*5e7646d2SAndroid Build Coastguard Worker 				serviceName, regtype, replyDomain);
876*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_DNSSD */
877*5e7646d2SAndroid Build Coastguard Worker 
878*5e7646d2SAndroid Build Coastguard Worker 	free(device->fullName);
879*5e7646d2SAndroid Build Coastguard Worker 	device->fullName = strdup(fullName);
880*5e7646d2SAndroid Build Coastguard Worker       }
881*5e7646d2SAndroid Build Coastguard Worker 
882*5e7646d2SAndroid Build Coastguard Worker       return (device);
883*5e7646d2SAndroid Build Coastguard Worker     }
884*5e7646d2SAndroid Build Coastguard Worker 
885*5e7646d2SAndroid Build Coastguard Worker  /*
886*5e7646d2SAndroid Build Coastguard Worker   * Yes, add the device...
887*5e7646d2SAndroid Build Coastguard Worker   */
888*5e7646d2SAndroid Build Coastguard Worker 
889*5e7646d2SAndroid Build Coastguard Worker   device           = calloc(sizeof(cups_device_t), 1);
890*5e7646d2SAndroid Build Coastguard Worker   device->name     = strdup(serviceName);
891*5e7646d2SAndroid Build Coastguard Worker   device->domain   = strdup(replyDomain);
892*5e7646d2SAndroid Build Coastguard Worker   device->type     = key.type;
893*5e7646d2SAndroid Build Coastguard Worker   device->priority = 50;
894*5e7646d2SAndroid Build Coastguard Worker 
895*5e7646d2SAndroid Build Coastguard Worker   cupsArrayAdd(devices, device);
896*5e7646d2SAndroid Build Coastguard Worker 
897*5e7646d2SAndroid Build Coastguard Worker  /*
898*5e7646d2SAndroid Build Coastguard Worker   * Set the "full name" of this service, which is used for queries...
899*5e7646d2SAndroid Build Coastguard Worker   */
900*5e7646d2SAndroid Build Coastguard Worker 
901*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_DNSSD
902*5e7646d2SAndroid Build Coastguard Worker   DNSServiceConstructFullName(fullName, serviceName, regtype, replyDomain);
903*5e7646d2SAndroid Build Coastguard Worker #else /* HAVE_AVAHI */
904*5e7646d2SAndroid Build Coastguard Worker   avahi_service_name_join(fullName, kDNSServiceMaxDomainName, serviceName, regtype, replyDomain);
905*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_DNSSD */
906*5e7646d2SAndroid Build Coastguard Worker 
907*5e7646d2SAndroid Build Coastguard Worker   device->fullName = strdup(fullName);
908*5e7646d2SAndroid Build Coastguard Worker 
909*5e7646d2SAndroid Build Coastguard Worker   return (device);
910*5e7646d2SAndroid Build Coastguard Worker }
911*5e7646d2SAndroid Build Coastguard Worker 
912*5e7646d2SAndroid Build Coastguard Worker 
913*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_AVAHI
914*5e7646d2SAndroid Build Coastguard Worker /*
915*5e7646d2SAndroid Build Coastguard Worker  * 'poll_callback()' - Wait for input on the specified file descriptors.
916*5e7646d2SAndroid Build Coastguard Worker  *
917*5e7646d2SAndroid Build Coastguard Worker  * Note: This function is needed because avahi_simple_poll_iterate is broken
918*5e7646d2SAndroid Build Coastguard Worker  *       and always uses a timeout of 0 (!) milliseconds.
919*5e7646d2SAndroid Build Coastguard Worker  *       (https://github.com/lathiat/avahi/issues/127)
920*5e7646d2SAndroid Build Coastguard Worker  */
921*5e7646d2SAndroid Build Coastguard Worker 
922*5e7646d2SAndroid Build Coastguard Worker static int				/* O - Number of file descriptors matching */
poll_callback(struct pollfd * pollfds,unsigned int num_pollfds,int timeout,void * context)923*5e7646d2SAndroid Build Coastguard Worker poll_callback(
924*5e7646d2SAndroid Build Coastguard Worker     struct pollfd *pollfds,		/* I - File descriptors */
925*5e7646d2SAndroid Build Coastguard Worker     unsigned int  num_pollfds,		/* I - Number of file descriptors */
926*5e7646d2SAndroid Build Coastguard Worker     int           timeout,		/* I - Timeout in milliseconds (unused) */
927*5e7646d2SAndroid Build Coastguard Worker     void          *context)		/* I - User data (unused) */
928*5e7646d2SAndroid Build Coastguard Worker {
929*5e7646d2SAndroid Build Coastguard Worker   int	val;				/* Return value */
930*5e7646d2SAndroid Build Coastguard Worker 
931*5e7646d2SAndroid Build Coastguard Worker 
932*5e7646d2SAndroid Build Coastguard Worker   (void)timeout;
933*5e7646d2SAndroid Build Coastguard Worker   (void)context;
934*5e7646d2SAndroid Build Coastguard Worker 
935*5e7646d2SAndroid Build Coastguard Worker   val = poll(pollfds, num_pollfds, 500);
936*5e7646d2SAndroid Build Coastguard Worker 
937*5e7646d2SAndroid Build Coastguard Worker   if (val < 0)
938*5e7646d2SAndroid Build Coastguard Worker     fprintf(stderr, "DEBUG: poll_callback: %s\n", strerror(errno));
939*5e7646d2SAndroid Build Coastguard Worker   else if (val > 0)
940*5e7646d2SAndroid Build Coastguard Worker     got_data = 1;
941*5e7646d2SAndroid Build Coastguard Worker 
942*5e7646d2SAndroid Build Coastguard Worker   return (val);
943*5e7646d2SAndroid Build Coastguard Worker }
944*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_AVAHI */
945*5e7646d2SAndroid Build Coastguard Worker 
946*5e7646d2SAndroid Build Coastguard Worker 
947*5e7646d2SAndroid Build Coastguard Worker #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
948*5e7646d2SAndroid Build Coastguard Worker #  ifdef HAVE_DNSSD
949*5e7646d2SAndroid Build Coastguard Worker /*
950*5e7646d2SAndroid Build Coastguard Worker  * 'query_callback()' - Process query data.
951*5e7646d2SAndroid Build Coastguard Worker  */
952*5e7646d2SAndroid Build Coastguard Worker 
953*5e7646d2SAndroid Build Coastguard Worker static void
query_callback(DNSServiceRef sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,DNSServiceErrorType errorCode,const char * fullName,uint16_t rrtype,uint16_t rrclass,uint16_t rdlen,const void * rdata,uint32_t ttl,void * context)954*5e7646d2SAndroid Build Coastguard Worker query_callback(
955*5e7646d2SAndroid Build Coastguard Worker     DNSServiceRef       sdRef,		/* I - Service reference */
956*5e7646d2SAndroid Build Coastguard Worker     DNSServiceFlags     flags,		/* I - Data flags */
957*5e7646d2SAndroid Build Coastguard Worker     uint32_t            interfaceIndex,	/* I - Interface */
958*5e7646d2SAndroid Build Coastguard Worker     DNSServiceErrorType errorCode,	/* I - Error, if any */
959*5e7646d2SAndroid Build Coastguard Worker     const char          *fullName,	/* I - Full service name */
960*5e7646d2SAndroid Build Coastguard Worker     uint16_t            rrtype,		/* I - Record type */
961*5e7646d2SAndroid Build Coastguard Worker     uint16_t            rrclass,	/* I - Record class */
962*5e7646d2SAndroid Build Coastguard Worker     uint16_t            rdlen,		/* I - Length of record data */
963*5e7646d2SAndroid Build Coastguard Worker     const void          *rdata,		/* I - Record data */
964*5e7646d2SAndroid Build Coastguard Worker     uint32_t            ttl,		/* I - Time-to-live */
965*5e7646d2SAndroid Build Coastguard Worker     void                *context)	/* I - Device */
966*5e7646d2SAndroid Build Coastguard Worker {
967*5e7646d2SAndroid Build Coastguard Worker #  else
968*5e7646d2SAndroid Build Coastguard Worker /*
969*5e7646d2SAndroid Build Coastguard Worker  * 'query_callback()' - Process query data.
970*5e7646d2SAndroid Build Coastguard Worker  */
971*5e7646d2SAndroid Build Coastguard Worker 
972*5e7646d2SAndroid Build Coastguard Worker static void
973*5e7646d2SAndroid Build Coastguard Worker query_callback(
974*5e7646d2SAndroid Build Coastguard Worker     AvahiRecordBrowser     *browser,	/* I - Record browser */
975*5e7646d2SAndroid Build Coastguard Worker     AvahiIfIndex           interfaceIndex,
976*5e7646d2SAndroid Build Coastguard Worker 					/* I - Interface index (unused) */
977*5e7646d2SAndroid Build Coastguard Worker     AvahiProtocol          protocol,	/* I - Network protocol (unused) */
978*5e7646d2SAndroid Build Coastguard Worker     AvahiBrowserEvent      event,	/* I - What happened? */
979*5e7646d2SAndroid Build Coastguard Worker     const char             *fullName,	/* I - Service name */
980*5e7646d2SAndroid Build Coastguard Worker     uint16_t               rrclass,	/* I - Record class */
981*5e7646d2SAndroid Build Coastguard Worker     uint16_t               rrtype,	/* I - Record type */
982*5e7646d2SAndroid Build Coastguard Worker     const void             *rdata,	/* I - TXT record */
983*5e7646d2SAndroid Build Coastguard Worker     size_t                 rdlen,	/* I - Length of TXT record */
984*5e7646d2SAndroid Build Coastguard Worker     AvahiLookupResultFlags flags,	/* I - Flags */
985*5e7646d2SAndroid Build Coastguard Worker     void                   *context)	/* I - Device */
986*5e7646d2SAndroid Build Coastguard Worker {
987*5e7646d2SAndroid Build Coastguard Worker   AvahiClient		*client = avahi_record_browser_get_client(browser);
988*5e7646d2SAndroid Build Coastguard Worker 					/* Client information */
989*5e7646d2SAndroid Build Coastguard Worker #  endif /* HAVE_DNSSD */
990*5e7646d2SAndroid Build Coastguard Worker   char		*ptr;			/* Pointer into string */
991*5e7646d2SAndroid Build Coastguard Worker   cups_device_t	*device = (cups_device_t *)context;
992*5e7646d2SAndroid Build Coastguard Worker 					/* Device */
993*5e7646d2SAndroid Build Coastguard Worker   const uint8_t	*data,			/* Pointer into data */
994*5e7646d2SAndroid Build Coastguard Worker 		*datanext,		/* Next key/value pair */
995*5e7646d2SAndroid Build Coastguard Worker 		*dataend;		/* End of entire TXT record */
996*5e7646d2SAndroid Build Coastguard Worker   uint8_t	datalen;		/* Length of current key/value pair */
997*5e7646d2SAndroid Build Coastguard Worker   char		key[256],		/* Key string */
998*5e7646d2SAndroid Build Coastguard Worker 		value[256],		/* Value string */
999*5e7646d2SAndroid Build Coastguard Worker 		make_and_model[512],	/* Manufacturer and model */
1000*5e7646d2SAndroid Build Coastguard Worker 		model[256],		/* Model */
1001*5e7646d2SAndroid Build Coastguard Worker 		pdl[256],		/* PDL */
1002*5e7646d2SAndroid Build Coastguard Worker 		device_id[2048];	/* 1284 device ID */
1003*5e7646d2SAndroid Build Coastguard Worker 
1004*5e7646d2SAndroid Build Coastguard Worker 
1005*5e7646d2SAndroid Build Coastguard Worker #  ifdef HAVE_DNSSD
1006*5e7646d2SAndroid Build Coastguard Worker   fprintf(stderr, "DEBUG2: query_callback(sdRef=%p, flags=%x, "
1007*5e7646d2SAndroid Build Coastguard Worker                   "interfaceIndex=%d, errorCode=%d, fullName=\"%s\", "
1008*5e7646d2SAndroid Build Coastguard Worker 		  "rrtype=%u, rrclass=%u, rdlen=%u, rdata=%p, ttl=%u, "
1009*5e7646d2SAndroid Build Coastguard Worker 		  "context=%p)\n",
1010*5e7646d2SAndroid Build Coastguard Worker           sdRef, flags, interfaceIndex, errorCode, fullName, rrtype, rrclass, rdlen, rdata, ttl, context);
1011*5e7646d2SAndroid Build Coastguard Worker 
1012*5e7646d2SAndroid Build Coastguard Worker  /*
1013*5e7646d2SAndroid Build Coastguard Worker   * Only process "add" data...
1014*5e7646d2SAndroid Build Coastguard Worker   */
1015*5e7646d2SAndroid Build Coastguard Worker 
1016*5e7646d2SAndroid Build Coastguard Worker   if (errorCode != kDNSServiceErr_NoError || !(flags & kDNSServiceFlagsAdd))
1017*5e7646d2SAndroid Build Coastguard Worker     return;
1018*5e7646d2SAndroid Build Coastguard Worker 
1019*5e7646d2SAndroid Build Coastguard Worker #  else
1020*5e7646d2SAndroid Build Coastguard Worker   fprintf(stderr, "DEBUG2: query_callback(browser=%p, interfaceIndex=%d, "
1021*5e7646d2SAndroid Build Coastguard Worker                   "protocol=%d, event=%d, fullName=\"%s\", rrclass=%u, "
1022*5e7646d2SAndroid Build Coastguard Worker 		  "rrtype=%u, rdata=%p, rdlen=%u, flags=%x, context=%p)\n",
1023*5e7646d2SAndroid Build Coastguard Worker           browser, interfaceIndex, protocol, event, fullName, rrclass, rrtype, rdata, (unsigned)rdlen, flags, context);
1024*5e7646d2SAndroid Build Coastguard Worker 
1025*5e7646d2SAndroid Build Coastguard Worker  /*
1026*5e7646d2SAndroid Build Coastguard Worker   * Only process "add" data...
1027*5e7646d2SAndroid Build Coastguard Worker   */
1028*5e7646d2SAndroid Build Coastguard Worker 
1029*5e7646d2SAndroid Build Coastguard Worker   if (event != AVAHI_BROWSER_NEW)
1030*5e7646d2SAndroid Build Coastguard Worker   {
1031*5e7646d2SAndroid Build Coastguard Worker     if (event == AVAHI_BROWSER_FAILURE)
1032*5e7646d2SAndroid Build Coastguard Worker       fprintf(stderr, "ERROR: %s\n",
1033*5e7646d2SAndroid Build Coastguard Worker 	      avahi_strerror(avahi_client_errno(client)));
1034*5e7646d2SAndroid Build Coastguard Worker 
1035*5e7646d2SAndroid Build Coastguard Worker     return;
1036*5e7646d2SAndroid Build Coastguard Worker   }
1037*5e7646d2SAndroid Build Coastguard Worker #  endif /* HAVE_DNSSD */
1038*5e7646d2SAndroid Build Coastguard Worker 
1039*5e7646d2SAndroid Build Coastguard Worker  /*
1040*5e7646d2SAndroid Build Coastguard Worker   * Pull out the priority and make and model from the TXT
1041*5e7646d2SAndroid Build Coastguard Worker   * record and save it...
1042*5e7646d2SAndroid Build Coastguard Worker   */
1043*5e7646d2SAndroid Build Coastguard Worker 
1044*5e7646d2SAndroid Build Coastguard Worker   device_id[0]      = '\0';
1045*5e7646d2SAndroid Build Coastguard Worker   make_and_model[0] = '\0';
1046*5e7646d2SAndroid Build Coastguard Worker   pdl[0]            = '\0';
1047*5e7646d2SAndroid Build Coastguard Worker 
1048*5e7646d2SAndroid Build Coastguard Worker   strlcpy(model, "Unknown", sizeof(model));
1049*5e7646d2SAndroid Build Coastguard Worker 
1050*5e7646d2SAndroid Build Coastguard Worker   for (data = rdata, dataend = data + rdlen;
1051*5e7646d2SAndroid Build Coastguard Worker        data < dataend;
1052*5e7646d2SAndroid Build Coastguard Worker        data = datanext)
1053*5e7646d2SAndroid Build Coastguard Worker   {
1054*5e7646d2SAndroid Build Coastguard Worker    /*
1055*5e7646d2SAndroid Build Coastguard Worker     * Read a key/value pair starting with an 8-bit length.  Since the
1056*5e7646d2SAndroid Build Coastguard Worker     * length is 8 bits and the size of the key/value buffers is 256, we
1057*5e7646d2SAndroid Build Coastguard Worker     * don't need to check for overflow...
1058*5e7646d2SAndroid Build Coastguard Worker     */
1059*5e7646d2SAndroid Build Coastguard Worker 
1060*5e7646d2SAndroid Build Coastguard Worker     datalen = *data++;
1061*5e7646d2SAndroid Build Coastguard Worker 
1062*5e7646d2SAndroid Build Coastguard Worker     if (!datalen || (data + datalen) > dataend)
1063*5e7646d2SAndroid Build Coastguard Worker       break;
1064*5e7646d2SAndroid Build Coastguard Worker 
1065*5e7646d2SAndroid Build Coastguard Worker     datanext = data + datalen;
1066*5e7646d2SAndroid Build Coastguard Worker 
1067*5e7646d2SAndroid Build Coastguard Worker     for (ptr = key; data < datanext && *data != '='; data ++)
1068*5e7646d2SAndroid Build Coastguard Worker       *ptr++ = (char)*data;
1069*5e7646d2SAndroid Build Coastguard Worker     *ptr = '\0';
1070*5e7646d2SAndroid Build Coastguard Worker 
1071*5e7646d2SAndroid Build Coastguard Worker     if (data < datanext && *data == '=')
1072*5e7646d2SAndroid Build Coastguard Worker     {
1073*5e7646d2SAndroid Build Coastguard Worker       data ++;
1074*5e7646d2SAndroid Build Coastguard Worker 
1075*5e7646d2SAndroid Build Coastguard Worker       if (data < datanext)
1076*5e7646d2SAndroid Build Coastguard Worker 	memcpy(value, data, (size_t)(datanext - data));
1077*5e7646d2SAndroid Build Coastguard Worker       value[datanext - data] = '\0';
1078*5e7646d2SAndroid Build Coastguard Worker 
1079*5e7646d2SAndroid Build Coastguard Worker       fprintf(stderr, "DEBUG2: query_callback: \"%s=%s\".\n",
1080*5e7646d2SAndroid Build Coastguard Worker 	      key, value);
1081*5e7646d2SAndroid Build Coastguard Worker     }
1082*5e7646d2SAndroid Build Coastguard Worker     else
1083*5e7646d2SAndroid Build Coastguard Worker     {
1084*5e7646d2SAndroid Build Coastguard Worker       fprintf(stderr, "DEBUG2: query_callback: \"%s\" with no value.\n",
1085*5e7646d2SAndroid Build Coastguard Worker 	      key);
1086*5e7646d2SAndroid Build Coastguard Worker       continue;
1087*5e7646d2SAndroid Build Coastguard Worker     }
1088*5e7646d2SAndroid Build Coastguard Worker 
1089*5e7646d2SAndroid Build Coastguard Worker     if (!_cups_strncasecmp(key, "usb_", 4))
1090*5e7646d2SAndroid Build Coastguard Worker     {
1091*5e7646d2SAndroid Build Coastguard Worker      /*
1092*5e7646d2SAndroid Build Coastguard Worker       * Add USB device ID information...
1093*5e7646d2SAndroid Build Coastguard Worker       */
1094*5e7646d2SAndroid Build Coastguard Worker 
1095*5e7646d2SAndroid Build Coastguard Worker       ptr = device_id + strlen(device_id);
1096*5e7646d2SAndroid Build Coastguard Worker       snprintf(ptr, sizeof(device_id) - (size_t)(ptr - device_id), "%s:%s;", key + 4, value);
1097*5e7646d2SAndroid Build Coastguard Worker     }
1098*5e7646d2SAndroid Build Coastguard Worker 
1099*5e7646d2SAndroid Build Coastguard Worker     if (!_cups_strcasecmp(key, "usb_MFG") || !_cups_strcasecmp(key, "usb_MANU") ||
1100*5e7646d2SAndroid Build Coastguard Worker 	!_cups_strcasecmp(key, "usb_MANUFACTURER"))
1101*5e7646d2SAndroid Build Coastguard Worker       strlcpy(make_and_model, value, sizeof(make_and_model));
1102*5e7646d2SAndroid Build Coastguard Worker     else if (!_cups_strcasecmp(key, "usb_MDL") || !_cups_strcasecmp(key, "usb_MODEL"))
1103*5e7646d2SAndroid Build Coastguard Worker       strlcpy(model, value, sizeof(model));
1104*5e7646d2SAndroid Build Coastguard Worker     else if (!_cups_strcasecmp(key, "product") && !strstr(value, "Ghostscript"))
1105*5e7646d2SAndroid Build Coastguard Worker     {
1106*5e7646d2SAndroid Build Coastguard Worker       if (value[0] == '(')
1107*5e7646d2SAndroid Build Coastguard Worker       {
1108*5e7646d2SAndroid Build Coastguard Worker        /*
1109*5e7646d2SAndroid Build Coastguard Worker 	* Strip parenthesis...
1110*5e7646d2SAndroid Build Coastguard Worker 	*/
1111*5e7646d2SAndroid Build Coastguard Worker 
1112*5e7646d2SAndroid Build Coastguard Worker 	if ((ptr = value + strlen(value) - 1) > value && *ptr == ')')
1113*5e7646d2SAndroid Build Coastguard Worker 	  *ptr = '\0';
1114*5e7646d2SAndroid Build Coastguard Worker 
1115*5e7646d2SAndroid Build Coastguard Worker 	strlcpy(model, value + 1, sizeof(model));
1116*5e7646d2SAndroid Build Coastguard Worker       }
1117*5e7646d2SAndroid Build Coastguard Worker       else
1118*5e7646d2SAndroid Build Coastguard Worker 	strlcpy(model, value, sizeof(model));
1119*5e7646d2SAndroid Build Coastguard Worker     }
1120*5e7646d2SAndroid Build Coastguard Worker     else if (!_cups_strcasecmp(key, "ty"))
1121*5e7646d2SAndroid Build Coastguard Worker     {
1122*5e7646d2SAndroid Build Coastguard Worker       strlcpy(model, value, sizeof(model));
1123*5e7646d2SAndroid Build Coastguard Worker 
1124*5e7646d2SAndroid Build Coastguard Worker       if ((ptr = strchr(model, ',')) != NULL)
1125*5e7646d2SAndroid Build Coastguard Worker 	*ptr = '\0';
1126*5e7646d2SAndroid Build Coastguard Worker     }
1127*5e7646d2SAndroid Build Coastguard Worker     else if (!_cups_strcasecmp(key, "pdl"))
1128*5e7646d2SAndroid Build Coastguard Worker       strlcpy(pdl, value, sizeof(pdl));
1129*5e7646d2SAndroid Build Coastguard Worker     else if (!_cups_strcasecmp(key, "priority"))
1130*5e7646d2SAndroid Build Coastguard Worker       device->priority = atoi(value);
1131*5e7646d2SAndroid Build Coastguard Worker     else if ((device->type == CUPS_DEVICE_IPP ||
1132*5e7646d2SAndroid Build Coastguard Worker 	      device->type == CUPS_DEVICE_IPPS ||
1133*5e7646d2SAndroid Build Coastguard Worker 	      device->type == CUPS_DEVICE_PRINTER) &&
1134*5e7646d2SAndroid Build Coastguard Worker 	     !_cups_strcasecmp(key, "printer-type"))
1135*5e7646d2SAndroid Build Coastguard Worker     {
1136*5e7646d2SAndroid Build Coastguard Worker      /*
1137*5e7646d2SAndroid Build Coastguard Worker       * This is a CUPS printer!
1138*5e7646d2SAndroid Build Coastguard Worker       */
1139*5e7646d2SAndroid Build Coastguard Worker 
1140*5e7646d2SAndroid Build Coastguard Worker       device->cups_shared = 1;
1141*5e7646d2SAndroid Build Coastguard Worker 
1142*5e7646d2SAndroid Build Coastguard Worker       if (device->type == CUPS_DEVICE_PRINTER)
1143*5e7646d2SAndroid Build Coastguard Worker 	device->sent = 1;
1144*5e7646d2SAndroid Build Coastguard Worker     }
1145*5e7646d2SAndroid Build Coastguard Worker     else if (!_cups_strcasecmp(key, "UUID"))
1146*5e7646d2SAndroid Build Coastguard Worker       device->uuid = strdup(value);
1147*5e7646d2SAndroid Build Coastguard Worker   }
1148*5e7646d2SAndroid Build Coastguard Worker 
1149*5e7646d2SAndroid Build Coastguard Worker   if (device->device_id)
1150*5e7646d2SAndroid Build Coastguard Worker     free(device->device_id);
1151*5e7646d2SAndroid Build Coastguard Worker 
1152*5e7646d2SAndroid Build Coastguard Worker   if (!device_id[0] && strcmp(model, "Unknown"))
1153*5e7646d2SAndroid Build Coastguard Worker   {
1154*5e7646d2SAndroid Build Coastguard Worker     if (make_and_model[0])
1155*5e7646d2SAndroid Build Coastguard Worker       snprintf(device_id, sizeof(device_id), "MFG:%s;MDL:%s;",
1156*5e7646d2SAndroid Build Coastguard Worker 	       make_and_model, model);
1157*5e7646d2SAndroid Build Coastguard Worker     else if (!_cups_strncasecmp(model, "designjet ", 10))
1158*5e7646d2SAndroid Build Coastguard Worker       snprintf(device_id, sizeof(device_id), "MFG:HP;MDL:%s;", model + 10);
1159*5e7646d2SAndroid Build Coastguard Worker     else if (!_cups_strncasecmp(model, "stylus ", 7))
1160*5e7646d2SAndroid Build Coastguard Worker       snprintf(device_id, sizeof(device_id), "MFG:EPSON;MDL:%s;", model + 7);
1161*5e7646d2SAndroid Build Coastguard Worker     else if ((ptr = strchr(model, ' ')) != NULL)
1162*5e7646d2SAndroid Build Coastguard Worker     {
1163*5e7646d2SAndroid Build Coastguard Worker      /*
1164*5e7646d2SAndroid Build Coastguard Worker       * Assume the first word is the make...
1165*5e7646d2SAndroid Build Coastguard Worker       */
1166*5e7646d2SAndroid Build Coastguard Worker 
1167*5e7646d2SAndroid Build Coastguard Worker       memcpy(make_and_model, model, (size_t)(ptr - model));
1168*5e7646d2SAndroid Build Coastguard Worker       make_and_model[ptr - model] = '\0';
1169*5e7646d2SAndroid Build Coastguard Worker 
1170*5e7646d2SAndroid Build Coastguard Worker       snprintf(device_id, sizeof(device_id), "MFG:%s;MDL:%s;",
1171*5e7646d2SAndroid Build Coastguard Worker 	       make_and_model, ptr + 1);
1172*5e7646d2SAndroid Build Coastguard Worker     }
1173*5e7646d2SAndroid Build Coastguard Worker   }
1174*5e7646d2SAndroid Build Coastguard Worker 
1175*5e7646d2SAndroid Build Coastguard Worker   if (device_id[0] &&
1176*5e7646d2SAndroid Build Coastguard Worker       !strstr(device_id, "CMD:") &&
1177*5e7646d2SAndroid Build Coastguard Worker       !strstr(device_id, "COMMAND SET:") &&
1178*5e7646d2SAndroid Build Coastguard Worker       (strstr(pdl, "application/pdf") ||
1179*5e7646d2SAndroid Build Coastguard Worker        strstr(pdl, "application/postscript") ||
1180*5e7646d2SAndroid Build Coastguard Worker        strstr(pdl, "application/vnd.hp-PCL") ||
1181*5e7646d2SAndroid Build Coastguard Worker        strstr(pdl, "image/")))
1182*5e7646d2SAndroid Build Coastguard Worker   {
1183*5e7646d2SAndroid Build Coastguard Worker     value[0] = '\0';
1184*5e7646d2SAndroid Build Coastguard Worker     if (strstr(pdl, "application/pdf"))
1185*5e7646d2SAndroid Build Coastguard Worker       strlcat(value, ",PDF", sizeof(value));
1186*5e7646d2SAndroid Build Coastguard Worker     if (strstr(pdl, "application/postscript"))
1187*5e7646d2SAndroid Build Coastguard Worker       strlcat(value, ",PS", sizeof(value));
1188*5e7646d2SAndroid Build Coastguard Worker     if (strstr(pdl, "application/vnd.hp-PCL"))
1189*5e7646d2SAndroid Build Coastguard Worker       strlcat(value, ",PCL", sizeof(value));
1190*5e7646d2SAndroid Build Coastguard Worker     for (ptr = strstr(pdl, "image/"); ptr; ptr = strstr(ptr, "image/"))
1191*5e7646d2SAndroid Build Coastguard Worker     {
1192*5e7646d2SAndroid Build Coastguard Worker       char *valptr = value + strlen(value);
1193*5e7646d2SAndroid Build Coastguard Worker       					/* Pointer into value */
1194*5e7646d2SAndroid Build Coastguard Worker 
1195*5e7646d2SAndroid Build Coastguard Worker       if (valptr < (value + sizeof(value) - 1))
1196*5e7646d2SAndroid Build Coastguard Worker         *valptr++ = ',';
1197*5e7646d2SAndroid Build Coastguard Worker 
1198*5e7646d2SAndroid Build Coastguard Worker       ptr += 6;
1199*5e7646d2SAndroid Build Coastguard Worker       while (isalnum(*ptr & 255) || *ptr == '-' || *ptr == '.')
1200*5e7646d2SAndroid Build Coastguard Worker       {
1201*5e7646d2SAndroid Build Coastguard Worker         if (isalnum(*ptr & 255) && valptr < (value + sizeof(value) - 1))
1202*5e7646d2SAndroid Build Coastguard Worker           *valptr++ = (char)toupper(*ptr++ & 255);
1203*5e7646d2SAndroid Build Coastguard Worker         else
1204*5e7646d2SAndroid Build Coastguard Worker           break;
1205*5e7646d2SAndroid Build Coastguard Worker       }
1206*5e7646d2SAndroid Build Coastguard Worker 
1207*5e7646d2SAndroid Build Coastguard Worker       *valptr = '\0';
1208*5e7646d2SAndroid Build Coastguard Worker     }
1209*5e7646d2SAndroid Build Coastguard Worker 
1210*5e7646d2SAndroid Build Coastguard Worker     ptr = device_id + strlen(device_id);
1211*5e7646d2SAndroid Build Coastguard Worker     snprintf(ptr, sizeof(device_id) - (size_t)(ptr - device_id), "CMD:%s;", value + 1);
1212*5e7646d2SAndroid Build Coastguard Worker   }
1213*5e7646d2SAndroid Build Coastguard Worker 
1214*5e7646d2SAndroid Build Coastguard Worker   if (device_id[0])
1215*5e7646d2SAndroid Build Coastguard Worker     device->device_id = strdup(device_id);
1216*5e7646d2SAndroid Build Coastguard Worker   else
1217*5e7646d2SAndroid Build Coastguard Worker     device->device_id = NULL;
1218*5e7646d2SAndroid Build Coastguard Worker 
1219*5e7646d2SAndroid Build Coastguard Worker   if (device->make_and_model)
1220*5e7646d2SAndroid Build Coastguard Worker     free(device->make_and_model);
1221*5e7646d2SAndroid Build Coastguard Worker 
1222*5e7646d2SAndroid Build Coastguard Worker   if (make_and_model[0])
1223*5e7646d2SAndroid Build Coastguard Worker   {
1224*5e7646d2SAndroid Build Coastguard Worker     strlcat(make_and_model, " ", sizeof(make_and_model));
1225*5e7646d2SAndroid Build Coastguard Worker     strlcat(make_and_model, model, sizeof(make_and_model));
1226*5e7646d2SAndroid Build Coastguard Worker 
1227*5e7646d2SAndroid Build Coastguard Worker     if (!_cups_strncasecmp(make_and_model, "EPSON EPSON ", 12))
1228*5e7646d2SAndroid Build Coastguard Worker       _cups_strcpy(make_and_model, make_and_model + 6);
1229*5e7646d2SAndroid Build Coastguard Worker     else if (!_cups_strncasecmp(make_and_model, "HP HP ", 6))
1230*5e7646d2SAndroid Build Coastguard Worker       _cups_strcpy(make_and_model, make_and_model + 3);
1231*5e7646d2SAndroid Build Coastguard Worker     else if (!_cups_strncasecmp(make_and_model, "Lexmark International Lexmark ", 30))
1232*5e7646d2SAndroid Build Coastguard Worker       _cups_strcpy(make_and_model, make_and_model + 22);
1233*5e7646d2SAndroid Build Coastguard Worker 
1234*5e7646d2SAndroid Build Coastguard Worker     device->make_and_model = strdup(make_and_model);
1235*5e7646d2SAndroid Build Coastguard Worker   }
1236*5e7646d2SAndroid Build Coastguard Worker   else
1237*5e7646d2SAndroid Build Coastguard Worker     device->make_and_model = strdup(model);
1238*5e7646d2SAndroid Build Coastguard Worker }
1239*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_DNSSD || HAVE_AVAHI */
1240*5e7646d2SAndroid Build Coastguard Worker 
1241*5e7646d2SAndroid Build Coastguard Worker 
1242*5e7646d2SAndroid Build Coastguard Worker /*
1243*5e7646d2SAndroid Build Coastguard Worker  * 'sigterm_handler()' - Handle termination signals.
1244*5e7646d2SAndroid Build Coastguard Worker  */
1245*5e7646d2SAndroid Build Coastguard Worker 
1246*5e7646d2SAndroid Build Coastguard Worker static void
1247*5e7646d2SAndroid Build Coastguard Worker sigterm_handler(int sig)		/* I - Signal number (unused) */
1248*5e7646d2SAndroid Build Coastguard Worker {
1249*5e7646d2SAndroid Build Coastguard Worker   (void)sig;
1250*5e7646d2SAndroid Build Coastguard Worker 
1251*5e7646d2SAndroid Build Coastguard Worker   if (job_canceled)
1252*5e7646d2SAndroid Build Coastguard Worker     _exit(CUPS_BACKEND_OK);
1253*5e7646d2SAndroid Build Coastguard Worker   else
1254*5e7646d2SAndroid Build Coastguard Worker     job_canceled = 1;
1255*5e7646d2SAndroid Build Coastguard Worker }
1256*5e7646d2SAndroid Build Coastguard Worker 
1257*5e7646d2SAndroid Build Coastguard Worker 
1258*5e7646d2SAndroid Build Coastguard Worker /*
1259*5e7646d2SAndroid Build Coastguard Worker  * 'unquote()' - Unquote a name string.
1260*5e7646d2SAndroid Build Coastguard Worker  */
1261*5e7646d2SAndroid Build Coastguard Worker 
1262*5e7646d2SAndroid Build Coastguard Worker static void
1263*5e7646d2SAndroid Build Coastguard Worker unquote(char       *dst,		/* I - Destination buffer */
1264*5e7646d2SAndroid Build Coastguard Worker         const char *src,		/* I - Source string */
1265*5e7646d2SAndroid Build Coastguard Worker 	size_t     dstsize)		/* I - Size of destination buffer */
1266*5e7646d2SAndroid Build Coastguard Worker {
1267*5e7646d2SAndroid Build Coastguard Worker   char	*dstend = dst + dstsize - 1;	/* End of destination buffer */
1268*5e7646d2SAndroid Build Coastguard Worker 
1269*5e7646d2SAndroid Build Coastguard Worker 
1270*5e7646d2SAndroid Build Coastguard Worker   while (*src && dst < dstend)
1271*5e7646d2SAndroid Build Coastguard Worker   {
1272*5e7646d2SAndroid Build Coastguard Worker     if (*src == '\\')
1273*5e7646d2SAndroid Build Coastguard Worker     {
1274*5e7646d2SAndroid Build Coastguard Worker       src ++;
1275*5e7646d2SAndroid Build Coastguard Worker       if (isdigit(src[0] & 255) && isdigit(src[1] & 255) &&
1276*5e7646d2SAndroid Build Coastguard Worker           isdigit(src[2] & 255))
1277*5e7646d2SAndroid Build Coastguard Worker       {
1278*5e7646d2SAndroid Build Coastguard Worker         *dst++ = ((((src[0] - '0') * 10) + src[1] - '0') * 10) + src[2] - '0';
1279*5e7646d2SAndroid Build Coastguard Worker 	src += 3;
1280*5e7646d2SAndroid Build Coastguard Worker       }
1281*5e7646d2SAndroid Build Coastguard Worker       else
1282*5e7646d2SAndroid Build Coastguard Worker         *dst++ = *src++;
1283*5e7646d2SAndroid Build Coastguard Worker     }
1284*5e7646d2SAndroid Build Coastguard Worker     else
1285*5e7646d2SAndroid Build Coastguard Worker       *dst++ = *src ++;
1286*5e7646d2SAndroid Build Coastguard Worker   }
1287*5e7646d2SAndroid Build Coastguard Worker 
1288*5e7646d2SAndroid Build Coastguard Worker   *dst = '\0';
1289*5e7646d2SAndroid Build Coastguard Worker }
1290