1141cc406Sopenharmony_ci/*
2141cc406Sopenharmony_ci  sane - Scanner Access Now Easy.
3141cc406Sopenharmony_ci  Copyright (C) 2006 Jon Chambers <jon@jon.demon.co.uk>
4141cc406Sopenharmony_ci
5141cc406Sopenharmony_ci  This file is part of the SANE package.
6141cc406Sopenharmony_ci
7141cc406Sopenharmony_ci  This program is free software; you can redistribute it and/or
8141cc406Sopenharmony_ci  modify it under the terms of the GNU General Public License as
9141cc406Sopenharmony_ci  published by the Free Software Foundation; either version 2 of the
10141cc406Sopenharmony_ci  License, or (at your option) any later version.
11141cc406Sopenharmony_ci
12141cc406Sopenharmony_ci  This program is distributed in the hope that it will be useful, but
13141cc406Sopenharmony_ci  WITHOUT ANY WARRANTY; without even the implied warranty of
14141cc406Sopenharmony_ci  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15141cc406Sopenharmony_ci  General Public License for more details.
16141cc406Sopenharmony_ci
17141cc406Sopenharmony_ci  You should have received a copy of the GNU General Public License
18141cc406Sopenharmony_ci  along with this program.  If not, see <https://www.gnu.org/licenses/>.
19141cc406Sopenharmony_ci
20141cc406Sopenharmony_ci  As a special exception, the authors of SANE give permission for
21141cc406Sopenharmony_ci  additional uses of the libraries contained in this release of SANE.
22141cc406Sopenharmony_ci
23141cc406Sopenharmony_ci  The exception is that, if you link a SANE library with other files
24141cc406Sopenharmony_ci  to produce an executable, this does not by itself cause the
25141cc406Sopenharmony_ci  resulting executable to be covered by the GNU General Public
26141cc406Sopenharmony_ci  License.  Your use of that executable is in no way restricted on
27141cc406Sopenharmony_ci  account of linking the SANE library code into it.
28141cc406Sopenharmony_ci
29141cc406Sopenharmony_ci  This exception does not, however, invalidate any other reasons why
30141cc406Sopenharmony_ci  the executable file might be covered by the GNU General Public
31141cc406Sopenharmony_ci  License.
32141cc406Sopenharmony_ci
33141cc406Sopenharmony_ci  If you submit changes to SANE to the maintainers to be included in
34141cc406Sopenharmony_ci  a subsequent release, you agree by submitting the changes that
35141cc406Sopenharmony_ci  those changes may be distributed with this exception intact.
36141cc406Sopenharmony_ci
37141cc406Sopenharmony_ci  If you write modifications of your own for SANE, it is your choice
38141cc406Sopenharmony_ci  whether to permit this exception to apply to your modifications.
39141cc406Sopenharmony_ci  If you do not wish that, delete this exception notice.
40141cc406Sopenharmony_ci
41141cc406Sopenharmony_ci  Dell 1600n network scan driver for SANE.
42141cc406Sopenharmony_ci
43141cc406Sopenharmony_ci  To debug:
44141cc406Sopenharmony_ci  SANE_DEBUG_DELL1600N_NET=255 scanimage --verbose 2>scan.errs 1>scan.png
45141cc406Sopenharmony_ci*/
46141cc406Sopenharmony_ci
47141cc406Sopenharmony_ci/***********************************************************
48141cc406Sopenharmony_ci * INCLUDES
49141cc406Sopenharmony_ci ***********************************************************/
50141cc406Sopenharmony_ci
51141cc406Sopenharmony_ci#include "../include/sane/config.h"
52141cc406Sopenharmony_ci#include "../include/sane/sane.h"
53141cc406Sopenharmony_ci#include "../include/sane/sanei.h"
54141cc406Sopenharmony_ci
55141cc406Sopenharmony_ci#define BACKEND_NAME    dell1600n_net
56141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h"
57141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h"
58141cc406Sopenharmony_ci
59141cc406Sopenharmony_ci#include <stdlib.h>
60141cc406Sopenharmony_ci#include <string.h>
61141cc406Sopenharmony_ci#include <stdio.h>
62141cc406Sopenharmony_ci#include <math.h>
63141cc406Sopenharmony_ci#include <unistd.h>
64141cc406Sopenharmony_ci
65141cc406Sopenharmony_ci/* :NOTE: these are likely to be platform-specific! */
66141cc406Sopenharmony_ci#include <sys/types.h>
67141cc406Sopenharmony_ci#include <sys/socket.h>
68141cc406Sopenharmony_ci#include <sys/time.h>
69141cc406Sopenharmony_ci#include <netinet/in.h>
70141cc406Sopenharmony_ci#include <netdb.h>
71141cc406Sopenharmony_ci
72141cc406Sopenharmony_ci#include <jpeglib.h>
73141cc406Sopenharmony_ci#include <tiffio.h>
74141cc406Sopenharmony_ci
75141cc406Sopenharmony_ci/* OS/2... */
76141cc406Sopenharmony_ci#ifndef SHUT_RDWR
77141cc406Sopenharmony_ci#define SHUT_RDWR 2
78141cc406Sopenharmony_ci#endif
79141cc406Sopenharmony_ci
80141cc406Sopenharmony_ci
81141cc406Sopenharmony_ci/***********************************************************
82141cc406Sopenharmony_ci * DEFINITIONS
83141cc406Sopenharmony_ci ***********************************************************/
84141cc406Sopenharmony_ci
85141cc406Sopenharmony_ci/* Maximum number of scanners */
86141cc406Sopenharmony_ci#define MAX_SCANNERS 32
87141cc406Sopenharmony_ci
88141cc406Sopenharmony_ci/* version number */
89141cc406Sopenharmony_ci#define DRIVER_VERSION SANE_VERSION_CODE( SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, 0 )
90141cc406Sopenharmony_ci
91141cc406Sopenharmony_ci/* size of buffer for socket communication */
92141cc406Sopenharmony_ci#define SOCK_BUF_SIZE 2048
93141cc406Sopenharmony_ci
94141cc406Sopenharmony_ci/* size of registation name */
95141cc406Sopenharmony_ci#define REG_NAME_SIZE 64
96141cc406Sopenharmony_ci
97141cc406Sopenharmony_cistruct DeviceRecord
98141cc406Sopenharmony_ci{
99141cc406Sopenharmony_ci  SANE_Device m_device;
100141cc406Sopenharmony_ci  char * m_pName;        /* storage of name */
101141cc406Sopenharmony_ci  char * m_pModel;       /* storage of model */
102141cc406Sopenharmony_ci};
103141cc406Sopenharmony_ci
104141cc406Sopenharmony_ci/* a buffer struct to store "stuff" */
105141cc406Sopenharmony_cistruct ComBuf
106141cc406Sopenharmony_ci{
107141cc406Sopenharmony_ci  size_t m_capacity;		/* current allocated size in bytes */
108141cc406Sopenharmony_ci  size_t m_used;		/* current used size in bytes */
109141cc406Sopenharmony_ci  unsigned char *m_pBuf;	/* storage (or NULL if none allocated) */
110141cc406Sopenharmony_ci};
111141cc406Sopenharmony_ci
112141cc406Sopenharmony_ci/* state data for a single scanner connection */
113141cc406Sopenharmony_cistruct ScannerState
114141cc406Sopenharmony_ci{
115141cc406Sopenharmony_ci  int m_udpFd;			/* file descriptor to UDP socket */
116141cc406Sopenharmony_ci  int m_tcpFd;			/* file descriptor to TCP socket */
117141cc406Sopenharmony_ci  struct sockaddr_in m_sockAddr;	/* printer address */
118141cc406Sopenharmony_ci  struct ComBuf m_buf;		/* buffer for network data */
119141cc406Sopenharmony_ci  struct ComBuf m_imageData;	/* storage for decoded image data */
120141cc406Sopenharmony_ci  int m_numPages;	        /* number of complete pages (host byte order) */
121141cc406Sopenharmony_ci  struct ComBuf m_pageInfo;	/* "array" of numPages PageInfo structs */
122141cc406Sopenharmony_ci  int m_bFinish;		/* set non-0 to signal that we are finished */
123141cc406Sopenharmony_ci  int m_bCancelled;		/* set non-0 that bFinish state arose from cancellation */
124141cc406Sopenharmony_ci  char m_regName[REG_NAME_SIZE];	/* name with which to register */
125141cc406Sopenharmony_ci  unsigned short m_xres;	/* x resolution (network byte order) */
126141cc406Sopenharmony_ci  unsigned short m_yres;	/* y resolution (network byte order) */
127141cc406Sopenharmony_ci  unsigned int m_composition;	/* composition (0x01=>TIFF/PDF,0x40=>JPEG) (network byte order) */
128141cc406Sopenharmony_ci  unsigned char m_brightness;	/* brightness */
129141cc406Sopenharmony_ci  unsigned int m_compression;	/* compression (0x08=>CCIT Group 4,0x20=>JPEG) (network byte order) */
130141cc406Sopenharmony_ci  unsigned int m_fileType;	/* file type (2=>TIFF,4=>PDF,8=>JPEG)(network byte order) */
131141cc406Sopenharmony_ci  unsigned int m_pixelWidth;	/* width in pixels (network byte order) */
132141cc406Sopenharmony_ci  unsigned int m_pixelHeight;	/* height in pixels (network byte order) */
133141cc406Sopenharmony_ci  unsigned int m_bytesRead;	/* bytes read by SANE (host byte order) */
134141cc406Sopenharmony_ci  unsigned int m_currentPageBytes;/* number of bytes of current page read (host byte order) */
135141cc406Sopenharmony_ci};
136141cc406Sopenharmony_ci
137141cc406Sopenharmony_ci/* state data for a single page
138141cc406Sopenharmony_ci   NOTE: all ints are in host byte order
139141cc406Sopenharmony_ci*/
140141cc406Sopenharmony_cistruct PageInfo
141141cc406Sopenharmony_ci{
142141cc406Sopenharmony_ci  int m_width;                 /* pixel width */
143141cc406Sopenharmony_ci  int m_height;                /* pixel height */
144141cc406Sopenharmony_ci  int m_totalSize;             /* total page size (bytes) */
145141cc406Sopenharmony_ci  int m_bytesRemaining;        /* number of bytes not yet passed to SANE client */
146141cc406Sopenharmony_ci};
147141cc406Sopenharmony_ci
148141cc406Sopenharmony_ci/* struct for in-memory jpeg decompression */
149141cc406Sopenharmony_cistruct JpegDataDecompState
150141cc406Sopenharmony_ci{
151141cc406Sopenharmony_ci  struct jpeg_decompress_struct m_cinfo;	/* base struct */
152141cc406Sopenharmony_ci  unsigned char *m_pData;	/* data pointer */
153141cc406Sopenharmony_ci  unsigned int m_bytesRemaining;	/* amount of unprocessed data */
154141cc406Sopenharmony_ci};
155141cc406Sopenharmony_ci
156141cc406Sopenharmony_ci/* initial ComBuf allocation */
157141cc406Sopenharmony_ci#define INITIAL_COM_BUF_SIZE 1024
158141cc406Sopenharmony_ci
159141cc406Sopenharmony_ci/***********************************************************
160141cc406Sopenharmony_ci * FUNCTION PROTOTYPES
161141cc406Sopenharmony_ci ***********************************************************/
162141cc406Sopenharmony_ci
163141cc406Sopenharmony_ci/* print hex buffer to stdout */
164141cc406Sopenharmony_cistatic void HexDump (int debugLevel, const unsigned char *buf,
165141cc406Sopenharmony_ci		     size_t bufSize);
166141cc406Sopenharmony_ci
167141cc406Sopenharmony_ci/* clears gKnownDevices array */
168141cc406Sopenharmony_cistatic void ClearKnownDevices (void);
169141cc406Sopenharmony_ci
170141cc406Sopenharmony_ci/* initialise a ComBuf struct */
171141cc406Sopenharmony_cistatic int InitComBuf (struct ComBuf *pBuf);
172141cc406Sopenharmony_ci
173141cc406Sopenharmony_ci/* free a ComBuf struct */
174141cc406Sopenharmony_cistatic void FreeComBuf (struct ComBuf *pBuf);
175141cc406Sopenharmony_ci
176141cc406Sopenharmony_ci/* add data to a ComBuf struct */
177141cc406Sopenharmony_cistatic int AppendToComBuf (struct ComBuf *pBuf, const unsigned char *pData,
178141cc406Sopenharmony_ci			   size_t datSize);
179141cc406Sopenharmony_ci
180141cc406Sopenharmony_ci/* remove data from the front of a ComBuf struct */
181141cc406Sopenharmony_cistatic int PopFromComBuf (struct ComBuf *pBuf, size_t datSize);
182141cc406Sopenharmony_ci
183141cc406Sopenharmony_ci/* initialise a packet */
184141cc406Sopenharmony_cistatic int InitPacket (struct ComBuf *pBuf, char type);
185141cc406Sopenharmony_ci
186141cc406Sopenharmony_ci/* append message to a packet */
187141cc406Sopenharmony_cistatic int AppendMessageToPacket (struct ComBuf *pBuf,
188141cc406Sopenharmony_ci				  char messageType,
189141cc406Sopenharmony_ci				  char *messageName,
190141cc406Sopenharmony_ci				  char valueType,
191141cc406Sopenharmony_ci				  void *pValue, size_t valueLen);
192141cc406Sopenharmony_ci
193141cc406Sopenharmony_ci/* write length data to packet header */
194141cc406Sopenharmony_cistatic void FinalisePacket (struct ComBuf *pBuf);
195141cc406Sopenharmony_ci
196141cc406Sopenharmony_ci/* \return 1 if message is complete, 0 otherwise */
197141cc406Sopenharmony_cistatic int MessageIsComplete (unsigned char *pData, size_t size);
198141cc406Sopenharmony_ci
199141cc406Sopenharmony_ci/* process a registration broadcast response
200141cc406Sopenharmony_ci   \return DeviceRecord pointer on success (caller frees), NULL on failure
201141cc406Sopenharmony_ci*/
202141cc406Sopenharmony_cistatic struct DeviceRecord *ProcessFindResponse (unsigned char *pData, size_t size);
203141cc406Sopenharmony_ci
204141cc406Sopenharmony_ci/* frees a scanner state struct stored in gOpenScanners */
205141cc406Sopenharmony_cistatic void FreeScannerState (int iHandle);
206141cc406Sopenharmony_ci
207141cc406Sopenharmony_ci/* \return 1 if iHandle is a valid member of gOpenScanners, 0 otherwise */
208141cc406Sopenharmony_cistatic int ValidScannerNumber (int iHandle);
209141cc406Sopenharmony_ci
210141cc406Sopenharmony_ci/* process UDP responses, \return 0 in success, >0 otherwise */
211141cc406Sopenharmony_cistatic int ProcessUdpResponse (unsigned char *pData, size_t size,
212141cc406Sopenharmony_ci			       struct ScannerState *pState);
213141cc406Sopenharmony_ci
214141cc406Sopenharmony_ci/* process TCP responses, \return 0 in success, >0 otherwise */
215141cc406Sopenharmony_cistatic int ProcessTcpResponse (struct ScannerState *pState,
216141cc406Sopenharmony_ci			       struct ComBuf *pTcpBufBuf);
217141cc406Sopenharmony_ci
218141cc406Sopenharmony_ci/* Process the data from a single scanned page, \return 0 in success, >0 otherwise */
219141cc406Sopenharmony_cistatic int ProcessPageData (struct ScannerState *pState);
220141cc406Sopenharmony_ci
221141cc406Sopenharmony_ci/* Libjpeg decompression interface */
222141cc406Sopenharmony_cistatic void JpegDecompInitSource (j_decompress_ptr cinfo);
223141cc406Sopenharmony_cistatic boolean JpegDecompFillInputBuffer (j_decompress_ptr cinfo);
224141cc406Sopenharmony_cistatic void JpegDecompSkipInputData (j_decompress_ptr cinfo, long numBytes);
225141cc406Sopenharmony_cistatic void JpegDecompTermSource (j_decompress_ptr cinfo);
226141cc406Sopenharmony_ci
227141cc406Sopenharmony_ci/***********************************************************
228141cc406Sopenharmony_ci * GLOBALS
229141cc406Sopenharmony_ci ***********************************************************/
230141cc406Sopenharmony_ci
231141cc406Sopenharmony_ci/* Results of last call to sane_get_devices */
232141cc406Sopenharmony_cistatic struct DeviceRecord *gKnownDevices[MAX_SCANNERS];
233141cc406Sopenharmony_ci
234141cc406Sopenharmony_ci/* Empty list for when network devices are not wanted */
235141cc406Sopenharmony_cistatic const SANE_Device *gEmptyDeviceList[1];
236141cc406Sopenharmony_ci
237141cc406Sopenharmony_ci/* Array of open scanner device states.
238141cc406Sopenharmony_ci   :NOTE: (int)SANE_Handle is an offset into this array */
239141cc406Sopenharmony_cistatic struct ScannerState *gOpenScanners[MAX_SCANNERS];
240141cc406Sopenharmony_ci
241141cc406Sopenharmony_ci/* scanner port */
242141cc406Sopenharmony_cistatic unsigned short gScannerPort = 1124;
243141cc406Sopenharmony_ci
244141cc406Sopenharmony_ci/* ms to wait for registration replies */
245141cc406Sopenharmony_cistatic unsigned short gRegReplyWaitMs = 300;
246141cc406Sopenharmony_ci
247141cc406Sopenharmony_ci/***********************************************************
248141cc406Sopenharmony_ci * FUNCTION IMPLEMENTATIONS
249141cc406Sopenharmony_ci ***********************************************************/
250141cc406Sopenharmony_ci
251141cc406Sopenharmony_ciSANE_Status
252141cc406Sopenharmony_cisane_init (SANE_Int * version_code,
253141cc406Sopenharmony_ci	   SANE_Auth_Callback __sane_unused__ authorize)
254141cc406Sopenharmony_ci{
255141cc406Sopenharmony_ci
256141cc406Sopenharmony_ci  /* init globals */
257141cc406Sopenharmony_ci  memset (gKnownDevices, 0, sizeof (gKnownDevices));
258141cc406Sopenharmony_ci  memset (gOpenScanners, 0, sizeof (gOpenScanners));
259141cc406Sopenharmony_ci
260141cc406Sopenharmony_ci  /* report version */
261141cc406Sopenharmony_ci  *version_code = DRIVER_VERSION;
262141cc406Sopenharmony_ci
263141cc406Sopenharmony_ci  /* init debug */
264141cc406Sopenharmony_ci  DBG_INIT ();
265141cc406Sopenharmony_ci
266141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
267141cc406Sopenharmony_ci
268141cc406Sopenharmony_ci} /* sane_init */
269141cc406Sopenharmony_ci
270141cc406Sopenharmony_ci/***********************************************************/
271141cc406Sopenharmony_ci
272141cc406Sopenharmony_civoid
273141cc406Sopenharmony_cisane_exit (void)
274141cc406Sopenharmony_ci{
275141cc406Sopenharmony_ci
276141cc406Sopenharmony_ci  int iHandle;
277141cc406Sopenharmony_ci
278141cc406Sopenharmony_ci  /* clean up */
279141cc406Sopenharmony_ci  ClearKnownDevices ();
280141cc406Sopenharmony_ci
281141cc406Sopenharmony_ci  for (iHandle = 0; iHandle < MAX_SCANNERS; ++iHandle)
282141cc406Sopenharmony_ci    {
283141cc406Sopenharmony_ci      if (gOpenScanners[iHandle])
284141cc406Sopenharmony_ci	FreeScannerState (iHandle);
285141cc406Sopenharmony_ci    }
286141cc406Sopenharmony_ci
287141cc406Sopenharmony_ci} /* sane_exit */
288141cc406Sopenharmony_ci
289141cc406Sopenharmony_ci/***********************************************************/
290141cc406Sopenharmony_ci
291141cc406Sopenharmony_ciSANE_Status
292141cc406Sopenharmony_cisane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
293141cc406Sopenharmony_ci{
294141cc406Sopenharmony_ci
295141cc406Sopenharmony_ci  int ret;
296141cc406Sopenharmony_ci  unsigned char sockBuf[SOCK_BUF_SIZE];
297141cc406Sopenharmony_ci  int sock, optYes;
298141cc406Sopenharmony_ci  struct DeviceRecord *pDevice;
299141cc406Sopenharmony_ci  struct ComBuf queryPacket;
300141cc406Sopenharmony_ci  struct sockaddr_in remoteAddr;
301141cc406Sopenharmony_ci  unsigned char ucVal;
302141cc406Sopenharmony_ci  fd_set readFds;
303141cc406Sopenharmony_ci  struct timeval selTimeVal;
304141cc406Sopenharmony_ci  int nread, iNextDevice;
305141cc406Sopenharmony_ci  FILE *fConfig;
306141cc406Sopenharmony_ci  char configBuf[ 256 ];
307141cc406Sopenharmony_ci  const char *pVal;
308141cc406Sopenharmony_ci  int valLen;
309141cc406Sopenharmony_ci
310141cc406Sopenharmony_ci  if (local_only) {
311141cc406Sopenharmony_ci    *device_list = gEmptyDeviceList;
312141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
313141cc406Sopenharmony_ci  }
314141cc406Sopenharmony_ci
315141cc406Sopenharmony_ci  /* init variables */
316141cc406Sopenharmony_ci  ret = SANE_STATUS_GOOD;
317141cc406Sopenharmony_ci  sock = 0;
318141cc406Sopenharmony_ci  pDevice = NULL;
319141cc406Sopenharmony_ci  optYes = 1;
320141cc406Sopenharmony_ci
321141cc406Sopenharmony_ci  InitComBuf (&queryPacket);
322141cc406Sopenharmony_ci
323141cc406Sopenharmony_ci  /* clear previous results */
324141cc406Sopenharmony_ci  ClearKnownDevices ();
325141cc406Sopenharmony_ci  iNextDevice = 0;
326141cc406Sopenharmony_ci
327141cc406Sopenharmony_ci  /* look for a config file */
328141cc406Sopenharmony_ci  fConfig = sanei_config_open( "dell1600n_net.conf" );
329141cc406Sopenharmony_ci  if ( fConfig )
330141cc406Sopenharmony_ci    {
331141cc406Sopenharmony_ci      while ( ! feof( fConfig ) )
332141cc406Sopenharmony_ci        {
333141cc406Sopenharmony_ci          if ( ! sanei_config_read ( configBuf, sizeof( configBuf ), fConfig ) ) break;
334141cc406Sopenharmony_ci
335141cc406Sopenharmony_ci          /* skip whitespace */
336141cc406Sopenharmony_ci          pVal = sanei_config_skip_whitespace ( configBuf );
337141cc406Sopenharmony_ci
338141cc406Sopenharmony_ci          /* skip comments */
339141cc406Sopenharmony_ci          if ( *pVal == '#' ) continue;
340141cc406Sopenharmony_ci
341141cc406Sopenharmony_ci          /* process named_scanner */
342141cc406Sopenharmony_ci          valLen = strlen( "named_scanner:" );
343141cc406Sopenharmony_ci          if ( ! strncmp( pVal, "extra_scanner:", valLen ) ){
344141cc406Sopenharmony_ci
345141cc406Sopenharmony_ci            pVal = sanei_config_skip_whitespace ( pVal + valLen );
346141cc406Sopenharmony_ci
347141cc406Sopenharmony_ci            pDevice = malloc (sizeof (struct DeviceRecord));
348141cc406Sopenharmony_ci            if (!pDevice)
349141cc406Sopenharmony_ci              {
350141cc406Sopenharmony_ci                DBG (1, "sane_get_devices: memory allocation failure\n");
351141cc406Sopenharmony_ci                break;
352141cc406Sopenharmony_ci              }
353141cc406Sopenharmony_ci
354141cc406Sopenharmony_ci            pDevice->m_pName = strdup (pVal);
355141cc406Sopenharmony_ci            pDevice->m_device.vendor = "Dell";
356141cc406Sopenharmony_ci            pDevice->m_pModel = strdup( "1600n" );
357141cc406Sopenharmony_ci            pDevice->m_device.type = "multi-function peripheral";
358141cc406Sopenharmony_ci
359141cc406Sopenharmony_ci            pDevice->m_device.name = pDevice->m_pName;
360141cc406Sopenharmony_ci            pDevice->m_device.model = pDevice->m_pModel;
361141cc406Sopenharmony_ci
362141cc406Sopenharmony_ci            /* add to list */
363141cc406Sopenharmony_ci            gKnownDevices[iNextDevice++] = pDevice;
364141cc406Sopenharmony_ci
365141cc406Sopenharmony_ci            continue;
366141cc406Sopenharmony_ci          } /* if */
367141cc406Sopenharmony_ci
368141cc406Sopenharmony_ci        } /* while */
369141cc406Sopenharmony_ci
370141cc406Sopenharmony_ci      /* Close the file */
371141cc406Sopenharmony_ci      fclose( fConfig );
372141cc406Sopenharmony_ci    }
373141cc406Sopenharmony_ci
374141cc406Sopenharmony_ci  /* open UDP socket */
375141cc406Sopenharmony_ci  sock = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP);
376141cc406Sopenharmony_ci  if (sock == -1)
377141cc406Sopenharmony_ci    {
378141cc406Sopenharmony_ci      DBG (1, "Error creating socket\n");
379141cc406Sopenharmony_ci      ret = SANE_STATUS_NO_MEM;
380141cc406Sopenharmony_ci      goto cleanup;
381141cc406Sopenharmony_ci    }
382141cc406Sopenharmony_ci  setsockopt (sock, SOL_SOCKET, SO_BROADCAST, &optYes, sizeof (optYes));
383141cc406Sopenharmony_ci
384141cc406Sopenharmony_ci  /* prepare select mask */
385141cc406Sopenharmony_ci  FD_ZERO (&readFds);
386141cc406Sopenharmony_ci  FD_SET (sock, &readFds);
387141cc406Sopenharmony_ci  selTimeVal.tv_sec = 0;
388141cc406Sopenharmony_ci  selTimeVal.tv_usec = gRegReplyWaitMs * 1000;
389141cc406Sopenharmony_ci
390141cc406Sopenharmony_ci  /* init a packet */
391141cc406Sopenharmony_ci  InitPacket (&queryPacket, 0x01);
392141cc406Sopenharmony_ci
393141cc406Sopenharmony_ci  /* add query */
394141cc406Sopenharmony_ci  ucVal = 0;
395141cc406Sopenharmony_ci  AppendMessageToPacket (&queryPacket, 0x25, "std-scan-discovery-all",
396141cc406Sopenharmony_ci			 0x02, &ucVal, sizeof (ucVal));
397141cc406Sopenharmony_ci
398141cc406Sopenharmony_ci  FinalisePacket (&queryPacket);
399141cc406Sopenharmony_ci
400141cc406Sopenharmony_ci  DBG (10, "Sending:\n");
401141cc406Sopenharmony_ci  HexDump (10, queryPacket.m_pBuf, queryPacket.m_used);
402141cc406Sopenharmony_ci
403141cc406Sopenharmony_ci
404141cc406Sopenharmony_ci  remoteAddr.sin_family = AF_INET;
405141cc406Sopenharmony_ci  remoteAddr.sin_port = htons (gScannerPort);
406141cc406Sopenharmony_ci  remoteAddr.sin_addr.s_addr = 0xFFFFFFFF;	/* broadcast */
407141cc406Sopenharmony_ci
408141cc406Sopenharmony_ci  if (sendto (sock, queryPacket.m_pBuf, queryPacket.m_used, 0,
409141cc406Sopenharmony_ci    (struct sockaddr *) &remoteAddr, sizeof (remoteAddr)) == -1)
410141cc406Sopenharmony_ci    {
411141cc406Sopenharmony_ci      DBG (1, "Error sending broadcast packet\n");
412141cc406Sopenharmony_ci      ret = SANE_STATUS_NO_MEM;
413141cc406Sopenharmony_ci      goto cleanup;
414141cc406Sopenharmony_ci    }
415141cc406Sopenharmony_ci
416141cc406Sopenharmony_ci  /* process replies */
417141cc406Sopenharmony_ci  while (select (sock + 1, &readFds, NULL, NULL, &selTimeVal))
418141cc406Sopenharmony_ci    {
419141cc406Sopenharmony_ci
420141cc406Sopenharmony_ci      /* break if we've got no more storage space in array */
421141cc406Sopenharmony_ci      if (iNextDevice >= MAX_SCANNERS)
422141cc406Sopenharmony_ci        {
423141cc406Sopenharmony_ci          DBG (1, "sane_get_devices: more than %d devices, ignoring\n",
424141cc406Sopenharmony_ci            MAX_SCANNERS);
425141cc406Sopenharmony_ci          break;
426141cc406Sopenharmony_ci        }
427141cc406Sopenharmony_ci
428141cc406Sopenharmony_ci      nread = read (sock, sockBuf, sizeof (sockBuf));
429141cc406Sopenharmony_ci      DBG (5, "Got a broadcast response, (%d bytes)\n", nread);
430141cc406Sopenharmony_ci
431141cc406Sopenharmony_ci      if (nread <= 0)
432141cc406Sopenharmony_ci        break;
433141cc406Sopenharmony_ci
434141cc406Sopenharmony_ci      HexDump (10, sockBuf, nread);
435141cc406Sopenharmony_ci
436141cc406Sopenharmony_ci      /* process response (skipping bad ones) */
437141cc406Sopenharmony_ci      if (!(pDevice = ProcessFindResponse (sockBuf, nread))) continue;
438141cc406Sopenharmony_ci
439141cc406Sopenharmony_ci      /* add to list */
440141cc406Sopenharmony_ci      gKnownDevices[iNextDevice++] = pDevice;
441141cc406Sopenharmony_ci
442141cc406Sopenharmony_ci    } /* while */
443141cc406Sopenharmony_ci
444141cc406Sopenharmony_ci  /* report our finds */
445141cc406Sopenharmony_ci  *device_list = (const SANE_Device **) gKnownDevices;
446141cc406Sopenharmony_ci
447141cc406Sopenharmony_cicleanup:
448141cc406Sopenharmony_ci
449141cc406Sopenharmony_ci  if (sock)
450141cc406Sopenharmony_ci    close (sock);
451141cc406Sopenharmony_ci  FreeComBuf (&queryPacket);
452141cc406Sopenharmony_ci
453141cc406Sopenharmony_ci  return ret;
454141cc406Sopenharmony_ci
455141cc406Sopenharmony_ci} /* sane_get_devices */
456141cc406Sopenharmony_ci
457141cc406Sopenharmony_ci/***********************************************************/
458141cc406Sopenharmony_ci
459141cc406Sopenharmony_ciSANE_Status
460141cc406Sopenharmony_cisane_open (SANE_String_Const devicename, SANE_Handle * handle)
461141cc406Sopenharmony_ci{
462141cc406Sopenharmony_ci
463141cc406Sopenharmony_ci  int iHandle = -1, i;
464141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_GOOD;
465141cc406Sopenharmony_ci  struct hostent *pHostent;
466141cc406Sopenharmony_ci  char *pDot;
467141cc406Sopenharmony_ci
468141cc406Sopenharmony_ci  DBG( 5, "sane_open: %s\n", devicename );
469141cc406Sopenharmony_ci
470141cc406Sopenharmony_ci  /* find the next available scanner pointer in gOpenScanners */
471141cc406Sopenharmony_ci  for (i = 0; i < MAX_SCANNERS; ++i)
472141cc406Sopenharmony_ci    {
473141cc406Sopenharmony_ci
474141cc406Sopenharmony_ci      if (gOpenScanners[i]) continue;
475141cc406Sopenharmony_ci
476141cc406Sopenharmony_ci      iHandle = i;
477141cc406Sopenharmony_ci      break;
478141cc406Sopenharmony_ci
479141cc406Sopenharmony_ci    } /* for */
480141cc406Sopenharmony_ci  if (iHandle == -1)
481141cc406Sopenharmony_ci    {
482141cc406Sopenharmony_ci      DBG (1, "sane_open: no space left in gOpenScanners array\n");
483141cc406Sopenharmony_ci      status = SANE_STATUS_NO_MEM;
484141cc406Sopenharmony_ci      goto cleanup;
485141cc406Sopenharmony_ci    }
486141cc406Sopenharmony_ci
487141cc406Sopenharmony_ci  /* allocate some space */
488141cc406Sopenharmony_ci  if (!(gOpenScanners[iHandle] = malloc (sizeof (struct ScannerState))))
489141cc406Sopenharmony_ci    {
490141cc406Sopenharmony_ci      status = SANE_STATUS_NO_MEM;
491141cc406Sopenharmony_ci      goto cleanup;
492141cc406Sopenharmony_ci    }
493141cc406Sopenharmony_ci
494141cc406Sopenharmony_ci  /* init data */
495141cc406Sopenharmony_ci  memset (gOpenScanners[iHandle], 0, sizeof (struct ScannerState));
496141cc406Sopenharmony_ci  InitComBuf (&gOpenScanners[iHandle]->m_buf);
497141cc406Sopenharmony_ci  InitComBuf (&gOpenScanners[iHandle]->m_imageData);
498141cc406Sopenharmony_ci  InitComBuf (&gOpenScanners[iHandle]->m_pageInfo);
499141cc406Sopenharmony_ci  gOpenScanners[iHandle]->m_xres = ntohs (200);
500141cc406Sopenharmony_ci  gOpenScanners[iHandle]->m_yres = ntohs (200);
501141cc406Sopenharmony_ci  gOpenScanners[iHandle]->m_composition = ntohl (0x01);
502141cc406Sopenharmony_ci  gOpenScanners[iHandle]->m_brightness = 0x80;
503141cc406Sopenharmony_ci  gOpenScanners[iHandle]->m_compression = ntohl (0x08);
504141cc406Sopenharmony_ci  gOpenScanners[iHandle]->m_fileType = ntohl (0x02);
505141cc406Sopenharmony_ci
506141cc406Sopenharmony_ci
507141cc406Sopenharmony_ci  /* look up scanner name */
508141cc406Sopenharmony_ci  pHostent = gethostbyname (devicename);
509141cc406Sopenharmony_ci  if ((!pHostent) || (!pHostent->h_addr_list))
510141cc406Sopenharmony_ci    {
511141cc406Sopenharmony_ci      DBG (1, "sane_open: error looking up scanner name %s\n", devicename);
512141cc406Sopenharmony_ci      status = SANE_STATUS_INVAL;
513141cc406Sopenharmony_ci      goto cleanup;
514141cc406Sopenharmony_ci    }
515141cc406Sopenharmony_ci
516141cc406Sopenharmony_ci  /* open a UDP socket */
517141cc406Sopenharmony_ci  if (!(gOpenScanners[iHandle]->m_udpFd =
518141cc406Sopenharmony_ci    socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)))
519141cc406Sopenharmony_ci    {
520141cc406Sopenharmony_ci      DBG (1, "sane_open: error opening socket\n");
521141cc406Sopenharmony_ci      status = SANE_STATUS_IO_ERROR;
522141cc406Sopenharmony_ci      goto cleanup;
523141cc406Sopenharmony_ci    }
524141cc406Sopenharmony_ci
525141cc406Sopenharmony_ci  /* connect to the scanner */
526141cc406Sopenharmony_ci  memset (&gOpenScanners[iHandle]->m_sockAddr, 0,
527141cc406Sopenharmony_ci    sizeof (gOpenScanners[iHandle]->m_sockAddr));
528141cc406Sopenharmony_ci  gOpenScanners[iHandle]->m_sockAddr.sin_family = AF_INET;
529141cc406Sopenharmony_ci  gOpenScanners[iHandle]->m_sockAddr.sin_port = htons (gScannerPort);
530141cc406Sopenharmony_ci  memcpy (&gOpenScanners[iHandle]->m_sockAddr.sin_addr,
531141cc406Sopenharmony_ci    pHostent->h_addr_list[0], pHostent->h_length);
532141cc406Sopenharmony_ci  if (connect (gOpenScanners[iHandle]->m_udpFd,
533141cc406Sopenharmony_ci    (struct sockaddr *) &gOpenScanners[iHandle]->m_sockAddr,
534141cc406Sopenharmony_ci    sizeof (gOpenScanners[iHandle]->m_sockAddr)))
535141cc406Sopenharmony_ci    {
536141cc406Sopenharmony_ci      DBG (1, "sane_open: error connecting to %s:%d\n", devicename,
537141cc406Sopenharmony_ci        gScannerPort);
538141cc406Sopenharmony_ci      status = SANE_STATUS_IO_ERROR;
539141cc406Sopenharmony_ci      goto cleanup;
540141cc406Sopenharmony_ci    }
541141cc406Sopenharmony_ci
542141cc406Sopenharmony_ci  /* set fallback registration name */
543141cc406Sopenharmony_ci  sprintf (gOpenScanners[iHandle]->m_regName, "Sane");
544141cc406Sopenharmony_ci
545141cc406Sopenharmony_ci  /* try to fill in hostname */
546141cc406Sopenharmony_ci  gethostname (gOpenScanners[iHandle]->m_regName, REG_NAME_SIZE);
547141cc406Sopenharmony_ci
548141cc406Sopenharmony_ci  /* just in case... */
549141cc406Sopenharmony_ci  gOpenScanners[iHandle]->m_regName[REG_NAME_SIZE - 1] = 0;
550141cc406Sopenharmony_ci
551141cc406Sopenharmony_ci  /* chop off any domain (if any) */
552141cc406Sopenharmony_ci  if ((pDot = strchr (gOpenScanners[iHandle]->m_regName, '.')))
553141cc406Sopenharmony_ci    *pDot = 0;
554141cc406Sopenharmony_ci
555141cc406Sopenharmony_ci  DBG (5, "sane_open: connected to %s:%d as %s\n", devicename, gScannerPort,
556141cc406Sopenharmony_ci       gOpenScanners[iHandle]->m_regName);
557141cc406Sopenharmony_ci
558141cc406Sopenharmony_ci
559141cc406Sopenharmony_ci  /* set the handle */
560141cc406Sopenharmony_ci  *handle = (SANE_Handle) (unsigned long)iHandle;
561141cc406Sopenharmony_ci
562141cc406Sopenharmony_ci  return status;
563141cc406Sopenharmony_ci
564141cc406Sopenharmony_cicleanup:
565141cc406Sopenharmony_ci
566141cc406Sopenharmony_ci  if (iHandle != -1)
567141cc406Sopenharmony_ci    FreeScannerState (iHandle);
568141cc406Sopenharmony_ci
569141cc406Sopenharmony_ci  return status;
570141cc406Sopenharmony_ci
571141cc406Sopenharmony_ci} /* sane_open */
572141cc406Sopenharmony_ci
573141cc406Sopenharmony_ci/***********************************************************/
574141cc406Sopenharmony_ci
575141cc406Sopenharmony_civoid
576141cc406Sopenharmony_cisane_close (SANE_Handle handle)
577141cc406Sopenharmony_ci{
578141cc406Sopenharmony_ci
579141cc406Sopenharmony_ci  DBG( 5, "sane_close: %lx\n", (unsigned long)handle );
580141cc406Sopenharmony_ci
581141cc406Sopenharmony_ci  FreeScannerState ((unsigned long) handle);
582141cc406Sopenharmony_ci
583141cc406Sopenharmony_ci} /* sane_close */
584141cc406Sopenharmony_ci
585141cc406Sopenharmony_ci/***********************************************************/
586141cc406Sopenharmony_ci
587141cc406Sopenharmony_ciconst SANE_Option_Descriptor *
588141cc406Sopenharmony_cisane_get_option_descriptor (SANE_Handle __sane_unused__ handle,
589141cc406Sopenharmony_ci			    SANE_Int option)
590141cc406Sopenharmony_ci{
591141cc406Sopenharmony_ci
592141cc406Sopenharmony_ci  static SANE_Option_Descriptor numOptions = {
593141cc406Sopenharmony_ci    "num_options",
594141cc406Sopenharmony_ci    "Number of options",
595141cc406Sopenharmony_ci    "Number of options",
596141cc406Sopenharmony_ci    SANE_TYPE_INT,
597141cc406Sopenharmony_ci    SANE_UNIT_NONE,
598141cc406Sopenharmony_ci    1,
599141cc406Sopenharmony_ci    0,
600141cc406Sopenharmony_ci    0,
601141cc406Sopenharmony_ci    {0}
602141cc406Sopenharmony_ci  };
603141cc406Sopenharmony_ci
604141cc406Sopenharmony_ci  if (option == 0)
605141cc406Sopenharmony_ci    return &numOptions;
606141cc406Sopenharmony_ci  else
607141cc406Sopenharmony_ci    return NULL;
608141cc406Sopenharmony_ci
609141cc406Sopenharmony_ci} /* sane_get_option_descriptor */
610141cc406Sopenharmony_ci
611141cc406Sopenharmony_ci/***********************************************************/
612141cc406Sopenharmony_ci
613141cc406Sopenharmony_ciSANE_Status
614141cc406Sopenharmony_cisane_control_option (SANE_Handle __sane_unused__ handle, SANE_Int option,
615141cc406Sopenharmony_ci		     SANE_Action action, void *value,
616141cc406Sopenharmony_ci		     SANE_Int __sane_unused__ * info)
617141cc406Sopenharmony_ci{
618141cc406Sopenharmony_ci
619141cc406Sopenharmony_ci  static int numOptions = 1;
620141cc406Sopenharmony_ci
621141cc406Sopenharmony_ci  if (action == SANE_ACTION_GET_VALUE && option == 0)
622141cc406Sopenharmony_ci    *(int *) value = numOptions;
623141cc406Sopenharmony_ci
624141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
625141cc406Sopenharmony_ci
626141cc406Sopenharmony_ci} /* sane_control_option  */
627141cc406Sopenharmony_ci
628141cc406Sopenharmony_ci/***********************************************************/
629141cc406Sopenharmony_ci
630141cc406Sopenharmony_ciSANE_Status
631141cc406Sopenharmony_cisane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
632141cc406Sopenharmony_ci{
633141cc406Sopenharmony_ci  int iHandle = (int) (unsigned long)handle;
634141cc406Sopenharmony_ci  unsigned int width, height, imageSize;
635141cc406Sopenharmony_ci  struct PageInfo pageInfo;
636141cc406Sopenharmony_ci
637141cc406Sopenharmony_ci  if (!gOpenScanners[iHandle])
638141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
639141cc406Sopenharmony_ci
640141cc406Sopenharmony_ci  /* fetch page info */
641141cc406Sopenharmony_ci  memcpy( & pageInfo, gOpenScanners[iHandle]->m_pageInfo.m_pBuf, sizeof( pageInfo ) );
642141cc406Sopenharmony_ci
643141cc406Sopenharmony_ci  width = pageInfo.m_width;
644141cc406Sopenharmony_ci  height = pageInfo.m_height;
645141cc406Sopenharmony_ci  imageSize = width * height * 3;
646141cc406Sopenharmony_ci
647141cc406Sopenharmony_ci  DBG( 5, "sane_get_parameters: bytes remaining on this page: %d, num pages: %d, size: %dx%d\n",
648141cc406Sopenharmony_ci       pageInfo.m_bytesRemaining,
649141cc406Sopenharmony_ci       gOpenScanners[iHandle]->m_numPages,
650141cc406Sopenharmony_ci       width,
651141cc406Sopenharmony_ci       height );
652141cc406Sopenharmony_ci
653141cc406Sopenharmony_ci  DBG (5,
654141cc406Sopenharmony_ci       "sane_get_parameters: handle %x: bytes outstanding: %lu, image size: %d\n",
655141cc406Sopenharmony_ci       iHandle, (unsigned long)gOpenScanners[iHandle]->m_imageData.m_used, imageSize);
656141cc406Sopenharmony_ci
657141cc406Sopenharmony_ci  /* check for enough data */
658141cc406Sopenharmony_ci  /*
659141cc406Sopenharmony_ci  if (gOpenScanners[iHandle]->m_imageData.m_used < imageSize)
660141cc406Sopenharmony_ci    {
661141cc406Sopenharmony_ci      DBG (1, "sane_get_parameters: handle %d: not enough data: %d < %d\n",
662141cc406Sopenharmony_ci	   iHandle, gOpenScanners[iHandle]->m_imageData.m_used, imageSize);
663141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
664141cc406Sopenharmony_ci    }
665141cc406Sopenharmony_ci  */
666141cc406Sopenharmony_ci
667141cc406Sopenharmony_ci
668141cc406Sopenharmony_ci  params->format = SANE_FRAME_RGB;
669141cc406Sopenharmony_ci  params->last_frame = SANE_TRUE;
670141cc406Sopenharmony_ci  params->lines = height;
671141cc406Sopenharmony_ci  params->depth = 8;
672141cc406Sopenharmony_ci  params->pixels_per_line = width;
673141cc406Sopenharmony_ci  params->bytes_per_line = width * 3;
674141cc406Sopenharmony_ci
675141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
676141cc406Sopenharmony_ci
677141cc406Sopenharmony_ci} /* sane_get_parameters  */
678141cc406Sopenharmony_ci
679141cc406Sopenharmony_ci/***********************************************************/
680141cc406Sopenharmony_ci
681141cc406Sopenharmony_ciSANE_Status
682141cc406Sopenharmony_cisane_start (SANE_Handle handle)
683141cc406Sopenharmony_ci{
684141cc406Sopenharmony_ci
685141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_GOOD;
686141cc406Sopenharmony_ci  struct ComBuf buf;
687141cc406Sopenharmony_ci  unsigned char sockBuf[SOCK_BUF_SIZE];
688141cc406Sopenharmony_ci  int iHandle, nread;
689141cc406Sopenharmony_ci  int errorCheck = 0;
690141cc406Sopenharmony_ci  struct sockaddr_in myAddr;
691141cc406Sopenharmony_ci  socklen_t addrSize;
692141cc406Sopenharmony_ci  fd_set readFds;
693141cc406Sopenharmony_ci  struct timeval selTimeVal;
694141cc406Sopenharmony_ci
695141cc406Sopenharmony_ci  iHandle = (int) (unsigned long)handle;
696141cc406Sopenharmony_ci
697141cc406Sopenharmony_ci  DBG( 5, "sane_start: %x\n", iHandle );
698141cc406Sopenharmony_ci
699141cc406Sopenharmony_ci  /* fetch and check scanner index */
700141cc406Sopenharmony_ci  if (!ValidScannerNumber (iHandle))
701141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
702141cc406Sopenharmony_ci
703141cc406Sopenharmony_ci  /* check if we still have outstanding pages of data on this handle */
704141cc406Sopenharmony_ci  if (gOpenScanners[iHandle]->m_imageData.m_used){
705141cc406Sopenharmony_ci
706141cc406Sopenharmony_ci    /* remove empty page */
707141cc406Sopenharmony_ci    PopFromComBuf ( & gOpenScanners[iHandle]->m_pageInfo, sizeof( struct PageInfo ) );
708141cc406Sopenharmony_ci    return SANE_STATUS_GOOD;
709141cc406Sopenharmony_ci
710141cc406Sopenharmony_ci  }
711141cc406Sopenharmony_ci
712141cc406Sopenharmony_ci  /* determine local IP address */
713141cc406Sopenharmony_ci  addrSize = sizeof (myAddr);
714141cc406Sopenharmony_ci  if (getsockname (gOpenScanners[iHandle]->m_udpFd, (struct sockaddr *) &myAddr, &addrSize))
715141cc406Sopenharmony_ci    {
716141cc406Sopenharmony_ci      DBG (1, "sane_start: Error getting own IP address\n");
717141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
718141cc406Sopenharmony_ci    }
719141cc406Sopenharmony_ci
720141cc406Sopenharmony_ci  /* init a buffer for our registration message */
721141cc406Sopenharmony_ci  errorCheck |= InitComBuf (&buf);
722141cc406Sopenharmony_ci
723141cc406Sopenharmony_ci  /* build packet */
724141cc406Sopenharmony_ci  errorCheck |= InitPacket (&buf, 1);
725141cc406Sopenharmony_ci  errorCheck |=
726141cc406Sopenharmony_ci    AppendMessageToPacket (&buf, 0x22, "std-scan-subscribe-user-name", 0x0b,
727141cc406Sopenharmony_ci      gOpenScanners[iHandle]->m_regName,
728141cc406Sopenharmony_ci      strlen (gOpenScanners[iHandle]->m_regName));
729141cc406Sopenharmony_ci  errorCheck |=
730141cc406Sopenharmony_ci    AppendMessageToPacket (&buf, 0x22, "std-scan-subscribe-ip-address", 0x0a,
731141cc406Sopenharmony_ci      &myAddr.sin_addr, 4);
732141cc406Sopenharmony_ci  FinalisePacket (&buf);
733141cc406Sopenharmony_ci
734141cc406Sopenharmony_ci  /* check nothing went wrong along the way */
735141cc406Sopenharmony_ci  if (errorCheck)
736141cc406Sopenharmony_ci    {
737141cc406Sopenharmony_ci      status = SANE_STATUS_NO_MEM;
738141cc406Sopenharmony_ci      goto cleanup;
739141cc406Sopenharmony_ci    }
740141cc406Sopenharmony_ci
741141cc406Sopenharmony_ci  /* send the packet */
742141cc406Sopenharmony_ci  send (gOpenScanners[iHandle]->m_udpFd, buf.m_pBuf, buf.m_used, 0);
743141cc406Sopenharmony_ci
744141cc406Sopenharmony_ci
745141cc406Sopenharmony_ci  /* loop until done */
746141cc406Sopenharmony_ci  gOpenScanners[iHandle]->m_bFinish = 0;
747141cc406Sopenharmony_ci  while (!gOpenScanners[iHandle]->m_bFinish)
748141cc406Sopenharmony_ci    {
749141cc406Sopenharmony_ci
750141cc406Sopenharmony_ci      /* prepare select mask */
751141cc406Sopenharmony_ci      FD_ZERO (&readFds);
752141cc406Sopenharmony_ci      FD_SET (gOpenScanners[iHandle]->m_udpFd, &readFds);
753141cc406Sopenharmony_ci      selTimeVal.tv_sec = 1;
754141cc406Sopenharmony_ci      selTimeVal.tv_usec = 0;
755141cc406Sopenharmony_ci
756141cc406Sopenharmony_ci
757141cc406Sopenharmony_ci
758141cc406Sopenharmony_ci      DBG (5, "sane_start: waiting for scan signal\n");
759141cc406Sopenharmony_ci
760141cc406Sopenharmony_ci      /* wait again if nothing received */
761141cc406Sopenharmony_ci      if (!select (gOpenScanners[iHandle]->m_udpFd + 1,
762141cc406Sopenharmony_ci        &readFds, NULL, NULL, &selTimeVal))
763141cc406Sopenharmony_ci        continue;
764141cc406Sopenharmony_ci
765141cc406Sopenharmony_ci      /* read from socket */
766141cc406Sopenharmony_ci      nread =
767141cc406Sopenharmony_ci        read (gOpenScanners[iHandle]->m_udpFd, sockBuf, sizeof (sockBuf));
768141cc406Sopenharmony_ci
769141cc406Sopenharmony_ci      if (nread <= 0)
770141cc406Sopenharmony_ci        {
771141cc406Sopenharmony_ci          DBG (1, "sane_start: read returned %d\n", nread);
772141cc406Sopenharmony_ci          break;
773141cc406Sopenharmony_ci        }
774141cc406Sopenharmony_ci
775141cc406Sopenharmony_ci      /* process the response */
776141cc406Sopenharmony_ci      if (ProcessUdpResponse (sockBuf, nread, gOpenScanners[iHandle]))
777141cc406Sopenharmony_ci        {
778141cc406Sopenharmony_ci          status = SANE_STATUS_IO_ERROR;
779141cc406Sopenharmony_ci          goto cleanup;
780141cc406Sopenharmony_ci        }
781141cc406Sopenharmony_ci
782141cc406Sopenharmony_ci    } /* while */
783141cc406Sopenharmony_ci
784141cc406Sopenharmony_ci  /* check whether we were cancelled */
785141cc406Sopenharmony_ci  if ( gOpenScanners[iHandle]->m_bCancelled ) status = SANE_STATUS_CANCELLED;
786141cc406Sopenharmony_ci
787141cc406Sopenharmony_cicleanup:
788141cc406Sopenharmony_ci
789141cc406Sopenharmony_ci  FreeComBuf (&buf);
790141cc406Sopenharmony_ci
791141cc406Sopenharmony_ci  return status;
792141cc406Sopenharmony_ci
793141cc406Sopenharmony_ci} /* sane_start */
794141cc406Sopenharmony_ci
795141cc406Sopenharmony_ci/***********************************************************/
796141cc406Sopenharmony_ci
797141cc406Sopenharmony_ciSANE_Status
798141cc406Sopenharmony_cisane_read (SANE_Handle handle, SANE_Byte * data,
799141cc406Sopenharmony_ci	   SANE_Int max_length, SANE_Int * length)
800141cc406Sopenharmony_ci{
801141cc406Sopenharmony_ci
802141cc406Sopenharmony_ci  int iHandle = (int) (unsigned long)handle;
803141cc406Sopenharmony_ci  int dataSize;
804141cc406Sopenharmony_ci  struct PageInfo pageInfo;
805141cc406Sopenharmony_ci
806141cc406Sopenharmony_ci  DBG( 5, "sane_read: %x (max_length=%d)\n", iHandle, max_length );
807141cc406Sopenharmony_ci
808141cc406Sopenharmony_ci  *length = 0;
809141cc406Sopenharmony_ci
810141cc406Sopenharmony_ci  if (!gOpenScanners[iHandle])
811141cc406Sopenharmony_ci    return SANE_STATUS_INVAL;
812141cc406Sopenharmony_ci
813141cc406Sopenharmony_ci  /* check for end of data (no further pages) */
814141cc406Sopenharmony_ci  if ( ( ! gOpenScanners[iHandle]->m_imageData.m_used )
815141cc406Sopenharmony_ci       || ( ! gOpenScanners[iHandle]->m_numPages ) )
816141cc406Sopenharmony_ci    {
817141cc406Sopenharmony_ci      /* remove empty page if there are no more cached pages */
818141cc406Sopenharmony_ci      PopFromComBuf ( & gOpenScanners[iHandle]->m_pageInfo, sizeof( struct PageInfo ) );
819141cc406Sopenharmony_ci
820141cc406Sopenharmony_ci      return SANE_STATUS_EOF;
821141cc406Sopenharmony_ci    }
822141cc406Sopenharmony_ci
823141cc406Sopenharmony_ci  /* fetch page info */
824141cc406Sopenharmony_ci  memcpy( & pageInfo, gOpenScanners[iHandle]->m_pageInfo.m_pBuf, sizeof( pageInfo ) );
825141cc406Sopenharmony_ci
826141cc406Sopenharmony_ci  /* check for end of page data (we still have further cached pages) */
827141cc406Sopenharmony_ci  if ( pageInfo.m_bytesRemaining < 1 ) return SANE_STATUS_EOF;
828141cc406Sopenharmony_ci
829141cc406Sopenharmony_ci  /*  send the remainder of the current image */
830141cc406Sopenharmony_ci  dataSize = pageInfo.m_bytesRemaining;
831141cc406Sopenharmony_ci
832141cc406Sopenharmony_ci  /* unless there's not enough room in the output buffer */
833141cc406Sopenharmony_ci  if (dataSize > max_length)
834141cc406Sopenharmony_ci    dataSize = max_length;
835141cc406Sopenharmony_ci
836141cc406Sopenharmony_ci  /* update the data sent counters */
837141cc406Sopenharmony_ci  gOpenScanners[iHandle]->m_bytesRead += dataSize;
838141cc406Sopenharmony_ci  pageInfo.m_bytesRemaining -= dataSize;
839141cc406Sopenharmony_ci
840141cc406Sopenharmony_ci  /* update counter */
841141cc406Sopenharmony_ci  memcpy( gOpenScanners[iHandle]->m_pageInfo.m_pBuf, & pageInfo, sizeof( pageInfo ) );
842141cc406Sopenharmony_ci
843141cc406Sopenharmony_ci  /* check for end of page */
844141cc406Sopenharmony_ci  if ( pageInfo.m_bytesRemaining < 1 ){
845141cc406Sopenharmony_ci
846141cc406Sopenharmony_ci    /* yes, so remove page info */
847141cc406Sopenharmony_ci    gOpenScanners[iHandle]->m_numPages--;
848141cc406Sopenharmony_ci
849141cc406Sopenharmony_ci  } /* if */
850141cc406Sopenharmony_ci
851141cc406Sopenharmony_ci  DBG (5,
852141cc406Sopenharmony_ci       "sane_read: sending %d bytes, image total %d, %d page bytes remaining, %lu total remaining, image: %dx%d\n",
853141cc406Sopenharmony_ci       dataSize, gOpenScanners[iHandle]->m_bytesRead, pageInfo.m_bytesRemaining ,
854141cc406Sopenharmony_ci       (unsigned long)(gOpenScanners[iHandle]->m_imageData.m_used - dataSize),
855141cc406Sopenharmony_ci       pageInfo.m_width,
856141cc406Sopenharmony_ci       pageInfo.m_height);
857141cc406Sopenharmony_ci
858141cc406Sopenharmony_ci  /* copy the data */
859141cc406Sopenharmony_ci  memcpy (data, gOpenScanners[iHandle]->m_imageData.m_pBuf, dataSize);
860141cc406Sopenharmony_ci  if (PopFromComBuf (&gOpenScanners[iHandle]->m_imageData, dataSize))
861141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
862141cc406Sopenharmony_ci
863141cc406Sopenharmony_ci  *length = dataSize;
864141cc406Sopenharmony_ci
865141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
866141cc406Sopenharmony_ci
867141cc406Sopenharmony_ci} /* sane_read */
868141cc406Sopenharmony_ci
869141cc406Sopenharmony_ci/***********************************************************/
870141cc406Sopenharmony_ci
871141cc406Sopenharmony_civoid
872141cc406Sopenharmony_cisane_cancel (SANE_Handle handle)
873141cc406Sopenharmony_ci{
874141cc406Sopenharmony_ci  int iHandle = (int) (unsigned long)handle;
875141cc406Sopenharmony_ci
876141cc406Sopenharmony_ci  DBG( 5, "sane_cancel: %x\n", iHandle );
877141cc406Sopenharmony_ci
878141cc406Sopenharmony_ci  /* signal that bad things are afoot */
879141cc406Sopenharmony_ci  gOpenScanners[iHandle]->m_bFinish = 1;
880141cc406Sopenharmony_ci  gOpenScanners[iHandle]->m_bCancelled = 1;
881141cc406Sopenharmony_ci
882141cc406Sopenharmony_ci} /* sane_cancel */
883141cc406Sopenharmony_ci
884141cc406Sopenharmony_ci/***********************************************************/
885141cc406Sopenharmony_ci
886141cc406Sopenharmony_ciSANE_Status
887141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle __sane_unused__ handle,
888141cc406Sopenharmony_ci		  SANE_Bool __sane_unused__ non_blocking)
889141cc406Sopenharmony_ci{
890141cc406Sopenharmony_ci
891141cc406Sopenharmony_ci  return SANE_STATUS_UNSUPPORTED;
892141cc406Sopenharmony_ci
893141cc406Sopenharmony_ci} /* sane_set_io_mode */
894141cc406Sopenharmony_ci
895141cc406Sopenharmony_ci/***********************************************************/
896141cc406Sopenharmony_ci
897141cc406Sopenharmony_ciSANE_Status
898141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle __sane_unused__ handle,
899141cc406Sopenharmony_ci		    SANE_Int __sane_unused__ * fd)
900141cc406Sopenharmony_ci{
901141cc406Sopenharmony_ci
902141cc406Sopenharmony_ci  return SANE_STATUS_UNSUPPORTED;
903141cc406Sopenharmony_ci
904141cc406Sopenharmony_ci} /* sane_get_select_fd */
905141cc406Sopenharmony_ci
906141cc406Sopenharmony_ci/***********************************************************/
907141cc406Sopenharmony_ci
908141cc406Sopenharmony_ci/* Clears the contents of gKnownDevices and zeros it */
909141cc406Sopenharmony_civoid
910141cc406Sopenharmony_ciClearKnownDevices ()
911141cc406Sopenharmony_ci{
912141cc406Sopenharmony_ci
913141cc406Sopenharmony_ci  int i;
914141cc406Sopenharmony_ci
915141cc406Sopenharmony_ci  for (i = 0; i < MAX_SCANNERS; ++i)
916141cc406Sopenharmony_ci    {
917141cc406Sopenharmony_ci
918141cc406Sopenharmony_ci      if (gKnownDevices[i])
919141cc406Sopenharmony_ci        {
920141cc406Sopenharmony_ci          if (gKnownDevices[i]->m_pName) free ( gKnownDevices[i]->m_pName );
921141cc406Sopenharmony_ci          if (gKnownDevices[i]->m_pModel) free ( gKnownDevices[i]->m_pModel );
922141cc406Sopenharmony_ci          free ( gKnownDevices[i] );
923141cc406Sopenharmony_ci        }
924141cc406Sopenharmony_ci      gKnownDevices[i] = NULL;
925141cc406Sopenharmony_ci
926141cc406Sopenharmony_ci    }
927141cc406Sopenharmony_ci
928141cc406Sopenharmony_ci} /* ClearKnownDevices */
929141cc406Sopenharmony_ci
930141cc406Sopenharmony_ci/***********************************************************/
931141cc406Sopenharmony_ci
932141cc406Sopenharmony_ci/* print hex buffer to debug output */
933141cc406Sopenharmony_civoid
934141cc406Sopenharmony_ciHexDump (int debugLevel, const unsigned char *buf, size_t bufSize)
935141cc406Sopenharmony_ci{
936141cc406Sopenharmony_ci
937141cc406Sopenharmony_ci  unsigned int i, j;
938141cc406Sopenharmony_ci  size_t lineBufFree;
939141cc406Sopenharmony_ci
940141cc406Sopenharmony_ci  char itemBuf[16] = { 0 }, lineBuf[256] = { 0 };
941141cc406Sopenharmony_ci
942141cc406Sopenharmony_ci  if (DBG_LEVEL < debugLevel)
943141cc406Sopenharmony_ci    return;
944141cc406Sopenharmony_ci
945141cc406Sopenharmony_ci  for (i = 0; i < bufSize; ++i)
946141cc406Sopenharmony_ci    {
947141cc406Sopenharmony_ci
948141cc406Sopenharmony_ci      if (!(i % 16))
949141cc406Sopenharmony_ci        sprintf (lineBuf, "%p: ", (void *) &buf[i]);
950141cc406Sopenharmony_ci
951141cc406Sopenharmony_ci      sprintf (itemBuf, "%02x ", (const unsigned int) buf[i]);
952141cc406Sopenharmony_ci
953141cc406Sopenharmony_ci      lineBufFree = sizeof (lineBuf) - strlen (lineBuf) - 1;
954141cc406Sopenharmony_ci      strncat (lineBuf, itemBuf, lineBufFree);
955141cc406Sopenharmony_ci
956141cc406Sopenharmony_ci      if ((i + 1) % 16)
957141cc406Sopenharmony_ci        continue;
958141cc406Sopenharmony_ci
959141cc406Sopenharmony_ci      /* print string equivalent */
960141cc406Sopenharmony_ci      for (j = i - 15; j <= i; ++j)
961141cc406Sopenharmony_ci        {
962141cc406Sopenharmony_ci
963141cc406Sopenharmony_ci      if ((buf[j] >= 0x20) && (!(buf[j] & 0x80)))
964141cc406Sopenharmony_ci        {
965141cc406Sopenharmony_ci          sprintf (itemBuf, "%c", buf[j]);
966141cc406Sopenharmony_ci        }
967141cc406Sopenharmony_ci      else
968141cc406Sopenharmony_ci        {
969141cc406Sopenharmony_ci          sprintf (itemBuf, ".");
970141cc406Sopenharmony_ci        }
971141cc406Sopenharmony_ci      lineBufFree = sizeof (lineBuf) - strlen (lineBuf) - 1;
972141cc406Sopenharmony_ci      strncat (lineBuf, itemBuf, lineBufFree);
973141cc406Sopenharmony_ci
974141cc406Sopenharmony_ci    } /* for j */
975141cc406Sopenharmony_ci
976141cc406Sopenharmony_ci      DBG (debugLevel, "%s\n", lineBuf);
977141cc406Sopenharmony_ci      lineBuf[0] = 0;
978141cc406Sopenharmony_ci
979141cc406Sopenharmony_ci    } /* for i */
980141cc406Sopenharmony_ci
981141cc406Sopenharmony_ci  if (i % 16)
982141cc406Sopenharmony_ci    {
983141cc406Sopenharmony_ci
984141cc406Sopenharmony_ci      for (j = (i % 16); j < 16; ++j)
985141cc406Sopenharmony_ci        {
986141cc406Sopenharmony_ci          lineBufFree = sizeof (lineBuf) - strlen (lineBuf) - 1;
987141cc406Sopenharmony_ci          strncat (lineBuf, "   ", lineBufFree);
988141cc406Sopenharmony_ci        }
989141cc406Sopenharmony_ci      for (j = 1 + i - ((i + 1) % 16); j < i; ++j)
990141cc406Sopenharmony_ci        {
991141cc406Sopenharmony_ci          if ((buf[j] >= 0x20) && (!(buf[j] & 0x80)))
992141cc406Sopenharmony_ci            {
993141cc406Sopenharmony_ci              sprintf (itemBuf, "%c", buf[j]);
994141cc406Sopenharmony_ci            }
995141cc406Sopenharmony_ci          else
996141cc406Sopenharmony_ci            {
997141cc406Sopenharmony_ci              strcpy (itemBuf, ".");
998141cc406Sopenharmony_ci            }
999141cc406Sopenharmony_ci          lineBufFree = sizeof (lineBuf) - strlen (lineBuf) - 1;
1000141cc406Sopenharmony_ci          strncat (lineBuf, itemBuf, lineBufFree);
1001141cc406Sopenharmony_ci        }
1002141cc406Sopenharmony_ci      DBG (debugLevel, "%s\n", lineBuf);
1003141cc406Sopenharmony_ci    }
1004141cc406Sopenharmony_ci} /* HexDump */
1005141cc406Sopenharmony_ci
1006141cc406Sopenharmony_ci/***********************************************************/
1007141cc406Sopenharmony_ci
1008141cc406Sopenharmony_ci/* initialise a ComBuf struct
1009141cc406Sopenharmony_ci   \return 0 on success, >0 on failure
1010141cc406Sopenharmony_ci*/
1011141cc406Sopenharmony_ciint
1012141cc406Sopenharmony_ciInitComBuf (struct ComBuf *pBuf)
1013141cc406Sopenharmony_ci{
1014141cc406Sopenharmony_ci
1015141cc406Sopenharmony_ci  memset (pBuf, 0, sizeof (struct ComBuf));
1016141cc406Sopenharmony_ci
1017141cc406Sopenharmony_ci  pBuf->m_pBuf = malloc (INITIAL_COM_BUF_SIZE);
1018141cc406Sopenharmony_ci  if (!pBuf->m_pBuf)
1019141cc406Sopenharmony_ci    return 1;
1020141cc406Sopenharmony_ci
1021141cc406Sopenharmony_ci  pBuf->m_capacity = INITIAL_COM_BUF_SIZE;
1022141cc406Sopenharmony_ci  pBuf->m_used = 0;
1023141cc406Sopenharmony_ci
1024141cc406Sopenharmony_ci  return 0;
1025141cc406Sopenharmony_ci
1026141cc406Sopenharmony_ci} /* InitComBuf */
1027141cc406Sopenharmony_ci
1028141cc406Sopenharmony_ci/***********************************************************/
1029141cc406Sopenharmony_ci
1030141cc406Sopenharmony_ci/* free a ComBuf struct */
1031141cc406Sopenharmony_civoid
1032141cc406Sopenharmony_ciFreeComBuf (struct ComBuf *pBuf)
1033141cc406Sopenharmony_ci{
1034141cc406Sopenharmony_ci
1035141cc406Sopenharmony_ci  if (pBuf->m_pBuf)
1036141cc406Sopenharmony_ci    free (pBuf->m_pBuf);
1037141cc406Sopenharmony_ci  memset (pBuf, 0, sizeof (struct ComBuf));
1038141cc406Sopenharmony_ci
1039141cc406Sopenharmony_ci} /* FreeComBuf */
1040141cc406Sopenharmony_ci
1041141cc406Sopenharmony_ci/***********************************************************/
1042141cc406Sopenharmony_ci
1043141cc406Sopenharmony_ci/* add data to a ComBuf struct
1044141cc406Sopenharmony_ci   \return 0 on success, >0 on failure
1045141cc406Sopenharmony_ci   \note If pData is NULL then buffer size will be increased but no copying will take place
1046141cc406Sopenharmony_ci   \note In case of failure pBuf will be released using FreeComBuf
1047141cc406Sopenharmony_ci*/
1048141cc406Sopenharmony_ciint
1049141cc406Sopenharmony_ciAppendToComBuf (struct ComBuf *pBuf, const unsigned char *pData,
1050141cc406Sopenharmony_ci		size_t datSize)
1051141cc406Sopenharmony_ci{
1052141cc406Sopenharmony_ci
1053141cc406Sopenharmony_ci  size_t newSize;
1054141cc406Sopenharmony_ci
1055141cc406Sopenharmony_ci  /* check we have enough space */
1056141cc406Sopenharmony_ci  if (pBuf->m_used + datSize > pBuf->m_capacity)
1057141cc406Sopenharmony_ci    {
1058141cc406Sopenharmony_ci      /* nope - allocate some more */
1059141cc406Sopenharmony_ci      newSize = pBuf->m_used + datSize + INITIAL_COM_BUF_SIZE;
1060141cc406Sopenharmony_ci      pBuf->m_pBuf = realloc (pBuf->m_pBuf, newSize);
1061141cc406Sopenharmony_ci      if (!pBuf->m_pBuf)
1062141cc406Sopenharmony_ci        {
1063141cc406Sopenharmony_ci          DBG (1, "AppendToComBuf: memory allocation error");
1064141cc406Sopenharmony_ci          FreeComBuf (pBuf);
1065141cc406Sopenharmony_ci          return (1);
1066141cc406Sopenharmony_ci        }
1067141cc406Sopenharmony_ci      pBuf->m_capacity = newSize;
1068141cc406Sopenharmony_ci    } /* if */
1069141cc406Sopenharmony_ci
1070141cc406Sopenharmony_ci  /* add data */
1071141cc406Sopenharmony_ci  if (pData)
1072141cc406Sopenharmony_ci    memcpy (pBuf->m_pBuf + pBuf->m_used, pData, datSize);
1073141cc406Sopenharmony_ci  pBuf->m_used += datSize;
1074141cc406Sopenharmony_ci
1075141cc406Sopenharmony_ci  return 0;
1076141cc406Sopenharmony_ci
1077141cc406Sopenharmony_ci} /* AppendToComBuf */
1078141cc406Sopenharmony_ci
1079141cc406Sopenharmony_ci/***********************************************************/
1080141cc406Sopenharmony_ci
1081141cc406Sopenharmony_ci/* append message to a packet
1082141cc406Sopenharmony_ci   \return 0 if  ok, 1 if bad */
1083141cc406Sopenharmony_ciint
1084141cc406Sopenharmony_ciAppendMessageToPacket (struct ComBuf *pBuf,	/* packet to which to append */
1085141cc406Sopenharmony_ci		       char messageType,	/* type of message */
1086141cc406Sopenharmony_ci		       char *messageName,	/* name of message */
1087141cc406Sopenharmony_ci		       char valueType,	        /* type of value */
1088141cc406Sopenharmony_ci		       void *pValue,	        /* pointer to value */
1089141cc406Sopenharmony_ci		       size_t valueLen	        /* length of value (bytes) */
1090141cc406Sopenharmony_ci  )
1091141cc406Sopenharmony_ci{
1092141cc406Sopenharmony_ci
1093141cc406Sopenharmony_ci  unsigned short slen;
1094141cc406Sopenharmony_ci
1095141cc406Sopenharmony_ci  /* message type */
1096141cc406Sopenharmony_ci  AppendToComBuf (pBuf, (void *) &messageType, 1);
1097141cc406Sopenharmony_ci
1098141cc406Sopenharmony_ci  /* message length */
1099141cc406Sopenharmony_ci  slen = htons (strlen (messageName));
1100141cc406Sopenharmony_ci  AppendToComBuf (pBuf, (void *) &slen, 2);
1101141cc406Sopenharmony_ci
1102141cc406Sopenharmony_ci  /* and name */
1103141cc406Sopenharmony_ci  AppendToComBuf (pBuf, (void *) messageName, strlen (messageName));
1104141cc406Sopenharmony_ci
1105141cc406Sopenharmony_ci  /* and value type */
1106141cc406Sopenharmony_ci  AppendToComBuf (pBuf, (void *) &valueType, 1);
1107141cc406Sopenharmony_ci
1108141cc406Sopenharmony_ci  /* value length */
1109141cc406Sopenharmony_ci  slen = htons (valueLen);
1110141cc406Sopenharmony_ci  AppendToComBuf (pBuf, (void *) &slen, 2);
1111141cc406Sopenharmony_ci
1112141cc406Sopenharmony_ci  /* and value */
1113141cc406Sopenharmony_ci  return (AppendToComBuf (pBuf, (void *) pValue, valueLen));
1114141cc406Sopenharmony_ci
1115141cc406Sopenharmony_ci} /* AppendMessageToPacket */
1116141cc406Sopenharmony_ci
1117141cc406Sopenharmony_ci/***********************************************************/
1118141cc406Sopenharmony_ci
1119141cc406Sopenharmony_ci/* Initialise a packet
1120141cc406Sopenharmony_ci   \param pBuf : An initialise ComBuf
1121141cc406Sopenharmony_ci   \param type : either 0x01 ("normal" ) or 0x02 ("reply" )
1122141cc406Sopenharmony_ci   \return 0 on success, >0 otherwise
1123141cc406Sopenharmony_ci*/
1124141cc406Sopenharmony_ciint
1125141cc406Sopenharmony_ciInitPacket (struct ComBuf *pBuf, char type)
1126141cc406Sopenharmony_ci{
1127141cc406Sopenharmony_ci
1128141cc406Sopenharmony_ci  char header[8] = { 2, 0, 0, 2, 0, 0, 0, 0 };
1129141cc406Sopenharmony_ci
1130141cc406Sopenharmony_ci  header[2] = type;
1131141cc406Sopenharmony_ci
1132141cc406Sopenharmony_ci  /* reset size */
1133141cc406Sopenharmony_ci  pBuf->m_used = 0;
1134141cc406Sopenharmony_ci
1135141cc406Sopenharmony_ci  /* add header */
1136141cc406Sopenharmony_ci  return (AppendToComBuf (pBuf, (void *) &header, 8));
1137141cc406Sopenharmony_ci
1138141cc406Sopenharmony_ci} /* InitPacket */
1139141cc406Sopenharmony_ci
1140141cc406Sopenharmony_ci/***********************************************************/
1141141cc406Sopenharmony_ci
1142141cc406Sopenharmony_ci/* write length data to packet header
1143141cc406Sopenharmony_ci*/
1144141cc406Sopenharmony_civoid
1145141cc406Sopenharmony_ciFinalisePacket (struct ComBuf *pBuf)
1146141cc406Sopenharmony_ci{
1147141cc406Sopenharmony_ci
1148141cc406Sopenharmony_ci  /* sanity check */
1149141cc406Sopenharmony_ci  if (pBuf->m_used < 8)
1150141cc406Sopenharmony_ci    return;
1151141cc406Sopenharmony_ci
1152141cc406Sopenharmony_ci  /* set the size */
1153141cc406Sopenharmony_ci  *((unsigned short *) (pBuf->m_pBuf + 6)) = htons (pBuf->m_used - 8);
1154141cc406Sopenharmony_ci
1155141cc406Sopenharmony_ci  DBG (20, "FinalisePacket: outgoing packet:\n");
1156141cc406Sopenharmony_ci  HexDump (20, pBuf->m_pBuf, pBuf->m_used);
1157141cc406Sopenharmony_ci
1158141cc406Sopenharmony_ci} /* FinalisePacket */
1159141cc406Sopenharmony_ci
1160141cc406Sopenharmony_ci/***********************************************************/
1161141cc406Sopenharmony_ci
1162141cc406Sopenharmony_ci/* \return 1 if message is complete, 0 otherwise */
1163141cc406Sopenharmony_ciint
1164141cc406Sopenharmony_ciMessageIsComplete (unsigned char *pData, size_t size)
1165141cc406Sopenharmony_ci{
1166141cc406Sopenharmony_ci  unsigned short dataSize;
1167141cc406Sopenharmony_ci
1168141cc406Sopenharmony_ci  /* sanity check */
1169141cc406Sopenharmony_ci  if (size < 8)
1170141cc406Sopenharmony_ci    return 0;
1171141cc406Sopenharmony_ci
1172141cc406Sopenharmony_ci  /* :NOTE: we can't just cast to a short as data may not be aligned */
1173141cc406Sopenharmony_ci  dataSize = (((unsigned short) pData[6]) << 8) | pData[7];
1174141cc406Sopenharmony_ci
1175141cc406Sopenharmony_ci  DBG (20, "MessageIsComplete: data size = %d\n", dataSize);
1176141cc406Sopenharmony_ci
1177141cc406Sopenharmony_ci  if (size >= (size_t) (dataSize + 8))
1178141cc406Sopenharmony_ci    return 1;
1179141cc406Sopenharmony_ci  else
1180141cc406Sopenharmony_ci    return 0;
1181141cc406Sopenharmony_ci
1182141cc406Sopenharmony_ci} /* MessageIsComplete */
1183141cc406Sopenharmony_ci
1184141cc406Sopenharmony_ci/***********************************************************/
1185141cc406Sopenharmony_ci
1186141cc406Sopenharmony_ci/* process a registration broadcast response
1187141cc406Sopenharmony_ci   \return struct DeviceRecord pointer on success (caller frees), NULL on failure
1188141cc406Sopenharmony_ci*/
1189141cc406Sopenharmony_cistruct DeviceRecord *
1190141cc406Sopenharmony_ciProcessFindResponse (unsigned char *pData, size_t size)
1191141cc406Sopenharmony_ci{
1192141cc406Sopenharmony_ci
1193141cc406Sopenharmony_ci  struct DeviceRecord *pDevice = NULL;
1194141cc406Sopenharmony_ci  unsigned short messageSize, nameSize, valueSize;
1195141cc406Sopenharmony_ci  unsigned char *pItem, *pEnd, *pValue;
1196141cc406Sopenharmony_ci  char printerName[256] = { 0 };
1197141cc406Sopenharmony_ci  char printerModel[256] = "1600n";
1198141cc406Sopenharmony_ci  char *pModel, *pName;
1199141cc406Sopenharmony_ci
1200141cc406Sopenharmony_ci
1201141cc406Sopenharmony_ci  DBG (10, "ProcessFindResponse: processing %lu bytes, pData=%p\n",
1202141cc406Sopenharmony_ci       (unsigned long) size, (void *) pData);
1203141cc406Sopenharmony_ci
1204141cc406Sopenharmony_ci  /* check we have a complete packet */
1205141cc406Sopenharmony_ci  if (!MessageIsComplete (pData, size))
1206141cc406Sopenharmony_ci    {
1207141cc406Sopenharmony_ci      DBG (1, "ProcessFindResponse: Ignoring incomplete packet\n");
1208141cc406Sopenharmony_ci      return NULL;
1209141cc406Sopenharmony_ci    }
1210141cc406Sopenharmony_ci
1211141cc406Sopenharmony_ci  /* extract data size */
1212141cc406Sopenharmony_ci  messageSize = (((unsigned short) (pData[6])) << 8) | pData[7];
1213141cc406Sopenharmony_ci
1214141cc406Sopenharmony_ci  /* loop through items in message */
1215141cc406Sopenharmony_ci  pItem = pData + 8;
1216141cc406Sopenharmony_ci  pEnd = pItem + messageSize;
1217141cc406Sopenharmony_ci  while (pItem < pEnd)
1218141cc406Sopenharmony_ci    {
1219141cc406Sopenharmony_ci
1220141cc406Sopenharmony_ci      pItem++;
1221141cc406Sopenharmony_ci      nameSize = (((unsigned short) pItem[0]) << 8) | pItem[1];
1222141cc406Sopenharmony_ci      pItem += 2;
1223141cc406Sopenharmony_ci      pName = (char *) pItem;
1224141cc406Sopenharmony_ci
1225141cc406Sopenharmony_ci      pItem += nameSize;
1226141cc406Sopenharmony_ci
1227141cc406Sopenharmony_ci      pItem++;
1228141cc406Sopenharmony_ci      valueSize = (((unsigned short) pItem[0]) << 8) | pItem[1];
1229141cc406Sopenharmony_ci      pItem += 2;
1230141cc406Sopenharmony_ci
1231141cc406Sopenharmony_ci      pValue = pItem;
1232141cc406Sopenharmony_ci
1233141cc406Sopenharmony_ci      pItem += valueSize;
1234141cc406Sopenharmony_ci
1235141cc406Sopenharmony_ci      /* process the item */
1236141cc406Sopenharmony_ci      if (!strncmp ("std-scan-discovery-ip", pName, nameSize))
1237141cc406Sopenharmony_ci        {
1238141cc406Sopenharmony_ci
1239141cc406Sopenharmony_ci          snprintf (printerName, sizeof (printerName), "%d.%d.%d.%d",
1240141cc406Sopenharmony_ci            (int) pValue[0],
1241141cc406Sopenharmony_ci            (int) pValue[1], (int) pValue[2], (int) pValue[3]);
1242141cc406Sopenharmony_ci          DBG (2, "%s\n", printerName);
1243141cc406Sopenharmony_ci
1244141cc406Sopenharmony_ci        }
1245141cc406Sopenharmony_ci      else if (!strncmp ("std-scan-discovery-model-name", pName, nameSize))
1246141cc406Sopenharmony_ci        {
1247141cc406Sopenharmony_ci
1248141cc406Sopenharmony_ci          memset (printerModel, 0, sizeof (printerModel));
1249141cc406Sopenharmony_ci          if (valueSize > (sizeof (printerModel) - 1))
1250141cc406Sopenharmony_ci            valueSize = sizeof (printerModel) - 1;
1251141cc406Sopenharmony_ci          memcpy (printerModel, pValue, valueSize);
1252141cc406Sopenharmony_ci          DBG (2, "std-scan-discovery-model-name: %s\n", printerModel);
1253141cc406Sopenharmony_ci
1254141cc406Sopenharmony_ci        }
1255141cc406Sopenharmony_ci
1256141cc406Sopenharmony_ci    } /* while pItem */
1257141cc406Sopenharmony_ci
1258141cc406Sopenharmony_ci  /* just in case nothing sensible was found */
1259141cc406Sopenharmony_ci  if ( ! strlen( printerName ) ) return NULL;
1260141cc406Sopenharmony_ci
1261141cc406Sopenharmony_ci  pDevice = malloc (sizeof (struct DeviceRecord));
1262141cc406Sopenharmony_ci  if (!pDevice)
1263141cc406Sopenharmony_ci    {
1264141cc406Sopenharmony_ci      DBG (1, "ProcessFindResponse: memory allocation failure\n");
1265141cc406Sopenharmony_ci      return NULL;
1266141cc406Sopenharmony_ci    }
1267141cc406Sopenharmony_ci
1268141cc406Sopenharmony_ci  /* knock off "Dell " from start of model name */
1269141cc406Sopenharmony_ci  pModel = printerModel;
1270141cc406Sopenharmony_ci  if ( ! strncmp( pModel, "Dell ", 5 ) )
1271141cc406Sopenharmony_ci    pModel += 5;
1272141cc406Sopenharmony_ci
1273141cc406Sopenharmony_ci  pDevice->m_pName = strdup( printerName );
1274141cc406Sopenharmony_ci  pDevice->m_device.vendor = "Dell";
1275141cc406Sopenharmony_ci  pDevice->m_pModel = strdup (pModel);
1276141cc406Sopenharmony_ci  pDevice->m_device.type = "multi-function peripheral";
1277141cc406Sopenharmony_ci
1278141cc406Sopenharmony_ci  pDevice->m_device.name = pDevice->m_pName;
1279141cc406Sopenharmony_ci  pDevice->m_device.model = pDevice->m_pModel;
1280141cc406Sopenharmony_ci
1281141cc406Sopenharmony_ci  return pDevice;
1282141cc406Sopenharmony_ci
1283141cc406Sopenharmony_ci} /* ProcessFindResponse */
1284141cc406Sopenharmony_ci
1285141cc406Sopenharmony_ci/***********************************************************/
1286141cc406Sopenharmony_ci
1287141cc406Sopenharmony_ci/* frees a scanner state struct stored in gOpenScanners */
1288141cc406Sopenharmony_civoid
1289141cc406Sopenharmony_ciFreeScannerState (int iHandle)
1290141cc406Sopenharmony_ci{
1291141cc406Sopenharmony_ci
1292141cc406Sopenharmony_ci  /* check range etc */
1293141cc406Sopenharmony_ci  if (!ValidScannerNumber (iHandle))
1294141cc406Sopenharmony_ci    return;
1295141cc406Sopenharmony_ci
1296141cc406Sopenharmony_ci  /* close UDP handle */
1297141cc406Sopenharmony_ci  if (gOpenScanners[iHandle]->m_udpFd)
1298141cc406Sopenharmony_ci    close (gOpenScanners[iHandle]->m_udpFd);
1299141cc406Sopenharmony_ci
1300141cc406Sopenharmony_ci  /* free m_buf */
1301141cc406Sopenharmony_ci  FreeComBuf (&gOpenScanners[iHandle]->m_buf);
1302141cc406Sopenharmony_ci
1303141cc406Sopenharmony_ci  /* free m_imageData */
1304141cc406Sopenharmony_ci  FreeComBuf (&gOpenScanners[iHandle]->m_imageData);
1305141cc406Sopenharmony_ci
1306141cc406Sopenharmony_ci  /* free the struct */
1307141cc406Sopenharmony_ci  free (gOpenScanners[iHandle]);
1308141cc406Sopenharmony_ci
1309141cc406Sopenharmony_ci  /* set pointer to NULL */
1310141cc406Sopenharmony_ci  gOpenScanners[iHandle] = NULL;
1311141cc406Sopenharmony_ci
1312141cc406Sopenharmony_ci} /* FreeScannerState */
1313141cc406Sopenharmony_ci
1314141cc406Sopenharmony_ci/***********************************************************/
1315141cc406Sopenharmony_ci
1316141cc406Sopenharmony_ci/* \return 1 if iHandle is a valid member of gOpenScanners, 0 otherwise */
1317141cc406Sopenharmony_ciint
1318141cc406Sopenharmony_ciValidScannerNumber (int iHandle)
1319141cc406Sopenharmony_ci{
1320141cc406Sopenharmony_ci  /* check range */
1321141cc406Sopenharmony_ci  if ((iHandle < 0) || (iHandle >= MAX_SCANNERS))
1322141cc406Sopenharmony_ci    {
1323141cc406Sopenharmony_ci      DBG (1, "ValidScannerNumber: invalid scanner index %d", iHandle);
1324141cc406Sopenharmony_ci      return 0;
1325141cc406Sopenharmony_ci    }
1326141cc406Sopenharmony_ci
1327141cc406Sopenharmony_ci  /* check non-NULL pointer */
1328141cc406Sopenharmony_ci  if (!gOpenScanners[iHandle])
1329141cc406Sopenharmony_ci    {
1330141cc406Sopenharmony_ci      DBG (1, "ValidScannerNumber: NULL scanner struct %d", iHandle);
1331141cc406Sopenharmony_ci      return 0;
1332141cc406Sopenharmony_ci    }
1333141cc406Sopenharmony_ci
1334141cc406Sopenharmony_ci  /* OK */
1335141cc406Sopenharmony_ci  return 1;
1336141cc406Sopenharmony_ci
1337141cc406Sopenharmony_ci} /* ValidScannerNumber */
1338141cc406Sopenharmony_ci
1339141cc406Sopenharmony_ci/***********************************************************/
1340141cc406Sopenharmony_ci
1341141cc406Sopenharmony_ci/* process UDP responses
1342141cc406Sopenharmony_ci   \return 0 in success, >0 otherwise */
1343141cc406Sopenharmony_cistatic int
1344141cc406Sopenharmony_ciProcessUdpResponse (unsigned char *pData, size_t size,
1345141cc406Sopenharmony_ci		    struct ScannerState *pState)
1346141cc406Sopenharmony_ci{
1347141cc406Sopenharmony_ci
1348141cc406Sopenharmony_ci  unsigned short messageSize, nameSize, valueSize;
1349141cc406Sopenharmony_ci  unsigned char *pItem, *pEnd;
1350141cc406Sopenharmony_ci  char sockBuf[SOCK_BUF_SIZE], *pName;
1351141cc406Sopenharmony_ci  struct ComBuf tcpBuf;
1352141cc406Sopenharmony_ci  int nread;
1353141cc406Sopenharmony_ci  unsigned int numUsed;
1354141cc406Sopenharmony_ci
1355141cc406Sopenharmony_ci  HexDump (15, pData, size);
1356141cc406Sopenharmony_ci
1357141cc406Sopenharmony_ci  DBG (10, "ProcessUdpResponse: processing %lu bytes, pData=%p\n",
1358141cc406Sopenharmony_ci       (unsigned long) size, (void *) pData);
1359141cc406Sopenharmony_ci
1360141cc406Sopenharmony_ci  /* check we have a complete packet */
1361141cc406Sopenharmony_ci  if (!MessageIsComplete (pData, size))
1362141cc406Sopenharmony_ci    {
1363141cc406Sopenharmony_ci      DBG (1, "ProcessUdpResponse: Ignoring incomplete packet\n");
1364141cc406Sopenharmony_ci      return 1;
1365141cc406Sopenharmony_ci    }
1366141cc406Sopenharmony_ci
1367141cc406Sopenharmony_ci  /* init a com buf for use in tcp communication */
1368141cc406Sopenharmony_ci  InitComBuf (&tcpBuf);
1369141cc406Sopenharmony_ci
1370141cc406Sopenharmony_ci  /* extract data size */
1371141cc406Sopenharmony_ci  messageSize = (((unsigned short) (pData[6])) << 8) | pData[7];
1372141cc406Sopenharmony_ci
1373141cc406Sopenharmony_ci  /* loop through items in message */
1374141cc406Sopenharmony_ci  pItem = pData + 8;
1375141cc406Sopenharmony_ci  pEnd = pItem + messageSize;
1376141cc406Sopenharmony_ci  while (pItem < pEnd)
1377141cc406Sopenharmony_ci    {
1378141cc406Sopenharmony_ci
1379141cc406Sopenharmony_ci      pItem++;
1380141cc406Sopenharmony_ci      nameSize = (((unsigned short) pItem[0]) << 8) | pItem[1];
1381141cc406Sopenharmony_ci      pItem += 2;
1382141cc406Sopenharmony_ci      pName = (char *) pItem;
1383141cc406Sopenharmony_ci
1384141cc406Sopenharmony_ci      pItem += nameSize;
1385141cc406Sopenharmony_ci
1386141cc406Sopenharmony_ci      pItem++;
1387141cc406Sopenharmony_ci      valueSize = (((unsigned short) pItem[0]) << 8) | pItem[1];
1388141cc406Sopenharmony_ci      pItem += 2;
1389141cc406Sopenharmony_ci
1390141cc406Sopenharmony_ci      pItem += valueSize;
1391141cc406Sopenharmony_ci
1392141cc406Sopenharmony_ci      /* process the item */
1393141cc406Sopenharmony_ci      if (!strncmp ("std-scan-request-tcp-connection", pName, nameSize))
1394141cc406Sopenharmony_ci        {
1395141cc406Sopenharmony_ci
1396141cc406Sopenharmony_ci          /* open TCP socket to scanner */
1397141cc406Sopenharmony_ci          if (!(pState->m_tcpFd = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)))
1398141cc406Sopenharmony_ci            {
1399141cc406Sopenharmony_ci              DBG (1, "ProcessUdpResponse: error opening TCP socket\n");
1400141cc406Sopenharmony_ci              return 2;
1401141cc406Sopenharmony_ci            }
1402141cc406Sopenharmony_ci          if (connect (pState->m_tcpFd,
1403141cc406Sopenharmony_ci                       (struct sockaddr *) &pState->m_sockAddr,
1404141cc406Sopenharmony_ci                       sizeof (pState->m_sockAddr)))
1405141cc406Sopenharmony_ci            {
1406141cc406Sopenharmony_ci              DBG (1,
1407141cc406Sopenharmony_ci                   "ProcessUdpResponse: error connecting to scanner TCP port\n");
1408141cc406Sopenharmony_ci              goto cleanup;
1409141cc406Sopenharmony_ci            }
1410141cc406Sopenharmony_ci
1411141cc406Sopenharmony_ci          DBG (1, "ProcessUdpResponse: opened TCP connection to scanner\n");
1412141cc406Sopenharmony_ci
1413141cc406Sopenharmony_ci          /* clear read buf */
1414141cc406Sopenharmony_ci          tcpBuf.m_used = 0;
1415141cc406Sopenharmony_ci
1416141cc406Sopenharmony_ci          /* TCP read loop */
1417141cc406Sopenharmony_ci          while (1)
1418141cc406Sopenharmony_ci            {
1419141cc406Sopenharmony_ci
1420141cc406Sopenharmony_ci              nread = read (pState->m_tcpFd, sockBuf, sizeof (sockBuf));
1421141cc406Sopenharmony_ci
1422141cc406Sopenharmony_ci              if (nread <= 0)
1423141cc406Sopenharmony_ci                {
1424141cc406Sopenharmony_ci                  DBG (1, "ProcessUdpResponse: TCP read returned %d\n",
1425141cc406Sopenharmony_ci                       nread);
1426141cc406Sopenharmony_ci                  break;
1427141cc406Sopenharmony_ci                }
1428141cc406Sopenharmony_ci
1429141cc406Sopenharmony_ci              /* append message to buffer */
1430141cc406Sopenharmony_ci              if (AppendToComBuf (&tcpBuf, (unsigned char *) sockBuf, nread))
1431141cc406Sopenharmony_ci                goto cleanup;
1432141cc406Sopenharmony_ci
1433141cc406Sopenharmony_ci              /* process all available responses */
1434141cc406Sopenharmony_ci              while (tcpBuf.m_used)
1435141cc406Sopenharmony_ci                {
1436141cc406Sopenharmony_ci
1437141cc406Sopenharmony_ci                  /* note the buffer size before the call */
1438141cc406Sopenharmony_ci                  numUsed = tcpBuf.m_used;
1439141cc406Sopenharmony_ci
1440141cc406Sopenharmony_ci                  /* process the response */
1441141cc406Sopenharmony_ci                  if (ProcessTcpResponse (pState, &tcpBuf))
1442141cc406Sopenharmony_ci                    goto cleanup;
1443141cc406Sopenharmony_ci
1444141cc406Sopenharmony_ci                  /* if the buffer size has not changed then assume no more processing is possible */
1445141cc406Sopenharmony_ci                  if (numUsed == tcpBuf.m_used)
1446141cc406Sopenharmony_ci                    break;
1447141cc406Sopenharmony_ci
1448141cc406Sopenharmony_ci                } /* while */
1449141cc406Sopenharmony_ci
1450141cc406Sopenharmony_ci            } /* while */
1451141cc406Sopenharmony_ci
1452141cc406Sopenharmony_ci          close (pState->m_tcpFd);
1453141cc406Sopenharmony_ci          DBG (1, "ProcessUdpResponse: closed TCP connection to scanner\n");
1454141cc406Sopenharmony_ci
1455141cc406Sopenharmony_ci          /* signal end of session */
1456141cc406Sopenharmony_ci          pState->m_bFinish = 1;
1457141cc406Sopenharmony_ci
1458141cc406Sopenharmony_ci        } /* if */
1459141cc406Sopenharmony_ci
1460141cc406Sopenharmony_ci    } /* while pItem */
1461141cc406Sopenharmony_ci
1462141cc406Sopenharmony_ci  return 0;
1463141cc406Sopenharmony_ci
1464141cc406Sopenharmony_cicleanup:
1465141cc406Sopenharmony_ci
1466141cc406Sopenharmony_ci  FreeComBuf (&tcpBuf);
1467141cc406Sopenharmony_ci  close (pState->m_tcpFd);
1468141cc406Sopenharmony_ci  return 3;
1469141cc406Sopenharmony_ci
1470141cc406Sopenharmony_ci} /* ProcessUdpResponse */
1471141cc406Sopenharmony_ci
1472141cc406Sopenharmony_ci/***********************************************************/
1473141cc406Sopenharmony_ci
1474141cc406Sopenharmony_ci/* process TCP responses, \return 0 in success, >0 otherwise */
1475141cc406Sopenharmony_ciint
1476141cc406Sopenharmony_ciProcessTcpResponse (struct ScannerState *pState, struct ComBuf *pTcpBuf)
1477141cc406Sopenharmony_ci{
1478141cc406Sopenharmony_ci
1479141cc406Sopenharmony_ci  struct ComBuf buf;
1480141cc406Sopenharmony_ci  unsigned short messageSize = 0, nameSize, valueSize, dataChunkSize;
1481141cc406Sopenharmony_ci  unsigned char *pItem, *pEnd, *pValue;
1482141cc406Sopenharmony_ci  unsigned char *pData = pTcpBuf->m_pBuf;
1483141cc406Sopenharmony_ci  char *pName;
1484141cc406Sopenharmony_ci  unsigned int uiVal;
1485141cc406Sopenharmony_ci  int errorCheck = 0;
1486141cc406Sopenharmony_ci  int bProcessImage = 0;
1487141cc406Sopenharmony_ci
1488141cc406Sopenharmony_ci  DBG (10, "ProcessTcpResponse: processing %lu bytes, pData=%p\n",
1489141cc406Sopenharmony_ci       (unsigned long) pTcpBuf->m_used, (void *) pData);
1490141cc406Sopenharmony_ci  HexDump (15, pData, pTcpBuf->m_used);
1491141cc406Sopenharmony_ci
1492141cc406Sopenharmony_ci  /* if message not complete then wait for more to arrive */
1493141cc406Sopenharmony_ci  if (!MessageIsComplete (pData, pTcpBuf->m_used))
1494141cc406Sopenharmony_ci    {
1495141cc406Sopenharmony_ci      DBG (10, "ProcessTcpResponse: incomplete message, returning\n");
1496141cc406Sopenharmony_ci      return 0;
1497141cc406Sopenharmony_ci    }
1498141cc406Sopenharmony_ci
1499141cc406Sopenharmony_ci  /* init a buffer for our outbound messages */
1500141cc406Sopenharmony_ci  if (InitComBuf (&buf))
1501141cc406Sopenharmony_ci    {
1502141cc406Sopenharmony_ci      errorCheck |= 1;
1503141cc406Sopenharmony_ci      goto cleanup;
1504141cc406Sopenharmony_ci    }
1505141cc406Sopenharmony_ci
1506141cc406Sopenharmony_ci  /* extract data size */
1507141cc406Sopenharmony_ci  messageSize = (((unsigned short) (pData[6])) << 8) | pData[7];
1508141cc406Sopenharmony_ci
1509141cc406Sopenharmony_ci  /* loop through items in message */
1510141cc406Sopenharmony_ci  pItem = pData + 8;
1511141cc406Sopenharmony_ci  pEnd = pItem + messageSize;
1512141cc406Sopenharmony_ci  while (pItem < pEnd)
1513141cc406Sopenharmony_ci    {
1514141cc406Sopenharmony_ci
1515141cc406Sopenharmony_ci      pItem++;
1516141cc406Sopenharmony_ci      nameSize = (((unsigned short) pItem[0]) << 8) | pItem[1];
1517141cc406Sopenharmony_ci      pItem += 2;
1518141cc406Sopenharmony_ci      pName = (char *) pItem;
1519141cc406Sopenharmony_ci
1520141cc406Sopenharmony_ci      pItem += nameSize;
1521141cc406Sopenharmony_ci
1522141cc406Sopenharmony_ci      pItem++;
1523141cc406Sopenharmony_ci      valueSize = (((unsigned short) pItem[0]) << 8) | pItem[1];
1524141cc406Sopenharmony_ci      pItem += 2;
1525141cc406Sopenharmony_ci
1526141cc406Sopenharmony_ci      pValue = pItem;
1527141cc406Sopenharmony_ci
1528141cc406Sopenharmony_ci      pItem += valueSize;
1529141cc406Sopenharmony_ci
1530141cc406Sopenharmony_ci      /* process the item */
1531141cc406Sopenharmony_ci      if (!strncmp ("std-scan-session-open", pName, nameSize))
1532141cc406Sopenharmony_ci        {
1533141cc406Sopenharmony_ci
1534141cc406Sopenharmony_ci          errorCheck |= InitPacket (&buf, 0x02);
1535141cc406Sopenharmony_ci          uiVal = 0;
1536141cc406Sopenharmony_ci          errorCheck |=
1537141cc406Sopenharmony_ci            AppendMessageToPacket (&buf, 0x22,
1538141cc406Sopenharmony_ci                                   "std-scan-session-open-response", 0x05,
1539141cc406Sopenharmony_ci                                   &uiVal, sizeof (uiVal));
1540141cc406Sopenharmony_ci          FinalisePacket (&buf);
1541141cc406Sopenharmony_ci          send (pState->m_tcpFd, buf.m_pBuf, buf.m_used, 0);
1542141cc406Sopenharmony_ci
1543141cc406Sopenharmony_ci        }
1544141cc406Sopenharmony_ci      else if (!strncmp ("std-scan-getclientpref", pName, nameSize))
1545141cc406Sopenharmony_ci        {
1546141cc406Sopenharmony_ci
1547141cc406Sopenharmony_ci          errorCheck |= InitPacket (&buf, 0x02);
1548141cc406Sopenharmony_ci          uiVal = 0;
1549141cc406Sopenharmony_ci          errorCheck |=
1550141cc406Sopenharmony_ci            AppendMessageToPacket (&buf, 0x22, "std-scan-getclientpref-x1",
1551141cc406Sopenharmony_ci                                   0x05, &uiVal, sizeof (uiVal));
1552141cc406Sopenharmony_ci          errorCheck |=
1553141cc406Sopenharmony_ci            AppendMessageToPacket (&buf, 0x22, "std-scan-getclientpref-x2",
1554141cc406Sopenharmony_ci                                   0x05, &uiVal, sizeof (uiVal));
1555141cc406Sopenharmony_ci          errorCheck |=
1556141cc406Sopenharmony_ci            AppendMessageToPacket (&buf, 0x22, "std-scan-getclientpref-y1",
1557141cc406Sopenharmony_ci                                   0x05, &uiVal, sizeof (uiVal));
1558141cc406Sopenharmony_ci          errorCheck |=
1559141cc406Sopenharmony_ci            AppendMessageToPacket (&buf, 0x22, "std-scan-getclientpref-y2",
1560141cc406Sopenharmony_ci                                   0x05, &uiVal, sizeof (uiVal));
1561141cc406Sopenharmony_ci          errorCheck |=
1562141cc406Sopenharmony_ci            AppendMessageToPacket (&buf, 0x22,
1563141cc406Sopenharmony_ci                                   "std-scan-getclientpref-xresolution", 0x04,
1564141cc406Sopenharmony_ci                                   &pState->m_xres, sizeof (pState->m_xres));
1565141cc406Sopenharmony_ci          errorCheck |=
1566141cc406Sopenharmony_ci            AppendMessageToPacket (&buf, 0x22,
1567141cc406Sopenharmony_ci                                   "std-scan-getclientpref-yresolution", 0x04,
1568141cc406Sopenharmony_ci                                   &pState->m_yres, sizeof (pState->m_yres));
1569141cc406Sopenharmony_ci          errorCheck |=
1570141cc406Sopenharmony_ci            AppendMessageToPacket (&buf, 0x22,
1571141cc406Sopenharmony_ci                                   "std-scan-getclientpref-image-composition",
1572141cc406Sopenharmony_ci                                   0x06, &pState->m_composition,
1573141cc406Sopenharmony_ci                                   sizeof (pState->m_composition));
1574141cc406Sopenharmony_ci          errorCheck |=
1575141cc406Sopenharmony_ci            AppendMessageToPacket (&buf, 0x22,
1576141cc406Sopenharmony_ci                                   "std-scan-getclientpref-brightness", 0x02,
1577141cc406Sopenharmony_ci                                   &pState->m_brightness,
1578141cc406Sopenharmony_ci                                   sizeof (pState->m_brightness));
1579141cc406Sopenharmony_ci          errorCheck |=
1580141cc406Sopenharmony_ci            AppendMessageToPacket (&buf, 0x22,
1581141cc406Sopenharmony_ci                                   "std-scan-getclientpref-image-compression",
1582141cc406Sopenharmony_ci                                   0x06, &pState->m_compression,
1583141cc406Sopenharmony_ci                                   sizeof (pState->m_compression));
1584141cc406Sopenharmony_ci          errorCheck |=
1585141cc406Sopenharmony_ci            AppendMessageToPacket (&buf, 0x22,
1586141cc406Sopenharmony_ci                                   "std-scan-getclientpref-file-type", 0x06,
1587141cc406Sopenharmony_ci                                   &pState->m_fileType,
1588141cc406Sopenharmony_ci                                   sizeof (pState->m_fileType));
1589141cc406Sopenharmony_ci          errorCheck |=
1590141cc406Sopenharmony_ci            AppendMessageToPacket (&buf, 0x22,
1591141cc406Sopenharmony_ci                                   "std-scan-getclientpref-paper-size-detect",
1592141cc406Sopenharmony_ci                                   0x06, &uiVal, sizeof (uiVal));
1593141cc406Sopenharmony_ci          errorCheck |=
1594141cc406Sopenharmony_ci            AppendMessageToPacket (&buf, 0x22,
1595141cc406Sopenharmony_ci                                   "std-scan-getclientpref-paper-scanner-type",
1596141cc406Sopenharmony_ci                                   0x06, &uiVal, sizeof (uiVal));
1597141cc406Sopenharmony_ci          FinalisePacket (&buf);
1598141cc406Sopenharmony_ci          send (pState->m_tcpFd, buf.m_pBuf, buf.m_used, 0);
1599141cc406Sopenharmony_ci
1600141cc406Sopenharmony_ci        }
1601141cc406Sopenharmony_ci      else if (!strncmp ("std-scan-document-start", pName, nameSize))
1602141cc406Sopenharmony_ci        {
1603141cc406Sopenharmony_ci          errorCheck |= InitPacket (&buf, 0x02);
1604141cc406Sopenharmony_ci          uiVal = 0;
1605141cc406Sopenharmony_ci          errorCheck |=
1606141cc406Sopenharmony_ci            AppendMessageToPacket (&buf, 0x22,
1607141cc406Sopenharmony_ci                                   "std-scan-document-start-response", 0x05,
1608141cc406Sopenharmony_ci                                   &uiVal, sizeof (uiVal));
1609141cc406Sopenharmony_ci          FinalisePacket (&buf);
1610141cc406Sopenharmony_ci          send (pState->m_tcpFd, buf.m_pBuf, buf.m_used, 0);
1611141cc406Sopenharmony_ci        }
1612141cc406Sopenharmony_ci      else if (!strncmp ("std-scan-document-file-type", pName, nameSize))
1613141cc406Sopenharmony_ci        {
1614141cc406Sopenharmony_ci          memcpy (&pState->m_fileType, pValue, sizeof (pState->m_fileType));
1615141cc406Sopenharmony_ci          DBG (5, "File type: %x\n", ntohl (pState->m_fileType));
1616141cc406Sopenharmony_ci        }
1617141cc406Sopenharmony_ci      else
1618141cc406Sopenharmony_ci        if (!strncmp ("std-scan-document-image-compression", pName, nameSize))
1619141cc406Sopenharmony_ci        {
1620141cc406Sopenharmony_ci          memcpy (&pState->m_compression, pValue,
1621141cc406Sopenharmony_ci                  sizeof (pState->m_compression));
1622141cc406Sopenharmony_ci          DBG (5, "Compression: %x\n", ntohl (pState->m_compression));
1623141cc406Sopenharmony_ci
1624141cc406Sopenharmony_ci        }
1625141cc406Sopenharmony_ci      else if (!strncmp ("std-scan-document-xresolution", pName, nameSize))
1626141cc406Sopenharmony_ci        {
1627141cc406Sopenharmony_ci          memcpy (&pState->m_xres, pValue, sizeof (pState->m_xres));
1628141cc406Sopenharmony_ci          DBG (5, "X resolution: %d\n", ntohs (pState->m_xres));
1629141cc406Sopenharmony_ci        }
1630141cc406Sopenharmony_ci      else if (!strncmp ("std-scan-document-yresolution", pName, nameSize))
1631141cc406Sopenharmony_ci        {
1632141cc406Sopenharmony_ci          memcpy (&pState->m_yres, pValue, sizeof (pState->m_yres));
1633141cc406Sopenharmony_ci          DBG (5, "Y resolution: %d\n", ntohs (pState->m_yres));
1634141cc406Sopenharmony_ci        }
1635141cc406Sopenharmony_ci      else if (!strncmp ("std-scan-page-widthpixel", pName, nameSize))
1636141cc406Sopenharmony_ci        {
1637141cc406Sopenharmony_ci          if (1 || !pState->m_pixelWidth)
1638141cc406Sopenharmony_ci            {
1639141cc406Sopenharmony_ci              memcpy (&pState->m_pixelWidth, pValue,
1640141cc406Sopenharmony_ci                      sizeof (pState->m_pixelWidth));
1641141cc406Sopenharmony_ci              DBG (5, "Width: %d\n", ntohl (pState->m_pixelWidth));
1642141cc406Sopenharmony_ci            }
1643141cc406Sopenharmony_ci          else
1644141cc406Sopenharmony_ci            {
1645141cc406Sopenharmony_ci              DBG (5, "Ignoring width (already have a value)\n");
1646141cc406Sopenharmony_ci            }
1647141cc406Sopenharmony_ci        }
1648141cc406Sopenharmony_ci      else if (!strncmp ("std-scan-page-heightpixel", pName, nameSize))
1649141cc406Sopenharmony_ci        {
1650141cc406Sopenharmony_ci          if (1 || !pState->m_pixelHeight)
1651141cc406Sopenharmony_ci            {
1652141cc406Sopenharmony_ci              memcpy (&pState->m_pixelHeight, pValue,
1653141cc406Sopenharmony_ci                      sizeof (pState->m_pixelHeight));
1654141cc406Sopenharmony_ci              DBG (5, "Height: %d\n", ntohl (pState->m_pixelHeight));
1655141cc406Sopenharmony_ci            }
1656141cc406Sopenharmony_ci          else
1657141cc406Sopenharmony_ci            {
1658141cc406Sopenharmony_ci              DBG (5, "Ignoring height (already have a value)\n");
1659141cc406Sopenharmony_ci            }
1660141cc406Sopenharmony_ci        }
1661141cc406Sopenharmony_ci      else if (!strncmp ("std-scan-page-start", pName, nameSize))
1662141cc406Sopenharmony_ci        {
1663141cc406Sopenharmony_ci          errorCheck |= InitPacket (&buf, 0x02);
1664141cc406Sopenharmony_ci          uiVal = 0;
1665141cc406Sopenharmony_ci          errorCheck |=
1666141cc406Sopenharmony_ci            AppendMessageToPacket (&buf, 0x22, "std-scan-page-start-response",
1667141cc406Sopenharmony_ci                                   0x05, &uiVal, sizeof (uiVal));
1668141cc406Sopenharmony_ci          FinalisePacket (&buf);
1669141cc406Sopenharmony_ci          send (pState->m_tcpFd, buf.m_pBuf, buf.m_used, 0);
1670141cc406Sopenharmony_ci
1671141cc406Sopenharmony_ci          /* reset the data buffer ready to store a new page */
1672141cc406Sopenharmony_ci          pState->m_buf.m_used = 0;
1673141cc406Sopenharmony_ci
1674141cc406Sopenharmony_ci          /* init current page size */
1675141cc406Sopenharmony_ci          pState->m_currentPageBytes = 0;
1676141cc406Sopenharmony_ci
1677141cc406Sopenharmony_ci          pState->m_pixelWidth = 0;
1678141cc406Sopenharmony_ci          pState->m_pixelHeight = 0;
1679141cc406Sopenharmony_ci        }
1680141cc406Sopenharmony_ci      else if (!strncmp ("std-scan-page-end", pName, nameSize))
1681141cc406Sopenharmony_ci        {
1682141cc406Sopenharmony_ci          bProcessImage = 1;
1683141cc406Sopenharmony_ci
1684141cc406Sopenharmony_ci          errorCheck |= InitPacket (&buf, 0x02);
1685141cc406Sopenharmony_ci          uiVal = 0;
1686141cc406Sopenharmony_ci          errorCheck |=
1687141cc406Sopenharmony_ci            AppendMessageToPacket (&buf, 0x22, "std-scan-page-end-response",
1688141cc406Sopenharmony_ci                                   0x05, &uiVal, sizeof (uiVal));
1689141cc406Sopenharmony_ci          FinalisePacket (&buf);
1690141cc406Sopenharmony_ci          send (pState->m_tcpFd, buf.m_pBuf, buf.m_used, 0);
1691141cc406Sopenharmony_ci        }
1692141cc406Sopenharmony_ci      else if (!strncmp ("std-scan-document-end", pName, nameSize))
1693141cc406Sopenharmony_ci        {
1694141cc406Sopenharmony_ci          errorCheck |= InitPacket (&buf, 0x02);
1695141cc406Sopenharmony_ci          uiVal = 0;
1696141cc406Sopenharmony_ci          errorCheck |=
1697141cc406Sopenharmony_ci            AppendMessageToPacket (&buf, 0x22,
1698141cc406Sopenharmony_ci                                   "std-scan-document-end-response", 0x05,
1699141cc406Sopenharmony_ci                                   &uiVal, sizeof (uiVal));
1700141cc406Sopenharmony_ci          FinalisePacket (&buf);
1701141cc406Sopenharmony_ci          send (pState->m_tcpFd, buf.m_pBuf, buf.m_used, 0);
1702141cc406Sopenharmony_ci
1703141cc406Sopenharmony_ci          /* reset the data buffer ready to store a new page */
1704141cc406Sopenharmony_ci          pState->m_buf.m_used = 0;
1705141cc406Sopenharmony_ci        }
1706141cc406Sopenharmony_ci      else if (!strncmp ("std-scan-session-end", pName, nameSize))
1707141cc406Sopenharmony_ci        {
1708141cc406Sopenharmony_ci          errorCheck |= InitPacket (&buf, 0x02);
1709141cc406Sopenharmony_ci          uiVal = 0;
1710141cc406Sopenharmony_ci          errorCheck |=
1711141cc406Sopenharmony_ci            AppendMessageToPacket (&buf, 0x22,
1712141cc406Sopenharmony_ci                                   "std-scan-session-end-response", 0x05,
1713141cc406Sopenharmony_ci                                   &uiVal, sizeof (uiVal));
1714141cc406Sopenharmony_ci          FinalisePacket (&buf);
1715141cc406Sopenharmony_ci          send (pState->m_tcpFd, buf.m_pBuf, buf.m_used, 0);
1716141cc406Sopenharmony_ci
1717141cc406Sopenharmony_ci          /* initialise a shutodwn of the socket */
1718141cc406Sopenharmony_ci          shutdown (pState->m_tcpFd, SHUT_RDWR);
1719141cc406Sopenharmony_ci        }
1720141cc406Sopenharmony_ci      else if (!strncmp ("std-scan-scandata-error", pName, nameSize))
1721141cc406Sopenharmony_ci        {
1722141cc406Sopenharmony_ci          /* determine the size of data in this chunk */
1723141cc406Sopenharmony_ci          dataChunkSize = (pItem[6] << 8) + pItem[7];
1724141cc406Sopenharmony_ci
1725141cc406Sopenharmony_ci          pItem += 8;
1726141cc406Sopenharmony_ci
1727141cc406Sopenharmony_ci          DBG (10, "Reading %d bytes of scan data\n", dataChunkSize);
1728141cc406Sopenharmony_ci
1729141cc406Sopenharmony_ci          /* append message to buffer */
1730141cc406Sopenharmony_ci          errorCheck |= AppendToComBuf (&pState->m_buf, pItem, dataChunkSize);
1731141cc406Sopenharmony_ci
1732141cc406Sopenharmony_ci          pItem += dataChunkSize;
1733141cc406Sopenharmony_ci
1734141cc406Sopenharmony_ci          DBG (10, "Accumulated %lu bytes of scan data so far\n",
1735141cc406Sopenharmony_ci               (unsigned long)pState->m_buf.m_used);
1736141cc406Sopenharmony_ci        } /* if */
1737141cc406Sopenharmony_ci    } /* while */
1738141cc406Sopenharmony_ci
1739141cc406Sopenharmony_ci  /* process page data if required */
1740141cc406Sopenharmony_ci  if ( bProcessImage ) errorCheck |= ProcessPageData (pState);
1741141cc406Sopenharmony_ci
1742141cc406Sopenharmony_cicleanup:
1743141cc406Sopenharmony_ci
1744141cc406Sopenharmony_ci  /* remove processed data (including 8 byte header) from start of tcp buffer */
1745141cc406Sopenharmony_ci  PopFromComBuf (pTcpBuf, messageSize + 8);
1746141cc406Sopenharmony_ci
1747141cc406Sopenharmony_ci  /* free com buf */
1748141cc406Sopenharmony_ci  FreeComBuf (&buf);
1749141cc406Sopenharmony_ci
1750141cc406Sopenharmony_ci  return errorCheck;
1751141cc406Sopenharmony_ci
1752141cc406Sopenharmony_ci} /* ProcessTcpResponse */
1753141cc406Sopenharmony_ci
1754141cc406Sopenharmony_ci/***********************************************************/
1755141cc406Sopenharmony_ci
1756141cc406Sopenharmony_ci/* remove data from the front of a ComBuf struct
1757141cc406Sopenharmony_ci   \return 0 if successful, >0 otherwise
1758141cc406Sopenharmony_ci*/
1759141cc406Sopenharmony_ciint
1760141cc406Sopenharmony_ciPopFromComBuf (struct ComBuf *pBuf, size_t datSize)
1761141cc406Sopenharmony_ci{
1762141cc406Sopenharmony_ci
1763141cc406Sopenharmony_ci  /* check if we're trying to remove more data than is present */
1764141cc406Sopenharmony_ci  if (datSize > pBuf->m_used)
1765141cc406Sopenharmony_ci    {
1766141cc406Sopenharmony_ci      pBuf->m_used = 0;
1767141cc406Sopenharmony_ci      return 1;
1768141cc406Sopenharmony_ci    }
1769141cc406Sopenharmony_ci
1770141cc406Sopenharmony_ci  /* check easy cases */
1771141cc406Sopenharmony_ci  if ((!datSize) || (datSize == pBuf->m_used))
1772141cc406Sopenharmony_ci    {
1773141cc406Sopenharmony_ci      pBuf->m_used -= datSize;
1774141cc406Sopenharmony_ci      return 0;
1775141cc406Sopenharmony_ci    }
1776141cc406Sopenharmony_ci
1777141cc406Sopenharmony_ci  /* move remaining memory contents to start */
1778141cc406Sopenharmony_ci  memmove (pBuf->m_pBuf, pBuf->m_pBuf + datSize, pBuf->m_used - datSize);
1779141cc406Sopenharmony_ci
1780141cc406Sopenharmony_ci  pBuf->m_used -= datSize;
1781141cc406Sopenharmony_ci  return 0;
1782141cc406Sopenharmony_ci
1783141cc406Sopenharmony_ci} /* PopFromComBuf */
1784141cc406Sopenharmony_ci
1785141cc406Sopenharmony_ci/***********************************************************/
1786141cc406Sopenharmony_ci
1787141cc406Sopenharmony_ci/* Process the data from a single scanned page, \return 0 in success, >0 otherwise */
1788141cc406Sopenharmony_ciint
1789141cc406Sopenharmony_ciProcessPageData (struct ScannerState *pState)
1790141cc406Sopenharmony_ci{
1791141cc406Sopenharmony_ci
1792141cc406Sopenharmony_ci  FILE *fTmp;
1793141cc406Sopenharmony_ci  int fdTmp;
1794141cc406Sopenharmony_ci  struct jpeg_source_mgr jpegSrcMgr;
1795141cc406Sopenharmony_ci  struct JpegDataDecompState jpegCinfo;
1796141cc406Sopenharmony_ci  struct jpeg_error_mgr jpegErr;
1797141cc406Sopenharmony_ci  int numPixels, iPixel, width, height, scanLineSize, imageBytes;
1798141cc406Sopenharmony_ci  int ret = 0;
1799141cc406Sopenharmony_ci  struct PageInfo pageInfo;
1800141cc406Sopenharmony_ci
1801141cc406Sopenharmony_ci  JSAMPLE *pJpegLine = NULL;
1802141cc406Sopenharmony_ci  uint32_t *pTiffRgba = NULL;
1803141cc406Sopenharmony_ci  unsigned char *pOut;
1804141cc406Sopenharmony_ci  char tiffErrBuf[1024];
1805141cc406Sopenharmony_ci
1806141cc406Sopenharmony_ci  TIFF *pTiff = NULL;
1807141cc406Sopenharmony_ci
1808141cc406Sopenharmony_ci  /* If there's no data then there's nothing to write */
1809141cc406Sopenharmony_ci  if (!pState->m_buf.m_used)
1810141cc406Sopenharmony_ci    return 0;
1811141cc406Sopenharmony_ci
1812141cc406Sopenharmony_ci  DBG (1, "ProcessPageData: Got compression %x\n",
1813141cc406Sopenharmony_ci       ntohl (pState->m_compression));
1814141cc406Sopenharmony_ci
1815141cc406Sopenharmony_ci  switch (ntohl (pState->m_compression))
1816141cc406Sopenharmony_ci    {
1817141cc406Sopenharmony_ci
1818141cc406Sopenharmony_ci    case 0x20:
1819141cc406Sopenharmony_ci      /* decode as JPEG if appropriate */
1820141cc406Sopenharmony_ci      {
1821141cc406Sopenharmony_ci
1822141cc406Sopenharmony_ci        jpegSrcMgr.resync_to_restart = jpeg_resync_to_restart;
1823141cc406Sopenharmony_ci        jpegSrcMgr.init_source = JpegDecompInitSource;
1824141cc406Sopenharmony_ci        jpegSrcMgr.fill_input_buffer = JpegDecompFillInputBuffer;
1825141cc406Sopenharmony_ci        jpegSrcMgr.skip_input_data = JpegDecompSkipInputData;
1826141cc406Sopenharmony_ci        jpegSrcMgr.term_source = JpegDecompTermSource;
1827141cc406Sopenharmony_ci
1828141cc406Sopenharmony_ci        jpegCinfo.m_cinfo.err = jpeg_std_error (&jpegErr);
1829141cc406Sopenharmony_ci        jpeg_create_decompress (&jpegCinfo.m_cinfo);
1830141cc406Sopenharmony_ci        jpegCinfo.m_cinfo.src = &jpegSrcMgr;
1831141cc406Sopenharmony_ci        jpegCinfo.m_bytesRemaining = pState->m_buf.m_used;
1832141cc406Sopenharmony_ci        jpegCinfo.m_pData = pState->m_buf.m_pBuf;
1833141cc406Sopenharmony_ci
1834141cc406Sopenharmony_ci        jpeg_read_header (&jpegCinfo.m_cinfo, TRUE);
1835141cc406Sopenharmony_ci        jpeg_start_decompress (&jpegCinfo.m_cinfo);
1836141cc406Sopenharmony_ci
1837141cc406Sopenharmony_ci        /* allocate space for a single scanline */
1838141cc406Sopenharmony_ci        scanLineSize = jpegCinfo.m_cinfo.output_width
1839141cc406Sopenharmony_ci          * jpegCinfo.m_cinfo.output_components;
1840141cc406Sopenharmony_ci        DBG (1, "ProcessPageData: image dimensions: %d x %d, line size: %d\n",
1841141cc406Sopenharmony_ci        jpegCinfo.m_cinfo.output_width,
1842141cc406Sopenharmony_ci        jpegCinfo.m_cinfo.output_height, scanLineSize);
1843141cc406Sopenharmony_ci
1844141cc406Sopenharmony_ci        pJpegLine = calloc (scanLineSize, sizeof (JSAMPLE));
1845141cc406Sopenharmony_ci        if (!pJpegLine)
1846141cc406Sopenharmony_ci          {
1847141cc406Sopenharmony_ci            DBG (1, "ProcessPageData: memory allocation error\n");
1848141cc406Sopenharmony_ci            ret = 1;
1849141cc406Sopenharmony_ci            goto JPEG_CLEANUP;
1850141cc406Sopenharmony_ci          } /* if */
1851141cc406Sopenharmony_ci
1852141cc406Sopenharmony_ci        /* note dimensions - may be different from those previously reported */
1853141cc406Sopenharmony_ci        pState->m_pixelWidth = htonl (jpegCinfo.m_cinfo.output_width);
1854141cc406Sopenharmony_ci        pState->m_pixelHeight = htonl (jpegCinfo.m_cinfo.output_height);
1855141cc406Sopenharmony_ci
1856141cc406Sopenharmony_ci        /* decode scanlines */
1857141cc406Sopenharmony_ci        while (jpegCinfo.m_cinfo.output_scanline
1858141cc406Sopenharmony_ci               < jpegCinfo.m_cinfo.output_height)
1859141cc406Sopenharmony_ci          {
1860141cc406Sopenharmony_ci            DBG (20, "Reading scanline %d of %d\n",
1861141cc406Sopenharmony_ci                 jpegCinfo.m_cinfo.output_scanline,
1862141cc406Sopenharmony_ci                 jpegCinfo.m_cinfo.output_height);
1863141cc406Sopenharmony_ci
1864141cc406Sopenharmony_ci            /* read scanline */
1865141cc406Sopenharmony_ci            jpeg_read_scanlines (&jpegCinfo.m_cinfo, &pJpegLine, 1);
1866141cc406Sopenharmony_ci
1867141cc406Sopenharmony_ci            /* append to output buffer */
1868141cc406Sopenharmony_ci            ret |= AppendToComBuf (&pState->m_imageData,
1869141cc406Sopenharmony_ci                                   pJpegLine, scanLineSize);
1870141cc406Sopenharmony_ci
1871141cc406Sopenharmony_ci          } /* while */
1872141cc406Sopenharmony_ci
1873141cc406Sopenharmony_ci        /* update info for this page */
1874141cc406Sopenharmony_ci        pageInfo.m_width = jpegCinfo.m_cinfo.output_width;
1875141cc406Sopenharmony_ci        pageInfo.m_height = jpegCinfo.m_cinfo.output_height;
1876141cc406Sopenharmony_ci        pageInfo.m_totalSize = pageInfo.m_width * pageInfo.m_height * 3;
1877141cc406Sopenharmony_ci        pageInfo.m_bytesRemaining = pageInfo.m_totalSize;
1878141cc406Sopenharmony_ci
1879141cc406Sopenharmony_ci        DBG( 1, "Process page data: page %d: JPEG image: %d x %d, %d bytes\n",
1880141cc406Sopenharmony_ci             pState->m_numPages, pageInfo.m_width, pageInfo.m_height, pageInfo.m_totalSize );
1881141cc406Sopenharmony_ci
1882141cc406Sopenharmony_ci        ret |= AppendToComBuf( & pState->m_pageInfo, (unsigned char*)& pageInfo, sizeof( pageInfo ) );
1883141cc406Sopenharmony_ci        ++( pState->m_numPages );
1884141cc406Sopenharmony_ci
1885141cc406Sopenharmony_ci      JPEG_CLEANUP:
1886141cc406Sopenharmony_ci        jpeg_finish_decompress (&jpegCinfo.m_cinfo);
1887141cc406Sopenharmony_ci        jpeg_destroy_decompress (&jpegCinfo.m_cinfo);
1888141cc406Sopenharmony_ci
1889141cc406Sopenharmony_ci        if (pJpegLine)
1890141cc406Sopenharmony_ci          free (pJpegLine);
1891141cc406Sopenharmony_ci
1892141cc406Sopenharmony_ci        return ret;
1893141cc406Sopenharmony_ci      } /* case JPEG */
1894141cc406Sopenharmony_ci
1895141cc406Sopenharmony_ci    case 0x08:
1896141cc406Sopenharmony_ci      /* CCITT Group 4 Fax data */
1897141cc406Sopenharmony_ci      {
1898141cc406Sopenharmony_ci        /* get a temp file
1899141cc406Sopenharmony_ci           :TODO: 2006-04-18: Use TIFFClientOpen and do everything in RAM
1900141cc406Sopenharmony_ci         */
1901141cc406Sopenharmony_ci        fTmp = tmpfile ();
1902141cc406Sopenharmony_ci        fdTmp = fileno (fTmp);
1903141cc406Sopenharmony_ci
1904141cc406Sopenharmony_ci        pTiff = TIFFFdOpen (fdTmp, "tempfile", "w");
1905141cc406Sopenharmony_ci        if (!pTiff)
1906141cc406Sopenharmony_ci          {
1907141cc406Sopenharmony_ci            DBG (1, "ProcessPageData: Error opening temp TIFF file");
1908141cc406Sopenharmony_ci            ret = SANE_STATUS_IO_ERROR;
1909141cc406Sopenharmony_ci            goto TIFF_CLEANUP;
1910141cc406Sopenharmony_ci          }
1911141cc406Sopenharmony_ci
1912141cc406Sopenharmony_ci        /* create a TIFF file */
1913141cc406Sopenharmony_ci        width = ntohl (pState->m_pixelWidth);
1914141cc406Sopenharmony_ci        height = ntohl (pState->m_pixelHeight);
1915141cc406Sopenharmony_ci        TIFFSetField (pTiff, TIFFTAG_IMAGEWIDTH, width);
1916141cc406Sopenharmony_ci        TIFFSetField (pTiff, TIFFTAG_IMAGELENGTH, height);
1917141cc406Sopenharmony_ci        TIFFSetField (pTiff, TIFFTAG_BITSPERSAMPLE, 1);
1918141cc406Sopenharmony_ci        TIFFSetField (pTiff, TIFFTAG_PHOTOMETRIC, 0);        /* 0 is white */
1919141cc406Sopenharmony_ci        TIFFSetField (pTiff, TIFFTAG_COMPRESSION, 4);        /* CCITT Group 4 */
1920141cc406Sopenharmony_ci        TIFFSetField (pTiff, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
1921141cc406Sopenharmony_ci
1922141cc406Sopenharmony_ci        TIFFWriteRawStrip (pTiff, 0, pState->m_buf.m_pBuf,
1923141cc406Sopenharmony_ci                           pState->m_buf.m_used);
1924141cc406Sopenharmony_ci
1925141cc406Sopenharmony_ci        if (0 > TIFFRGBAImageOK (pTiff, tiffErrBuf))
1926141cc406Sopenharmony_ci          {
1927141cc406Sopenharmony_ci            DBG (1, "ProcessPageData: %s\n", tiffErrBuf);
1928141cc406Sopenharmony_ci            ret = SANE_STATUS_IO_ERROR;
1929141cc406Sopenharmony_ci            goto TIFF_CLEANUP;
1930141cc406Sopenharmony_ci          }
1931141cc406Sopenharmony_ci
1932141cc406Sopenharmony_ci        /* allocate space for RGBA representation of image */
1933141cc406Sopenharmony_ci        numPixels = height * width;
1934141cc406Sopenharmony_ci        DBG (20, "ProcessPageData: num TIFF RGBA pixels: %d\n", numPixels);
1935141cc406Sopenharmony_ci        if (!(pTiffRgba = calloc (numPixels, sizeof (u_long))))
1936141cc406Sopenharmony_ci          {
1937141cc406Sopenharmony_ci            ret = SANE_STATUS_NO_MEM;
1938141cc406Sopenharmony_ci            goto TIFF_CLEANUP;
1939141cc406Sopenharmony_ci          }
1940141cc406Sopenharmony_ci
1941141cc406Sopenharmony_ci        /* make space in image buffer to store the results */
1942141cc406Sopenharmony_ci        imageBytes = width * height * 3;
1943141cc406Sopenharmony_ci        ret |= AppendToComBuf (&pState->m_imageData, NULL, imageBytes);
1944141cc406Sopenharmony_ci        if (ret)
1945141cc406Sopenharmony_ci          goto TIFF_CLEANUP;
1946141cc406Sopenharmony_ci
1947141cc406Sopenharmony_ci        /* get a pointer to the start of the output data */
1948141cc406Sopenharmony_ci        pOut = pState->m_imageData.m_pBuf
1949141cc406Sopenharmony_ci          + pState->m_imageData.m_used - imageBytes;
1950141cc406Sopenharmony_ci
1951141cc406Sopenharmony_ci        /* read RGBA image */
1952141cc406Sopenharmony_ci        DBG (20, "ProcessPageData: setting up read buffer\n");
1953141cc406Sopenharmony_ci        TIFFReadBufferSetup (pTiff, NULL, width * height * sizeof (u_long));
1954141cc406Sopenharmony_ci        DBG (20, "ProcessPageData: reading RGBA data\n");
1955141cc406Sopenharmony_ci        TIFFReadRGBAImageOriented (pTiff, width, height, pTiffRgba,
1956141cc406Sopenharmony_ci                                   ORIENTATION_TOPLEFT, 0);
1957141cc406Sopenharmony_ci
1958141cc406Sopenharmony_ci        /* loop over pixels */
1959141cc406Sopenharmony_ci        for (iPixel = 0; iPixel < numPixels; ++iPixel)
1960141cc406Sopenharmony_ci          {
1961141cc406Sopenharmony_ci
1962141cc406Sopenharmony_ci            *(pOut++) = TIFFGetR (pTiffRgba[iPixel]);
1963141cc406Sopenharmony_ci            *(pOut++) = TIFFGetG (pTiffRgba[iPixel]);
1964141cc406Sopenharmony_ci            *(pOut++) = TIFFGetB (pTiffRgba[iPixel]);
1965141cc406Sopenharmony_ci
1966141cc406Sopenharmony_ci          } /* for iRow */
1967141cc406Sopenharmony_ci
1968141cc406Sopenharmony_ci
1969141cc406Sopenharmony_ci
1970141cc406Sopenharmony_ci        /* update info for this page */
1971141cc406Sopenharmony_ci        pageInfo.m_width = width;
1972141cc406Sopenharmony_ci        pageInfo.m_height = height;
1973141cc406Sopenharmony_ci        pageInfo.m_totalSize = pageInfo.m_width * pageInfo.m_height * 3;
1974141cc406Sopenharmony_ci        pageInfo.m_bytesRemaining = pageInfo.m_totalSize;
1975141cc406Sopenharmony_ci
1976141cc406Sopenharmony_ci        DBG( 1, "Process page data: page %d: TIFF image: %d x %d, %d bytes\n",
1977141cc406Sopenharmony_ci             pState->m_numPages, width, height, pageInfo.m_totalSize );
1978141cc406Sopenharmony_ci
1979141cc406Sopenharmony_ci        ret |= AppendToComBuf( & pState->m_pageInfo, (unsigned char*)& pageInfo, sizeof( pageInfo ) );
1980141cc406Sopenharmony_ci        ++( pState->m_numPages );
1981141cc406Sopenharmony_ci
1982141cc406Sopenharmony_ci      TIFF_CLEANUP:
1983141cc406Sopenharmony_ci        if (pTiff)
1984141cc406Sopenharmony_ci          TIFFClose (pTiff);
1985141cc406Sopenharmony_ci        if (fTmp)
1986141cc406Sopenharmony_ci          fclose (fTmp);
1987141cc406Sopenharmony_ci        if (pTiffRgba)
1988141cc406Sopenharmony_ci          free (pTiffRgba);
1989141cc406Sopenharmony_ci        return ret;
1990141cc406Sopenharmony_ci
1991141cc406Sopenharmony_ci      } /* case CCITT */
1992141cc406Sopenharmony_ci    default:
1993141cc406Sopenharmony_ci      /* this is not expected or very useful */
1994141cc406Sopenharmony_ci      {
1995141cc406Sopenharmony_ci        DBG (1, "ProcessPageData: Unexpected compression flag %d\n", ntohl (pState->m_compression));
1996141cc406Sopenharmony_ci        ret = SANE_STATUS_IO_ERROR;
1997141cc406Sopenharmony_ci      }
1998141cc406Sopenharmony_ci    } /* switch */
1999141cc406Sopenharmony_ci
2000141cc406Sopenharmony_ci  return ret;
2001141cc406Sopenharmony_ci} /* ProcessPageData */
2002141cc406Sopenharmony_ci
2003141cc406Sopenharmony_ci/***********************************************************/
2004141cc406Sopenharmony_ci
2005141cc406Sopenharmony_civoid
2006141cc406Sopenharmony_ciJpegDecompInitSource (j_decompress_ptr cinfo)
2007141cc406Sopenharmony_ci/* Libjpeg decompression interface */
2008141cc406Sopenharmony_ci{
2009141cc406Sopenharmony_ci  cinfo->src->bytes_in_buffer = 0;
2010141cc406Sopenharmony_ci
2011141cc406Sopenharmony_ci} /* JpegDecompInitSource */
2012141cc406Sopenharmony_ci
2013141cc406Sopenharmony_ci/***********************************************************/
2014141cc406Sopenharmony_ci
2015141cc406Sopenharmony_ciboolean
2016141cc406Sopenharmony_ciJpegDecompFillInputBuffer (j_decompress_ptr cinfo)
2017141cc406Sopenharmony_ci/* Libjpeg decompression interface */
2018141cc406Sopenharmony_ci{
2019141cc406Sopenharmony_ci  struct JpegDataDecompState *pState = (struct JpegDataDecompState *) cinfo;
2020141cc406Sopenharmony_ci  static const unsigned char eoiByte[] = {
2021141cc406Sopenharmony_ci    0xFF, JPEG_EOI
2022141cc406Sopenharmony_ci  };
2023141cc406Sopenharmony_ci
2024141cc406Sopenharmony_ci  DBG (10, "JpegDecompFillInputBuffer: bytes remaining: %d\n",
2025141cc406Sopenharmony_ci       pState->m_bytesRemaining);
2026141cc406Sopenharmony_ci
2027141cc406Sopenharmony_ci  if (!pState->m_bytesRemaining)
2028141cc406Sopenharmony_ci    {
2029141cc406Sopenharmony_ci
2030141cc406Sopenharmony_ci      /* no input data available so return dummy data */
2031141cc406Sopenharmony_ci      cinfo->src->bytes_in_buffer = 2;
2032141cc406Sopenharmony_ci      cinfo->src->next_input_byte = (const JOCTET *) eoiByte;
2033141cc406Sopenharmony_ci
2034141cc406Sopenharmony_ci    }
2035141cc406Sopenharmony_ci  else
2036141cc406Sopenharmony_ci    {
2037141cc406Sopenharmony_ci
2038141cc406Sopenharmony_ci      /* point to data */
2039141cc406Sopenharmony_ci      cinfo->src->bytes_in_buffer = pState->m_bytesRemaining;
2040141cc406Sopenharmony_ci      cinfo->src->next_input_byte = (const JOCTET *) pState->m_pData;
2041141cc406Sopenharmony_ci
2042141cc406Sopenharmony_ci      /* note that data is now gone */
2043141cc406Sopenharmony_ci      pState->m_bytesRemaining = 0;
2044141cc406Sopenharmony_ci
2045141cc406Sopenharmony_ci    } /* if */
2046141cc406Sopenharmony_ci
2047141cc406Sopenharmony_ci  return TRUE;
2048141cc406Sopenharmony_ci
2049141cc406Sopenharmony_ci} /* JpegDecompFillInputBuffer */
2050141cc406Sopenharmony_ci
2051141cc406Sopenharmony_ci/***********************************************************/
2052141cc406Sopenharmony_ci
2053141cc406Sopenharmony_civoid
2054141cc406Sopenharmony_ciJpegDecompSkipInputData (j_decompress_ptr cinfo, long numBytes)
2055141cc406Sopenharmony_ci/* Libjpeg decompression interface */
2056141cc406Sopenharmony_ci{
2057141cc406Sopenharmony_ci  DBG (10, "JpegDecompSkipInputData: skipping %ld bytes\n", numBytes);
2058141cc406Sopenharmony_ci
2059141cc406Sopenharmony_ci  cinfo->src->bytes_in_buffer -= numBytes;
2060141cc406Sopenharmony_ci  cinfo->src->next_input_byte += numBytes;
2061141cc406Sopenharmony_ci
2062141cc406Sopenharmony_ci} /* JpegDecompSkipInputData */
2063141cc406Sopenharmony_ci
2064141cc406Sopenharmony_ci/***********************************************************/
2065141cc406Sopenharmony_ci
2066141cc406Sopenharmony_civoid
2067141cc406Sopenharmony_ciJpegDecompTermSource (j_decompress_ptr __sane_unused__ cinfo)
2068141cc406Sopenharmony_ci/* Libjpeg decompression interface */
2069141cc406Sopenharmony_ci{
2070141cc406Sopenharmony_ci  /* nothing to do */
2071141cc406Sopenharmony_ci
2072141cc406Sopenharmony_ci} /* JpegDecompTermSource */
2073141cc406Sopenharmony_ci
2074141cc406Sopenharmony_ci/***********************************************************/
2075