From c4068760a6735db6c5b785827ccf2bb9f95eb25c Mon Sep 17 00:00:00 2001
From: "A. Wilcox" <AWilcox@Wilcox-Tech.com>
Date: Thu, 30 Jul 2020 04:08:43 +0000
Subject: [PATCH] user/sane-airscan: Update to 0.99.10

---
 user/sane-airscan/APKBUILD  |   11 +-
 user/sane-airscan/git.patch | 1212 -----------------------------------
 2 files changed, 4 insertions(+), 1219 deletions(-)
 delete mode 100644 user/sane-airscan/git.patch

diff --git a/user/sane-airscan/APKBUILD b/user/sane-airscan/APKBUILD
index c106204f87..1694d3d0f5 100644
--- a/user/sane-airscan/APKBUILD
+++ b/user/sane-airscan/APKBUILD
@@ -1,8 +1,8 @@
 # Contributor: A. Wilcox <awilfox@adelielinux.org>
 # Maintainer: A. Wilcox <awilfox@adelielinux.org>
 pkgname=sane-airscan
-pkgver=0.99.8
-pkgrel=1
+pkgver=0.99.10
+pkgrel=0
 pkgdesc="Universal scanner driver for AirScan (eSCL) scanners"
 url=" "
 arch="all"
@@ -11,9 +11,7 @@ depends=""
 makedepends="avahi-dev glib-dev libjpeg-turbo-dev libpng-dev libsoup-dev
 	libxml2-dev meson ninja sane-dev"
 subpackages="$pkgname-doc"
