From d4e17e51c444d9a52ed986b726b5fe188c6be117 Mon Sep 17 00:00:00 2001 From: Zdenek Dohnal Date: Wed, 4 Oct 2017 16:15:45 +0200 Subject: [PATCH] 1498091 - Cannot browse CUPS servers in GNOME Control Panel Printers --- cups-cupsenumdests2.patch | 509 ++++++++++++++++++++++++++++++++++++++ cups.spec | 8 +- 2 files changed, 516 insertions(+), 1 deletion(-) create mode 100644 cups-cupsenumdests2.patch diff --git a/cups-cupsenumdests2.patch b/cups-cupsenumdests2.patch new file mode 100644 index 0000000..9e2e9f1 --- /dev/null +++ b/cups-cupsenumdests2.patch @@ -0,0 +1,509 @@ +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) + { diff --git a/cups.spec b/cups.spec index e56bf9a..bad8e4e 100644 --- a/cups.spec +++ b/cups.spec @@ -15,7 +15,7 @@ Summary: CUPS printing system Name: cups Epoch: 1 Version: 2.2.4 -Release: 5%{?dist} +Release: 6%{?dist} License: GPLv2 Url: http://www.cups.org/ Source0: https://github.com/apple/cups/releases/download/v%{VERSION}/cups-%{VERSION}-source.tar.gz @@ -64,6 +64,7 @@ Patch37: cups-synconclose.patch Patch38: cups-resolv_reload.patch Patch39: cups-ypbind.patch Patch40: cups-no-dest.patch +Patch41: cups-cupsenumdests2.patch Patch100: cups-lspp.patch @@ -261,6 +262,8 @@ Sends IPP requests to the specified URI and tests and/or displays the results. %patch39 -p1 -b .ypbind # Can not get destinations from CUPS server (bug #1484916) %patch40 -p1 -b .no-dest +# Cannot browse CUPS servers in GNOME Control Panel Printers (bug #1498091) +%patch41 -p1 -b .cupsenumdests2 %if %{lspp} # LSPP support. @@ -626,6 +629,9 @@ rm -f %{cups_serverbin}/backend/smb %{_mandir}/man5/ipptoolfile.5.gz %changelog +* Wed Oct 04 2017 Zdenek Dohnal - 1:2.2.4-6 +- 1498091 - Cannot browse CUPS servers in GNOME Control Panel Printers + * Mon Oct 02 2017 Zdenek Dohnal - 1:2.2.4-5 - 1484916 - Can not get destinations from CUPS server