From 44916ca6d75e0b5f258a098a50d659f31c6625fd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= <debian@jff.email>
Date: Sun, 3 Mar 2024 09:54:51 +0100
Subject: New upstream version 1.3.0

---
 frontend/.gitignore           |   4 +
 frontend/Makefile.am          |  19 ++-
 frontend/jpegtopdf.c          |   2 +-
 frontend/saned.c              | 361 +++++++++++++++++++++++-------------------
 frontend/saned.socket         |  10 ++
 frontend/saned.xinetd.conf.in |  13 ++
 frontend/saned@.service.in    |  11 ++
 frontend/scanimage.c          | 201 +++++++++++------------
 8 files changed, 359 insertions(+), 262 deletions(-)
 create mode 100644 frontend/saned.socket
 create mode 100644 frontend/saned.xinetd.conf.in
 create mode 100644 frontend/saned@.service.in

(limited to 'frontend')

diff --git a/frontend/.gitignore b/frontend/.gitignore
index 90f73a9..e42f6b0 100644
--- a/frontend/.gitignore
+++ b/frontend/.gitignore
@@ -1,2 +1,6 @@
 saned
+saned@.service
+saned.xinetd.conf
 scanimage
+test
+tstbackend
diff --git a/frontend/Makefile.am b/frontend/Makefile.am
index 9b92645..8573aba 100644
--- a/frontend/Makefile.am
+++ b/frontend/Makefile.am
@@ -44,5 +44,20 @@ tstbackend_LDADD += -lstdc++
 endif
 endif
 
-clean-local:
-	rm -f test tstbackend
+BUILT_SOURCES = saned@.service saned.xinetd.conf
+
+EXTRA_DIST = saned.socket saned@.service.in saned.xinetd.conf.in
+
+CLEANFILES = $(EXTRA_PROGRAMS) $(BUILT_SOURCES)
+
+SUFFIXES = .in
+.in:
+	$(AM_V_GEN)
+	@if $(AM_V_P); then echo Generating $@ from $^; fi
+	@sed -e 's|@DATADIR@|$(datadir)|g' \
+	     -e 's|@CONFIGDIR@|$(configdir)|g' \
+	     -e 's|@DOCDIR@|$(docdir)|g' \
+	     -e 's|@LIBDIR@|$(libdir)/sane|g' \
+	     -e 's|@BINDIR@|$(bindir)|g' \
+	     -e 's|@SBINDIR@|$(sbindir)|g' \
+	     -e 's|@PACKAGEVERSION@|$(PACKAGE_VERSION)|g' $? > $@
diff --git a/frontend/jpegtopdf.c b/frontend/jpegtopdf.c
index 5c5d712..309411c 100644
--- a/frontend/jpegtopdf.c
+++ b/frontend/jpegtopdf.c
@@ -91,7 +91,7 @@
 #define SANE_PDF_LENGTH_OBJ "%d 0 obj\n%d\nendobj\n"
 
 /* end of stream/object */
-#define SANE_PDF_END_ST_OBJ "endstream\nendobj\n"
+#define SANE_PDF_END_ST_OBJ "\nendstream\nendobj\n"
 
 
 /* object id of first page */
diff --git a/frontend/saned.c b/frontend/saned.c
index e31758a..d71d428 100644
--- a/frontend/saned.c
+++ b/frontend/saned.c
@@ -53,6 +53,7 @@
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <stdint.h>
 #include <string.h>
 #include <syslog.h>
 #include <time.h>
@@ -257,6 +258,7 @@ static int data_connect_timeout = 4000;
 static Handle *handle;
 static char *bind_addr;
 static short bind_port = -1;
