diff -up cups-2.2.4/cups/cups.h.cupsenumdests2 cups-2.2.4/cups/cups.h --- cups-2.2.4/cups/cups.h.cupsenumdests2 2017-06-30 17:44:38.000000000 +0200 +++ cups-2.2.4/cups/cups.h 2017-10-04 15:31:45.358029517 +0200 @@ -527,11 +527,20 @@ extern int cupsEnumDests(unsigned flags cups_ptype_t type, cups_ptype_t mask, cups_dest_cb_t cb, void *user_data) _CUPS_API_1_6; +extern int cupsEnumDests2(http_t *http, unsigned flags, int msec, int *cancel, + cups_ptype_t type, cups_ptype_t mask, + cups_dest_cb_t cb, void *user_data) + _CUPS_API_1_6; # ifdef __BLOCKS__ extern int cupsEnumDestsBlock(unsigned flags, int msec, int *cancel, cups_ptype_t type, cups_ptype_t mask, cups_dest_block_t block) + _CUPS_API_1_6; +extern int cupsEnumDestsBlock2(http_t *http, unsigned flags, int msec, + int *cancel, cups_ptype_t type, + cups_ptype_t mask, + cups_dest_block_t block) _CUPS_API_1_6; # endif /* __BLOCKS__ */ extern ipp_status_t cupsFinishDestDocument(http_t *http, diff -up cups-2.2.4/cups/dest.c.cupsenumdests2 cups-2.2.4/cups/dest.c --- cups-2.2.4/cups/dest.c.cupsenumdests2 2017-10-04 15:31:45.356029534 +0200 +++ cups-2.2.4/cups/dest.c 2017-10-04 15:31:45.359029509 +0200 @@ -1377,6 +1377,423 @@ cupsEnumDests( return (1); } +/* + * 'cupsEnumDests2()' - same as cupsEnumDests(), but for not default http connection + */ + +int /* O - 1 on success, 0 on failure */ +cupsEnumDests2( + http_t *http, /* I - Connection to server */ + unsigned flags, /* I - Enumeration flags */ + int msec, /* I - Timeout in milliseconds, -1 for indefinite */ + int *cancel, /* I - Pointer to "cancel" variable */ + cups_ptype_t type, /* I - Printer type bits */ + cups_ptype_t mask, /* I - Mask for printer type bits */ + cups_dest_cb_t cb, /* I - Callback function */ + void *user_data) /* I - User data */ +{ + int i, /* Looping var */ + num_dests; /* Number of destinations */ + cups_dest_t *dests = NULL, /* Destinations */ + *dest; /* Current destination */ + const char *defprinter; /* Default printer */ + char name[1024], /* Copy of printer name */ + *instance, /* Pointer to instance name */ + *user_default; /* User default printer */ +#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) + int count, /* Number of queries started */ + completed, /* Number of completed queries */ + remaining; /* Remainder of timeout */ + struct timeval curtime; /* Current time */ + _cups_dnssd_data_t data; /* Data for callback */ + _cups_dnssd_device_t *device; /* Current device */ +# ifdef HAVE_DNSSD + int nfds, /* Number of files responded */ + main_fd; /* File descriptor for lookups */ + DNSServiceRef ipp_ref = NULL, /* IPP browser */ + local_ipp_ref = NULL; /* Local IPP browser */ +# ifdef HAVE_SSL + DNSServiceRef ipps_ref = NULL,/* IPPS browser */ + local_ipps_ref = NULL; /* Local IPPS browser */ +# endif /* HAVE_SSL */ +# ifdef HAVE_POLL + struct pollfd pfd; /* Polling data */ +# else + fd_set input; /* Input set for select() */ + struct timeval timeout; /* Timeout for select() */ +# endif /* HAVE_POLL */ +# else /* HAVE_AVAHI */ + int error; /* Error value */ + AvahiServiceBrowser *ipp_ref = NULL;/* IPP browser */ +# ifdef HAVE_SSL + AvahiServiceBrowser *ipps_ref = NULL; /* IPPS browser */ +# endif /* HAVE_SSL */ +# endif /* HAVE_DNSSD */ +#endif /* HAVE_DNSSD || HAVE_AVAHI */ + + + /* + * Range check input... + */ + + (void)flags; + + if (!cb) + return (0); + + /* + * Get ready to enumerate... + */ + +#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) + memset(&data, 0, sizeof(data)); + + data.type = type; + data.mask = mask; + data.cb = cb; + data.user_data = user_data; + data.devices = cupsArrayNew3((cups_array_func_t)cups_dnssd_compare_devices, NULL, NULL, 0, NULL, (cups_afree_func_t)cups_dnssd_free_device); +#endif /* HAVE_DNSSD || HAVE_AVAHI */ + + if (!(mask & CUPS_PRINTER_DISCOVERED) || !(type & CUPS_PRINTER_DISCOVERED)) + { + /* + * Get the list of local printers and pass them to the callback function... + */ + + num_dests = _cupsGetDests(http, IPP_OP_CUPS_GET_PRINTERS, NULL, + &dests, type, mask); + + if ((user_default = _cupsUserDefault(name, sizeof(name))) != NULL) + defprinter = name; + else if ((defprinter = cupsGetDefault2(http)) != NULL) + { + strlcpy(name, defprinter, sizeof(name)); + defprinter = name; + } + + if (defprinter) + { + /* + * Separate printer and instance name... + */ + + if ((instance = strchr(name, '/')) != NULL) + *instance++ = '\0'; + + /* + * Lookup the printer and instance and make it the default... + */ + + if ((dest = cupsGetDest(name, instance, num_dests, dests)) != NULL) + dest->is_default = 1; + } + + for (i = num_dests, dest = dests; + i > 0 && (!cancel || !*cancel); + i --, dest ++) + { +#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) + const char *device_uri; /* Device URI */ +#endif /* HAVE_DNSSD || HAVE_AVAHI */ + + if (!(*cb)(user_data, i > 1 ? CUPS_DEST_FLAGS_MORE : CUPS_DEST_FLAGS_NONE, + dest)) + break; + +#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) + if (!dest->instance && (device_uri = cupsGetOption("device-uri", dest->num_options, dest->options)) != NULL && !strncmp(device_uri, "dnssd://", 8)) + { + /* + * Add existing queue using service name, etc. so we don't list it again... + */ + + char scheme[32], /* URI scheme */ + userpass[32], /* Username:password */ + serviceName[256], /* Service name (host field) */ + resource[256], /* Resource (options) */ + *regtype, /* Registration type */ + *replyDomain; /* Registration domain */ + int port; /* Port number (not used) */ + + if (httpSeparateURI(HTTP_URI_CODING_ALL, device_uri, scheme, sizeof(scheme), userpass, sizeof(userpass), serviceName, sizeof(serviceName), &port, resource, sizeof(resource)) >= HTTP_URI_STATUS_OK) + { + if ((regtype = strstr(serviceName, "._ipp")) != NULL) + { + *regtype++ = '\0'; + + if ((replyDomain = strstr(regtype, "._tcp.")) != NULL) + { + replyDomain[5] = '\0'; + replyDomain += 6; + + if ((device = cups_dnssd_get_device(&data, serviceName, regtype, replyDomain)) != NULL) + device->state = _CUPS_DNSSD_ACTIVE; + } + } + } + } +#endif /* HAVE_DNSSD || HAVE_AVAHI */ + } + + cupsFreeDests(num_dests, dests); + + if (i > 0 || msec == 0) + goto enum_finished; + } + + /* + * Return early if the caller doesn't want to do discovery... + */ + + if ((mask & CUPS_PRINTER_DISCOVERED) && !(type & CUPS_PRINTER_DISCOVERED)) + goto enum_finished; + +#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) + /* + * Get Bonjour-shared printers... + */ + + gettimeofday(&curtime, NULL); + +# ifdef HAVE_DNSSD + if (DNSServiceCreateConnection(&data.main_ref) != kDNSServiceErr_NoError) + return (0); + + main_fd = DNSServiceRefSockFD(data.main_ref); + + ipp_ref = data.main_ref; + DNSServiceBrowse(&ipp_ref, kDNSServiceFlagsShareConnection, 0, + "_ipp._tcp", NULL, + (DNSServiceBrowseReply)cups_dnssd_browse_cb, &data); + + local_ipp_ref = data.main_ref; + DNSServiceBrowse(&local_ipp_ref, kDNSServiceFlagsShareConnection, + kDNSServiceInterfaceIndexLocalOnly, + "_ipp._tcp", NULL, + (DNSServiceBrowseReply)cups_dnssd_local_cb, &data); + +# ifdef HAVE_SSL + ipps_ref = data.main_ref; + DNSServiceBrowse(&ipps_ref, kDNSServiceFlagsShareConnection, 0, + "_ipps._tcp", NULL, + (DNSServiceBrowseReply)cups_dnssd_browse_cb, &data); + + local_ipps_ref = data.main_ref; + DNSServiceBrowse(&local_ipps_ref, kDNSServiceFlagsShareConnection, + kDNSServiceInterfaceIndexLocalOnly, + "_ipps._tcp", NULL, + (DNSServiceBrowseReply)cups_dnssd_local_cb, &data); +# endif /* HAVE_SSL */ + +# else /* HAVE_AVAHI */ + if ((data.simple_poll = avahi_simple_poll_new()) == NULL) + { + DEBUG_puts("cupsEnumDests2: Unable to create Avahi simple poll object."); + return (1); + } + + avahi_simple_poll_set_func(data.simple_poll, cups_dnssd_poll_cb, &data); + + data.client = avahi_client_new(avahi_simple_poll_get(data.simple_poll), + 0, cups_dnssd_client_cb, &data, + &error); + if (!data.client) + { + DEBUG_puts("cupsEnumDests2: Unable to create Avahi client."); + avahi_simple_poll_free(data.simple_poll); + return (1); + } + + data.browsers = 1; + ipp_ref = avahi_service_browser_new(data.client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_ipp._tcp", NULL, 0, cups_dnssd_browse_cb, &data); + +# ifdef HAVE_SSL + data.browsers ++; + ipps_ref = avahi_service_browser_new(data.client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_ipps._tcp", NULL, 0, cups_dnssd_browse_cb, &data); +# endif /* HAVE_SSL */ +# endif /* HAVE_DNSSD */ + + if (msec < 0) + remaining = INT_MAX; + else + remaining = msec; + + while (remaining > 0 && (!cancel || !*cancel)) + { + /* + * Check for input... + */ + + DEBUG_printf(("1cupsEnumDests2: remaining=%d", remaining)); + + cups_elapsed(&curtime); + +# ifdef HAVE_DNSSD +# ifdef HAVE_POLL + pfd.fd = main_fd; + pfd.events = POLLIN; + + nfds = poll(&pfd, 1, remaining > _CUPS_DNSSD_MAXTIME ? _CUPS_DNSSD_MAXTIME : remaining); + +# else + FD_ZERO(&input); + FD_SET(main_fd, &input); + + timeout.tv_sec = 0; + timeout.tv_usec = 1000 * (remaining > _CUPS_DNSSD_MAXTIME ? _CUPS_DNSSD_MAXTIME : remaining); + + nfds = select(main_fd + 1, &input, NULL, NULL, &timeout); +# endif /* HAVE_POLL */ + + if (nfds > 0) + DNSServiceProcessResult(data.main_ref); + +# else /* HAVE_AVAHI */ + data.got_data = 0; + + if ((error = avahi_simple_poll_iterate(data.simple_poll, _CUPS_DNSSD_MAXTIME)) > 0) + { + /* + * We've been told to exit the loop. Perhaps the connection to + * Avahi failed. + */ + + break; + } + + DEBUG_printf(("1cupsEnumDests2: got_data=%d", data.got_data)); +# endif /* HAVE_DNSSD */ + + remaining -= cups_elapsed(&curtime); + + for (device = (_cups_dnssd_device_t *)cupsArrayFirst(data.devices), + count = 0, completed = 0; + device; + device = (_cups_dnssd_device_t *)cupsArrayNext(data.devices)) + { + if (device->ref) + count ++; + + if (device->state == _CUPS_DNSSD_ACTIVE) + completed ++; + + if (!device->ref && device->state == _CUPS_DNSSD_NEW) + { + DEBUG_printf(("1cupsEnumDests2: Querying '%s'.", device->fullName)); + +# ifdef HAVE_DNSSD + device->ref = data.main_ref; + + if (DNSServiceQueryRecord(&(device->ref), + kDNSServiceFlagsShareConnection, + 0, device->fullName, + kDNSServiceType_TXT, + kDNSServiceClass_IN, + (DNSServiceQueryRecordReply)cups_dnssd_query_cb, + &data) == kDNSServiceErr_NoError) + { + count ++; + } + else + { + device->ref = 0; + device->state = _CUPS_DNSSD_ERROR; + + DEBUG_puts("1cupsEnumDests2: Query failed."); + } + +# else /* HAVE_AVAHI */ + if ((device->ref = avahi_record_browser_new(data.client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, device->fullName, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_TXT, 0, cups_dnssd_query_cb, &data)) != NULL) + { + DEBUG_printf(("1cupsEnumDests2: Query ref=%p", device->ref)); + count ++; + } + else + { + device->state = _CUPS_DNSSD_ERROR; + + DEBUG_printf(("1cupsEnumDests2: Query failed: %s", avahi_strerror(avahi_client_errno(data.client)))); + } +# endif /* HAVE_DNSSD */ + } + else if (device->ref && device->state == _CUPS_DNSSD_PENDING) + { + completed ++; + + DEBUG_printf(("1cupsEnumDests2: Query for \"%s\" is complete.", device->fullName)); + + if ((device->type & mask) == type) + { + DEBUG_printf(("1cupsEnumDests2: Add callback for \"%s\".", device->dest.name)); + if (!(*cb)(user_data, CUPS_DEST_FLAGS_NONE, &device->dest)) + { + remaining = -1; + break; + } + } + + device->state = _CUPS_DNSSD_ACTIVE; + } + } + +# ifdef HAVE_AVAHI + DEBUG_printf(("1cupsEnumDests2: remaining=%d, browsers=%d, completed=%d, count=%d, devices count=%d", remaining, data.browsers, completed, count, cupsArrayCount(data.devices))); + + if (data.browsers == 0 && completed == cupsArrayCount(data.devices)) + break; +# else + DEBUG_printf(("1cupsEnumDests2: remaining=%d, completed=%d, count=%d, devices count=%d", remaining, completed, count, cupsArrayCount(data.devices))); + + if (completed == cupsArrayCount(data.devices)) + break; +# endif /* HAVE_AVAHI */ + } +#endif /* HAVE_DNSSD || HAVE_AVAHI */ + + /* + * Return... + */ + + enum_finished: + +#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) + cupsArrayDelete(data.devices); + +# ifdef HAVE_DNSSD + if (ipp_ref) + DNSServiceRefDeallocate(ipp_ref); + if (local_ipp_ref) + DNSServiceRefDeallocate(local_ipp_ref); + +# ifdef HAVE_SSL + if (ipps_ref) + DNSServiceRefDeallocate(ipps_ref); + if (local_ipps_ref) + DNSServiceRefDeallocate(local_ipps_ref); +# endif /* HAVE_SSL */ + + if (data.main_ref) + DNSServiceRefDeallocate(data.main_ref); + +# else /* HAVE_AVAHI */ + if (ipp_ref) + avahi_service_browser_free(ipp_ref); +# ifdef HAVE_SSL + if (ipps_ref) + avahi_service_browser_free(ipps_ref); +# endif /* HAVE_SSL */ + + if (data.client) + avahi_client_free(data.client); + if (data.simple_poll) + avahi_simple_poll_free(data.simple_poll); +# endif /* HAVE_DNSSD */ +#endif /* HAVE_DNSSD || HAVE_AVAHI */ + + return (1); +} + # ifdef __BLOCKS__ /* @@ -1413,6 +1830,24 @@ cupsEnumDestsBlock( return (cupsEnumDests(flags, timeout, cancel, type, mask, (cups_dest_cb_t)cups_block_cb, (void *)block)); } + +/* + * 'cupsEnumDestsBlock2()' - same as cupsEnumDestsBlock(), only with non default http connection + */ + +int /* O - 1 on success, 0 on failure */ +cupsEnumDestsBlock2( + http_t *http, /* I - Connection to server@ */ + unsigned flags, /* I - Enumeration flags */ + int timeout, /* I - Timeout in milliseconds, 0 for indefinite */ + int *cancel, /* I - Pointer to "cancel" variable */ + cups_ptype_t type, /* I - Printer type bits */ + cups_ptype_t mask, /* I - Mask for printer type bits */ + cups_dest_block_t block) /* I - Block */ +{ + return (cupsEnumDests2(http, flags, timeout, cancel, type, mask, + (cups_dest_cb_t)cups_block_cb, (void *)block)); +} # endif /* __BLOCKS__ */ @@ -2057,7 +2492,13 @@ cupsGetDests2(http_t *http, /* I - data.num_dests = 0; data.dests = NULL; - cupsEnumDests(0, 1000, NULL, 0, 0, (cups_dest_cb_t)cups_get_cb, &data); + if (!http) + http = CUPS_HTTP_DEFAULT; + + if (http == CUPS_HTTP_DEFAULT) + cupsEnumDests(0, 1000, NULL, 0, 0, (cups_dest_cb_t)cups_get_cb, &data); + else + cupsEnumDests2(http, 0, 1000, NULL, 0, 0, (cups_dest_cb_t)cups_get_cb, &data); /* * Make a copy of the "real" queues for a later sanity check... diff -up cups-2.2.4/cups/util.c.cupsenumdests2 cups-2.2.4/cups/util.c --- cups-2.2.4/cups/util.c.cupsenumdests2 2017-06-30 17:44:38.000000000 +0200 +++ cups-2.2.4/cups/util.c 2017-10-04 15:36:08.453828842 +0200 @@ -197,7 +197,13 @@ cupsCreateJob( data.name = name; data.dest = NULL; - cupsEnumDests(0, 1000, NULL, 0, 0, (cups_dest_cb_t)cups_create_cb, &data); + if (!http) + http = CUPS_HTTP_DEFAULT; + + if (http == CUPS_HTTP_DEFAULT) + cupsEnumDests(0, 1000, NULL, 0, 0, (cups_dest_cb_t)cups_create_cb, &data); + else + cupsEnumDests2(http, 0, 1000, NULL, 0, 0, (cups_dest_cb_t)cups_create_cb, &data); if (!data.dest) {