diff -up cups-1.4rc1/backend/dnssd.c.avahi cups-1.4rc1/backend/dnssd.c --- cups-1.4rc1/backend/dnssd.c.avahi 2009-07-29 14:00:53.767272320 +0100 +++ cups-1.4rc1/backend/dnssd.c 2009-07-29 14:01:36.574271697 +0100 @@ -22,6 +22,7 @@ * exec_backend() - Execute the backend that corresponds to the * resolved service name. * get_device() - Create or update a device. +* find_device() * query_callback() - Process query data. * sigterm_handler() - Handle termination signals... * unquote() - Unquote a name string. @@ -33,7 +34,18 @@ #include "backend-private.h" #include -#include +#ifdef HAVE_DNSSD +# include +#endif /* HAVE_DNSSD */ +#ifdef HAVE_AVAHI +# include +# include +# include +# include +# include +# include +#define kDNSServiceMaxDomainName AVAHI_DOMAIN_NAME_MAX +#endif /* HAVE_AVAHI */ /* @@ -52,7 +64,9 @@ typedef enum typedef struct { +#ifdef HAVE_DNSSD DNSServiceRef ref; /* Service reference for resolve */ +#endif /* HAVE_DNSSD */ char *name, /* Service name */ *domain, /* Domain name */ *fullName, /* Full name */ @@ -64,6 +78,20 @@ typedef struct sent; /* Did we list the device? */ } cups_device_t; +typedef struct +{ + char key[256]; + char value[256]; + +#ifdef HAVE_DNSSD + const uint8_t *data; + const uint8_t *datanext; + const uint8_t *dataend; +#else /* HAVE_AVAHI */ + AvahiStringList *txt; +#endif /* HAVE_DNSSD */ +} cups_txt_records_t; + /* * Local globals... @@ -77,6 +105,7 @@ static int job_canceled = 0; * Local functions... */ +#ifdef HAVE_DNSSD static void browse_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, @@ -92,12 +121,6 @@ static void browse_local_callback(DNSSe const char *regtype, const char *replyDomain, void *context); -static int compare_devices(cups_device_t *a, cups_device_t *b); -static void exec_backend(char **argv); -static cups_device_t *get_device(cups_array_t *devices, - const char *serviceName, - const char *regtype, - const char *replyDomain); static void query_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, @@ -106,9 +129,111 @@ static void query_callback(DNSServiceRe uint16_t rrclass, uint16_t rdlen, const void *rdata, uint32_t ttl, void *context); +#endif /* HAVE_DNSSD */ +#ifdef HAVE_AVAHI +static void avahi_client_callback (AvahiClient *client, + AvahiClientState state, + void *context); +static void avahi_browse_callback (AvahiServiceBrowser *browser, + AvahiIfIndex interface, + AvahiProtocol protocol, + AvahiBrowserEvent event, + const char *serviceName, + const char *regtype, + const char *replyDomain, + AvahiLookupResultFlags flags, + void *context); +#endif /* HAVE_AVAHI */ + +static cups_device_t * find_device (cups_array_t *devices, + cups_txt_records_t *txt, + cups_device_t *dkey); +static int compare_devices(cups_device_t *a, cups_device_t *b); +static void exec_backend(char **argv); +static cups_device_t *get_device(cups_array_t *devices, + const char *serviceName, + const char *regtype, + const char *replyDomain); static void sigterm_handler(int sig); static void unquote(char *dst, const char *src, size_t dstsize); +#ifdef HAVE_AVAHI +static AvahiSimplePoll *simple_poll = NULL; +static int avahi_got_callback; +#endif /* HAVE_AVAHI */ + + +/* + * cups_txt_records_t access functions + */ +static cups_txt_records_t * +next_txt_record (cups_txt_records_t *txt) +{ +#ifdef HAVE_DNSSD + txt->data = txt->datanext; +#else /* HAVE_AVAHI */ + txt->txt = avahi_string_list_get_next (txt->txt); + if (txt->txt == NULL) + return NULL; +#endif /* HAVE_DNSSD */ + + return txt; +} + +static int +parse_txt_record_pair (cups_txt_records_t *txt) +{ +#ifdef HAVE_DNSSD + uint8_t datalen; + uint8_t *data = txt->data; + char *ptr; + + /* + * Read a key/value pair starting with an 8-bit length. Since the + * length is 8 bits and the size of the key/value buffers is 256, we + * don't need to check for overflow... + */ + + datalen = *data++; + if (!datalen || (data + datalen) >= txt->dataend) + return NULL; + txt->datanext = data + datalen; + + for (ptr = txt->key; data < txt->datanext && *data != '='; data ++) + *ptr++ = *data; + *ptr = '\0'; + + if (data < txt->datanext && *data == '=') + { + data++; + + if (data < datanext) + memcpy (txt->value, data, txt->datanext - data); + value[txt->datanext - data] = '\0'; + } + else + return 1; +#else /* HAVE_AVAHI */ + char *key, *value; + size_t len; + avahi_string_list_get_pair (txt->txt, &key, &value, &len); + if (len > sizeof (txt->value) - 1) + len = sizeof (txt->value) - 1; + + memcpy (txt->value, value, len); + txt->value[len] = '\0'; + len = strlen (key); + if (len > sizeof (txt->key) - 1) + len = sizeof (txt->key) - 1; + + memcpy (txt->key, key, len); + txt->key[len] = '\0'; + avahi_free (key); + avahi_free (value); +#endif /* HAVE_AVAHI */ + + return 0; +} /* * 'main()' - Browse for printers. @@ -119,6 +244,13 @@ main(int argc, /* I - Number of comm char *argv[]) /* I - Command-line arguments */ { const char *name; /* Backend name */ + cups_array_t *devices; /* Device array */ + cups_device_t *device; /* Current device */ + char uriName[1024]; /* Unquoted fullName for URI */ +#ifdef HAVE_DNSSD + int fd; /* Main file descriptor */ + fd_set input; /* Input set for select() */ + struct timeval timeout; /* Timeout for select() */ DNSServiceRef main_ref, /* Main service reference */ fax_ipp_ref, /* IPP fax service reference */ ipp_ref, /* IPP service reference */ @@ -130,12 +262,11 @@ main(int argc, /* I - Number of comm pdl_datastream_ref, /* AppSocket service reference */ printer_ref, /* LPD service reference */ riousbprint_ref; /* Remote IO service reference */ - int fd; /* Main file descriptor */ - fd_set input; /* Input set for select() */ - struct timeval timeout; /* Timeout for select() */ - cups_array_t *devices; /* Device array */ - cups_device_t *device; /* Current device */ - char uriName[1024]; /* Unquoted fullName for URI */ +#endif /* HAVE_DNSSD */ +#ifdef HAVE_AVAHI + AvahiClient *client; + int error; +#endif /* HAVE_AVAHI */ #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) struct sigaction action; /* Actions for POSIX signals */ #endif /* HAVE_SIGACTION && !HAVE_SIGSET */ @@ -194,6 +325,49 @@ main(int argc, /* I - Number of comm * Browse for different kinds of printers... */ +#ifdef HAVE_AVAHI + if ((simple_poll = avahi_simple_poll_new ()) == NULL) + { + perror ("ERROR: Unable to create avahi simple poll object"); + return (1); + } + + client = avahi_client_new (avahi_simple_poll_get (simple_poll), + 0, avahi_client_callback, NULL, &error); + if (!client) + { + perror ("ERROR: Unable to create avahi client"); + return (1); + } + + avahi_service_browser_new (client, AVAHI_IF_UNSPEC, + AVAHI_PROTO_UNSPEC, + "_fax-ipp._tcp", NULL, 0, + avahi_browse_callback, devices); + avahi_service_browser_new (client, AVAHI_IF_UNSPEC, + AVAHI_PROTO_UNSPEC, + "_ipp._tcp", NULL, 0, + avahi_browse_callback, devices); + avahi_service_browser_new (client, AVAHI_IF_UNSPEC, + AVAHI_PROTO_UNSPEC, + "_ipp-tls._tcp", NULL, 0, + avahi_browse_callback, devices); + avahi_service_browser_new (client, AVAHI_IF_UNSPEC, + AVAHI_PROTO_UNSPEC, + "_pdl-datastream._tcp", + NULL, 0, + avahi_browse_callback, + devices); + avahi_service_browser_new (client, AVAHI_IF_UNSPEC, + AVAHI_PROTO_UNSPEC, + "_printer._tcp", NULL, 0, + avahi_browse_callback, devices); + avahi_service_browser_new (client, AVAHI_IF_UNSPEC, + AVAHI_PROTO_UNSPEC, + "_riousbprint._tcp", NULL, 0, + avahi_browse_callback, devices); +#endif /* HAVE_AVAHI */ +#ifdef HAVE_DNSSD if (DNSServiceCreateConnection(&main_ref) != kDNSServiceErr_NoError) { perror("ERROR: Unable to create service connection"); @@ -245,6 +419,7 @@ main(int argc, /* I - Number of comm riousbprint_ref = main_ref; DNSServiceBrowse(&riousbprint_ref, kDNSServiceFlagsShareConnection, 0, "_riousbprint._tcp", NULL, browse_callback, devices); +#endif /* HAVE_DNSSD */ /* * Loop until we are killed... @@ -252,6 +427,9 @@ main(int argc, /* I - Number of comm while (!job_canceled) { + int announce = 0; + +#ifdef HAVE_DNSSD FD_ZERO(&input); FD_SET(fd, &input); @@ -271,11 +449,35 @@ main(int argc, /* I - Number of comm } else { + announce = 1; + } +#else /* HAVE_AVAHI */ + int r; + avahi_got_callback = 0; + r = avahi_simple_poll_iterate (simple_poll, 1); + if (r != 0 && r != EINTR) + { + /* + * We've been told to exit the loop. Perhaps the connection to + * avahi failed. + */ + + break; + } + + if (avahi_got_callback) + announce = 1; +#endif /* HAVE_DNSSD */ + + if (announce) + { /* * Announce any devices we've found... */ +#ifdef HAVE_DNSSD DNSServiceErrorType status; /* DNS query status */ +#endif /* HAVE_DNSSD */ cups_device_t *best; /* Best matching device */ char device_uri[1024]; /* Device URI */ int count; /* Number of queries */ @@ -285,6 +487,7 @@ main(int argc, /* I - Number of comm best = NULL, count = 0; device; device = (cups_device_t *)cupsArrayNext(devices)) +#ifdef HAVE_DNSSD if (!device->ref && !device->sent) { /* @@ -313,14 +516,18 @@ main(int argc, /* I - Number of comm count ++; } } - else if (!device->sent) + else +#endif /* HAVE_DNSSD */ + if (!device->sent) { +#ifdef HAVE_DNSSD /* * Got the TXT records, now report the device... */ DNSServiceRefDeallocate(device->ref); device->ref = 0; +#endif /* HAVE_DNSSD */ if (!best) best = device; @@ -372,6 +579,7 @@ main(int argc, /* I - Number of comm * 'browse_callback()' - Browse devices. */ +#ifdef HAVE_DNSSD static void browse_callback( DNSServiceRef sdRef, /* I - Service reference */ @@ -405,12 +613,14 @@ browse_callback( get_device((cups_array_t *)context, serviceName, regtype, replyDomain); } +#endif /* HAVE_DNSSD */ /* * 'browse_local_callback()' - Browse local devices. */ +#ifdef HAVE_DNSSD static void browse_local_callback( DNSServiceRef sdRef, /* I - Service reference */ @@ -456,6 +666,7 @@ browse_local_callback( device->fullName); device->sent = 1; } +#endif /* HAVE_DNSSD */ /* @@ -528,6 +739,32 @@ exec_backend(char **argv) /* I - Comman exit(CUPS_BACKEND_STOP); } +static int +device_type (const char *regtype) +{ +#ifdef HAVE_AVAHI + if (!strcmp(regtype, "_ipp._tcp") || + !strcmp(regtype, "_ipp-tls._tcp")) + return (CUPS_DEVICE_IPP); + else if (!strcmp(regtype, "_fax-ipp._tcp")) + return (CUPS_DEVICE_FAX_IPP); + else if (!strcmp(regtype, "_printer._tcp")) + return (CUPS_DEVICE_PDL_DATASTREAM); +#else + if (!strcmp(regtype, "_ipp._tcp.") || + !strcmp(regtype, "_ipp-tls._tcp.")) + return (CUPS_DEVICE_IPP); + else if (!strcmp(regtype, "_fax-ipp._tcp.")) + return (CUPS_DEVICE_FAX_IPP); + else if (!strcmp(regtype, "_printer._tcp.")) + return (CUPS_DEVICE_PRINTER); + else if (!strcmp(regtype, "_pdl-datastream._tcp.")) + return (CUPS_DEVICE_PDL_DATASTREAM); +#endif /* HAVE_AVAHI */ + + return (CUPS_DEVICE_RIOUSBPRINT); +} + /* * 'get_device()' - Create or update a device. @@ -550,18 +787,7 @@ get_device(cups_array_t *devices, /* I - */ key.name = (char *)serviceName; - - if (!strcmp(regtype, "_ipp._tcp.") || - !strcmp(regtype, "_ipp-tls._tcp.")) - key.type = CUPS_DEVICE_IPP; - else if (!strcmp(regtype, "_fax-ipp._tcp.")) - key.type = CUPS_DEVICE_FAX_IPP; - else if (!strcmp(regtype, "_printer._tcp.")) - key.type = CUPS_DEVICE_PRINTER; - else if (!strcmp(regtype, "_pdl-datastream._tcp.")) - key.type = CUPS_DEVICE_PDL_DATASTREAM; - else - key.type = CUPS_DEVICE_RIOUSBPRINT; + key.type = device_type (regtype); for (device = cupsArrayFind(devices, &key); device; @@ -581,8 +807,14 @@ get_device(cups_array_t *devices, /* I - free(device->domain); device->domain = strdup(replyDomain); +#ifdef HAVE_DNSSD DNSServiceConstructFullName(fullName, device->name, regtype, replyDomain); +#else /* HAVE_AVAHI */ + avahi_service_name_join (fullName, kDNSServiceMaxDomainName, + serviceName, regtype, replyDomain); +#endif /* HAVE_DNSSD */ + free(device->fullName); device->fullName = strdup(fullName); } @@ -609,7 +841,13 @@ get_device(cups_array_t *devices, /* I - * Set the "full name" of this service, which is used for queries... */ +#ifdef HAVE_DNSSD DNSServiceConstructFullName(fullName, serviceName, regtype, replyDomain); +#else /* HAVE_AVAHI */ + avahi_service_name_join (fullName, kDNSServiceMaxDomainName, + serviceName, regtype, replyDomain); +#endif /* HAVE_DNSSD */ + device->fullName = strdup(fullName); return (device); @@ -620,6 +858,7 @@ get_device(cups_array_t *devices, /* I - * 'query_callback()' - Process query data. */ +#ifdef HAVE_DNSSD static void query_callback( DNSServiceRef sdRef, /* I - Service reference */ @@ -639,7 +878,7 @@ query_callback( *ptr; /* Pointer into string */ cups_device_t dkey, /* Search key */ *device; /* Device */ - + cups_txt_records_t txt; fprintf(stderr, "DEBUG2: query_callback(sdRef=%p, flags=%x, " "interfaceIndex=%d, errorCode=%d, fullName=\"%s\", " @@ -673,84 +912,211 @@ query_callback( if ((ptr = strstr(name, "._")) != NULL) *ptr = '\0'; - if (strstr(fullName, "_ipp._tcp.") || - strstr(fullName, "_ipp-tls._tcp.")) - dkey.type = CUPS_DEVICE_IPP; - else if (strstr(fullName, "_fax-ipp._tcp.")) - dkey.type = CUPS_DEVICE_FAX_IPP; - else if (strstr(fullName, "_printer._tcp.")) - dkey.type = CUPS_DEVICE_PRINTER; - else if (strstr(fullName, "_pdl-datastream._tcp.")) - dkey.type = CUPS_DEVICE_PDL_DATASTREAM; + dkey.type = device_type (fullName); + + txt.data = rdata; + txt.dataend = rdata + rdlen; + device = find_device ((cups_array_t *) context, &txt, &dkey); + if (!device) + fprintf(stderr, "DEBUG: Ignoring TXT record for \"%s\"...\n", fullName); +} +#endif /* HAVE_DNSSD */ + +#ifdef HAVE_AVAHI +static void +avahi_client_callback(AvahiClient *client, + AvahiClientState state, + void *context) +{ + /* + * If the connection drops, quit. + */ + + if (state == AVAHI_CLIENT_FAILURE) + { + fprintf (stderr, "ERROR: Avahi connection failed\n"); + avahi_simple_poll_quit (simple_poll); + } +} + +static void +avahi_query_callback(AvahiServiceResolver *resolver, + AvahiIfIndex interface, + AvahiProtocol protocol, + AvahiResolverEvent event, + const char *name, + const char *type, + const char *domain, + const char *host_name, + const AvahiAddress *address, + uint16_t port, + AvahiStringList *txt, + AvahiLookupResultFlags flags, + void *context) +{ + AvahiClient *client; + cups_device_t key, + *device; + char uqname[1024], + *ptr; + cups_txt_records_t txtr; + + client = avahi_service_resolver_get_client (resolver); + if (event != AVAHI_RESOLVER_FOUND) + { + if (event == AVAHI_RESOLVER_FAILURE) + { + fprintf (stderr, "ERROR: %s\n", + avahi_strerror (avahi_client_errno (client))); + } + + avahi_service_resolver_free (resolver); + return; + } + + /* + * Set search key for device. + */ + + key.name = uqname; + unquote (uqname, name, sizeof (uqname)); + if ((ptr = strstr(name, "._")) != NULL) + *ptr = '\0'; + + key.domain = (char *) domain; + key.type = device_type (type); + + /* + * Find the device and the the TXT information. + */ + + txtr.txt = txt; + device = find_device ((cups_array_t *) context, &txtr, &key); + if (device) + { + /* + * Let the main loop know to announce the device. + */ + + avahi_got_callback = 1; + } else - dkey.type = CUPS_DEVICE_RIOUSBPRINT; + fprintf (stderr, "DEBUG: Ignoring TXT record for \"%s\"...\n", name); - for (device = cupsArrayFind(devices, &dkey); + avahi_service_resolver_free (resolver); +} + +static void +avahi_browse_callback(AvahiServiceBrowser *browser, + AvahiIfIndex interface, + AvahiProtocol protocol, + AvahiBrowserEvent event, + const char *name, + const char *type, + const char *domain, + AvahiLookupResultFlags flags, + void *context) +{ + AvahiClient *client = avahi_service_browser_get_client (browser); + + switch (event) + { + case AVAHI_BROWSER_FAILURE: + fprintf (stderr, "ERROR: %s\n", + avahi_strerror (avahi_client_errno (client))); + avahi_simple_poll_quit (simple_poll); + return; + + case AVAHI_BROWSER_NEW: + /* + * This object is new on the network. + */ + + if (flags & AVAHI_LOOKUP_RESULT_LOCAL) + { + /* + * This comes from the local machine so ignore it. + */ + + fprintf (stderr, "DEBUG: ignoring local service %s\n", name); + } + else + { + /* + * Create a device entry for it if it doesn't yet exist. + */ + + get_device ((cups_array_t *)context, name, type, domain); + + /* + * Now look for a TXT entry. + */ + + if (avahi_service_resolver_new (client, interface, protocol, + name, type, domain, + AVAHI_PROTO_UNSPEC, 0, + avahi_query_callback, context) == NULL) + { + fprintf (stderr, "ERROR: failed to resolve service %s: %s\n", + name, avahi_strerror (avahi_client_errno (client))); + } + } + + break; + + case AVAHI_BROWSER_REMOVE: + case AVAHI_BROWSER_ALL_FOR_NOW: + case AVAHI_BROWSER_CACHE_EXHAUSTED: + break; + } +} +#endif /* HAVE_AVAHI */ + +static cups_device_t * +find_device (cups_array_t *devices, + cups_txt_records_t *txt, + cups_device_t *dkey) +{ + cups_device_t *device; + char *ptr; + + for (device = cupsArrayFind(devices, dkey); device; device = cupsArrayNext(devices)) { - if (strcasecmp(device->name, dkey.name) || - strcasecmp(device->domain, dkey.domain)) + if (strcasecmp(device->name, dkey->name) || + strcasecmp(device->domain, dkey->domain)) { device = NULL; break; } - else if (device->type == dkey.type) + else if (device->type == dkey->type) { /* * Found it, pull out the priority and make and model from the TXT * record and save it... */ - const uint8_t *data, /* Pointer into data */ - *datanext, /* Next key/value pair */ - *dataend; /* End of entire TXT record */ - uint8_t datalen; /* Length of current key/value pair */ - char key[256], /* Key string */ - value[256], /* Value string */ - make_and_model[512], + char make_and_model[512], /* Manufacturer and model */ model[256], /* Model */ - device_id[2048];/* 1284 device ID */ - + device_id[2048]; /* 1284 device ID */ device_id[0] = '\0'; make_and_model[0] = '\0'; strcpy(model, "Unknown"); - for (data = rdata, dataend = data + rdlen; - data < dataend; - data = datanext) + for (;;) { - /* - * Read a key/value pair starting with an 8-bit length. Since the - * length is 8 bits and the size of the key/value buffers is 256, we - * don't need to check for overflow... - */ - - datalen = *data++; - - if (!datalen || (data + datalen) >= dataend) - break; - - datanext = data + datalen; + char *key; + char *value; - for (ptr = key; data < datanext && *data != '='; data ++) - *ptr++ = *data; - *ptr = '\0'; - - if (data < datanext && *data == '=') - { - data ++; - - if (data < datanext) - memcpy(value, data, datanext - data); - value[datanext - data] = '\0'; - } - else - continue; + if (parse_txt_record_pair (txt)) + goto next; + key = txt->key; + value = txt->value; if (!strncasecmp(key, "usb_", 4)) { /* @@ -805,6 +1171,10 @@ query_callback( if (device->type == CUPS_DEVICE_PRINTER) device->sent = 1; } + + next: + if (next_txt_record (txt) == NULL) + break; } if (device->device_id) @@ -854,11 +1224,9 @@ query_callback( } } - if (!device) - fprintf(stderr, "DEBUG: Ignoring TXT record for \"%s\"...\n", fullName); + return device; } - /* * 'sigterm_handler()' - Handle termination signals... */ diff -up cups-1.4rc1/config.h.in.avahi cups-1.4rc1/config.h.in --- cups-1.4rc1/config.h.in.avahi 2009-05-14 21:48:55.000000000 +0100 +++ cups-1.4rc1/config.h.in 2009-07-29 14:01:36.575271644 +0100 @@ -344,6 +344,13 @@ /* + * Do we have Avahi for DNS Service Discovery? + */ + +#undef HAVE_AVAHI + + +/* * Do we have ? */ diff -up cups-1.4rc1/config-scripts/cups-dnssd.m4.avahi cups-1.4rc1/config-scripts/cups-dnssd.m4 --- cups-1.4rc1/config-scripts/cups-dnssd.m4.avahi 2009-02-10 17:05:35.000000000 +0000 +++ cups-1.4rc1/config-scripts/cups-dnssd.m4 2009-07-29 14:01:36.575271644 +0100 @@ -27,6 +27,21 @@ AC_ARG_WITH(dnssd-includes, [ --with-dn DNSSDLIBS="" DNSSD_BACKEND="" +AC_ARG_ENABLE(avahi, [ --enable-avahi turn on DNS Service Discovery support, default=no], + [if test x$enable_avahi = xyes; then + AC_MSG_CHECKING(for Avahi) + if $PKGCONFIG --exists avahi-client; then + AC_MSG_RESULT(yes) + CFLAGS="$CFLAGS `$PKGCONFIG --cflags avahi-client`" + DNSSDLIBS="`$PKGCONFIG --libs avahi-client`" + DNSSD_BACKEND="dnssd" + AC_DEFINE(HAVE_AVAHI) + enable_dnssd=no + else + AC_MSG_RESULT(no) + fi + fi]) + if test x$enable_dnssd != xno; then AC_CHECK_HEADER(dns_sd.h, [ case "$uname" in diff -up cups-1.4rc1/cups/http-support.c.avahi cups-1.4rc1/cups/http-support.c --- cups-1.4rc1/cups/http-support.c.avahi 2009-04-30 23:15:05.000000000 +0100 +++ cups-1.4rc1/cups/http-support.c 2009-07-29 14:01:36.577396783 +0100 @@ -54,6 +54,11 @@ # include # include #endif /* HAVE_DNSSD */ +#ifdef HAVE_AVAHI +# include +# include +# include +#endif /* HAVE_AVAHI */ /* @@ -120,6 +125,24 @@ static void resolve_callback(DNSService void *context); #endif /* HAVE_DNSSD */ +#ifdef HAVE_AVAHI +static void avahi_resolve_uri_client_cb(AvahiClient *client, + AvahiClientState state, + void *simple_poll); +static void avahi_resolve_uri_resolver_cb(AvahiServiceResolver *resolver, + AvahiIfIndex interface, + AvahiProtocol protocol, + AvahiResolverEvent event, + const char *name, + const char *type, + const char *domain, + const char *host_name, + const AvahiAddress *address, + uint16_t port, + AvahiStringList *txt, + AvahiLookupResultFlags flags, + void *context); +#endif /* HAVE_AVAHI */ /* * 'httpAssembleURI()' - Assemble a uniform resource identifier from its @@ -1348,15 +1371,26 @@ _httpResolveURI( if (strstr(hostname, "._tcp")) { +#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) + char *regtype, /* Pointer to type in hostname */ + *domain; /* Pointer to domain in hostname */ #ifdef HAVE_DNSSD DNSServiceRef ref, /* DNS-SD master service reference */ domainref, /* DNS-SD service reference for domain */ localref; /* DNS-SD service reference for .local */ int domainsent = 0; /* Send the domain resolve? */ - char *regtype, /* Pointer to type in hostname */ - *domain; /* Pointer to domain in hostname */ _http_uribuf_t uribuf; /* URI buffer */ struct pollfd polldata; /* Polling data */ +#else /* HAVE_AVAHI */ + AvahiSimplePoll *simple_poll; + AvahiClient *client; + int error; + struct + { + AvahiSimplePoll *poll; + _http_uribuf_t uribuf; + } user_data; +#endif /* HAVE_DNSSD */ if (logit) @@ -1394,8 +1428,13 @@ _httpResolveURI( if (domain) *domain++ = '\0'; +#ifdef HAVE_DNSSD uribuf.buffer = resolved_uri; uribuf.bufsize = resolved_size; +#else + user_data.uribuf.buffer = resolved_uri; + user_data.uribuf.bufsize = resolved_size; +#endif resolved_uri[0] = '\0'; @@ -1411,6 +1450,7 @@ _httpResolveURI( uri = NULL; +#ifdef HAVE_DNSSD if (DNSServiceCreateConnection(&ref) == kDNSServiceErr_NoError) { localref = ref; @@ -1457,6 +1497,36 @@ _httpResolveURI( DNSServiceRefDeallocate(ref); } +#else /* HAVE_AVAHI */ + if ((simple_poll = avahi_simple_poll_new ()) != NULL) + { + if ((client = avahi_client_new (avahi_simple_poll_get (simple_poll), + 0, avahi_resolve_uri_client_cb, + &simple_poll, &error)) != NULL) + { + user_data.poll = simple_poll; + if (avahi_service_resolver_new (client, AVAHI_IF_UNSPEC, + AVAHI_PROTO_UNSPEC, hostname, + regtype, domain, AVAHI_PROTO_UNSPEC, 0, + avahi_resolve_uri_resolver_cb, + &user_data) != NULL) + { + avahi_simple_poll_loop (simple_poll); + + /* + * Collect the result. + */ + + if (resolved_uri[0]) + uri = resolved_uri; + } + + avahi_client_free (client); + } + + avahi_simple_poll_free (simple_poll); + } +#endif /* HAVE_DNSSD */ if (logit) { @@ -1468,13 +1538,13 @@ _httpResolveURI( fputs("STATE: -connecting-to-device\n", stderr); } -#else +#else /* HAVE_DNSSD || HAVE_AVAHI */ /* * No DNS-SD support... */ uri = NULL; -#endif /* HAVE_DNSSD */ +#endif /* HAVE_DNSSD || HAVE_AVAHI */ if (logit && !uri) _cupsLangPuts(stderr, _("Unable to find printer!\n")); @@ -1679,6 +1749,105 @@ resolve_callback( } #endif /* HAVE_DNSSD */ +#ifdef HAVE_AVAHI +static void +avahi_resolve_uri_client_cb (AvahiClient *client, + AvahiClientState state, + void *simple_poll) +{ + DEBUG_printf(("avahi_resolve_uri_client_callback(client=%p, state=%d, " + "simple_poll=%p)\n", client, state, simple_poll)); + + /* + * If the connection drops, quit. + */ + + if (state == AVAHI_CLIENT_FAILURE) + avahi_simple_poll_quit (simple_poll); +} + +static void +avahi_resolve_uri_resolver_cb (AvahiServiceResolver *resolver, + AvahiIfIndex interface, + AvahiProtocol protocol, + AvahiResolverEvent event, + const char *name, + const char *type, + const char *domain, + const char *host_name, + const AvahiAddress *address, + uint16_t port, + AvahiStringList *txt, + AvahiLookupResultFlags flags, + void *context) +{ + const char *scheme; /* URI scheme */ + char rp[256]; /* Remote printer */ + AvahiStringList *pair; + char *value; + size_t valueLen = 0; + char addr[AVAHI_ADDRESS_STR_MAX]; + struct + { + AvahiSimplePoll *poll; + _http_uribuf_t uribuf; + } *poll_uribuf = context; + + DEBUG_printf(("avahi_resolve_uri_resolver_callback(resolver=%p, " + "interface=%d, protocol=%d, event=%d, name=\"%s\", " + "type=\"%s\", domain=\"%s\", host_name=\"%s\", address=%p, " + "port=%d, txt=%p, flags=%d, context=%p)\n", + resolver, interface, protocol, event, name, type, domain, + host_name, address, port, txt, flags, context)); + + if (event != AVAHI_RESOLVER_FOUND) + { + avahi_service_resolver_free (resolver); + avahi_simple_poll_quit (poll_uribuf->poll); + return; + } + + /* + * Figure out the scheme from the full name... + */ + + if (strstr(type, "_ipp.")) + scheme = "ipp"; + else if (strstr(type, "_printer.")) + scheme = "lpd"; + else if (strstr(type, "_pdl-datastream.")) + scheme = "socket"; + else + scheme = "riousbprint"; + + /* + * Extract the "remote printer key from the TXT record... + */ + + if ((pair = avahi_string_list_find (txt, "rp")) != NULL) + { + avahi_string_list_get_pair (pair, NULL, &value, &valueLen); + rp[0] = '/'; + memcpy (rp + 1, value, valueLen); + rp[valueLen + 1] = '\0'; + } + else + rp[0] = '\0'; + + /* + * Assemble the final device URI... + */ + + avahi_address_snprint (addr, AVAHI_ADDRESS_STR_MAX, address); + httpAssembleURI(HTTP_URI_CODING_ALL, poll_uribuf->uribuf.buffer, + poll_uribuf->uribuf.bufsize, scheme, NULL, + addr, port, rp); + DEBUG_printf(("avahi_resolve_uri_resolver_callback: Resolved URI is \"%s\"\n", + poll_uribuf->uribuf.buffer)); + avahi_simple_poll_quit (poll_uribuf->poll); +} +#endif /* HAVE_AVAHI */ + /* * End of "$Id: http-support.c 8585 2009-04-30 22:15:05Z mike $".