+static size_t buffer_size = (1 * 1024 * 1024);
 static union
 {
   int w;
@@ -1651,168 +1653,186 @@ store_reclen (SANE_Byte * buf, size_t buf_size, int i, size_t reclen)
 static void
 do_scan (Wire * w, int h, int data_fd)
 {
-  int num_fds, be_fd = -1, reader, writer, bytes_in_buf, status_dirty = 0;
+  int num_fds, be_fd = -1, reader, bytes_in_buf, status_dirty = 0;
+  size_t writer;
   SANE_Handle be_handle = handle[h].handle;
   struct timeval tv, *timeout = 0;
   fd_set rd_set, rd_mask, wr_set, wr_mask;
-  SANE_Byte buf[8192];
+  SANE_Byte *buf = NULL;
   SANE_Status status;
-  long int nwritten;
+  ssize_t nwritten;
   SANE_Int length;
   size_t nbytes;
 
   DBG (3, "do_scan: start\n");
 
-  FD_ZERO (&rd_mask);
-  FD_SET (w->io.fd, &rd_mask);
-  num_fds = w->io.fd + 1;
-
-  FD_ZERO (&wr_mask);
-  FD_SET (data_fd, &wr_mask);
-  if (data_fd >= num_fds)
-    num_fds = data_fd + 1;
-
-  sane_set_io_mode (be_handle, SANE_TRUE);
-  if (sane_get_select_fd (be_handle, &be_fd) == SANE_STATUS_GOOD)
+  /*
+   * Allocate the read buffer.
+   *
+   */
+  buf = malloc (buffer_size);
+  if (!buf)
     {
-      FD_SET (be_fd, &rd_mask);
-      if (be_fd >= num_fds)
-	num_fds = be_fd + 1;
+      status = SANE_STATUS_NO_MEM;
+      DBG (DBG_ERR, "do_scan: failed to allocate read buffer (%zu bytes)\n",
+           buffer_size);
     }
   else
     {
-      memset (&tv, 0, sizeof (tv));
-      timeout = &tv;
-    }
+      FD_ZERO(&rd_mask);
+      FD_SET(w->io.fd, &rd_mask);
+      num_fds = w->io.fd + 1;
 
-  status = SANE_STATUS_GOOD;
-  reader = writer = bytes_in_buf = 0;
-  do
-    {
-      rd_set = rd_mask;
-      wr_set = wr_mask;
-      if (select (num_fds, &rd_set, &wr_set, 0, timeout) < 0)
-	{
-	  if (be_fd >= 0 && errno == EBADF)
-	    {
-	      /* This normally happens when a backend closes a select
-		 filedescriptor when reaching the end of file.  So
-		 pass back this status to the client: */
-	      FD_CLR (be_fd, &rd_mask);
-	      be_fd = -1;
-	      /* only set status_dirty if EOF hasn't been already detected */
-	      if (status == SANE_STATUS_GOOD)
-		status_dirty = 1;
-	      status = SANE_STATUS_EOF;
-	      DBG (DBG_INFO, "do_scan: select_fd was closed --> EOF\n");
-	      continue;
-	    }
-	  else
-	    {
-	      status = SANE_STATUS_IO_ERROR;
-	      DBG (DBG_ERR, "do_scan: select failed (%s)\n", strerror (errno));
-	      break;
-	    }
-	}
+      FD_ZERO(&wr_mask);
+      FD_SET(data_fd, &wr_mask);
+      if (data_fd >= num_fds)
+        num_fds = data_fd + 1;
 
-      if (bytes_in_buf)
-	{
-	  if (FD_ISSET (data_fd, &wr_set))
-	    {
-	      if (bytes_in_buf > 0)
-		{
-		  /* write more input data */
-		  nbytes = bytes_in_buf;
-		  if (writer + nbytes > sizeof (buf))
-		    nbytes = sizeof (buf) - writer;
-		  DBG (DBG_INFO,
-		       "do_scan: trying to write %d bytes to client\n",
-		       nbytes);
-		  nwritten = write (data_fd, buf + writer, nbytes);
-		  DBG (DBG_INFO,
-		       "do_scan: wrote %ld bytes to client\n", nwritten);
-		  if (nwritten < 0)
-		    {
-		      DBG (DBG_ERR, "do_scan: write failed (%s)\n",
-			   strerror (errno));
-		      status = SANE_STATUS_CANCELLED;
-	              handle[h].docancel = 1;
-		      break;
-		    }
-		  bytes_in_buf -= nwritten;
-		  writer += nwritten;
-		  if (writer == sizeof (buf))
-		    writer = 0;
-		}
-	    }
-	}
-      else if (status == SANE_STATUS_GOOD
-	       && (timeout || FD_ISSET (be_fd, &rd_set)))
-	{
-	  int i;
+      sane_set_io_mode (be_handle, SANE_TRUE);
+      if (sane_get_select_fd (be_handle, &be_fd) == SANE_STATUS_GOOD)
+        {
+          FD_SET(be_fd, &rd_mask);
+          if (be_fd >= num_fds)
+            num_fds = be_fd + 1;
+        }
+      else
+        {
+          memset (&tv, 0, sizeof(tv));
+          timeout = &tv;
+        }
 
-	  /* get more input data */
+      status = SANE_STATUS_GOOD;
+      reader = writer = bytes_in_buf = 0;
+      do
+        {
+          rd_set = rd_mask;
+          wr_set = wr_mask;
+          if (select (num_fds, &rd_set, &wr_set, 0, timeout) < 0)
+            {
+              if (be_fd >= 0 && errno == EBADF)
+                {
+                  /* This normally happens when a backend closes a select
+                   filedescriptor when reaching the end of file.  So
+                   pass back this status to the client: */
+                  FD_CLR(be_fd, &rd_mask);
+                  be_fd = -1;
+                  /* only set status_dirty if EOF hasn't been already detected */
+                  if (status == SANE_STATUS_GOOD)
+                    status_dirty = 1;
+                  status = SANE_STATUS_EOF;
+                  DBG (DBG_INFO, "do_scan: select_fd was closed --> EOF\n");
+                  continue;
+                }
+              else
+                {
+                  status = SANE_STATUS_IO_ERROR;
+                  DBG (DBG_ERR, "do_scan: select failed (%s)\n",
+                       strerror (errno));
+                  break;
+                }
+            }
 
-	  /* reserve 4 bytes to store the length of the data record: */
-	  i = reader;
-	  reader += 4;
-	  if (reader >= (int) sizeof (buf))
-	    reader -= sizeof(buf);
+          if (bytes_in_buf)
+            {
+              if (FD_ISSET(data_fd, &wr_set))
+                {
+                  if (bytes_in_buf > 0)
+                    {
+                      /* write more input data */
+                      nbytes = bytes_in_buf;
+                      if (writer + nbytes > buffer_size)
+                        nbytes = buffer_size - writer;
+                      DBG (DBG_INFO,
+                           "do_scan: trying to write %d bytes to client\n",
+                           nbytes);
+                      nwritten = write (data_fd, buf + writer, nbytes);
+                      DBG (DBG_INFO, "do_scan: wrote %ld bytes to client\n",
+                           nwritten);
+                      if (nwritten < 0)
+                        {
+                          DBG (DBG_ERR, "do_scan: write failed (%s)\n",
+                               strerror (errno));
+                          status = SANE_STATUS_CANCELLED;
+                          handle[h].docancel = 1;
+                          break;
+                        }
+                      bytes_in_buf -= (size_t) nwritten;
+                      writer += (size_t) nwritten;
+                      if (writer == buffer_size)
+                        writer = 0;
+                    }
+                }
+            }
+          else if (status == SANE_STATUS_GOOD
+              && (timeout || FD_ISSET(be_fd, &rd_set)))
+            {
+              int i;
 
-	  assert (bytes_in_buf == 0);
-	  nbytes = sizeof (buf) - 4;
-	  if (reader + nbytes > sizeof (buf))
-	    nbytes = sizeof (buf) - reader;
+              /* get more input data */
 
-	  DBG (DBG_INFO,
-	       "do_scan: trying to read %d bytes from scanner\n", nbytes);
-	  status = sane_read (be_handle, buf + reader, nbytes, &length);
-	  DBG (DBG_INFO,
-	       "do_scan: read %d bytes from scanner\n", length);
+              /* reserve 4 bytes to store the length of the data record: */
+              i = reader;
+              reader += 4;
+              if (reader >= (int) buffer_size)
+                reader -= buffer_size;
 
-	  reset_watchdog ();
+              assert(bytes_in_buf == 0);
+              nbytes = buffer_size - 4;
+              if (reader + nbytes > buffer_size)
+                nbytes = buffer_size - reader;
 
-	  reader += length;
-	  if (reader >= (int) sizeof (buf))
-	    reader = 0;
-	  bytes_in_buf += length + 4;
+              DBG (DBG_INFO, "do_scan: trying to read %d bytes from scanner\n",
+                   nbytes);
+              status = sane_read (be_handle, buf + reader, nbytes, &length);
+              DBG (DBG_INFO, "do_scan: read %d bytes from scanner\n", length);
 
-	  if (status != SANE_STATUS_GOOD)
-	    {
-	      reader = i;	/* restore reader index */
-	      status_dirty = 1;
-	      DBG (DBG_MSG,
-		   "do_scan: status = `%s'\n", sane_strstatus(status));
-	    }
-	  else
-	    store_reclen (buf, sizeof (buf), i, length);
-	}
+              reset_watchdog ();
 
-      if (status_dirty && sizeof (buf) - bytes_in_buf >= 5)
-	{
-	  status_dirty = 0;
-	  reader = store_reclen (buf, sizeof (buf), reader, 0xffffffff);
-	  buf[reader] = status;
-	  bytes_in_buf += 5;
-	  DBG (DBG_MSG, "do_scan: statuscode `%s' was added to buffer\n",
-	       sane_strstatus(status));
-	}
+              reader += length;
+              if (reader >= (int) buffer_size)
+                reader = 0;
+              bytes_in_buf += length + 4;
 
-      if (FD_ISSET (w->io.fd, &rd_set))
-	{
-	  DBG (DBG_MSG,
-	       "do_scan: processing RPC request on fd %d\n", w->io.fd);
-	  if(process_request (w) < 0)
-	    handle[h].docancel = 1;
+              if (status != SANE_STATUS_GOOD)
+                {
+                  reader = i; /* restore reader index */
+                  status_dirty = 1;
+                  DBG (DBG_MSG, "do_scan: status = `%s'\n",
+                       sane_strstatus (status));
+                }
+              else
+                store_reclen (buf, buffer_size, i, length);
+            }
 
-	  if (handle[h].docancel)
-	    break;
-	}
+          if (status_dirty && buffer_size - bytes_in_buf >= 5)
+            {
+              status_dirty = 0;
+              reader = store_reclen (buf, buffer_size, reader, 0xffffffff);
+              buf[reader] = status;
+              bytes_in_buf += 5;
+              DBG (DBG_MSG, "do_scan: statuscode `%s' was added to buffer\n",
+                   sane_strstatus (status));
+            }
+
+          if (FD_ISSET(w->io.fd, &rd_set))
+            {
+              DBG (DBG_MSG, "do_scan: processing RPC request on fd %d\n",
+                   w->io.fd);
+              if (process_request (w) < 0)
+                handle[h].docancel = 1;
+
+              if (handle[h].docancel)
+                break;
+            }
+        }
+      while (status == SANE_STATUS_GOOD || bytes_in_buf > 0 || status_dirty);
+      DBG (DBG_MSG, "do_scan: done, status=%s\n", sane_strstatus (status));
+
+      free (buf);
+      buf = NULL;
     }
-  while (status == SANE_STATUS_GOOD || bytes_in_buf > 0 || status_dirty);
-  DBG (DBG_MSG, "do_scan: done, status=%s\n", sane_strstatus (status));
 
-  if(handle[h].docancel)
+  if (handle[h].docancel)
     sane_cancel (handle[h].handle);
 
   handle[h].docancel = 0;
@@ -2236,8 +2256,8 @@ process_request (Wire * w)
 		     strerror (errno));
 		return 1;
 	      }
