summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDidier Raboud <odyx@debian.org>2019-08-18 16:30:06 +0200
committerDidier Raboud <odyx@debian.org>2019-08-17 16:51:34 +0200
commit332d6359c62d8224bfbc61bc269f91de168d8dcf (patch)
tree9532ad55fadc556920f3dae47e026301f464b296
parent639a21dc0055a25ff5cf04a8be292a809fbaeaa0 (diff)
parentbe3a8d7798bff9fff249f47ad9fd678a593a949e (diff)
record new upstream branch and merge it
-rw-r--r--INSTALL2
-rw-r--r--NEWS43
-rw-r--r--README2
-rwxr-xr-xconfigure20
-rw-r--r--configure.ac2
-rw-r--r--debian/.git-dpm14
-rw-r--r--filter/foomatic-rip/spooler.c3
-rw-r--r--filter/imagetopdf.c22
-rw-r--r--filter/pdftoraster.cxx50
-rw-r--r--utils/cups-browsed.c660
-rw-r--r--utils/cups-browsed.conf.57
-rw-r--r--utils/cups-browsed.conf.in7
12 files changed, 548 insertions, 284 deletions
diff --git a/INSTALL b/INSTALL
index 70469863d..6117c6720 100644
--- a/INSTALL
+++ b/INSTALL
@@ -1,4 +1,4 @@
-INSTALL - OpenPrinting CUPS Filters v1.25.0 - 2019-06-06
+INSTALL - OpenPrinting CUPS Filters v1.25.2 - 2019-08-16
--------------------------------------------------------
This file describes how to compile and install OpenPrinting CUPS
diff --git a/NEWS b/NEWS
index f83dc910c..6c82c1a89 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,47 @@
-NEWS - OpenPrinting CUPS Filters v1.25.0 - 2019-06-06
+NEWS - OpenPrinting CUPS Filters v1.25.2 - 2019-08-16
-----------------------------------------------------
+CHANGES IN V1.25.2
+
+ - foomatic-rip: Fixed segmentation fault when running
+ foomatic-rip by hand and the PRINTER environment variable is
+ not set (Pull request #139).
+ - cups-browsed: Added note to cups-browsed.conf and man page
+ about IP-based URIs depending on the network interface used.
+ - cups-browsed: For each DNS-SD-discovered printer register
+ each DNS-SD discovery instance with network interface,
+ family, and IPP type. When DNS-SD messages of instances
+ disappearing show up, only unregister this instance and
+ remove the printer only if no instance is left. This
+ prevents a local queue of a still available printer being
+ removed when Wi-Fi (= one interface) is turned off (Issue
+ #136).
+ - cups-browsed: If a remote printer is served from the local
+ machine, prefer the "localhost"/loopback interface URI.
+ - cups-browsed: If a remote printer is discovered more than
+ once, use the new instance only if it has no downgrades and
+ at least one upgrade compared to the old one. Features
+ currently compared are IPP/IPPS, loopback interface or not,
+ and discovery via CUPS legacy/LDAP/DNS-SD.
+ - cups-browsed: If an Avahi-discovered entry comes through the
+ "lo" interface, always use the host name "localhost". Use
+ IP addresses instead of host names only if explicitly
+ requested.
+ - cups-browsed: Consider remote printer entries also as from
+ the same printer if one has the local machine's network name
+ and the other "localhost" as host name (Issue #136).
+
+CHANGES IN V1.25.1
+
+ - imagetopdf: Fixed crash when no PPD file was supplied (Pull
+ request #133).
+ - pdftoraster: Fixed offset issues leading to segmentation
+ faults (Issue #131, Pull request #132).
+ - pdftoraster: Added anti-aliasing for better raster image
+ quality (Pull request #129).
+ - pdftoraster: Added graceful handling of zero-page input
+ (Issue #117, Pull request #127).
+
CHANGES IN V1.25.0
- pdftoijs, pdftoopvp: Removed these deprecated filters
diff --git a/README b/README
index ab1d75ac9..12ae008b4 100644
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
-README - OpenPrinting CUPS Filters v1.25.0 - 2019-06-06
+README - OpenPrinting CUPS Filters v1.25.2 - 2019-08-16
-------------------------------------------------------
Looking for compile instructions? Read the file "INSTALL.txt"
diff --git a/configure b/configure
index 1ca4f0651..d7bc902d4 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for cups-filters 1.25.0.
+# Generated by GNU Autoconf 2.69 for cups-filters 1.25.2.
#
#
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
@@ -587,8 +587,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='cups-filters'
PACKAGE_TARNAME='cups-filters'
-PACKAGE_VERSION='1.25.0'
-PACKAGE_STRING='cups-filters 1.25.0'
+PACKAGE_VERSION='1.25.2'
+PACKAGE_STRING='cups-filters 1.25.2'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''
@@ -1490,7 +1490,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures cups-filters 1.25.0 to adapt to many kinds of systems.
+\`configure' configures cups-filters 1.25.2 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1561,7 +1561,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of cups-filters 1.25.0:";;
+ short | recursive ) echo "Configuration of cups-filters 1.25.2:";;
esac
cat <<\_ACEOF
@@ -1787,7 +1787,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-cups-filters configure 1.25.0
+cups-filters configure 1.25.2
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2425,7 +2425,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by cups-filters $as_me 1.25.0, which was
+It was created by cups-filters $as_me 1.25.2, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -3460,7 +3460,7 @@ fi
# Define the identity of the package.
PACKAGE='cups-filters'
- VERSION='1.25.0'
+ VERSION='1.25.2'
cat >>confdefs.h <<_ACEOF
@@ -21664,7 +21664,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by cups-filters $as_me 1.25.0, which was
+This file was extended by cups-filters $as_me 1.25.2, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -21730,7 +21730,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-cups-filters config.status 1.25.0
+cups-filters config.status 1.25.2
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
diff --git a/configure.ac b/configure.ac
index c472457f7..27383e7f3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -7,7 +7,7 @@ AC_PREREQ([2.65])
# ====================
m4_define([cups_filters_version_major],[1])
m4_define([cups_filters_version_minor],[25])
-m4_define([cups_filters_version_micro],[0])
+m4_define([cups_filters_version_micro],[2])
m4_define([cups_filters_version],[cups_filters_version_major.cups_filters_version_minor.cups_filters_version_micro])
# =============
diff --git a/debian/.git-dpm b/debian/.git-dpm
index 3bba89730..13d56e935 100644
--- a/debian/.git-dpm
+++ b/debian/.git-dpm
@@ -1,8 +1,8 @@
# see git-dpm(1) from git-dpm package
-f898bd47af3228196fc4b41f6d276a44be5a4048
-f898bd47af3228196fc4b41f6d276a44be5a4048
-f898bd47af3228196fc4b41f6d276a44be5a4048
-f898bd47af3228196fc4b41f6d276a44be5a4048
-cups-filters_1.25.0.orig.tar.xz
-0b711c4977bd6e8d370c7d11b719661b6d990df0
-1447496
+be3a8d7798bff9fff249f47ad9fd678a593a949e
+be3a8d7798bff9fff249f47ad9fd678a593a949e
+be3a8d7798bff9fff249f47ad9fd678a593a949e
+be3a8d7798bff9fff249f47ad9fd678a593a949e
+cups-filters_1.25.2.orig.tar.xz
+dc32bfbf9112b67c08a4fe7bc1a6ebec9361ec86
+1449984
diff --git a/filter/foomatic-rip/spooler.c b/filter/foomatic-rip/spooler.c
index 7f0cb8eeb..50dcbaf3e 100644
--- a/filter/foomatic-rip/spooler.c
+++ b/filter/foomatic-rip/spooler.c
@@ -94,8 +94,7 @@ void init_cups(list_t *arglist, dstr_t *filelist, jobparams_t *job)
CUPS puts the print queue name into the PRINTER environment variable
when calling filters. */
strncpy(job->printer, getenv("PRINTER"), 256);
- if (strlen(getenv("PRINTER")) > 255)
- job->printer[255] = '\0';
+ job->printer[255] = '\0';
free(cups_options);
}
diff --git a/filter/imagetopdf.c b/filter/imagetopdf.c
index c4efc3e1f..606967b52 100644
--- a/filter/imagetopdf.c
+++ b/filter/imagetopdf.c
@@ -165,7 +165,7 @@ void emitJCLOptions(FILE *fp, int copies)
datawritten = 1;
}
}
-
+
snprintf(buf,sizeof(buf),"%d",copies);
if (ppdFindOption(ppd,"Copies") != NULL) {
ppdMarkOption(ppd,"Copies",buf);
@@ -265,7 +265,7 @@ static void putcPdf(char c)
static void outPdf(const char *str)
{
- unsigned long len = strlen(str);
+ unsigned long len = strlen(str);
fputs(str,stdout);
currentOffset += len;
@@ -964,8 +964,8 @@ main(int argc, /* I - Number of command-line arguments */
int fidelity = 0;
int document_large = 0;
- if(ppd->custom_margins[0]||ppd->custom_margins[1]||
- ppd->custom_margins[2]||ppd->custom_margins[3]) // In case of custom margins
+ if(ppd && (ppd->custom_margins[0]||ppd->custom_margins[1]||
+ ppd->custom_margins[2]||ppd->custom_margins[3])) // In case of custom margins
margin_defined = 1;
if(PageLength!=PageTop-PageBottom||PageWidth!=PageRight-PageLeft)
margin_defined = 1;
@@ -1104,7 +1104,7 @@ main(int argc, /* I - Number of command-line arguments */
if(temp1>w) temp1 = w;
if(temp2>h) temp2 = h;
if(temp3>h) temp3 = h;
- if(temp4>w) temp4 = w;
+ if(temp4>w) temp4 = w;
if(temp1*temp2<temp3*temp4)
{
int temp = pw;
@@ -1117,7 +1117,7 @@ main(int argc, /* I - Number of command-line arguments */
float final_w,final_h;
if(w*ph/pw <=h){
final_w =w;
- final_h =w*ph/pw;
+ final_h =w*ph/pw;
}
else{
final_w = h*pw/ph;
@@ -1228,7 +1228,7 @@ main(int argc, /* I - Number of command-line arguments */
/*
* Scale the image as neccesary to match the desired pixels-per-inch.
*/
-
+
if (Orientation & 1)
{
xprint = (PageTop - PageBottom) / 72.0;
@@ -1381,7 +1381,7 @@ main(int argc, /* I - Number of command-line arguments */
if (zoom == 1.0) {
/* If fitplot is specified, make xpages, ypages 1 forcedly.
- Because calculation error may be caused and
+ Because calculation error may be caused and
result of ceil function may be larger than 1.
*/
xpages = ypages = 1;
@@ -1567,7 +1567,7 @@ main(int argc, /* I - Number of command-line arguments */
printer and the PPD is for this mode, having the "*JCLToPDFInterpreter:"
keyword. We need to read this keyword manually from the PPD and replace
the content of ppd->jcl_ps by the value of this keyword, so that
- ppdEmitJCL() actalually adds JCL based on the presence on
+ ppdEmitJCL() actalually adds JCL based on the presence on
"*JCLToPDFInterpreter:". */
ppd_attr_t *attr;
char buf[1024];
@@ -1599,12 +1599,12 @@ main(int argc, /* I - Number of command-line arguments */
snprintf(ppd->jcl_ps, size, "@PJL SET COPIES=%d\n%s",
deviceCopies, attr->value);
}
- }
+ }
else
ppd->jcl_ps = strdup(attr->value);
ppd_decode(ppd->jcl_ps);
pdf_printer = 1;
- }
+ }
else
{
ppd->jcl_ps = NULL;
diff --git a/filter/pdftoraster.cxx b/filter/pdftoraster.cxx
index e553e76b8..d3f681089 100644
--- a/filter/pdftoraster.cxx
+++ b/filter/pdftoraster.cxx
@@ -1547,7 +1547,7 @@ static unsigned char *removeAlpha(unsigned char *src, unsigned char *dst, unsign
return temp;
}
-static void writePageImage(cups_raster_t *raster, poppler::document *doc1,
+static void writePageImage(cups_raster_t *raster, poppler::document *doc,
int pageNo)
{
ConvertLineFunc convertLine;
@@ -1555,9 +1555,10 @@ static void writePageImage(cups_raster_t *raster, poppler::document *doc1,
unsigned char *dp;
unsigned int rowsize;
- poppler::page *current_page =doc1->create_page(pageNo-1);
+ poppler::page *current_page =doc->create_page(pageNo-1);
poppler::page_renderer pr;
- pr.set_render_hint(poppler::page_renderer::text_antialiasing);
+ pr.set_render_hint(poppler::page_renderer::antialiasing, true);
+ pr.set_render_hint(poppler::page_renderer::text_antialiasing, true);
unsigned char *colordata,*newdata,*graydata,*onebitdata;
unsigned int pixel_count;
@@ -1596,7 +1597,7 @@ static void writePageImage(cups_raster_t *raster, poppler::document *doc1,
case CUPS_CSPACE_CMY:
case CUPS_CSPACE_RGBW:
default:
- im = pr.render_page(current_page,header.HWResolution[0],header.HWResolution[1],0,0,header.cupsWidth,header.cupsHeight);
+ im = pr.render_page(current_page,header.HWResolution[0],header.HWResolution[1],bitmapoffset[0],bitmapoffset[1],header.cupsWidth,header.cupsHeight);
newdata = (unsigned char *)malloc(sizeof(char)*3*im.width()*im.height());
newdata = removeAlpha((unsigned char *)im.const_data(),newdata,im.width(),im.height());
pixel_count=im.width()*im.height();
@@ -1616,8 +1617,6 @@ static void writePageImage(cups_raster_t *raster, poppler::document *doc1,
for (unsigned int plane = 0;plane < nplanes;plane++) {
unsigned char *bp = colordata;
- bp += rowsize * (bitmapoffset[1] + header.cupsHeight - 1) +
- popplerBitsPerPixel * bitmapoffset[0] / 8;
for (unsigned int h = header.cupsHeight;h > 0;h--) {
for (unsigned int band = 0;band < nbands;band++) {
dp = convertLine(bp,lineBuf,h,plane+band,header.cupsWidth,
@@ -1631,8 +1630,6 @@ static void writePageImage(cups_raster_t *raster, poppler::document *doc1,
for (unsigned int plane = 0;plane < nplanes;plane++) {
unsigned char *bp = colordata;
- bp += rowsize * bitmapoffset[1] +
- popplerBitsPerPixel * bitmapoffset[0] / 8;
for (unsigned int h = 0;h < header.cupsHeight;h++) {
for (unsigned int band = 0;band < nbands;band++) {
dp = convertLine(bp,lineBuf,h,plane+band,header.cupsWidth,
@@ -1646,11 +1643,9 @@ static void writePageImage(cups_raster_t *raster, poppler::document *doc1,
if (allocLineBuf) delete[] lineBuf;
}
-static void outPage(poppler::document *doc1, int pageNo,
+static void outPage(poppler::document *doc, int pageNo,
cups_raster_t *raster)
{
- // Page *page = catalog->getPage(pageNo);
- // PDFRectangle mediaBox = *page->getMediaBox();
int rotate = 0;
double paperdimensions[2], /* Physical size of the paper */
margins[4]; /* Physical margins of print */
@@ -1658,7 +1653,7 @@ static void outPage(poppler::document *doc1, int pageNo,
double l, swap;
int i;
- poppler::page *current_page =doc1->create_page(pageNo-1);
+ poppler::page *current_page =doc->create_page(pageNo-1);
poppler::page_box_enum box = poppler::page_box_enum::media_box;
poppler::rectf mediaBox = current_page->page_rect(box);
poppler::page::orientation_enum orient = current_page->orientation();
@@ -1834,7 +1829,7 @@ static void outPage(poppler::document *doc1, int pageNo,
}
/* write page image */
- writePageImage(raster,doc1,pageNo);
+ writePageImage(raster,doc,pageNo);
}
static void setPopplerColorProfile()
@@ -1923,9 +1918,9 @@ static void setPopplerColorProfile()
}
int main(int argc, char *argv[]) {
- poppler::document *doc1;
+ poppler::document *doc;
int i;
- int npages;
+ int npages=0;
cups_raster_t *raster;
cmsSetLogErrorHandler(lcmsErrorHandler);
@@ -1953,7 +1948,7 @@ int main(int argc, char *argv[]) {
}
}
close(fd);
- doc1=poppler::document::load_from_file(name,"","");
+ doc=poppler::document::load_from_file(name,"","");
/* remove name */
unlink(name);
} else {
@@ -1966,15 +1961,11 @@ int main(int argc, char *argv[]) {
}
parsePDFTOPDFComment(fp);
fclose(fp);
- doc1=poppler::document::load_from_file(argv[6],"","");
+ doc=poppler::document::load_from_file(argv[6],"","");
}
- if (doc1==NULL) {
- exitCode = 1;
- goto err1;
- }
-
- npages = doc1->pages();
+ if(doc != NULL)
+ npages = doc->pages();
/* fix NumCopies, Collate ccording to PDFTOPDFComments */
header.NumCopies = deviceCopies;
@@ -2073,13 +2064,20 @@ int main(int argc, char *argv[]) {
exit(1);
}
selectConvertFunc(raster);
- for (i = 1;i <= npages;i++) {
- outPage(doc1,i,raster);
+ if(doc != NULL){
+ for (i = 1;i <= npages;i++) {
+ outPage(doc,i,raster);
+ }
}
+ else{
+ exitCode = 1;
+ goto err1;
+ }
+
cupsRasterClose(raster);
err1:
- delete doc1;
+ delete doc;
if (ppd != NULL) {
ppdClose(ppd);
}
diff --git a/utils/cups-browsed.c b/utils/cups-browsed.c
index db335aefa..a0de0904e 100644
--- a/utils/cups-browsed.c
+++ b/utils/cups-browsed.c
@@ -162,6 +162,14 @@ typedef enum printer_status_e {
STATUS_TO_BE_RELEASED /* Scheduled for release from cups-browsed */
} printer_status_t;
+/* Data structure for taking note of each time the remote printer
+ appears as a discovered IPP service */
+typedef struct ipp_discovery_s {
+ char *interface;
+ char *type;
+ int family;
+} ipp_discovery_t;
+
/* Data structure for remote printers */
typedef struct remote_printer_s {
char *queue_name;
@@ -186,6 +194,7 @@ typedef struct remote_printer_s {
char *service_name;
char *type;
char *domain;
+ cups_array_t *ipp_discoveries;
int no_autosave;
int overwritten;
int netprinter;
@@ -504,6 +513,8 @@ static remote_printer_t
const char *info,
const char *type,
const char *domain,
+ const char *interface,
+ int family,
void *txt);
#if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 5)
@@ -4439,7 +4450,7 @@ cupsdUpdateLDAPBrowse(void)
examine_discovered_printer_record(host, NULL, port, local_resource,
service_name, location, info, "", "",
- NULL);
+ "", 0, NULL);
}
@@ -6649,6 +6660,101 @@ get_printer_attributes(const char* uri)
}
#endif /* HAVE_CUPS_1_6 */
+
+/* This compare function makes the "lo" (looback) interface always
+ sorted to the beginning of the array, this way one only needs to
+ check the first element of the error to find out whether a remote
+ printer is already available through the loopback interface (preferred
+ interface) or not.
+ All other interfaces are sorted alphabetically, the types let IPPS
+ appear before IPP, and the families numerically (makes IPv4 appear
+ before IPv6). */
+
+int
+ipp_discovery_cmp(void *va, void *vb, void *data) {
+ ipp_discovery_t *a = (ipp_discovery_t *)va;
+ ipp_discovery_t *b = (ipp_discovery_t *)vb;
+ int cmp;
+
+ if (!a && !b)
+ return 0;
+ if (a && !b)
+ return -1;
+ if (!a && b)
+ return 1;
+
+ if (!strcasecmp(a->interface, "lo") && strcasecmp(b->interface, "lo"))
+ return -1;
+ if (strcasecmp(a->interface, "lo") && !strcasecmp(b->interface, "lo"))
+ return 1;
+
+ cmp = strcasecmp(a->interface, b->interface);
+ if (cmp)
+ return cmp;
+
+ if (strcasestr(a->type, "ipps") && !strcasestr(b->type, "ipps"))
+ return -1;
+ if (!strcasestr(a->type, "ipps") && strcasestr(b->type, "ipps"))
+ return 1;
+
+ cmp = strcasecmp(a->type, b->type);
+ if (cmp)
+ return cmp;
+
+ if (a->family < b->family)
+ return -1;
+ else if (a->family > b->family)
+ return 1;
+ else
+ return 0;
+}
+
+void
+ipp_discovery_free(void *ve, void *data) {
+ ipp_discovery_t *e = (ipp_discovery_t *)ve;
+
+ if (e) {
+ if (e->interface)
+ free(e->interface);
+ if (e->type)
+ free(e->type);
+ free(e);
+ }
+}
+
+void
+ipp_discoveries_list(cups_array_t *a) {
+ ipp_discovery_t *e;
+
+ debug_printf("Printer discovered %d times:\n", cupsArrayCount(a));
+ for (e = cupsArrayFirst(a); e; e = cupsArrayNext(a))
+ debug_printf(" %s, %s, %s\n", e->interface, e->type,
+ (e->family == AF_INET ? "IPv4" :
+ (e->family == AF_INET6 ? "IPv6" : "???")));
+}
+
+int
+ipp_discoveries_add(cups_array_t *a,
+ const char *interface,
+ const char *type,
+ int family) {
+ ipp_discovery_t *e;
+
+ if (!interface || !type)
+ return 0;
+ if ((e = (ipp_discovery_t *)calloc(1, sizeof(ipp_discovery_t))) ==
+ NULL) {
+ debug_printf("ERROR: Unable to allocate memory.\n");
+ return 0;
+ }
+ e->interface = strdup(interface);
+ e->type = strdup(type);
+ e->family = family;
+ cupsArrayAdd(a, e);
+ ipp_discoveries_list(a);
+ return 1;
+}
+
static remote_printer_t *
create_remote_printer_entry (const char *queue_name,
const char *location,
@@ -6660,6 +6766,8 @@ create_remote_printer_entry (const char *queue_name,
const char *service_name,
const char *type,
const char *domain,
+ const char *interface,
+ int family,
const char *pdl,
int color,
int duplex,
@@ -6754,6 +6862,16 @@ create_remote_printer_entry (const char *queue_name,
if (!p->domain)
goto fail;
+ p->ipp_discoveries =
+ cupsArrayNew3(ipp_discovery_cmp, NULL, NULL, 0, NULL, ipp_discovery_free);
+ if (p->ipp_discoveries == NULL) {
+ debug_printf("ERROR: Unable to allocate memory.\n");
+ return NULL;
+ }
+ if (domain != NULL && domain[0] != '\0' &&
+ type != NULL && type[0] != '\0')
+ ipp_discoveries_add(p->ipp_discoveries, interface, type, family);
+
/* Schedule for immediate creation of the CUPS queue */
p->status = STATUS_TO_BE_CREATED;
p->timeout = time(NULL) + TIMEOUT_IMMEDIATELY;
@@ -7114,6 +7232,7 @@ create_remote_printer_entry (const char *queue_name,
if (p->service_name) free (p->service_name);
if (p->host) free (p->host);
if (p->domain) free (p->domain);
+ cupsArrayDelete(p->ipp_discoveries);
if (p->ip) free (p->ip);
cupsFreeOptions(p->num_options, p->options);
if (p->uri) free (p->uri);
@@ -7421,6 +7540,7 @@ gboolean update_cups_queues(gpointer unused) {
if (p->service_name) free (p->service_name);
if (p->type) free (p->type);
if (p->domain) free (p->domain);
+ cupsArrayDelete(p->ipp_discoveries);
if (p->prattrs) ippDelete (p->prattrs);
if (p->nickname) free (p->nickname);
free(p);
@@ -8573,6 +8693,181 @@ matched_filters (const char *queue_name,
return FALSE;
}
+static gboolean
+update_netifs (gpointer data)
+{
+ struct ifaddrs *ifaddr, *ifa;
+ netif_t *iface, *iface2;
+ int i, add_to_netifs, addr_size, dupe;
+ char *host, buf[HTTP_MAX_HOST], *p;
+
+ debug_printf("update_netifs() in THREAD %ld\n", pthread_self());
+
+ update_netifs_sourceid = 0;
+ if (getifaddrs (&ifaddr) == -1) {
+ debug_printf("unable to get interface addresses: %s\n",
+ strerror (errno));
+ return FALSE;
+ }
+
+ while ((iface = cupsArrayFirst (netifs)) != NULL) {
+ cupsArrayRemove (netifs, iface);
+ free (iface->address);
+ free (iface);
+ }
+ while ((host = cupsArrayFirst (local_hostnames)) != NULL) {
+ cupsArrayRemove (local_hostnames, host);
+ free (host);
+ }
+
+ for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
+ netif_t *iface;
+
+ add_to_netifs = 1;
+
+ if (ifa->ifa_addr == NULL)
+ continue;
+
+ if (ifa->ifa_broadaddr == NULL)
+ add_to_netifs = 0;
+
+ if (ifa->ifa_flags & IFF_LOOPBACK)
+ add_to_netifs = 0;
+
+ if (!(ifa->ifa_flags & IFF_BROADCAST))
+ add_to_netifs = 0;
+
+ if (ifa->ifa_addr->sa_family == AF_INET)
+ addr_size = sizeof (struct sockaddr_in);
+ else if (ifa->ifa_addr->sa_family == AF_INET6)
+ addr_size = sizeof (struct sockaddr_in6);
+ else
+ addr_size = 0;
+ if (addr_size)
+ for (i = 0; i <= 1; i ++)
+ if (getnameinfo (ifa->ifa_addr, addr_size,
+ buf, HTTP_MAX_HOST, NULL, 0,
+ i == 0 ? NI_NUMERICHOST : NI_NAMEREQD) == 0)
+ if (buf[0]) {
+ /* Cut off "%..." from IPv6 IP addresses */
+ if (ifa->ifa_addr->sa_family == AF_INET6 && i == 0 &&
+ (p = strchr(buf, '%')) != NULL)
+ *p = '\0';
+ /* discard if we already have this name or address */
+ dupe = 0;
+ for (host = (char *)cupsArrayFirst (local_hostnames);
+ host != NULL;
+ host = (char *)cupsArrayNext (local_hostnames))
+ if (strcasecmp(buf, host) == 0) {
+ dupe = 1;
+ break;
+ }
+ if (dupe == 0) {
+ cupsArrayAdd (local_hostnames, strdup(buf));
+ debug_printf("network interface %s: Local host name/address: %s\n",
+ ifa->ifa_name, buf);
+ }
+ }
+
+ if (add_to_netifs == 0)
+ continue;
+
+ iface = malloc (sizeof (netif_t));
+ if (iface == NULL) {
+ debug_printf ("malloc failure\n");
+ exit (1);
+ }
+
+ iface->address = malloc (HTTP_MAX_HOST);
+ if (iface->address == NULL) {
+ free (iface);
+ debug_printf ("malloc failure\n");
+ exit (1);
+ }
+
+ iface->address[0] = '\0';
+ switch (ifa->ifa_addr->sa_family) {
+ case AF_INET:
+ /* copy broadcast addr/fill in port first to faciliate dupe compares */
+ memcpy (&iface->broadcast, ifa->ifa_broadaddr,
+ sizeof (struct sockaddr_in));
+ iface->broadcast.ipv4.sin_port = htons (BrowsePort);
+ /* discard if we already have an interface sharing the broadcast
+ address */
+ dupe = 0;
+ for (iface2 = (netif_t *)cupsArrayFirst (netifs);
+ iface2 != NULL;
+ iface2 = (netif_t *)cupsArrayNext (netifs)) {
+ if (memcmp(&iface2->broadcast, &iface->broadcast,
+ sizeof(struct sockaddr_in)) == 0) {
+ dupe = 1;
+ break;
+ }
+ }
+ if (dupe) break;
+ getnameinfo (ifa->ifa_addr, sizeof (struct sockaddr_in),
+ iface->address, HTTP_MAX_HOST,
+ NULL, 0, NI_NUMERICHOST);
+ break;
+
+ case AF_INET6:
+ if (IN6_IS_ADDR_LINKLOCAL (&((struct sockaddr_in6 *)(ifa->ifa_addr))
+ ->sin6_addr))
+ break;
+
+ /* see above for order */
+ memcpy (&iface->broadcast, ifa->ifa_broadaddr,
+ sizeof (struct sockaddr_in6));
+ iface->broadcast.ipv6.sin6_port = htons (BrowsePort);
+ /* discard alias addresses (identical broadcast) */
+ dupe = 0;
+ for (iface2 = (netif_t *)cupsArrayFirst (netifs);
+ iface2 != NULL;
+ iface2 = (netif_t *)cupsArrayNext (netifs)) {
+ if (memcmp(&iface2->broadcast, ifa->ifa_broadaddr,
+ sizeof(struct sockaddr_in6)) == 0) {
+ dupe = 1;
+ break;
+ }
+ }
+ if (dupe) break;
+ getnameinfo (ifa->ifa_addr, sizeof (struct sockaddr_in6),
+ iface->address, HTTP_MAX_HOST, NULL, 0, NI_NUMERICHOST);
+ break;
+ }
+
+ if (iface->address[0]) {
+ cupsArrayAdd (netifs, iface);
+ debug_printf("Network interface %s at %s for legacy CUPS browsing/broadcasting\n",
+ ifa->ifa_name, iface->address);
+ } else {
+ free (iface->address);
+ free (iface);
+ }
+ }
+
+ freeifaddrs (ifaddr);
+
+ /* If run as a timeout, don't run it again. */
+ return FALSE;
+}
+
+int
+is_local_hostname(const char *host_name) {
+ char *host;
+
+ for (host = (char *)cupsArrayFirst (local_hostnames);
+ host != NULL;
+ host = (char *)cupsArrayNext (local_hostnames))
+ if (strncasecmp(host_name, host, strlen(host)) == 0 &&
+ (strlen(host_name) == strlen(host) ||
+ strcasecmp(host_name + strlen(host), ".local") == 0 ||
+ strcasecmp(host_name + strlen(host), ".local.") == 0))
+ return 1;
+
+ return 0;
+}
+
static remote_printer_t *
examine_discovered_printer_record(const char *host,
const char *ip,
@@ -8583,6 +8878,8 @@ examine_discovered_printer_record(const char *host,
const char *info,
const char *type,
const char *domain,
+ const char *interface,
+ int family,
void *txt) {
char uri[HTTP_MAX_URI];
@@ -8599,7 +8896,8 @@ examine_discovered_printer_record(const char *host,
char *local_queue_name = NULL;
int is_cups_queue;
int raw_queue = 0;
-
+ char *ptr;
+
if (!host || !resource || !service_name || !location || !info || !type ||
!domain) {
debug_printf("ERROR: examine_discovered_printer_record(): Input value missing!\n");
@@ -8782,6 +9080,14 @@ examine_discovered_printer_record(const char *host,
goto fail;
}
+
+ /* Update network interface info if we were discovered by LDAP
+ or legacy CUPS, needed for the is_local_hostname() function calls.
+ During DNS-SD discovery the update is already done by the Avahi
+ event handler function. */
+ if (type == NULL || type[0] == '\0')
+ update_netifs(NULL);
+
/* Check if we have already created a queue for the discovered
printer */
for (p = (remote_printer_t *)cupsArrayFirst(remote_printers);
@@ -8790,7 +9096,8 @@ examine_discovered_printer_record(const char *host,
(p->host[0] == '\0' ||
p->status == STATUS_UNCONFIRMED ||
p->status == STATUS_DISAPPEARED ||
- (!strcasecmp(p->host, remote_host) &&
+ ((!strcasecmp(p->host, remote_host) ||
+ (is_local_hostname(p->host) && is_local_hostname(remote_host))) &&
(p->port == port ||
(p->port == 631 && port == 443) ||
(p->port == 443 && port == 631)) &&
@@ -8818,33 +9125,71 @@ examine_discovered_printer_record(const char *host,
whether the discovered queue is discovered via DNS-SD
having more info in contrary to the existing being
discovered by legacy CUPS or LDAP */
- if ((strcasestr(type, "_ipps") &&
- !strncasecmp(p->uri, "ipp:", 4)) ||
- strcasecmp(strchr(p->uri, ':'), strchr(uri, ':')) ||
- ((p->domain == NULL || p->domain[0] == '\0') &&
- domain != NULL && domain[0] != '\0' &&
- (p->type == NULL || p->type[0] == '\0') &&
- type != NULL && type[0] != '\0')) {
-
- /* Schedule local queue for upgrade to ipps: or for URI change */
+
+ int downgrade = 0, upgrade = 0;
+
+ /* Get first element of array of interfaces on which this printer
+ got already discovered, as this one is "lo" when it already got
+ discovered through the loopback interface (preferred interface) */
+ ipp_discovery_t *ippdis = cupsArrayFirst(p->ipp_discoveries);
+
+ /* Check if there is a downgrade */
+ /* IPPS -> IPP */
+ if ((ptr = strcasestr(type, "_ipp")) != NULL &&
+ *(ptr + 4) != 's' &&
+ !strncasecmp(p->uri, "ipps:", 5)) {
+ downgrade = 1;
+ debug_printf("Printer %s: New discovered service from host %s, port %d, URI %s is only IPP, we have already IPPS, skipping\n",
+ p->queue_name, remote_host, port, uri);
+ /* "lo" -> Any non-"lo" interface */
+ } else if (strcasecmp(interface, "lo") &&
+ ippdis && !strcasecmp(ippdis->interface, "lo")) {
+ downgrade = 1;
+ debug_printf("Printer %s: New discovered service from host %s, port %d, URI %s is from a non-loopback interface, we have already one from the loopback interface, skipping\n",
+ p->queue_name, remote_host, port, uri);
+ /* DNS-SD -> CUPS Legacy/LDAP */
+ } else if (p->domain != NULL && p->domain[0] != '\0' &&
+ (domain == NULL || domain[0] == '\0') &&
+ p->type != NULL && p->type[0] != '\0' &&
+ (type == NULL || type[0] == '\0')) {
+ downgrade = 1;
+ debug_printf("Printer %s: New discovered service from host %s, port %d, URI %s is only discovered via legacy CUPS or LDAP, we have already a DNS-SD-discovered one, skipping\n",
+ p->queue_name, remote_host, port, uri);
+ }
+
+ if (downgrade == 0) {
+ /* Check if there is an upgrade */
+ /* IPP -> IPPS */
if (strcasestr(type, "_ipps") &&
- !strncasecmp(p->uri, "ipp:", 4))
+ !strncasecmp(p->uri, "ipp:", 4)) {
+ upgrade = 1;
debug_printf("Upgrading printer %s (Host: %s, Port: %d) to IPPS. New URI: %s\n",
p->queue_name, remote_host, port, uri);
- if (strcasecmp(strchr(p->uri, ':'), strchr(uri, ':')))
- debug_printf("Changing URI of printer %s (Host: %s, Port: %d) to %s.\n",
+ /* Any non-"lo" interface -> "lo" */
+ } else if (!strcasecmp(interface, "lo")) {
+ upgrade = 1;
+ debug_printf("Upgrading printer %s (Host: %s, Port: %d) to use loopback interface \"lo\". New URI: %s\n",
p->queue_name, remote_host, port, uri);
- if ((p->domain == NULL || p->domain[0] == '\0') &&
- domain != NULL && domain[0] != '\0' &&
- (p->type == NULL || p->type[0] == '\0') &&
- type != NULL && type[0] != '\0') {
+ /* CUPS Legacy/LDAP -> DNS-SD */
+ } else if ((p->domain == NULL || p->domain[0] == '\0') &&
+ domain != NULL && domain[0] != '\0' &&
+ (p->type == NULL || p->type[0] == '\0') &&
+ type != NULL && type[0] != '\0') {
+ upgrade = 1;
debug_printf("Discovered printer %s (Host: %s, Port: %d, URI: %s) by DNS-SD now.\n",
p->queue_name, remote_host, port, uri);
- if (p->is_legacy) {
+ }
+ }
+
+ /* Switch local queue over to this newly discovered service */
+ if (upgrade == 1) {
+ /* Remove tiemout of legacy CUPS broadcasting */
+ if (domain != NULL && domain[0] != '\0' &&
+ type != NULL && type[0] != '\0' &&
+ p->is_legacy) {
p->is_legacy = 0;
if (p->status == STATUS_CONFIRMED)
p->timeout = (time_t) -1;
- }
}
free(p->location);
free(p->info);
@@ -8871,8 +9216,9 @@ examine_discovered_printer_record(const char *host,
p->service_name = strdup(service_name);
p->type = strdup(type);
p->domain = strdup(domain);
-
- }
+ debug_printf("Switched over to newly discovered entry for this printer.\n");
+ } else
+ debug_printf("Staying with previously discovered entry for this printer.\n");
/* Mark queue entry as confirmed if the entry
is unconfirmed */
@@ -8897,6 +9243,7 @@ examine_discovered_printer_record(const char *host,
record_printer_options(p->queue_name);
}
+ /* Gather extra info from our new discovery */
if (p->uri[0] == '\0') {
free (p->uri);
p->uri = strdup(uri);
@@ -8941,6 +9288,9 @@ examine_discovered_printer_record(const char *host,
free (p->domain);
p->domain = strdup(domain);
}
+ if (domain != NULL && domain[0] != '\0' &&
+ type != NULL && type[0] != '\0')
+ ipp_discoveries_add(p->ipp_discoveries, interface, type, family);
p->netprinter = is_cups_queue ? 0 : 1;
} else {
@@ -8949,8 +9299,8 @@ examine_discovered_printer_record(const char *host,
p = create_remote_printer_entry (local_queue_name, location, info, uri,
remote_host, ip, port,
service_name ? service_name : "", type,
- domain, pdl, color, duplex, make_model,
- is_cups_queue);
+ domain, interface, family, pdl, color,
+ duplex, make_model, is_cups_queue);
}
fail:
@@ -9079,165 +9429,6 @@ allowed (struct sockaddr *srcaddr)
return server_allowed;
}
-static gboolean
-update_netifs (gpointer data)
-{
- struct ifaddrs *ifaddr, *ifa;
- netif_t *iface, *iface2;
- int i, add_to_netifs, addr_size, dupe;
- char *host, buf[HTTP_MAX_HOST], *p;
-
- debug_printf("update_netifs() in THREAD %ld\n", pthread_self());
-
- update_netifs_sourceid = 0;
- if (getifaddrs (&ifaddr) == -1) {
- debug_printf("unable to get interface addresses: %s\n",
- strerror (errno));
- return FALSE;
- }
-
- while ((iface = cupsArrayFirst (netifs)) != NULL) {
- cupsArrayRemove (netifs, iface);
- free (iface->address);
- free (iface);
- }
- while ((host = cupsArrayFirst (local_hostnames)) != NULL) {
- cupsArrayRemove (local_hostnames, host);
- free (host);
- }
-
- for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
- netif_t *iface;
-
- add_to_netifs = 1;
-
- if (ifa->ifa_addr == NULL)
- continue;
-
- if (ifa->ifa_broadaddr == NULL)
- add_to_netifs = 0;
-
- if (ifa->ifa_flags & IFF_LOOPBACK)
- add_to_netifs = 0;
-
- if (!(ifa->ifa_flags & IFF_BROADCAST))
- add_to_netifs = 0;
-
- if (ifa->ifa_addr->sa_family == AF_INET)
- addr_size = sizeof (struct sockaddr_in);
- else if (ifa->ifa_addr->sa_family == AF_INET6)
- addr_size = sizeof (struct sockaddr_in6);
- else
- addr_size = 0;
- if (addr_size)
- for (i = 0; i <= 1; i ++)
- if (getnameinfo (ifa->ifa_addr, addr_size,
- buf, HTTP_MAX_HOST, NULL, 0,
- i == 0 ? NI_NUMERICHOST : NI_NAMEREQD) == 0)
- if (buf[0]) {
- /* Cut off "%..." from IPv6 IP addresses */
- if (ifa->ifa_addr->sa_family == AF_INET6 && i == 0 &&
- (p = strchr(buf, '%')) != NULL)
- *p = '\0';
- /* discard if we already have this name or address */
- dupe = 0;
- for (host = (char *)cupsArrayFirst (local_hostnames);
- host != NULL;
- host = (char *)cupsArrayNext (local_hostnames))
- if (strcasecmp(buf, host) == 0) {
- dupe = 1;
- break;
- }
- if (dupe == 0) {
- cupsArrayAdd (local_hostnames, strdup(buf));
- debug_printf("network interface %s: Local host name/address: %s\n",
- ifa->ifa_name, buf);
- }
- }
-
- if (add_to_netifs == 0)
- continue;
-
- iface = malloc (sizeof (netif_t));
- if (iface == NULL) {
- debug_printf ("malloc failure\n");
- exit (1);
- }
-
- iface->address = malloc (HTTP_MAX_HOST);
- if (iface->address == NULL) {
- free (iface);
- debug_printf ("malloc failure\n");
- exit (1);
- }
-
- iface->address[0] = '\0';
- switch (ifa->ifa_addr->sa_family) {
- case AF_INET:
- /* copy broadcast addr/fill in port first to faciliate dupe compares */
- memcpy (&iface->broadcast, ifa->ifa_broadaddr,
- sizeof (struct sockaddr_in));
- iface->broadcast.ipv4.sin_port = htons (BrowsePort);
- /* discard if we already have an interface sharing the broadcast
- address */
- dupe = 0;
- for (iface2 = (netif_t *)cupsArrayFirst (netifs);
- iface2 != NULL;
- iface2 = (netif_t *)cupsArrayNext (netifs)) {
- if (memcmp(&iface2->broadcast, &iface->broadcast,
- sizeof(struct sockaddr_in)) == 0) {
- dupe = 1;
- break;
- }
- }
- if (dupe) break;
- getnameinfo (ifa->ifa_addr, sizeof (struct sockaddr_in),
- iface->address, HTTP_MAX_HOST,
- NULL, 0, NI_NUMERICHOST);
- break;
-
- case AF_INET6:
- if (IN6_IS_ADDR_LINKLOCAL (&((struct sockaddr_in6 *)(ifa->ifa_addr))
- ->sin6_addr))
- break;
-
- /* see above for order */
- memcpy (&iface->broadcast, ifa->ifa_broadaddr,
- sizeof (struct sockaddr_in6));
- iface->broadcast.ipv6.sin6_port = htons (BrowsePort);
- /* discard alias addresses (identical broadcast) */
- dupe = 0;
- for (iface2 = (netif_t *)cupsArrayFirst (netifs);
- iface2 != NULL;
- iface2 = (netif_t *)cupsArrayNext (netifs)) {
- if (memcmp(&iface2->broadcast, ifa->ifa_broadaddr,
- sizeof(struct sockaddr_in6)) == 0) {
- dupe = 1;
- break;
- }
- }
- if (dupe) break;
- getnameinfo (ifa->ifa_addr, sizeof (struct sockaddr_in6),
- iface->address, HTTP_MAX_HOST, NULL, 0, NI_NUMERICHOST);
- break;
- }
-
- if (iface->address[0]) {
- cupsArrayAdd (netifs, iface);
- debug_printf("Network interface %s at %s for legacy CUPS browsing/broadcasting\n",
- ifa->ifa_name, iface->address);
- } else {
- free (iface->address);
- free (iface);
- }
- }
-
- freeifaddrs (ifaddr);
-
- /* If run as a timeout, don't run it again. */
- return FALSE;
-}
-
#ifdef HAVE_AVAHI
static void resolve_callback(AvahiServiceResolver *r,
AvahiIfIndex interface,
@@ -9267,8 +9458,11 @@ static void resolve_callback(AvahiServiceResolver *r,
}
/* Ignore local queues on the port of the cupsd we are serving for */
- if (flags & AVAHI_LOOKUP_RESULT_LOCAL && port == ippPort()) {
- debug_printf("Avahi Resolver: Service '%s' of type '%s' in domain '%s' with host name '%s' and port %d on interface '%s' (%s) is from local CUPS, ignored (Avahi lookup result of local machine).\n",
+ update_netifs(NULL);
+ if (port == ippPort() &&
+ ((flags & AVAHI_LOOKUP_RESULT_LOCAL) || !strcasecmp(ifname, "lo") ||
+ is_local_hostname(host_name))) {
+ debug_printf("Avahi Resolver: Service '%s' of type '%s' in domain '%s' with host name '%s' and port %d on interface '%s' (%s) is from local CUPS, ignored (Avahi lookup result or host name of local machine).\n",
name, type, domain, host_name, port, ifname,
(address ?
(address->proto == AVAHI_PROTO_INET ? "IPv4" :
@@ -9277,26 +9471,6 @@ static void resolve_callback(AvahiServiceResolver *r,
"IPv4/IPv6 Unknown"));
goto ignore;
}
- if (port == ippPort()) {
- char *host;
- update_netifs(NULL);
- for (host = (char *)cupsArrayFirst (local_hostnames);
- host != NULL;
- host = (char *)cupsArrayNext (local_hostnames))
- if (strncasecmp(host_name, host, strlen(host)) == 0 &&
- (strlen(host_name) == strlen(host) ||
- strcasecmp(host_name + strlen(host), ".local") == 0 ||
- strcasecmp(host_name + strlen(host), ".local.") == 0)) {
- debug_printf("Avahi Resolver: Service '%s' of type '%s' in domain '%s' with host name '%s' and port %d on interface '%s' (%s) is from local CUPS, ignored (Host name of local machine).\n",
- name, type, domain, host_name, port, ifname,
- (address ?
- (address->proto == AVAHI_PROTO_INET ? "IPv4" :
- address->proto == AVAHI_PROTO_INET6 ? "IPv6" :
- "IPv4/IPv6 Unknown") :
- "IPv4/IPv6 Unknown"));
- goto ignore;
- }
- }
/* Called whenever a service has been resolved successfully or timed out */
@@ -9379,7 +9553,7 @@ static void resolve_callback(AvahiServiceResolver *r,
instance[0] = '\0';
}
/* Determine the remote printer's IP */
- if (IPBasedDeviceURIs != IP_BASED_URIS_NO || !strcasecmp(ifname, "lo") ||
+ if (IPBasedDeviceURIs != IP_BASED_URIS_NO ||
(!browseallow_all && cupsArrayCount(browseallow) > 0)) {
struct sockaddr saddr;
struct sockaddr *addr = &saddr;
@@ -9432,19 +9606,21 @@ static void resolve_callback(AvahiServiceResolver *r,
/* Check remote printer type and create appropriate local queue to
point to it */
if (IPBasedDeviceURIs != IP_BASED_URIS_NO ||
- !strcasecmp(ifname, "lo") ||
!host_name) {
debug_printf("Avahi Resolver: Service '%s' of type '%s' in domain '%s' with IP address %s.\n",
name, type, domain, addrstr);
- examine_discovered_printer_record((strcasecmp(ifname, "lo") &&
- host_name ? host_name : addrstr),
+ examine_discovered_printer_record((strcasecmp(ifname, "lo") ?
+ host_name : "localhost"),
addrstr, port, rp_value, name,
"", instance, type, domain,
- txt);
+ ifname, addr->sa_family, txt);
} else
- examine_discovered_printer_record(host_name, NULL, port, rp_value,
+ examine_discovered_printer_record((strcasecmp(ifname, "lo") ?
+ host_name : "localhost"),
+ NULL, port, rp_value,
name, "", instance, type,
- domain, txt);
+ domain, ifname, addr->sa_family,
+ txt);
} else
debug_printf("Avahi Resolver: Service '%s' of type '%s' in domain '%s' skipped, could not determine IP address.\n",
name, type, domain);
@@ -9453,8 +9629,16 @@ static void resolve_callback(AvahiServiceResolver *r,
/* Check remote printer type and create appropriate local queue to
point to it */
if (host_name)
- examine_discovered_printer_record(host_name, NULL, port, rp_value,
+ examine_discovered_printer_record((strcasecmp(ifname, "lo") ?
+ host_name : "localhost"),
+ NULL, port, rp_value,
name, "", instance, type, domain,
+ ifname,
+ (address->proto ==
+ AVAHI_PROTO_INET ? AF_INET :
+ (address->proto ==
+ AVAHI_PROTO_INET6 ? AF_INET6 :
+ 0)),
txt);
else
debug_printf("Avahi Resolver: Service '%s' of type '%s' in domain '%s' skipped, host name not supplied.\n",
@@ -9536,8 +9720,10 @@ static void browse_callback(AvahiServiceBrowser *b,
if (c == NULL || name == NULL || type == NULL || domain == NULL)
return;
- debug_printf("Avahi Browser: NEW: service '%s' of type '%s' in domain '%s' on interface '%s'\n",
- name, type, domain, ifname);
+ debug_printf("Avahi Browser: NEW: service '%s' of type '%s' in domain '%s' on interface '%s' (%s)\n",
+ name, type, domain, ifname,
+ protocol != AVAHI_PROTO_UNSPEC ?
+ avahi_proto_to_string(protocol) : "Unknown");
/* Ignore if terminated (by SIGTERM) */
if (terminating) {
@@ -9562,8 +9748,10 @@ static void browse_callback(AvahiServiceBrowser *b,
if (name == NULL || type == NULL || domain == NULL)
return;
- debug_printf("Avahi Browser: REMOVE: service '%s' of type '%s' in domain '%s' on interface '%s'\n",
- name, type, domain, ifname);
+ debug_printf("Avahi Browser: REMOVE: service '%s' of type '%s' in domain '%s' on interface '%s' (%s)\n",
+ name, type, domain, ifname,
+ protocol != AVAHI_PROTO_UNSPEC ?
+ avahi_proto_to_string(protocol) : "Unknown");
/* Ignore if terminated (by SIGTERM) */
if (terminating) {
@@ -9577,13 +9765,35 @@ static void browse_callback(AvahiServiceBrowser *b,
if (p->status != STATUS_DISAPPEARED &&
p->status != STATUS_TO_BE_RELEASED &&
!strcasecmp(p->service_name, name) &&
- !strcasecmp(p->type, type) &&
!strcasecmp(p->domain, domain))
break;
if (p) {
- remove_printer_entry(p);
- debug_printf("DNS-SD IDs: Service name: \"%s\", Service type: \"%s\", Domain: \"%s\"\n",
- p->service_name, p->type, p->domain);
+ int family =
+ (protocol == AVAHI_PROTO_INET ? AF_INET :
+ (protocol == AVAHI_PROTO_INET6 ? AF_INET6 : 0));
+ if (p->ipp_discoveries) {
+ ipp_discovery_t *ippdis;
+ for (ippdis = cupsArrayFirst(p->ipp_discoveries); ippdis;
+ ippdis = cupsArrayNext(p->ipp_discoveries))
+ if (!strcasecmp(ippdis->interface, ifname) &&
+ !strcasecmp(ippdis->type, type) &&
+ ippdis->family == family) {
+ debug_printf("Discovered instance for printer with Service name \"%s\", Domain \"%s\" unregistered: Interface \"%s\", Service type: \"%s\", Protocol: \"%s\"\n",
+ p->service_name, p->domain,
+ ippdis->interface, ippdis->type,
+ (ippdis->family == AF_INET ? "IPv4" :
+ (ippdis->family == AF_INET6 ? "IPv6" : "Unknown")));
+ cupsArrayRemove(p->ipp_discoveries, (void *)ippdis);
+ ipp_discoveries_list(p->ipp_discoveries);
+ break;
+ }
+ /* Remove the entry if no discovered instances are left */
+ if (cupsArrayCount(p->ipp_discoveries) == 0) {
+ debug_printf("Removing printer with Service name \"%s\", Domain \"%s\", all discovered instances disappeared.\n",
+ p->service_name, p->domain);
+ remove_printer_entry(p);
+ }
+ }
if (in_shutdown == 0)
recheck_timer ();
@@ -9849,7 +10059,8 @@ found_cups_printer (const char *remote_host, const char *uri,
printer = examine_discovered_printer_record(host, NULL, port, local_resource,
service_name,
location ? location : "",
- info ? info : "", "", "", NULL);
+ info ? info : "", "", "", "", 0,
+ NULL);
if (printer &&
(printer->domain == NULL || printer->domain[0] == '\0' ||
@@ -11258,7 +11469,8 @@ find_previous_queue (gpointer key,
if (printer->cups_browsed_controlled) {
/* Queue found, add to our list */
p = create_remote_printer_entry (name, "", "", printer->device_uri, "", "",
- 0, "", "", "", NULL, 0, 0, NULL, -1);
+ 0, "", "", "", "", 0, NULL, 0, 0, NULL,
+ -1);
if (p) {
/* Mark as unconfirmed, if no Avahi report of this queue appears
in a certain time frame, we will remove the queue */
diff --git a/utils/cups-browsed.conf.5 b/utils/cups-browsed.conf.5
index 745a3d2a5..d629f2257 100644
--- a/utils/cups-browsed.conf.5
+++ b/utils/cups-browsed.conf.5
@@ -554,6 +554,13 @@ is only run for printer discovery and already stopped while still
printing. By default this mode is turned off, meaning that we use URIs
with host names.
.PP
+Note that the IP addresses depend on the network interface through
+which the printer is accessed. So do not use IP-based URIs on systems
+with many network interfaces and where interfaces can appear and
+disappear frequently.
+.PP
+This mode could also be useful for development and debugging.
+.PP
If you prefer IPv4 or IPv6 IP addresses in the URIs, you can set
IPBasedDeviceURIs to "IPv4" to only get IPv4 IP addresses or
IPBasedDeviceURIs to "IPv6" to only get IPv6 IP addresses.
diff --git a/utils/cups-browsed.conf.in b/utils/cups-browsed.conf.in
index de3b06218..46cca3cd4 100644
--- a/utils/cups-browsed.conf.in
+++ b/utils/cups-browsed.conf.in
@@ -403,6 +403,13 @@ BrowseRemoteProtocols @BROWSEREMOTEPROTOCOLS@
# stopped while still printing. By default this mode is turned off,
# meaning that we use URIs with host names.
+# Note that the IP addresses depend on the network interface through
+# which the printer is accessed. So do not use IP-based URIs on systems
+# with many network interfaces and where interfaces can appear and
+# disappear frequently.
+
+# This mode could also be useful for development and debugging.
+
# If you prefer IPv4 or IPv6 IP addresses in the URIs, you can set
# IPBasedDeviceURIs to "IPv4" to only get IPv4 IP addresses or
# IPBasedDeviceURIs to "IPv6" to only get IPv6 IP addresses.