-source="sane-airscan-$pkgver.tar.gz::https://github.com/alexpevzner/sane-airscan/archive/$pkgver.tar.gz
-	git.patch
-	"
+source="sane-airscan-$pkgver.tar.gz::https://github.com/alexpevzner/sane-airscan/archive/$pkgver.tar.gz"
 
 build() {
 	meson \
@@ -36,5 +34,4 @@ package() {
 	rm "$pkgdir"/etc/sane.d/dll.conf
 }
 
-sha512sums="2828deeea31297c64b9927bb2b2b982f16a16cbb446cf2ca685b13f79cb264e94c017b8930fe04004636a6e1122f1882bd58252a3302c0a13b3fc60566072155  sane-airscan-0.99.8.tar.gz
-a195c23edaf399b6fc1ba7693afd34fa87504c9c8ff10d1d793b97c1b592bff90214cd18af764451a3af9860884509fa7701037322a551226a0bcd29473ca1cc  git.patch"
+sha512sums="7a3d98e01ad883856eb79c522aff50243b399717a6ba2db07eec66e49a83d365ad4db6d3f87718592f3b85832a2098e86ae094d9f06ed951ebc23887cddb75b7  sane-airscan-0.99.10.tar.gz"
diff --git a/user/sane-airscan/git.patch b/user/sane-airscan/git.patch
deleted file mode 100644
index 8185805532..0000000000
--- a/user/sane-airscan/git.patch
+++ /dev/null
@@ -1,1212 +0,0 @@
-diff --git a/COPYING b/COPYING
-index 60549be..d159169 100644
---- a/COPYING
-+++ b/COPYING
-@@ -1,12 +1,12 @@
--		    GNU GENERAL PUBLIC LICENSE
--		       Version 2, June 1991
-+                    GNU GENERAL PUBLIC LICENSE
-+                       Version 2, June 1991
- 
-- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
--                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
-+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-  Everyone is permitted to copy and distribute verbatim copies
-  of this license document, but changing it is not allowed.
- 
--			    Preamble
-+                            Preamble
- 
-   The licenses for most software are designed to take away your
- freedom to share and change it.  By contrast, the GNU General Public
-@@ -15,7 +15,7 @@ software--to make sure the software is free for all its users.  This
- General Public License applies to most of the Free Software
- Foundation's software and to any other program whose authors commit to
- using it.  (Some other Free Software Foundation software is covered by
--the GNU Library General Public License instead.)  You can apply it to
-+the GNU Lesser General Public License instead.)  You can apply it to
- your programs, too.
- 
-   When we speak of free software, we are referring to freedom, not
-@@ -55,8 +55,8 @@ patent must be licensed for everyone's free use or not licensed at all.
- 
-   The precise terms and conditions for copying, distribution and
- modification follow.
--
--		    GNU GENERAL PUBLIC LICENSE
-+
-+                    GNU GENERAL PUBLIC LICENSE
-    TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
- 
-   0. This License applies to any program or other work which contains
-@@ -110,7 +110,7 @@ above, provided that you also meet all of these conditions:
-     License.  (Exception: if the Program itself is interactive but
-     does not normally print such an announcement, your work based on
-     the Program is not required to print an announcement.)
--
-+
- These requirements apply to the modified work as a whole.  If
- identifiable sections of that work are not derived from the Program,
- and can be reasonably considered independent and separate works in
-@@ -168,7 +168,7 @@ access to copy from a designated place, then offering equivalent
- access to copy the source code from the same place counts as
- distribution of the source code, even though third parties are not
- compelled to copy the source along with the object code.
--
-+
-   4. You may not copy, modify, sublicense, or distribute the Program
- except as expressly provided under this License.  Any attempt
- otherwise to copy, modify, sublicense or distribute the Program is
-@@ -225,7 +225,7 @@ impose that choice.
- 
- This section is intended to make thoroughly clear what is believed to
- be a consequence of the rest of this License.
--
-+
-   8. If the distribution and/or use of the Program is restricted in
- certain countries either by patents or by copyrighted interfaces, the
- original copyright holder who places the Program under this License
-@@ -255,7 +255,7 @@ make exceptions for this.  Our decision will be guided by the two goals
- of preserving the free status of all derivatives of our free software and
- of promoting the sharing and reuse of software generally.
- 
--			    NO WARRANTY
-+                            NO WARRANTY
- 
-   11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
- FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
-@@ -277,9 +277,9 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
- PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
- POSSIBILITY OF SUCH DAMAGES.
- 
--		     END OF TERMS AND CONDITIONS
--
--	    How to Apply These Terms to Your New Programs
-+                     END OF TERMS AND CONDITIONS
-+
-+            How to Apply These Terms to Your New Programs
- 
-   If you develop a new program, and you want it to be of the greatest
- possible use to the public, the best way to achieve this is to make it
-@@ -291,7 +291,7 @@ convey the exclusion of warranty; and each file should have at least
- the "copyright" line and a pointer to where the full notice is found.
- 
-     <one line to give the program's name and a brief idea of what it does.>
--    Copyright (C) 19yy  <name of author>
-+    Copyright (C) <year>  <name of author>
- 
-     This program is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published by
-@@ -303,17 +303,16 @@ the "copyright" line and a pointer to where the full notice is found.
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-     GNU General Public License for more details.
- 
--    You should have received a copy of the GNU General Public License
--    along with this program; if not, write to the Free Software
--    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
--
-+    You should have received a copy of the GNU General Public License along
-+    with this program; if not, write to the Free Software Foundation, Inc.,
-+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- 
- Also add information on how to contact you by electronic and paper mail.
- 
- If the program is interactive, make it output a short notice like this
- when it starts in an interactive mode:
- 
--    Gnomovision version 69, Copyright (C) 19yy name of author
-+    Gnomovision version 69, Copyright (C) year name of author
-     Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
-     This is free software, and you are welcome to redistribute it
-     under certain conditions; type `show c' for details.
-@@ -336,5 +335,5 @@ necessary.  Here is a sample; alter the names:
- This General Public License does not permit incorporating your program into
- proprietary programs.  If your program is a subroutine library, you may
- consider it more useful to permit linking proprietary applications with the
--library.  If this is what you want to do, use the GNU Library General
-+library.  If this is what you want to do, use the GNU Lesser General
- Public License instead of this License.
-diff --git a/LICENSE b/LICENSE
-index fe71f02..db02cb9 100644
---- a/LICENSE
-+++ b/LICENSE
-@@ -16,8 +16,8 @@ General Public License for more details.
- 
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
--Foundation, Inc., 59 Temple Place - Suite 330, Boston,
--MA 02111-1307, USA.
-+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
-+MA 02110-1301 USA.
- 
- As a special exception, the authors of sane-airscan give permission for
- additional uses of the libraries contained in this release of sane-airscan.
-diff --git a/Makefile b/Makefile
-index 9d4e082..70555a8 100644
---- a/Makefile
-+++ b/Makefile
-@@ -17,7 +17,7 @@
- 
- CC	= gcc
- COMPRESS = gzip
--CFLAGS	= -O2 -g -W -Wall -Werror
-+CFLAGS	+= -O2 -g -W -Wall -Werror $(CPPFLAGS)
- MANDIR	= /usr/share/man/
- PKG_CONFIG = /usr/bin/pkg-config
- STRIP 	= -s
-@@ -82,7 +82,7 @@ $(BACKEND): $(OBJDIR)airscan.o $(LIBAIRSCAN) airscan.sym
- 	$(CC) -o $(BACKEND) -shared $(OBJDIR)/airscan.o $(LIBAIRSCAN) $(airscan_LDFLAGS)
- 
- $(DISCOVER): $(OBJDIR)discover.o $(LIBAIRSCAN)
--	 $(CC) -o $(DISCOVER) discover.c $(CPPFLAGS) $(airscan_CFLAGS) $(LIBAIRSCAN) $(airscan_LIBS) -fPIE
-+	 $(CC) -o $(DISCOVER) discover.c $(CPPFLAGS) $(airscan_CFLAGS) $(LIBAIRSCAN) $(airscan_LIBS) $(LDFLAGS) -fPIE
- 
- $(LIBAIRSCAN): $(OBJ) Makefile
- 	ar cru $(LIBAIRSCAN) $(OBJ)
-@@ -105,6 +105,13 @@ clean:
- 	rm -f test $(BACKEND) tags
- 	rm -rf $(OBJDIR)
- 
-+uninstall:
-+	rm -f $(DESTDIR)$(PREFIX)$(BINDIR)/$(DISCOVER)
-+	rm -f $(DESTDIR)$(PREFIX)$(CONFDIR)/dll.d/airscan
-+	rm -f $(DESTDIR)$(PREFIX)$(LIBDIR)/sane/$(BACKEND)
-+	rm -f $(DESTDIR)$(PREFIX)$(MANDIR)/man1/$(MAN_DISCOVER)*
-+	rm -f $(DESTDIR)$(PREFIX)$(MANDIR)/man5/$(MAN_BACKEND)*
-+
- man: $(MAN_DISCOVER) $(MAN_BACKEND)
- 
- $(MAN_DISCOVER): $(MAN_DISCOVER).md
-@@ -114,7 +121,7 @@ $(MAN_BACKEND): $(MAN_BACKEND).md
- 	ronn --roff --manual=$(MAN_BACKEND_TITLE) $(MAN_BACKEND).md
- 
- test:	$(BACKEND) test.c
--	$(CC) -o test test.c $(BACKEND) -Wl,-rpath . ${airscan_CFLAGS}
-+	$(CC) -o test test.c $(BACKEND) -Wl,-rpath . $(LDFLAGS) ${airscan_CFLAGS}
- 
- test-decode: test-decode.c $(LIBAIRSCAN)
--	 $(CC) -o test-decode test-decode.c $(CPPFLAGS) $(airscan_CFLAGS) $(LIBAIRSCAN) $(airscan_LIBS)
-+	 $(CC) -o test-decode test-decode.c $(CPPFLAGS) $(airscan_CFLAGS) $(LIBAIRSCAN) $(LDFLAGS) $(airscan_LIBS)
-diff --git a/README.md b/README.md
-index 469a2cd..f05f4d0 100644
---- a/README.md
-+++ b/README.md
-@@ -51,10 +51,13 @@ Legend:
- | Canon D570                         | Yes                       |                           |
- | Canon ImageCLASS MF743cdw          | Yes<sup>[1](#note1)</sup> |                           |
- | Canon imageRUNNER ADVANCE 4545/4551| Yes                       | Yes                       |
-+| Canon imageRUNNER C3120L           | Yes                       | Yes                       |
- | Canon i-SENSYS MF641C              | No                        | Yes                       |
--| Canon Lide 400                     | Yes                       |                           |
-+| Canon Lide 400                     | Yes<sup>[2](#note1)</sup> |                           |
- | Canon MF745C/746C                  | Yes                       | Yes                       |
-+| Canon PIXMA MG5500 Series          | No                        | Yes                       |
- | Canon PIXMA MG7700 Series          | Yes                       |                           |
-+| Canon PIXMA TS5000 Series          | Yes                       |                           |
- | Canon PIXMA TS 9550 Series         | Yes                       |                           |
- | Canon TR4529 (PIXMA TR4500 Series) | Yes                       |                           |
- | Canon TR7500 Series                | No                        | Yes                       |
-@@ -89,10 +92,10 @@ Legend:
- | HP OfficeJet Pro 8730              | Yes                       | Yes                       |
- | HP OfficeJet Pro 9010 series       | Yes                       |                           |
- | HP Smart Tank Plus 550 series      | Yes                       |                           |
--| Kyocera ECOSYS M2040dn             | Yes                       | Yes<sup>[2](#note2)</sup> |
--| Lexmark CX317dn                    | Yes<sup>[3](#note3)</sup> | Yes<sup>[3](#note3)</sup> |
-+| Kyocera ECOSYS M2040dn             | Yes                       | Yes<sup>[3](#note2)</sup> |
-+| Lexmark CX317dn                    | Yes<sup>[4](#note3)</sup> | Yes<sup>[4](#note3)</sup> |
- | Lexmark MC2535adwe                 | Yes                       |                           |
--| Ricoh MP C3003                     | No                        | Yes<sup>[4](#note3)</sup> |
-+| Ricoh MP C3003                     | No                        | Yes<sup>[5](#note3)</sup> |
- | Samsung M288x Series               | No                        | Yes                       |
- | Xerox VersaLink B405               | Yes                       |                           |
- | TODO                               |                           |                           |
-@@ -102,15 +105,21 @@ Legend:
- scanning on its web console: Home->Menu->Preferences->Network->TCP/IP
- Settings->Network Link Scan Settings->On.
- 
--<a name="note2"><sup>[2]</sup></a>: this device requires manual action on its front
-+<a name="note3"><sup>[2]</sup></a>: this USB device supports IPP over USB protocol, which
-+allows it to be used with network protocols like eSCL. To enable IPP over USB, you need
-+to install additional program: either [ippusbxd](https://github.com/OpenPrinting/ippusbxd), which
-+comes with some distros, or [ipp-usb](https://github.com/OpenPrinting/ipp-usb). 'ipp-usb`
-+works better, binary packages available for many popular distros.
-+
-+<a name="note3"><sup>[3]</sup></a>: this device requires manual action on its front
- panel to initiate WSD scan: Send->WSD Scan->From Computer
- 
--<a name="note3"><sup>[3]</sup></a>: when low in memory, this device may scan at 400 DPI
-+<a name="note4"><sup>[4]</sup></a>: when low in memory, this device may scan at 400 DPI
- instead of requested 600 DPI. As sane-airscan reports image parameters to SANE before actual
- image is received, and then adjust actual image to reported parameters, image will
- be scaled down by the factor 2/3 at this case. Lower resolutions works well.
- 
--<a name="note3"><sup>[4]</sup></a>: by default, WSD scan command is disabled on this
-+<a name="note5"><sup>[5]</sup></a>: by default, WSD scan command is disabled on this
- device and needs to be enabled before use: Click [Configuration], click [Initial Settings]
- under [Scanner], and then set [Prohibit WSD Scan Command] to [Do not Prohibit] (from
- http://support.ricoh.com/bb_v1oi/pub_e/oi_view/0001047/0001047003/view/scanner/int/0095.htm)
-diff --git a/airscan-device.c b/airscan-device.c
-index f76fa23..82e267a 100644
---- a/airscan-device.c
-+++ b/airscan-device.c
-@@ -119,7 +119,6 @@ struct device {
-     SANE_Int             read_line_end;      /* If read_line_num>read_line_end
-                                                 no more lines left in image */
-     SANE_Int             read_line_off;      /* Current offset in the line */
--    SANE_Int             read_skip_lines;    /* How many lines to skip */
-     SANE_Int             read_skip_bytes;    /* How many bytes to skip at line
-                                                 beginning */
- };
-@@ -487,6 +486,8 @@ static void
- device_probe_endpoint (device *dev, zeroconf_endpoint *endpoint)
- {
-     /* Switch endpoint */
-+    log_assert(dev->log, endpoint->proto != ID_PROTO_UNKNOWN);
-+
-     if (dev->endpoint_current == NULL ||
-         dev->endpoint_current->proto != endpoint->proto) {
-         device_proto_set(dev, endpoint->proto);
-@@ -851,8 +852,8 @@ device_geom;
-  *   First of all, we use 3 different units to deal with geometrical
-  *   parameters:
-  *     1) we communicate with frontend in millimeters
-- *     2) we communicate with scanner in pixels, assuming protoc-specific DPI
-- *        (defined by devcaps::units)
-+ *     2) we communicate with scanner in pixels, assuming
-+ *        protocol-specific DPI (defined by devcaps::units)
-  *     3) when we deal with image, sizes are in pixels in real resolution
-  *
-  *   Second, scanner returns minimal and maximal window size, but
-@@ -1289,6 +1290,7 @@ device_read_next (device *dev)
-     SANE_Parameters params;
-     image_decoder   *decoder = dev->decoders[dev->proto_ctx.params.format];
-     int             wid, hei;
-+    int             skip_lines = 0;
- 
-     log_assert(dev->log, decoder != NULL);
- 
-@@ -1330,7 +1332,7 @@ device_read_next (device *dev)
-     /* Setup image clipping */
-     if (dev->job_skip_x >= wid || dev->job_skip_y >= hei) {
-         /* Trivial case - just skip everything */
--        dev->read_skip_lines = hei;
-+        dev->read_line_end = 0;
-         dev->read_skip_bytes = 0;
-         line_capacity = dev->opt.params.bytes_per_line;
-     } else {
-@@ -1352,12 +1354,12 @@ device_read_next (device *dev)
-             dev->read_skip_bytes = bpp * (dev->job_skip_x - win.x_off);
-         }
- 
--        dev->read_skip_lines = 0;
-         if (win.y_off != dev->job_skip_y) {
--            dev->read_skip_lines = dev->job_skip_y - win.y_off;
-+            skip_lines = dev->job_skip_y - win.y_off;
-         }
- 
-         line_capacity = math_max(dev->opt.params.bytes_per_line, wid * bpp);
-+        line_capacity += dev->read_skip_bytes;
-     }
- 
-     /* Initialize image decoding */
-@@ -1366,7 +1368,14 @@ device_read_next (device *dev)
- 
-     dev->read_line_num = 0;
-     dev->read_line_off = dev->opt.params.bytes_per_line;
--    dev->read_line_end = hei - dev->read_skip_lines;
-+    dev->read_line_end = hei - skip_lines;
-+
-+    for (;skip_lines > 0; skip_lines --) {
-+        err = image_decoder_read_line(decoder, dev->read_line_buf);
-+        if (err != NULL) {
-+            goto DONE;
-+        }
-+    }
- 
-     /* Wake up reader */
-     pollable_signal(dev->read_pollable);
-@@ -1408,8 +1417,9 @@ device_read_decode_line (device *dev)
-         return SANE_STATUS_EOF;
-     }
- 
--    if (n < dev->read_skip_lines || n >= dev->read_line_end) {
--        memset(dev->read_line_buf, 0xff, dev->opt.params.bytes_per_line);
-+    if (n >= dev->read_line_end) {
-+        memset(dev->read_line_buf + dev->read_skip_bytes, 0xff,
-+            dev->opt.params.bytes_per_line);
-     } else {
-         error err = image_decoder_read_line(decoder, dev->read_line_buf);
- 
-@@ -1419,7 +1429,7 @@ device_read_decode_line (device *dev)
-         }
-     }
- 
--    dev->read_line_off = dev->read_skip_bytes;
-+    dev->read_line_off = 0;
-     dev->read_line_num ++;
- 
-     return SANE_STATUS_GOOD;
-@@ -1482,12 +1492,14 @@ device_read (device *dev, SANE_Byte *data, SANE_Int max_len, SANE_Int *len_out)
-     /* Read line by line */
-     for (len = 0; status == SANE_STATUS_GOOD && len < max_len; ) {
-         if (dev->read_line_off == dev->opt.params.bytes_per_line) {
--            status = device_read_decode_line (dev);
-+            status = device_read_decode_line(dev);
-         } else {
-             SANE_Int sz = math_min(max_len - len,
-                 dev->opt.params.bytes_per_line - dev->read_line_off);
- 
--            memcpy(data, dev->read_line_buf + dev->read_line_off, sz);
-+            memcpy(data, dev->read_line_buf + dev->read_skip_bytes +
-+                dev->read_line_off, sz);
-+
-             data += sz;
-             dev->read_line_off += sz;
-             len += sz;
-diff --git a/airscan-escl.c b/airscan-escl.c
-index dbaa370..163bdd1 100644
---- a/airscan-escl.c
-+++ b/airscan-escl.c
-@@ -335,16 +335,16 @@ escl_devcaps_source_parse (xml_rd *xml, devcaps_source **out)
-         goto DONE;
-     }
- 
--    if (src->max_wid_px != 0 && src->max_hei_px != 0 )
-+    if (src->max_wid_px != 0 && src->max_hei_px != 0)
-     {
-         /* Validate window size */
--        if (src->min_wid_px >= src->max_wid_px )
-+        if (src->min_wid_px > src->max_wid_px)
-         {
-             err = ERROR("Invalid scan:MinWidth or scan:MaxWidth");
-             goto DONE;
-         }
- 
--        if (src->min_hei_px >= src->max_hei_px)
-+        if (src->min_hei_px > src->max_hei_px)
-         {
-             err = ERROR("Invalid scan:MinHeight or scan:MaxHeight");
-             goto DONE;
-diff --git a/airscan-http.c b/airscan-http.c
-index 6758368..ca6f8b0 100644
---- a/airscan-http.c
-+++ b/airscan-http.c
-@@ -114,6 +114,7 @@ http_uri_new_relative (const http_uri *base, const char *path,
- 
- /* Free the URI
-  */
-+#ifndef __clang_analyzer__
- void
- http_uri_free (http_uri *uri)
- {
-@@ -123,6 +124,7 @@ http_uri_free (http_uri *uri)
-         g_free(uri);
-     }
- }
-+#endif
- 
- /* Get URI string
-  */
-@@ -689,9 +691,21 @@ http_client_onerror (http_client *client,
- void
- http_client_cancel (http_client *client)
- {
--    while (client->pending->len != 0) {
--        http_query_cancel(client->pending->pdata[0]);
-+    size_t     i, len = client->pending->len;
-+    size_t     sz = len * sizeof(http_query*);
-+    http_query **qlist = g_alloca(len);
-+
-+    /* Note, without this stupid copying of client->pending->pdata,
-+     * clang analyzer doesn't understand that http_query_cancel()
-+     * has a side effect of removing http_query pointer from the
-+     * array and erroneously claims that memory used after free
-+     */
-+    memcpy(qlist, client->pending->pdata, sz);
-+    for (i = 0; i < len; i ++) {
-+        http_query_cancel(qlist[i]);
-     }
-+
-+    log_assert(client->log, client->pending->len == 0);
- }
- 
- /* Cancel all pending queries with matching address family and uintptr
-@@ -988,12 +1002,13 @@ http_query_cancel (http_query *q)
-     g_object_ref(q->msg);
-     soup_session_cancel_message(http_session, q->msg, SOUP_STATUS_CANCELLED);
-     soup_message_set_status(q->msg, SOUP_STATUS_CANCELLED);
--    g_object_unref(q->msg);
- 
-     log_debug(q->client->log, "HTTP %s %s: %s", q->msg->method,
-             http_uri_str(q->uri),
-             soup_status_get_phrase(SOUP_STATUS_CANCELLED));
- 
-+    g_object_unref(q->msg);
-+
-     http_query_free(q);
- }
- 
-@@ -1225,6 +1240,8 @@ http_start_stop (bool start)
-         g_object_set_property(G_OBJECT(http_session),
-             SOUP_SESSION_SSL_STRICT, &val);
-     } else {
-+        ll_node *node;
-+
-         soup_session_abort(http_session);
-         g_object_unref(http_session);
-         http_session = NULL;
-@@ -1232,10 +1249,8 @@ http_start_stop (bool start)
-         /* Note, soup_session_abort() may leave some requests
-          * pending, so we must free them here explicitly
-          */
--        while (!ll_empty(&http_query_list)) {
--            ll_node    *node = ll_first(&http_query_list);
-+        while ((node = ll_pop_beg(&http_query_list)) != NULL) {
-             http_query *q = OUTER_STRUCT(node, http_query, list_node);
--
-             http_query_free(q);
-         }
-     }
-diff --git a/airscan-math.c b/airscan-math.c
-index d801304..ee7f301 100644
---- a/airscan-math.c
-+++ b/airscan-math.c
-@@ -99,7 +99,6 @@ math_range_merge (SANE_Range *out, const SANE_Range *r1, const SANE_Range *r2)
-     SANE_Word quant = math_lcm(r1->quant, r2->quant);
-     SANE_Word min, max, bounds_min, bounds_max;
- 
--    min = math_min(r1->min, r2->min);
-     bounds_min = math_max(r1->min, r2->min);
-     bounds_max = math_min(r1->max, r2->max);
- 
-diff --git a/airscan-netif.c b/airscan-netif.c
-index a762377..a086792 100644
---- a/airscan-netif.c
-+++ b/airscan-netif.c
-@@ -92,6 +92,41 @@ netif_distance_get (const struct sockaddr *addr)
-     return distance;
- }
- 
-+/* Check that interface has non-link-local address
-+ * of particular address family
-+ */
-+bool
-+netif_has_non_link_local_addr (int af, int ifindex)
-+{
-+    struct ifaddrs *ifa;
-+
-+    for (ifa = netif_ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
-+        struct sockaddr *addr;
-+
-+        /* Skip interface without address */
-+        if ((addr = ifa->ifa_addr) == NULL) {
-+            continue;
-+        }
-+
-+        /* Check address family against requested */
-+        if (addr->sa_family != af) {
-+            continue;
-+        }
-+
-+        /* Skip link-local addresses */
-+        if (ip_sockaddr_is_linklocal(addr)) {
-+            continue;
-+        }
-+
-+        /* Check interface index */
-+        if (ifindex == (int) if_nametoindex(ifa->ifa_name)) {
-+            return true;
-+        }
-+    }
-+
-+    return false;
-+}
-+
- /* Get list of network interfaces addresses
-  */
- netif_addr*
-diff --git a/airscan-wsdd.c b/airscan-wsdd.c
-index 15bf02a..c53105b 100644
---- a/airscan-wsdd.c
-+++ b/airscan-wsdd.c
-@@ -26,6 +26,12 @@
- #define WSDD_RETRANSMIT_MAX     250     /* Max retransmit time */
- #define WSDD_DISCOVERY_TIME     2500    /* Overall discovery time */
- 
-+/* This delay is taken, if we have discovered, say, device's IPv6
-+ * addresses and have a strong suspicion that device has not yet
-+ * discovered IPv4 addresses as well
-+ */
-+#define WSDD_PUBLISH_DELAY      1000
-+
- /* WS-Discovery stable endpoint path
-  */
- #define WSDD_STABLE_ENDPOINT    \
-@@ -49,12 +55,13 @@ typedef struct {
-  * device discovery
-  */
- typedef struct {
--    zeroconf_finding  finding;      /* Base class */
--    const char        *address;     /* Device "address" in WS-SD sense */
--    ll_head           xaddrs;       /* List of wsdd_xaddr */
--    http_client       *http_client; /* HTTP client */
--    ll_node           list_node;    /* In wsdd_finding_list */
--    bool              published;    /* This finding is published */
-+    zeroconf_finding  finding;        /* Base class */
-+    const char        *address;       /* Device "address" in WS-SD sense */
-+    ll_head           xaddrs;         /* List of wsdd_xaddr */
-+    http_client       *http_client;   /* HTTP client */
-+    ll_node           list_node;      /* In wsdd_finding_list */
-+    eloop_timer       *publish_timer; /* WSDD_PUBLISH_DELAY timer */
-+    bool              published;      /* This finding is published */
- } wsdd_finding;
- 
- /* wsdd_xaddr represents device transport address
-@@ -207,9 +214,8 @@ wsdd_xaddr_list_purge (ll_head *list)
- {
-     ll_node    *node;
- 
--    while ((node = ll_first(list)) != NULL) {
-+    while ((node = ll_pop_beg(list)) != NULL) {
-         wsdd_xaddr *xaddr = OUTER_STRUCT(node, wsdd_xaddr, list_node);
--        ll_del(&xaddr->list_node);
-         wsdd_xaddr_free(xaddr);
-     }
- }
-@@ -269,6 +275,10 @@ wsdd_finding_free (wsdd_finding *wsdd)
-     http_client_cancel(wsdd->http_client);
-     http_client_free(wsdd->http_client);
- 
-+    if (wsdd->publish_timer != NULL) {
-+        eloop_timer_cancel(wsdd->publish_timer);
-+    }
-+
-     zeroconf_endpoint_list_free(wsdd->finding.endpoints);
-     g_free((char*) wsdd->address);
-     wsdd_xaddr_list_purge(&wsdd->xaddrs);
-@@ -282,17 +292,100 @@ wsdd_finding_free (wsdd_finding *wsdd)
- static void
- wsdd_finding_publish (wsdd_finding *wsdd)
- {
--    if (!wsdd->published) {
--        wsdd->published = true;
--        zeroconf_finding_publish(&wsdd->finding);
-+    if (wsdd->published) {
-+        return;
-+    }
-+
-+    wsdd->published = true;
-+    wsdd->finding.endpoints = zeroconf_endpoint_list_sort_dedup(
-+            wsdd->finding.endpoints);
-+
-+    if (wsdd->publish_timer != NULL) {
-+        log_debug(wsdd_log, "\"%s\": publish-delay timer canceled",
-+                wsdd->finding.model);
-+
-+        eloop_timer_cancel(wsdd->publish_timer);
-+        wsdd->publish_timer = NULL;
-+    }
-+
-+    zeroconf_finding_publish(&wsdd->finding);
-+}
-+
-+/* WSDD_PUBLISH_DELAY timer callback
-+ */
-+static void
-+wsdd_finding_publish_delay_timer_callback (void *data)
-+{
-+    wsdd_finding *wsdd = data;
-+
-+    wsdd->publish_timer = NULL;
-+    log_debug(wsdd_log, "\"%s\": publish-delay timer expired",
-+            wsdd->finding.model);
-+
-+    wsdd_finding_publish(wsdd);
-+}
-+
-+/* Publish wsdd_finding with optional delay
-+ */
-+static void
-+wsdd_finding_publish_delay (wsdd_finding *wsdd)
-+{
-+    bool delay = false;
-+
-+    if (wsdd->published) {
-+        return;
-+    }
-+
-+    /* Continue discovery, if interface has IPv4/IPv6 address,
-+     * and we have not yet discovered address of the same address
-+     * family of device
-+     *
-+     * Some devices doesn't return their IPv4 endpoints, if
-+     * metadata is queried via IPv6, and visa versa. This is
-+     * possible that we will finish discovery of the particular
-+     * address family, before we'll ever know that the device
-+     * may have address of another address family, so part
-+     * of addresses will be never discovered (see #44 for details).
-+     *
-+     * To prevent this situation, we continue discovery with
-+     * some reasonable delay, if network interface has IPv4/IPv6
-+     * address, but device is not yet.
-+     */
-+
-+    if (netif_has_non_link_local_addr(AF_INET, wsdd->finding.ifindex) &&
-+        !zeroconf_endpoint_list_has_non_link_local_addr(AF_INET,
-+            wsdd->finding.endpoints)) {
-+        log_debug(wsdd_log,
-+                "\"%s\": IPv4 address expected but not yet discovered",
-+                wsdd->finding.model);
-+        delay = true;
-+    }
-+
-+    if (netif_has_non_link_local_addr(AF_INET6, wsdd->finding.ifindex) &&
-+        !zeroconf_endpoint_list_has_non_link_local_addr(AF_INET6,
-+            wsdd->finding.endpoints)) {
-+        log_debug(wsdd_log,
-+                "\"%s\": IPv6 address expected but not yet discovered",
-+                wsdd->finding.model);
-+        delay = true;
-+    }
-+
-+    if (delay) {
-+        if (wsdd->publish_timer == NULL) {
-+            wsdd->publish_timer = eloop_timer_new(WSDD_PUBLISH_DELAY,
-+                wsdd_finding_publish_delay_timer_callback, wsdd);
-+        }
-+
-+        return;
-     }
-+
-+    wsdd_finding_publish(wsdd);
- }
- 
--/* Add wsdd_finding to the wsdd_finding_list.
-- * If finding already present, does nothing and returns NULL
-+/* Get existent finding or add a new one
-  */
- static wsdd_finding*
--wsdd_finding_add (int ifindex, const char *address)
-+wsdd_finding_get (int ifindex, const char *address)
- {
-     ll_node      *node;
-     wsdd_finding *wsdd;
-@@ -302,7 +395,7 @@ wsdd_finding_add (int ifindex, const char *address)
-         wsdd = OUTER_STRUCT(node, wsdd_finding, list_node);
-         if (wsdd->finding.ifindex == ifindex &&
-             !strcmp(wsdd->address, address)) {
--            return NULL;
-+            return wsdd;
-         }
-     }
- 
-@@ -343,6 +436,25 @@ wsdd_finding_by_address (ip_addr addr)
-     return NULL;
- }
- 
-+/* Check if finding already has particular xaddr
-+ */
-+static bool
-+wsdd_finding_has_xaddr (wsdd_finding *wsdd, const wsdd_xaddr *xaddr)
-+{
-+    ll_node    *node;
-+    wsdd_xaddr *xaddr2;
-+
-+    for (LL_FOR_EACH(node, &wsdd->xaddrs)) {
-+        xaddr2 = OUTER_STRUCT(node, wsdd_xaddr, list_node);
-+
-+        if (http_uri_equal(xaddr->uri, xaddr2->uri)) {
-+            return true;
-+        }
-+    }
-+
-+    return false;
-+}
-+
- /* Delete wsdd_finding from the wsdd_finding_list
-  */
- static void
-@@ -532,24 +644,7 @@ DONE:
-     g_free(manufacturer);
- 
-     if (http_client_num_pending(wsdd->http_client) == 0) {
--        zeroconf_endpoint *endpoint;
--
--        wsdd->finding.endpoints = zeroconf_endpoint_list_sort_dedup(
--                wsdd->finding.endpoints);
--
--        log_debug(wsdd_log, "\"%s\": address: %s",
--                wsdd->finding.model, wsdd->address);
--        log_debug(wsdd_log, "\"%s\": uuid: %s",
--                wsdd->finding.model, wsdd->finding.uuid.text);
--        log_debug(wsdd_log, "\"%s\": discovered endpoints:",
--                wsdd->finding.model);
--
--        for (endpoint = wsdd->finding.endpoints; endpoint != NULL;
--            endpoint = endpoint->next) {
--            log_debug(wsdd_log, "  %s", http_uri_str(endpoint->uri));
--        }
--
--        wsdd_finding_publish(wsdd);
-+        wsdd_finding_publish_delay(wsdd);
-     }
- }
- 
-@@ -738,28 +833,42 @@ wsdd_resolver_message_dispatch (wsdd_resolver *resolver,
-             goto DONE;
-         }
- 
--        /* Add a finding. Do nothing if device already exist */
--        wsdd = wsdd_finding_add(resolver->ifindex, msg->address);
--        if (wsdd == NULL) {
--            goto DONE;
--        }
-+        /* Add a finding or get existent one */
-+        wsdd = wsdd_finding_get(resolver->ifindex, msg->address);
- 
--        /* If device is not scanner or (which is very unlikely)
--         * has no xaddrs, just publish it without endpoints,
--         * so zeroconf stuff will know that there is no need to
--         * wait anymore for a device with this UUID, and we
--         * are done
-+        /* Import newly discovered xaddrs and initiate metadata
-+         * query
-          */
--        if (!msg->is_scanner || ll_empty(&msg->xaddrs)) {
--            wsdd_finding_publish(wsdd);
--            goto DONE;
-+        while ((node = ll_pop_beg(&msg->xaddrs)) != NULL) {
-+            xaddr = OUTER_STRUCT(node, wsdd_xaddr, list_node);
-+
-+            if (wsdd_finding_has_xaddr(wsdd, xaddr)) {
-+                wsdd_xaddr_free(xaddr);
-+                continue;
-+            }
-+
-+            ll_push_end(&wsdd->xaddrs, &xaddr->list_node);
-+            if (msg->is_scanner) {
-+                wsdd_finding_get_metadata(wsdd, resolver->ifindex, xaddr);
-+            }
-         }
- 
--        /* Initiate metadata query */
--        ll_cat(&wsdd->xaddrs, &msg->xaddrs);
--        for (LL_FOR_EACH(node, &wsdd->xaddrs)) {
--            xaddr = OUTER_STRUCT(node, wsdd_xaddr, list_node);
--            wsdd_finding_get_metadata(wsdd, resolver->ifindex, xaddr);
-+        /* If there is no pending metadata queries, it may mean
-+         * one of the following:
-+         *   1) device is not scanner, metadata won't be requested
-+         *   2) there is no xaddrs (which is very unlikely, but
-+         *      just in case...)
-+         *   3) device already known and all metadata queries
-+         *      already finished
-+         *
-+         * At this case we can publish device now
-+         */
-+        if (http_client_num_pending(wsdd->http_client) == 0) {
-+            if (msg->is_scanner) {
-+                wsdd_finding_publish_delay(wsdd);
-+            } else {
-+                wsdd_finding_publish(wsdd);
-+            }
-         }
-         break;
- 
-@@ -774,6 +883,7 @@ wsdd_resolver_message_dispatch (wsdd_resolver *resolver,
-     /* Cleanup and exit */
- DONE:
-     wsdd_message_free(msg);
-+    log_trace(wsdd_log, "");
- }
- 
- 
-diff --git a/airscan-zeroconf.c b/airscan-zeroconf.c
-index dfff5b8..293a05d 100644
---- a/airscan-zeroconf.c
-+++ b/airscan-zeroconf.c
-@@ -129,11 +129,8 @@ zeroconf_device_add (zeroconf_finding *finding)
-     }
- 
-     ll_init(&device->findings);
--
--    device->ifaces_cap = ZEROCONF_DEVICE_IFACES_INITIAL_LEN;
--    device->ifaces = g_malloc(device->ifaces_cap * sizeof(*device->ifaces));
--
-     ll_push_end(&zeroconf_device_list, &device->node_list);
-+
-     return device;
- }
- 
-@@ -233,7 +230,12 @@ zeroconf_device_ifaces_add (zeroconf_device *device, int ifindex)
- {
-     if (!zeroconf_device_ifaces_lookup(device, ifindex)) {
-         if (device->ifaces_len == device->ifaces_cap) {
--            device->ifaces_cap *= 2;
-+            if (device->ifaces_cap == 0) {
-+                device->ifaces_cap = ZEROCONF_DEVICE_IFACES_INITIAL_LEN;
-+            } else {
-+                device->ifaces_cap *= 2;
-+            }
-+
-             device->ifaces = g_realloc(device->ifaces,
-                 device->ifaces_cap * sizeof(*device->ifaces));
-         }
-@@ -260,7 +262,7 @@ zeroconf_device_rebuild_sets (zeroconf_device *device)
-         finding = OUTER_STRUCT(node, zeroconf_finding, list_node);
-         proto = zeroconf_method_to_proto(finding->method);
- 
--        zeroconf_device_ifaces_add(device, finding->ifindex );
-+        zeroconf_device_ifaces_add(device, finding->ifindex);
-         if (proto != ID_PROTO_UNKNOWN) {
-             device->protocols |= 1 << proto;
-         }
-@@ -316,19 +318,26 @@ static void
- zeroconf_device_borrow_findings (zeroconf_device *device,
-     int ifindex, ll_head *output)
- {
--    ll_node          *node, *next;
--    zeroconf_finding *finding;
-+    ll_node          *node;
-+    ll_head          leftover;
- 
--    for (node = ll_first(&device->findings); node != NULL; node = next) {
--        next = ll_next(&device->findings, node);
-+    ll_init(&leftover);
-+
-+    while ((node = ll_pop_beg(&device->findings)) != NULL) {
-+        zeroconf_finding *finding;
- 
-         finding = OUTER_STRUCT(node, zeroconf_finding, list_node);
-+
-         if (finding->ifindex == ifindex) {
-             finding->device = NULL;
-             ll_push_end(output, node);
-+        } else {
-+            ll_push_end(&leftover, node);
-         }
-     }
- 
-+    ll_cat(&device->findings, &leftover);
-+
-     if (ll_empty(&device->findings)) {
-         zeroconf_device_del(device);
-         return;
-@@ -556,7 +565,7 @@ zeroconf_ident_split (const char *ident, unsigned int *devid, ID_PROTO *proto)
- 
-     /* Decode proto and devid */
-     *proto = zeroconf_ident_proto_decode(*ident);
--    if (*proto == NUM_ID_PROTO) {
-+    if (*proto == ID_PROTO_UNKNOWN) {
-         return NULL;
-     }
- 
-@@ -774,6 +783,25 @@ zeroconf_endpoint_list_sort_dedup (zeroconf_endpoint *list)
-     return list;
- }
- 
-+/* Check if endpoints list contains a non-link-local address
-+ * of the specified address family
-+ */
-+bool
-+zeroconf_endpoint_list_has_non_link_local_addr (int af,
-+        const zeroconf_endpoint *list)
-+{
-+    for (;list != NULL; list = list->next) {
-+        const struct sockaddr *addr = http_uri_addr(list->uri);
-+        if (addr != NULL && addr->sa_family == af) {
-+            if (!ip_sockaddr_is_linklocal(addr)) {
-+                return true;
-+            }
-+        }
-+    }
-+
-+    return false;
-+}
-+
- /******************** Static configuration *********************/
- /* Look for device's static configuration by device name
-  */
-@@ -850,7 +878,7 @@ zeroconf_finding_publish (zeroconf_finding *finding)
-      */
-     device = zeroconf_device_find_by_uuid(finding->uuid);
-     if (device != NULL && finding->name != NULL) {
--        if (device->ifaces_len == 1 && device->ifaces[0] == finding->ifindex ){
-+        if (device->ifaces_len == 1 && device->ifaces[0] == finding->ifindex){
-             /* Case 2: all findings belongs to the same network
-              * interface; upgrade anonymous device to named
-              */
-@@ -1055,6 +1083,41 @@ zeroconf_device_list_qsort_cmp (const void *p1, const void *p2)
-     return cmp;
- }
- 
-+/* Format list of protocols, for zeroconf_device_list_log
-+ */
-+static void
-+zeroconf_device_list_fmt_protocols (char *buf, size_t buflen, unsigned int protocols)
-+{
-+    ID_PROTO proto;
-+    size_t   off = 0;
-+
-+    buf[0] = '\0';
-+    for (proto = 0; proto < NUM_ID_PROTO; proto ++) {
-+        if ((protocols & (1 << proto)) != 0) {
-+            off += snprintf(buf + off, buflen - off, " %s",
-+                id_proto_name(proto));
-+        }
-+    }
-+
-+    if (buf[0] == '\0') {
-+        strcpy(buf, " none");
-+    }
-+}
-+
-+/* Log device information in a context of zeroconf_device_list_get
-+ */
-+static void
-+zeroconf_device_list_log (zeroconf_device *device, const char *name, unsigned int protocols)
-+{
-+    char     buf[64];
-+
-+    zeroconf_device_list_fmt_protocols(buf, sizeof(buf), device->protocols);
-+    log_debug(zeroconf_log, "%s: supported protocols:%s", name, buf);
-+
-+    zeroconf_device_list_fmt_protocols(buf, sizeof(buf), protocols);
-+    log_debug(zeroconf_log, "%s: chosen protocols:%s", name, buf);
-+}
-+
- /* Get list of devices, in SANE format
-  */
- const SANE_Device**
-@@ -1065,10 +1128,14 @@ zeroconf_device_list_get (void)
-     const SANE_Device **dev_list = sane_device_array_new();
-     ll_node     *node;
- 
-+    log_debug(zeroconf_log, "zeroconf_device_list_get: requested");
-+
-     /* Wait until device table is ready */
-     zeroconf_initscan_wait();
- 
-     /* Build list of devices */
-+    log_debug(zeroconf_log, "zeroconf_device_list_get: building list of devices");
-+
-     dev_count = 0;
- 
-     for (dev_conf = conf.devices; dev_conf != NULL; dev_conf = dev_conf->next) {
-@@ -1097,8 +1164,18 @@ zeroconf_device_list_get (void)
-         zeroconf_device_name_model(device, &name, &model);
-         protocols = zeroconf_device_protocols(device);
- 
-+        zeroconf_device_list_log(device, name, protocols);
-+
-         if (zeroconf_find_static_by_name(name) != NULL) {
-             /* Static configuration overrides discovery */
-+            log_debug(zeroconf_log,
-+                "%s: skipping, device clashes statically configured", name);
-+            continue;
-+        }
-+
-+        if (protocols == 0) {
-+            log_debug(zeroconf_log,
-+                "%s: skipping, no of supported protocols discovered", name);
-             continue;
-         }
- 
-@@ -1327,6 +1404,8 @@ zeroconf_init (void)
-     log_trace(zeroconf_log, "  protocol     = %s", s);
- 
-     s = "?";
-+    (void) s; /* Silence CLANG analyzer warning */
-+
-     switch (conf.wsdd_mode) {
-     case WSDD_FAST: s = "fast"; break;
-     case WSDD_FULL: s = "full"; break;
-diff --git a/airscan.h b/airscan.h
-index 3aca207..2a36333 100644
---- a/airscan.h
-+++ b/airscan.h
-@@ -130,8 +130,10 @@ ll_push_beg (ll_head *head, ll_node *node)
- static inline void
- ll_del (ll_node *node)
- {
--    node->ll_prev->ll_next = node->ll_next;
--    node->ll_next->ll_prev = node->ll_prev;
-+    ll_node *p = node->ll_prev, *n = node->ll_next;
-+
-+    p->ll_next = n;
-+    n->ll_prev = p;
- 
-     /* Make double-delete safe */
-     node->ll_next = node->ll_prev = node;
-@@ -143,14 +145,19 @@ ll_del (ll_node *node)
- static inline ll_node*
- ll_pop_beg (ll_head *head)
- {
--    ll_node *node;
-+    ll_node *node, *next;
- 
--    if (ll_empty(head)) {
--        return NULL;
-+    node = head->node.ll_next;
-+    if (node == &head->node) {
-+        return NULL; /* List is empty if it is looped to itself */
-     }
- 
--    node = head->node.ll_next;
--    ll_del(node);
-+    next = node->ll_next;
-+    next->ll_prev = &head->node;
-+    head->node.ll_next = next;
-+
-+    /* Make double-delete safe */
-+    node->ll_next = node->ll_prev = node;
- 
-     return node;
- }
-@@ -161,14 +168,19 @@ ll_pop_beg (ll_head *head)
- static inline ll_node*
- ll_pop_end (ll_head *head)
- {
--    ll_node *node;
-+    ll_node *node, *prev;
- 
--    if (ll_empty(head)) {
--        return NULL;
-+    node = head->node.ll_prev;
-+    if (node == &head->node) {
-+        return NULL; /* List is empty if it is looped to itself */
-     }
- 
--    node = head->node.ll_prev;
--    ll_del(node);
-+    prev = node->ll_prev;
-+    prev->ll_next = &head->node;
-+    head->node.ll_prev = prev;
-+
-+    /* Make double-delete safe */
-+    node->ll_next = node->ll_prev = node;
- 
-     return node;
- }
-@@ -702,6 +714,12 @@ typedef enum {
- NETIF_DISTANCE
- netif_distance_get (const struct sockaddr *addr);
- 
-+/* Check that interface has non-link-local address
-+ * of particular address family
-+ */
-+bool
-+netif_has_non_link_local_addr (int af, int ifindex);
-+
- /* Compare addresses by distance. Returns:
-  *   <0, if addr1 is closer that addr2
-  *   >0, if addr2 is farther that addr2
-@@ -2055,6 +2073,13 @@ zeroconf_endpoint_list_sort (zeroconf_endpoint *list);
- zeroconf_endpoint*
- zeroconf_endpoint_list_sort_dedup (zeroconf_endpoint *list);
- 
-+/* Check if endpoints list contains a non-link-local address
-+ * of the specified address family
-+ */
-+bool
-+zeroconf_endpoint_list_has_non_link_local_addr (int af,
-+        const zeroconf_endpoint *list);
-+
- /******************** MDNS Discovery ********************/
- /* Called by zeroconf to notify MDNS about initial scan timer expiration
-  */
-@@ -2594,6 +2619,7 @@ log_panic (log_ctx *log, const char *fmt, ...);
-          if (!(expr)) {                                                 \
-              log_panic(log,"file %s: line %d (%s): assertion failed: (%s)",\
-                      __FILE__, __LINE__, __PRETTY_FUNCTION__, #expr);   \
-+             __builtin_unreachable();                                   \
-          }                                                              \
-      } while (0)
- 
-@@ -2603,6 +2629,7 @@ log_panic (log_ctx *log, const char *fmt, ...);
-      do {                                                               \
-          log_panic(log,"file %s: line %d (%s): internal error",         \
-                  __FILE__, __LINE__, __PRETTY_FUNCTION__);              \
-+         __builtin_unreachable();                                       \
-      } while (0)
- 
- #endif
-diff --git a/sane-airscan.5 b/sane-airscan.5
-index 84ed929..32656e1 100644
---- a/sane-airscan.5
-+++ b/sane-airscan.5
-@@ -1,7 +1,7 @@
- .\" generated with Ronn/v0.7.3
- .\" http://github.com/rtomayko/ronn/tree/0.7.3
- .
--.TH "SANE\-AIRSCAN" "5" "May 2020" "" "AirScan (eSCL) and WSD SANE backend"
-+.TH "SANE\-AIRSCAN" "5" "July 2020" "" "AirScan (eSCL) and WSD SANE backend"
- .
- .SH "NAME"
- \fBsane\-airscan\fR \- SANE backend for AirScan (eSCL) and WSD scanners and MFP
-@@ -82,7 +82,7 @@ To manually configure a device, add the following section to the configuration f
- [devices]
- "Kyocera eSCL" = http://192\.168\.1\.102:9095/eSCL, eSCL
- "Kyocera WSD" = http://192\.168\.1\.102:5358/WSDScanner, WSD
--"Device I don\'t want to see" = disable
-+"Device I do not want to see" = disable
- .
- .fi
- .
-@@ -146,8 +146,8 @@ Debuggung facilities can be controlled using the \fB[debug]\fR section of the co
- enable = false | true
- 
- ; Enable protocol trace and configure output directory
--; for trace files\. To specify path relative to user\'s
--; home directory, start it with tilda character, followed
-+; for trace files\. Like in shell, to specify path relative to
-+; the home directory, start it with tilda character, followed
- ; by slash, i\.e\., "~/airscan/trace"\. The directory will
- ; be created automatically\.
- trace = path
-diff --git a/sane-airscan.5.md b/sane-airscan.5.md
-index 4461900..6c6ec10 100644
---- a/sane-airscan.5.md
-+++ b/sane-airscan.5.md
-@@ -46,7 +46,7 @@ file:
-     [devices]
-     "Kyocera eSCL" = http://192.168.1.102:9095/eSCL, eSCL
-     "Kyocera WSD" = http://192.168.1.102:5358/WSDScanner, WSD
--    "Device I don't want to see" = disable
-+    "Device I do not want to see" = disable
- 
- The `[devices]` section contains all manually configured devices, one line per
- device, and each line contains a device name on a left side of equation and
-@@ -109,8 +109,8 @@ of the configuration file:
-     enable = false | true
- 
-     ; Enable protocol trace and configure output directory
--    ; for trace files. To specify path relative to user's
--    ; home directory, start it with tilda character, followed
-+    ; for trace files. Like in shell, to specify path relative to
-+    ; the home directory, start it with tilda character, followed
-     ; by slash, i.e., "~/airscan/trace". The directory will
-     ; be created automatically.
-     trace = path
-diff --git a/test-decode.c b/test-decode.c
-index 5b2879e..af774a5 100644
---- a/test-decode.c
-+++ b/test-decode.c
-@@ -26,7 +26,7 @@ typedef struct {
- 
- /* Print error message and exit
-  */
--void
-+void __attribute__((noreturn))
- die (const char *format, ...)
- {
-     va_list ap;
-@@ -218,6 +218,7 @@ main (int argc, char **argv)
-         save_write(save, line);
-     }
- 
-+    g_free(line);
-     save_close(save);
- 
-     return 0;
-- 
GitLab