-	    fcntl (data_fd, F_SETFL, 1);      /* set non-blocking */
-	    shutdown (data_fd, 0);
+	    fcntl (data_fd, F_SETFL, O_NONBLOCK);      /* set non-blocking */
+	    shutdown (data_fd, SHUT_RD);
 	    do_scan (w, h, data_fd);
 	    close (data_fd);
 	  }
@@ -3413,16 +3433,17 @@ static void usage(char *me, int err)
   fprintf (stderr,
        "Usage: %s [OPTIONS]\n\n"
        " Options:\n\n"
-       "  -a, --alone[=user]	equal to `-l -D -u user'\n"
-       "  -l, --listen		run in standalone mode (listen for connection)\n"
-       "  -u, --user=user	run as `user'\n"
-       "  -D, --daemonize	run in background\n"
-       "  -o, --once		exit after first client disconnects\n"
-       "  -d, --debug=level	set debug level `level' (default is 2)\n"
-       "  -e, --stderr		output to stderr\n"
-       "  -b, --bind=addr	bind address `addr' (default all interfaces)\n"
-       "  -p, --port=port	bind port `port` (default sane-port or 6566)\n"
-       "  -h, --help		show this help message and exit\n", me);
+       "  -a, --alone[=user]	        equal to `-l -D -u user'\n"
+       "  -l, --listen		        run in standalone mode (listen for connection)\n"
+       "  -u, --user=user	        run as `user'\n"
+       "  -D, --daemonize	        run in background\n"
+       "  -o, --once		        exit after first client disconnects\n"
+       "  -d, --debug=level	        set debug level `level' (default is 2)\n"
+       "  -e, --stderr		        output to stderr\n"
+       "  -b, --bind=addr	        bind address `addr' (default all interfaces)\n"
+       "  -p, --port=port               bind port `port` (default sane-port or 6566)\n"
+       "  -B, --buffer-size=size        set size of read buffer in KB (default: 1024)\n"
+       "  -h, --help		        show this help message and exit\n", me);
 
   exit(err);
 }
@@ -3432,17 +3453,18 @@ static int debug;
 static struct option long_options[] =
 {
 /* These options set a flag. */
-  {"help",	no_argument,		0, 'h'},
-  {"alone",	optional_argument,	0, 'a'},
-  {"listen",	no_argument,		0, 'l'},
-  {"user",	required_argument,	0, 'u'},
-  {"daemonize", no_argument,		0, 'D'},
-  {"once",	no_argument,		0, 'o'},
-  {"debug",	required_argument,	0, 'd'},
-  {"stderr",	no_argument,		0, 'e'},
-  {"bind",	required_argument,	0, 'b'},
-  {"port",	required_argument,	0, 'p'},
-  {0,		0,			0,  0 }
+  {"help",              no_argument,            0, 'h'},
+  {"alone",             optional_argument,      0, 'a'},
+  {"listen",            no_argument,            0, 'l'},
+  {"user",              required_argument,      0, 'u'},
+  {"daemonize",         no_argument,            0, 'D'},
+  {"once",              no_argument,            0, 'o'},
+  {"debug",             required_argument,      0, 'd'},
+  {"stderr",            no_argument,            0, 'e'},
+  {"bind",              required_argument,      0, 'b'},
+  {"port",              required_argument,      0, 'p'},
+  {"buffer-size",       required_argument,      0, 'B'},
+  {0,                   0,                      0,  0 }
 };
 
 int
@@ -3467,7 +3489,7 @@ main (int argc, char *argv[])
   run_foreground = SANE_TRUE;
   run_once = SANE_FALSE;
 
-  while((c = getopt_long(argc, argv,"ha::lu:Dod:eb:p:", long_options, &long_index )) != -1)
+  while((c = getopt_long(argc, argv,"ha::lu:Dod:eb:p:B:", long_options, &long_index )) != -1)
     {
       switch(c) {
       case 'a':
@@ -3498,8 +3520,25 @@ main (int argc, char *argv[])
 	bind_addr = optarg;
 	break;
       case 'p':
-	bind_port = atoi(optarg);
-	break;
+        bind_port = atoi(optarg);
+        break;
+      case 'B':
+        {
+          int buffer_arg = atoi(optarg);
+
+          if ((buffer_arg < 0) || ((size_t)buffer_arg > (SIZE_MAX / 1024)))
+            {
+              DBG (
+                  DBG_ERR,
+                  "saned: specified buffer size in KB is invalid. Default of %zuKB will be substituted.\n",
+                  buffer_size / 1024);
+            }
+          else
+            {
+              buffer_size = 1024 * (size_t)buffer_arg;
+            }
+          break;
+        }
       case 'h':
 	usage(argv[0], EXIT_SUCCESS);
 	break;
diff --git a/frontend/saned.socket b/frontend/saned.socket
new file mode 100644
index 0000000..1aa19e7
--- /dev/null
+++ b/frontend/saned.socket
@@ -0,0 +1,10 @@
+[Unit]
+Description=saned incoming socket
+
+[Socket]
+ListenStream=6566
+Accept=yes
+MaxConnections=1
+
+[Install]
+WantedBy=sockets.target
diff --git a/frontend/saned.xinetd.conf.in b/frontend/saned.xinetd.conf.in
new file mode 100644
index 0000000..3465dee
--- /dev/null
+++ b/frontend/saned.xinetd.conf.in
@@ -0,0 +1,13 @@
+# default: off
+# description: The sane server accepts requests
+# for network access to a local scanner via the
+# network.
+service sane-port
+{
+   port        = 6566
+   socket_type = stream
+   wait        = no
+   user        = saned
+   group       = saned
+   server      = @SBINDIR@/saned
+}
diff --git a/frontend/saned@.service.in b/frontend/saned@.service.in
new file mode 100644
index 0000000..1682109
--- /dev/null
+++ b/frontend/saned@.service.in
@@ -0,0 +1,11 @@
+[Unit]
+Description=Scanner Service
+Requires=saned.socket
+
+[Service]
+ExecStart=@SBINDIR@/saned
+User=saned
+Group=saned
+
+[Install]
+Also=saned.socket
diff --git a/frontend/scanimage.c b/frontend/scanimage.c
index d79d487..ff53157 100644
--- a/frontend/scanimage.c
+++ b/frontend/scanimage.c
@@ -39,15 +39,8 @@
 #include <string.h>
 #include <unistd.h>
 #include <stdarg.h>
-
-#ifdef __FreeBSD__
-#include <libgen.h>
-#endif
-
-#if defined (__APPLE__) && defined (__MACH__)
+#include <errno.h>
 #include <libgen.h>     // for basename()
-#endif
-
 #include <sys/types.h>
 #include <sys/stat.h>
 
@@ -111,7 +104,7 @@ static struct option basic_options[] = {
   {"test", no_argument, NULL, 'T'},
   {"all-options", no_argument, NULL, 'A'},
   {"version", no_argument, NULL, 'V'},
-  {"buffer-size", optional_argument, NULL, 'B'},
+  {"buffer-size", required_argument, NULL, 'B'},
   {"batch", optional_argument, NULL, 'b'},
   {"batch-count", required_argument, NULL, OPTION_BATCH_COUNT},
   {"batch-start", required_argument, NULL, OPTION_BATCH_START_AT},
@@ -133,29 +126,30 @@ static struct option basic_options[] = {
 #define OUTPUT_JPEG     4
 #define OUTPUT_PDF      5
 
-#define BASE_OPTSTRING	"d:hi:Lf:o:B::nvVTAbp"
+#define BASE_OPTSTRING	"d:hi:Lf:o:B:nvVTAbp"
 #define STRIP_HEIGHT	256	/* # lines we increment image height */
 
-static struct option *all_options;
-static int option_number_len;
-static int *option_number;
-static SANE_Handle device;
-static int verbose;
+static struct option *all_options = NULL;
+static int option_number_len = 0;
+static int *option_number = 0;
+static SANE_Handle device = 0;
+static int verbose = 0;
 static int progress = 0;
 static const char* output_file = NULL;
-static int test;
-static int all;
+static int test = 0;
+static int all = 0;
 static int output_format = OUTPUT_UNKNOWN;
-static int help;
+static int help = 0;
 static int dont_scan = 0;
-static const char *prog_name;
+static const char *prog_name = NULL;
 static int resolution_optind = -1, resolution_value = 0;
 
 /* window (area) related options */
-static SANE_Option_Descriptor window_option[4]; /*updated descs for x,y,l,t*/
-static int window[4]; /*index into backend options for x,y,l,t*/
-static SANE_Word window_val[2]; /*the value for x,y options*/
-static int window_val_user[2];	/* is x,y user-specified? */
+static SANE_Option_Descriptor window_option[4] = {0}; /*updated descs for x,y,l,t*/
+static int window[4] = {0}; /*index into backend options for x,y,l,t*/
+static SANE_Word window_val[2] = {0}; /*the value for x,y options*/
+static int window_val_user[2] = {0};	/* is x,y user-specified? */
+static char *full_optstring = NULL;
 
 static int accept_only_md5_auth = 0;
 static const char *icc_profile = NULL;
@@ -167,18 +161,16 @@ static SANE_Word tl_x = 0;
 static SANE_Word tl_y = 0;
 static SANE_Word br_x = 0;
 static SANE_Word br_y = 0;
-static SANE_Byte *buffer;
-static size_t buffer_size;
+static SANE_Byte *buffer = NULL;
+static size_t buffer_size = 0;
 
 
 static void
 auth_callback (SANE_String_Const resource,
 	       SANE_Char * username, SANE_Char * password)
 {
-  char tmp[3 + 128 + SANE_MAX_USERNAME_LEN + SANE_MAX_PASSWORD_LEN], *wipe;
-  unsigned char md5digest[16];
+  char tmp[3 + 128 + SANE_MAX_USERNAME_LEN + SANE_MAX_PASSWORD_LEN];
   int md5mode = 0, len, query_user = 1;
-  FILE *pass_file;
   struct stat stat_buf;
   char * uname = NULL;
 
@@ -202,6 +194,7 @@ auth_callback (SANE_String_Const resource,
 	}
       else
 	{
+          FILE *pass_file;
 
 	  if ((pass_file = fopen (tmp, "r")) != NULL)
 	    {
@@ -291,6 +284,7 @@ auth_callback (SANE_String_Const resource,
   if (query_user == 1)
     {
 #ifdef HAVE_GETPASS
+      char *wipe;
       strcpy (password, (wipe = getpass ("Enter password: ")));
       memset (wipe, 0, strlen (password));
 #else
@@ -300,6 +294,7 @@ auth_callback (SANE_String_Const resource,
 
   if (md5mode)
     {
+      unsigned char md5digest[16];
 
       sprintf (tmp, "%.128s%.*s", (strstr (resource, "$MD5$")) + 5,
 	       SANE_MAX_PASSWORD_LEN - 1, password);
@@ -323,10 +318,10 @@ auth_callback (SANE_String_Const resource,
 static void
 sighandler (int signum)
 {
-  static SANE_Bool first_time = SANE_TRUE;
-
   if (device)
     {
+      static SANE_Bool first_time = SANE_TRUE;
+
       fprintf (stderr, "%s: received signal %d\n", prog_name, signum);
       if (first_time)
 	{
@@ -1210,18 +1205,17 @@ write_png_header (SANE_Frame format, int width, int height, int depth, int dpi,
   /* There are nominally 39.3700787401575 inches in a meter. */
   const double pixels_per_meter = dpi * 39.3700787401575;
   size_t icc_size = 0;
-  void *icc_buffer;
 
   *png_ptr = png_create_write_struct
        (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
   if (!*png_ptr) {
     fprintf(stderr, "png_create_write_struct failed\n");
-    exit(1);
+    scanimage_exit (1);
   }
   *info_ptr = png_create_info_struct(*png_ptr);
   if (!*info_ptr) {
     fprintf(stderr, "png_create_info_struct failed\n");
-    exit(1);
+    scanimage_exit (1);
   }
   png_init_io(*png_ptr, ofp);
 
@@ -1249,7 +1243,7 @@ write_png_header (SANE_Frame format, int width, int height, int depth, int dpi,
 
   if (icc_profile)
     {
-      icc_buffer = sanei_load_icc_profile(icc_profile, &icc_size);
+      void *icc_buffer = sanei_load_icc_profile(icc_profile, &icc_size);
       if (icc_size > 0)
         {
 	  /* libpng will abort if the profile and image colour spaces do not match*/
@@ -1260,7 +1254,21 @@ write_png_header (SANE_Frame format, int width, int height, int depth, int dpi,
 	  if ((is_gray_profile && color_type == PNG_COLOR_TYPE_GRAY) ||
 	      (is_rgb_profile && color_type == PNG_COLOR_TYPE_RGB))
 	    {
-	      png_set_iCCP(*png_ptr, *info_ptr, basename(icc_profile), PNG_COMPRESSION_TYPE_BASE, icc_buffer, icc_size);
+	      char *icc_profile_cp = strdup(icc_profile);
+	      if (icc_profile_cp == NULL)
+	        {
+                  fprintf(stderr, "Memory allocation failure prevented the setting of PNG ICC profile.\n");
+	        }
+	      else
+	        {
+                  png_set_iCCP (*png_ptr,
+                                *info_ptr,
+                                basename (icc_profile_cp),
+                                PNG_COMPRESSION_TYPE_BASE,
+                                icc_buffer,
+                                icc_size);
+                  free(icc_profile_cp);
+	        }
 	    }
 	  else
 	    {
@@ -1625,11 +1633,11 @@ scan_it (FILE *ofp, void* pw)
 #ifdef HAVE_LIBPNG
 	      if (output_format == OUTPUT_PNG)
 	        {
-		  int i = 0;
+		  int idx = 0;
 		  int left = len;
 		  while(pngrow + left >= parm.bytes_per_line)
 		    {
-		      memcpy(pngbuf + pngrow, buffer + i, parm.bytes_per_line - pngrow);
+		      memcpy(pngbuf + pngrow, buffer + idx, parm.bytes_per_line - pngrow);
 		      if(parm.depth == 1)
 			{
 			  int j;
@@ -1652,11 +1660,11 @@ scan_it (FILE *ofp, void* pw)
                         }
 #endif
 		      png_write_row(png_ptr, pngbuf);
-		      i += parm.bytes_per_line - pngrow;
+		      idx += parm.bytes_per_line - pngrow;
 		      left -= parm.bytes_per_line - pngrow;
 		      pngrow = 0;
 		    }
-		  memcpy(pngbuf + pngrow, buffer + i, left);
+		  memcpy(pngbuf + pngrow, buffer + idx, left);
 		  pngrow += left;
 		}
 	      else
@@ -1664,28 +1672,28 @@ scan_it (FILE *ofp, void* pw)
 #ifdef HAVE_LIBJPEG
 	      if (output_format == OUTPUT_JPEG || output_format == OUTPUT_PDF)
 	        {
-		  int i = 0;
+		  int idx = 0;
 		  int left = len;
 		  while(jpegrow + left >= parm.bytes_per_line)
 		    {
-		      memcpy(jpegbuf + jpegrow, buffer + i, parm.bytes_per_line - jpegrow);
+		      memcpy(jpegbuf + jpegrow, buffer + idx, parm.bytes_per_line - jpegrow);
 		      if(parm.depth == 1)
 			{
 			  int col1, col8;
 			  JSAMPLE *buf8 = malloc(parm.bytes_per_line * 8);
 			  for(col1 = 0; col1 < parm.bytes_per_line; col1++)
 			    for(col8 = 0; col8 < 8; col8++)
-			      buf8[col1 * 8 + col8] = jpegbuf[col1] & (1 << (8 - col8 - 1)) ? 0 : 0xff;
+			      buf8[col1 * 8 + col8] = (jpegbuf[col1] & (1 << (8 - col8 - 1))) ? 0 : 0xff;
 		          jpeg_write_scanlines(&cinfo, &buf8, 1);
 			  free(buf8);
 			} else {
 		          jpeg_write_scanlines(&cinfo, &jpegbuf, 1);
 			}
-		      i += parm.bytes_per_line - jpegrow;
+		      idx += parm.bytes_per_line - jpegrow;
 		      left -= parm.bytes_per_line - jpegrow;
 		      jpegrow = 0;
 		    }
-		  memcpy(jpegbuf + jpegrow, buffer + i, left);
+		  memcpy(jpegbuf + jpegrow, buffer + idx, left);
 		  jpegrow += left;
 		}
 	      else
@@ -1695,7 +1703,7 @@ scan_it (FILE *ofp, void* pw)
 	      else
 		{
 #if !defined(WORDS_BIGENDIAN)
-		  int i, start = 0;
+		  int start = 0;
 
 		  /* check if we have saved one byte from the last sane_read */
 		  if (hang_over > -1)
@@ -1709,12 +1717,12 @@ scan_it (FILE *ofp, void* pw)
 			}
 		    }
 		  /* now do the byte-swapping */
-		  for (i = start; i < (len - 1); i += 2)
+		  for (int idx = start; idx < (len - 1); idx += 2)
 		    {
 		      unsigned char LSB;
-		      LSB = buffer[i];
-		      buffer[i] = buffer[i + 1];
-		      buffer[i + 1] = LSB;
+		      LSB = buffer[idx];
+		      buffer[idx] = buffer[idx + 1];
+		      buffer[idx + 1] = LSB;
 		    }
 		  /* check if we have an odd number of bytes */
 		  if (((len - start) % 2) != 0)
@@ -1783,13 +1791,12 @@ scan_it (FILE *ofp, void* pw)
       /* FIXME: other bit depths? */
       if (output_format != OUTPUT_TIFF && parm.depth == 16)
 	{
-	  int i;
-	  for (i = 0; i < image.height * image.width; i += 2)
+	  for (int idx = 0; idx < image.height * image.width; idx += 2)
 	    {
 	      unsigned char LSB;
-	      LSB = image.data[i];
-	      image.data[i] = image.data[i + 1];
-	      image.data[i + 1] = LSB;
+	      LSB = image.data[idx];
+	      image.data[idx] = image.data[idx + 1];
+	      image.data[idx + 1] = LSB;
 	    }
 	}
 #endif
@@ -1996,6 +2003,8 @@ scanimage_exit (int status)
     fprintf (stderr, "Calling sane_exit\n");
   sane_exit ();
 
+  if (full_optstring)
+    free(full_optstring);
   if (all_options)
     free (all_options);
   if (option_number)
@@ -2013,15 +2022,12 @@ scanimage_exit (int status)
  */
 static void print_options(SANE_Device * device, SANE_Int num_dev_options, SANE_Bool ro)
 {
-  int i, j;
-  const SANE_Option_Descriptor *opt;
-
-  for (i = 1; i < num_dev_options; ++i)
+  for (int i = 1; i < num_dev_options; ++i)
     {
-      opt = 0;
+      const SANE_Option_Descriptor *opt = 0;
 
       /* scan area uses modified option struct */
-      for (j = 0; j < 4; ++j)
+      for (int j = 0; j < 4; ++j)
 	if (i == window[j])
 	  opt = window_option + j;
 
@@ -2072,36 +2078,31 @@ static int guess_output_format(const char* output_file)
         }
     }
 
-  // it would be very confusing if user makes a typo in the filename and the output format changes.
-  // This is most likely not what the user wanted.
-  fprintf(stderr, "Could not guess output format from the given path and no --format given.\n");
-  exit(1);
+  return OUTPUT_UNKNOWN;
 }
 
 int
 main (int argc, char **argv)
 {
-  int ch, i, index, all_options_len;
+  int ch, index;
   const SANE_Device **device_list;
   SANE_Int num_dev_options = 0;
   const char *devname = 0;
   const char *defdevname = 0;
   const char *format = 0;
-  char readbuf[2];
-  char *readbuf2;
   int batch = 0;
   int batch_print = 0;
   int batch_prompt = 0;
   int batch_count = BATCH_COUNT_UNLIMITED;
   int batch_start_at = 1;
   int batch_increment = 1;
+  int promptc;
   SANE_Status status;
-  char *full_optstring;
   SANE_Int version_code;
   void *pw = NULL;
   FILE *ofp = NULL;
 
-  buffer_size = (32 * 1024);	/* default size */
+  buffer_size = (1024 * 1024);	/* default size */
 
   prog_name = strrchr (argv[0], '/');
   if (prog_name)
@@ -2148,10 +2149,7 @@ main (int argc, char **argv)
           output_file = optarg;
           break;
 	case 'B':
-          if (optarg)
-	    buffer_size = 1024 * atoi(optarg);
-          else
-	    buffer_size = (1024 * 1024);
+          buffer_size = 1024 * atoi(optarg);
 	  break;
 	case 'T':
 	  test = 1;
@@ -2190,7 +2188,7 @@ main (int argc, char **argv)
 	      output_format = OUTPUT_PNG;
 #else
 	      fprintf(stderr, "PNG support not compiled in\n");
-	      exit(1);
+	      scanimage_exit (1);
 #endif
 	    }
 	  else if (strcmp (optarg, "jpeg") == 0)
@@ -2199,7 +2197,7 @@ main (int argc, char **argv)
 	      output_format = OUTPUT_JPEG;
 #else
 	      fprintf(stderr, "JPEG support not compiled in\n");
-	      exit(1);
+	      scanimage_exit (1);
 #endif
 	    }
 	  else if (strcmp (optarg, "pdf") == 0)
@@ -2208,7 +2206,7 @@ main (int argc, char **argv)
 	      output_format = OUTPUT_PDF;
 #else
 	      fprintf(stderr, "PDF support not compiled in\n");
-	      exit(1);
+	      scanimage_exit (1);
 #endif
 	    }
           else if (strcmp (optarg, "pnm") == 0)
@@ -2226,7 +2224,7 @@ main (int argc, char **argv)
               fprintf(stderr, ", jpeg");
 #endif
               fprintf(stderr, ".\n");
-              exit(1);
+              scanimage_exit (1);
             }
 	  break;
 	case OPTION_MD5:
@@ -2256,14 +2254,14 @@ main (int argc, char **argv)
 	      }
 	    else
 	      {
-		int i = 0, int_arg = 0;
-		const char *percent, *start;
+		int int_arg = 0;
+		const char *percent;
 		const char *text_arg = 0;
 		char ftype;
 
-		for (i = 0; device_list[i]; ++i)
+		for (int dev_num = 0; device_list[dev_num]; ++dev_num)
 		  {
-		    start = optarg;
+		    const char *start = optarg;
 		    while (*start && (percent = strchr (start, '%')))
 		      {
 			int start_len = percent - start;
@@ -2273,23 +2271,23 @@ main (int argc, char **argv)
 			    switch (*percent)
 			      {
 			      case 'd':
-				text_arg = device_list[i]->name;
+				text_arg = device_list[dev_num]->name;
 				ftype = 's';
 				break;
 			      case 'v':
-				text_arg = device_list[i]->vendor;
+				text_arg = device_list[dev_num]->vendor;
 				ftype = 's';
 				break;
 			      case 'm':
-				text_arg = device_list[i]->model;
+				text_arg = device_list[dev_num]->model;
 				ftype = 's';
 				break;
 			      case 't':
-				text_arg = device_list[i]->type;
+				text_arg = device_list[dev_num]->type;
 				ftype = 's';
 				break;
 			      case 'i':
-				int_arg = i;
+				int_arg = dev_num;
 				ftype = 'i';
 				break;
 			      case 'n':
@@ -2401,12 +2399,20 @@ Parameters are separated by a blank from single-character options (e.g.\n\
   if (batch && output_file != NULL)
     {
       fprintf(stderr, "--batch and --output-file can't be used together.\n");
-      exit(1);
+      scanimage_exit (1);
     }
 
   if (output_format == OUTPUT_UNKNOWN)
-    output_format = guess_output_format(output_file);
-
+    {
+      output_format = guess_output_format(output_file);
+      if (output_format == OUTPUT_UNKNOWN)
+        {
+          // it would be very confusing if user makes a typo in the filename and the output format changes.
+          // This is most likely not what the user wanted.
+          fprintf(stderr, "Could not guess output format from the given path and no --format given.\n");
+          scanimage_exit (1);
+        }
+    }
   if (!devname)
     {
       /* If no device name was specified explicitly, we look at the
@@ -2474,7 +2480,7 @@ Parameters are separated by a blank from single-character options (e.g.\n\
 	}
 
       /* malloc global option lists */
-      all_options_len = num_dev_options + NELEMS (basic_options) + 1;
+      int all_options_len = num_dev_options + NELEMS (basic_options) + 1;
       all_options = malloc (all_options_len * sizeof (all_options[0]));
       option_number_len = num_dev_options;
       option_number = malloc (option_number_len * sizeof (option_number[0]));
@@ -2579,6 +2585,7 @@ Parameters are separated by a blank from single-character options (e.g.\n\
 	}
 
       free (full_optstring);
+      full_optstring = NULL;
 
       /* convert x/y to br_x/br_y */
       for (index = 0; index < 2; ++index)
@@ -2624,7 +2631,7 @@ List of available devices:", prog_name);
 	{
 	  int column = 80;
 
-	  for (i = 0; device_list[i]; ++i)
+	  for (int i = 0; device_list[i]; ++i)
 	    {
 	      if (column + strlen (device_list[i]->name) + 1 >= 80)
 		{
@@ -2741,21 +2748,19 @@ List of available devices:", prog_name);
 	      if (output_format != OUTPUT_PDF)
 #endif
      	         strcat (part_path, ".part");
-	    }
 
-
-	  if (batch)
-	    {
 	      if (batch_prompt)
 		{
 		  fprintf (stderr, "Place document no. %d on the scanner.\n",
 			   n);
 		  fprintf (stderr, "Press <RETURN> to continue.\n");
-		  fprintf (stderr, "Press Ctrl + D to terminate.\n");
-		  readbuf2 = fgets (readbuf, 2, stdin);
+		  fprintf (stderr, "Press Ctrl + D (EOF) to terminate.\n");
+		  while ((promptc = getchar()) != '\n' && promptc != EOF);
 
-		  if (readbuf2 == NULL)
+		  if (promptc == EOF)
 		    {
+		      if (ferror(stdin))
+			fprintf(stderr, "%s: stdin error: %s\n", prog_name, strerror(errno));
 		      if (ofp)
 			{
 #ifdef HAVE_LIBJPEG
-- 
cgit v1.2.3