• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* sane - Scanner Access Now Easy.
2 
3    Copyright (C) 2019 Touboul Nathane
4    Copyright (C) 2019 Thierry HUCHARD <thierry@ordissimo.com>
5 
6    This file is part of the SANE package.
7 
8    SANE is free software; you can redistribute it and/or modify it under
9    the terms of the GNU General Public License as published by the Free
10    Software Foundation; either version 3 of the License, or (at your
11    option) any later version.
12 
13    SANE is distributed in the hope that it will be useful, but WITHOUT
14    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16    for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with sane; see the file COPYING.
20    If not, see <https://www.gnu.org/licenses/>.
21 
22    This file implements a SANE backend for eSCL scanners.  */
23 
24 #include "escl.h"
25 
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 
30 #include <setjmp.h>
31 
32 #include "../include/sane/saneopts.h"
33 #include "../include/sane/sanei.h"
34 #include "../include/sane/sanei_backend.h"
35 #include "../include/sane/sanei_config.h"
36 
37 
38 #ifndef SANE_NAME_SHARPEN
39 # define SANE_NAME_SHARPEN "sharpen"
40 # define SANE_TITLE_SHARPEN SANE_I18N("Sharpen")
41 # define SANE_DESC_SHARPEN SANE_I18N("Set sharpen value.")
42 #endif
43 
44 #ifndef SANE_NAME_THRESHOLD
45 # define SANE_NAME_THRESHOLD "threshold"
46 #endif
47 #ifndef SANE_TITLE_THRESHOLD
48 # define SANE_TITLE_THRESHOLD SANE_I18N("Threshold")
49 #endif
50 #ifndef SANE_DESC_THRESHOLD
51 # define SANE_DESC_THRESHOLD \
52     SANE_I18N("Set threshold for line-art scans.")
53 #endif
54 
55 #define min(A,B) (((A)<(B)) ? (A) : (B))
56 #define max(A,B) (((A)>(B)) ? (A) : (B))
57 #define IS_ACTIVE(OPTION) (((handler->opt[OPTION].cap) & SANE_CAP_INACTIVE) == 0)
58 #define INPUT_BUFFER_SIZE 4096
59 
60 static const SANE_Device **devlist = NULL;
61 static ESCL_Device *list_devices_primary = NULL;
62 static int num_devices = 0;
63 
64 #ifdef CURL_SSLVERSION_MAX_DEFAULT
65 static int proto_tls[] = {
66         CURL_SSLVERSION_MAX_DEFAULT,
67    #ifdef CURL_SSLVERSION_MAX_TLSv1_3
68         CURL_SSLVERSION_MAX_TLSv1_3,
69    #endif
70    #ifdef CURL_SSLVERSION_MAX_TLSv1_2
71         CURL_SSLVERSION_MAX_TLSv1_2,
72    #endif
73    #ifdef CURL_SSLVERSION_MAX_TLSv1_1
74         CURL_SSLVERSION_MAX_TLSv1_1,
75    #endif
76    #ifdef CURL_SSLVERSION_MAX_TLSv1_0
77         CURL_SSLVERSION_MAX_TLSv1_0,
78    #endif
79         -1
80 };
81 #endif
82 
83 
84 typedef struct Handled {
85     struct Handled *next;
86     ESCL_Device *device;
87     char *result;
88     ESCL_ScanParam param;
89     SANE_Option_Descriptor opt[NUM_OPTIONS];
90     Option_Value val[NUM_OPTIONS];
91     capabilities_t *scanner;
92     SANE_Range x_range1;
93     SANE_Range x_range2;
94     SANE_Range y_range1;
95     SANE_Range y_range2;
96     SANE_Range brightness_range;
97     SANE_Range contrast_range;
98     SANE_Range sharpen_range;
99     SANE_Range thresold_range;
100     SANE_Bool cancel;
101     SANE_Bool write_scan_data;
102     SANE_Bool decompress_scan_data;
103     SANE_Bool end_read;
104     SANE_Parameters ps;
105 } escl_sane_t;
106 
107 static ESCL_Device *
escl_free_device(ESCL_Device * current)108 escl_free_device(ESCL_Device *current)
109 {
110     if (!current) return NULL;
111     free((void*)current->ip_address);
112     free((void*)current->model_name);
113     free((void*)current->type);
114     free((void*)current->is);
115     free((void*)current->uuid);
116     free((void*)current->unix_socket);
117     curl_slist_free_all(current->hack);
118     free(current);
119     return NULL;
120 }
121 
122 
123 #ifdef CURL_SSLVERSION_MAX_DEFAULT
124 static int
escl_tls_protocol_supported(char * url,int proto)125 escl_tls_protocol_supported(char *url, int proto)
126 {
127    CURLcode res = CURLE_UNSUPPORTED_PROTOCOL;
128    CURL *curl = curl_easy_init();
129    if(curl) {
130       curl_easy_setopt(curl, CURLOPT_URL, url);
131 
132       /* ask libcurl to use TLS version 1.0 or later */
133       curl_easy_setopt(curl, CURLOPT_SSLVERSION, proto);
134       curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
135       curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
136       curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
137       curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 3L);
138       /* Perform the request */
139       res = curl_easy_perform(curl);
140       curl_easy_cleanup(curl);
141    }
142    return res;
143 }
144 
145 static int
escl_is_tls(char * url,char * type)146 escl_is_tls(char * url, char *type)
147 {
148     int tls_version = 0;
149     if(!strcmp(type, "_uscans._tcp") ||
150        !strcmp(type, "https"))
151       {
152          while(proto_tls[tls_version] != -1)
153           {
154                 if (escl_tls_protocol_supported(url, proto_tls[tls_version]) == CURLE_OK)
155                 {
156                         DBG(10, "curl tls compatible (%d)\n", proto_tls[tls_version]);
157                         break;
158                 }
159                 tls_version++;
160           }
161          if (proto_tls[tls_version] < 1)
162             return 0;
163       }
164       return proto_tls[tls_version];
165 }
166 #else
167 static int
escl_is_tls(char * url,char * type)168 escl_is_tls(char * url, char *type)
169 {
170     (void)url;
171     (void)type;
172     return 0;
173 }
174 #endif
175 
176 void
escl_free_handler(escl_sane_t * handler)177 escl_free_handler(escl_sane_t *handler)
178 {
179     if (handler == NULL)
180         return;
181 
182     escl_free_device(handler->device);
183     free(handler);
184 }
185 
186 SANE_Status escl_parse_name(SANE_String_Const name, ESCL_Device *device);
187 
188 static SANE_Status
escl_check_and_add_device(ESCL_Device * current)189 escl_check_and_add_device(ESCL_Device *current)
190 {
191     if(!current) {
192       DBG (10, "ESCL_Device *current us null.\n");
193       return (SANE_STATUS_NO_MEM);
194     }
195     if (!current->ip_address) {
196       DBG (10, "Ip Address allocation failure.\n");
197       return (SANE_STATUS_NO_MEM);
198     }
199     if (current->port_nb == 0) {
200       DBG (10, "No port defined.\n");
201       return (SANE_STATUS_NO_MEM);
202     }
203     if (!current->model_name) {
204       DBG (10, "Modele Name allocation failure.\n");
205       return (SANE_STATUS_NO_MEM);
206     }
207     if (!current->type) {
208       DBG (10, "Scanner Type allocation failure.\n");
209       return (SANE_STATUS_NO_MEM);
210     }
211     if (!current->is) {
212       DBG (10, "Scanner Is allocation failure.\n");
213       return (SANE_STATUS_NO_MEM);
214     }
215     ++num_devices;
216     current->next = list_devices_primary;
217     list_devices_primary = current;
218     return (SANE_STATUS_GOOD);
219 }
220 
221 /**
222  * \fn static SANE_Status escl_add_in_list(ESCL_Device *current)
223  * \brief Function that adds all the element needed to my list :
224  *        the port number, the model name, the ip address, and the type of url (http/https).
225  *        Moreover, this function counts the number of devices found.
226  *
227  * \return SANE_STATUS_GOOD if everything is OK.
228  */
229 static SANE_Status
escl_add_in_list(ESCL_Device * current)230 escl_add_in_list(ESCL_Device *current)
231 {
232     if(!current) {
233       DBG (10, "ESCL_Device *current us null.\n");
234       return (SANE_STATUS_NO_MEM);
235     }
236 
237     if (SANE_STATUS_GOOD ==
238         escl_check_and_add_device(current)) {
239         list_devices_primary = current;
240         return (SANE_STATUS_GOOD);
241     }
242     current = escl_free_device(current);
243     return (SANE_STATUS_NO_MEM);
244 }
245 
246 /**
247  * \fn SANE_Status escl_device_add(int port_nb, const char *model_name, char *ip_address, char *type)
248  * \brief Function that browses my list ('for' loop) and returns the "escl_add_in_list" function to
249  *        adds all the element needed to my list :
250  *        the port number, the model name, the ip address and the type of the url (http / https).
251  *
252  * \return escl_add_in_list(current)
253  */
254 SANE_Status
escl_device_add(int port_nb,const char * model_name,char * ip_address,const char * is,const char * uuid,char * type)255 escl_device_add(int port_nb,
256                 const char *model_name,
257                 char *ip_address,
258                 const char *is,
259                 const char *uuid,
260                 char *type)
261 {
262     char tmp[PATH_MAX] = { 0 };
263     char *model = NULL;
264     char url_port[512] = { 0 };
265     int tls_version = 0;
266     ESCL_Device *current = NULL;
267     DBG (10, "escl_device_add\n");
268     snprintf(url_port, sizeof(url_port), "https://%s:%d", ip_address, port_nb);
269     tls_version = escl_is_tls(url_port, type);
270 
271     for (current = list_devices_primary; current; current = current->next) {
272 	if ((strcmp(current->ip_address, ip_address) == 0) ||
273             (uuid && current->uuid && !strcmp(current->uuid, uuid)))
274            {
275 	      if (strcmp(current->type, type))
276                 {
277                   if(!strcmp(type, "_uscans._tcp") ||
278                      !strcmp(type, "https"))
279                     {
280                        free (current->type);
281                        current->type = strdup(type);
282                        if (strcmp(current->ip_address, ip_address)) {
283                            free (current->ip_address);
284                            current->ip_address = strdup(ip_address);
285                        }
286                        current->port_nb = port_nb;
287                        current->https = SANE_TRUE;
288                        current->tls = tls_version;
289                     }
290 	          return (SANE_STATUS_GOOD);
291                 }
292               else if (current->port_nb == port_nb)
293 	        return (SANE_STATUS_GOOD);
294            }
295     }
296     current = (ESCL_Device*)calloc(1, sizeof(*current));
297     if (current == NULL) {
298        DBG (10, "New device allocation failure.\n");
299        return (SANE_STATUS_NO_MEM);
300     }
301     current->port_nb = port_nb;
302 
303     if (strcmp(type, "_uscan._tcp") != 0 && strcmp(type, "http") != 0) {
304         snprintf(tmp, sizeof(tmp), "%s SSL", model_name);
305         current->https = SANE_TRUE;
306     } else {
307         current->https = SANE_FALSE;
308     }
309     current->tls = tls_version;
310     model = (char*)(tmp[0] != 0 ? tmp : model_name);
311     current->model_name = strdup(model);
312     current->ip_address = strdup(ip_address);
313     memset(tmp, 0, PATH_MAX);
314     snprintf(tmp, sizeof(tmp), "%s scanner", (is ? is : "flatbed or ADF"));
315     current->is = strdup(tmp);
316     current->type = strdup(type);
317     if (uuid)
318        current->uuid = strdup(uuid);
319     return escl_add_in_list(current);
320 }
321 
322 /**
323  * \fn static inline size_t max_string_size(const SANE_String_Const strings[])
324  * \brief Function that browses the string ('for' loop) and counts the number of character in the string.
325  *        --> this allows to know the maximum size of the string.
326  *
327  * \return max_size + 1 (the size max)
328  */
329 static inline size_t
max_string_size(const SANE_String_Const strings[])330 max_string_size(const SANE_String_Const strings[])
331 {
332     size_t max_size = 0;
333     int i = 0;
334 
335     for (i = 0; strings[i]; ++i) {
336 	size_t size = strlen (strings[i]);
337 	if (size > max_size)
338 	    max_size = size;
339     }
340     return (max_size + 1);
341 }
342 
343 static char *
get_vendor(char * search)344 get_vendor(char *search)
345 {
346 	if(strcasestr(search, "Epson"))
347 		return strdup("Epson");
348 	else if(strcasestr(search, "Fujitsu"))
349 		return strdup("Fujitsu");
350 	else if(strcasestr(search, "HP"))
351 		return strdup("HP");
352 	else if(strcasestr(search, "Canon"))
353 		return strdup("Canon");
354 	else if(strcasestr(search, "Lexmark"))
355 		return strdup("Lexmark");
356 	else if(strcasestr(search, "Samsung"))
357 		return strdup("Samsung");
358 	else if(strcasestr(search, "Xerox"))
359 		return strdup("Xerox");
360 	else if(strcasestr(search, "OKI"))
361 		return strdup("OKI");
362 	else if(strcasestr(search, "Hewlett Packard"))
363 		return strdup("Hewlett Packard");
364 	else if(strcasestr(search, "IBM"))
365 		return strdup("IBM");
366 	else if(strcasestr(search, "Mustek"))
367 		return strdup("Mustek");
368 	else if(strcasestr(search, "Ricoh"))
369 		return strdup("Ricoh");
370 	else if(strcasestr(search, "Sharp"))
371 		return strdup("Sharp");
372 	else if(strcasestr(search, "UMAX"))
373 		return strdup("UMAX");
374 	else if(strcasestr(search, "PINT"))
375 		return strdup("PINT");
376 	else if(strcasestr(search, "Brother"))
377 		return strdup("Brother");
378 	return NULL;
379 }
380 
381 /**
382  * \fn static SANE_Device *convertFromESCLDev(ESCL_Device *cdev)
383  * \brief Function that checks if the url of the received scanner is secured or not (http / https).
384  *        --> if the url is not secured, our own url will be composed like "http://'ip':'port'".
385  *        --> else, our own url will be composed like "https://'ip':'port'".
386  *        AND, it's in this function that we gather all the information of the url (that were in our list) :
387  *        the model_name, the port, the ip, and the type of url.
388  *        SO, leaving this function, we have in memory the complete url.
389  *
390  * \return sdev (structure that contains the elements of the url)
391  */
392 static SANE_Device *
convertFromESCLDev(ESCL_Device * cdev)393 convertFromESCLDev(ESCL_Device *cdev)
394 {
395     char *tmp;
396     int len, lv = 0;
397     char unix_path[PATH_MAX+7] = { 0 };
398     SANE_Device *sdev = (SANE_Device*) calloc(1, sizeof(SANE_Device));
399     if (!sdev) {
400        DBG (10, "Sane_Device allocation failure.\n");
401        return NULL;
402     }
403 
404     if (cdev->unix_socket && strlen(cdev->unix_socket)) {
405         snprintf(unix_path, sizeof(unix_path), "unix:%s:", cdev->unix_socket);
406     }
407     len = snprintf(NULL, 0, "%shttp%s://%s:%d",
408              unix_path, cdev->https ? "s" : "", cdev->ip_address, cdev->port_nb);
409     len++;
410     tmp = (char *)malloc(len);
411     if (!tmp) {
412         DBG (10, "Name allocation failure.\n");
413         goto freedev;
414     }
415     snprintf(tmp, len, "%shttp%s://%s:%d",
416              unix_path, cdev->https ? "s" : "", cdev->ip_address, cdev->port_nb);
417     sdev->name = tmp;
418 
419     DBG( 1, "Escl add device : %s\n", tmp);
420     sdev->vendor = get_vendor(cdev->model_name);
421 
422     if (!sdev->vendor)
423        sdev->vendor = strdup("ESCL");
424     else
425        lv = strlen(sdev->vendor) + 1;
426     if (!sdev->vendor) {
427        DBG (10, "Vendor allocation failure.\n");
428        goto freemodel;
429     }
430     sdev->model = strdup(lv + cdev->model_name);
431     if (!sdev->model) {
432        DBG (10, "Model allocation failure.\n");
433        goto freename;
434     }
435     sdev->type = strdup(cdev->is);
436     if (!sdev->type) {
437        DBG (10, "Scanner Type allocation failure.\n");
438        goto freevendor;
439     }
440     return (sdev);
441 freevendor:
442     free((void*)sdev->vendor);
443 freemodel:
444     free((void*)sdev->model);
445 freename:
446     free((void*)sdev->name);
447 freedev:
448     free((void*)sdev);
449     return NULL;
450 }
451 
452 /**
453  * \fn SANE_Status sane_init(SANE_Int *version_code, SANE_Auth_Callback authorize)
454  * \brief Function that's called before any other SANE function ; it's the first SANE function called.
455  *        --> this function checks the SANE config. and can check the authentication of the user if
456  *        'authorize' value is more than SANE_TRUE.
457  *        In this case, it will be necessary to define an authentication method.
458  *
459  * \return SANE_STATUS_GOOD (everything is OK)
460  */
461 SANE_Status
sane_init(SANE_Int * version_code,SANE_Auth_Callback __sane_unused__ authorize)462 sane_init(SANE_Int *version_code, SANE_Auth_Callback __sane_unused__ authorize)
463 {
464     DBG_INIT();
465     DBG (10, "escl sane_init\n");
466     SANE_Status status = SANE_STATUS_GOOD;
467     curl_global_init(CURL_GLOBAL_ALL);
468     if (version_code != NULL)
469 	*version_code = SANE_VERSION_CODE(1, 0, 0);
470     if (status != SANE_STATUS_GOOD)
471 	return (status);
472     return (SANE_STATUS_GOOD);
473 }
474 
475 /**
476  * \fn void sane_exit(void)
477  * \brief Function that must be called to terminate use of a backend.
478  *        This function will first close all device handles that still might be open.
479  *        --> by freeing all the elements of my list.
480  *        After this function, no function other than 'sane_init' may be called.
481  */
482 void
sane_exit(void)483 sane_exit(void)
484 {
485     DBG (10, "escl sane_exit\n");
486     ESCL_Device *next = NULL;
487 
488     while (list_devices_primary != NULL) {
489 	next = list_devices_primary->next;
490 	free(list_devices_primary);
491 	list_devices_primary = next;
492     }
493     if (devlist)
494 	free (devlist);
495     list_devices_primary = NULL;
496     devlist = NULL;
497     curl_global_cleanup();
498 }
499 
500 /**
501  * \fn static SANE_Status attach_one_config(SANEI_Config *config, const char *line)
502  * \brief Function that implements a configuration file to the user :
503  *        if the user can't detect some devices, he will be able to force their detection with this config' file to use them.
504  *        Thus, this function parses the config' file to use the device of the user with the information below :
505  *        the type of protocol (http/https), the ip, the port number, and the model name.
506  *
507  * \return escl_add_in_list(escl_device) if the parsing worked, SANE_STATUS_GOOD otherwise.
508  */
509 static SANE_Status
attach_one_config(SANEI_Config __sane_unused__ * config,const char * line,void __sane_unused__ * data)510 attach_one_config(SANEI_Config __sane_unused__ *config, const char *line,
511 		  void __sane_unused__ *data)
512 {
513     int port = 0;
514     SANE_Status status;
515     static ESCL_Device *escl_device = NULL;
516     if (*line == '#') return SANE_STATUS_GOOD;
517     if (!strncmp(line, "pdfblacklist", 12)) return SANE_STATUS_GOOD;
518     if (strncmp(line, "device", 6) == 0) {
519         char *name_str = NULL;
520         char *opt_model = NULL;
521         char *opt_hack = NULL;
522 
523         line = sanei_config_get_string(line + 6, &name_str);
524         DBG (10, "New Escl_Device URL [%s].\n", (name_str ? name_str : "VIDE"));
525         if (!name_str || !*name_str) {
526             DBG (1, "Escl_Device URL missing.\n");
527             return SANE_STATUS_INVAL;
528         }
529         if (*line) {
530             line = sanei_config_get_string(line, &opt_model);
531             DBG (10, "New Escl_Device model [%s].\n", opt_model);
532         }
533         if (*line) {
534             line = sanei_config_get_string(line, &opt_hack);
535             DBG (10, "New Escl_Device hack [%s].\n", opt_hack);
536         }
537 
538         escl_free_device(escl_device);
539         escl_device = (ESCL_Device*)calloc(1, sizeof(ESCL_Device));
540         if (!escl_device) {
541            DBG (10, "New Escl_Device allocation failure.\n");
542            free(name_str);
543            return (SANE_STATUS_NO_MEM);
544         }
545         status = escl_parse_name(name_str, escl_device);
546         free(name_str);
547         if (status != SANE_STATUS_GOOD) {
548             escl_free_device(escl_device);
549             escl_device = NULL;
550             return status;
551         }
552         escl_device->model_name = opt_model ? opt_model : strdup("Unknown model");
553         escl_device->is = strdup("flatbed or ADF scanner");
554         escl_device->uuid = NULL;
555     }
556 
557     if (strncmp(line, "[device]", 8) == 0) {
558 	escl_device = escl_free_device(escl_device);
559 	escl_device = (ESCL_Device*)calloc(1, sizeof(ESCL_Device));
560 	if (!escl_device) {
561 	   DBG (10, "New Escl_Device allocation failure.");
562 	   return (SANE_STATUS_NO_MEM);
563 	}
564     }
565     else if (strncmp(line, "ip", 2) == 0) {
566 	const char *ip_space = sanei_config_skip_whitespace(line + 2);
567 	DBG (10, "New Escl_Device IP [%s].", (ip_space ? ip_space : "VIDE"));
568 	if (escl_device != NULL && ip_space != NULL) {
569 	    DBG (10, "New Escl_Device IP Affected.");
570 	    escl_device->ip_address = strdup(ip_space);
571 	}
572     }
573     else if (sscanf(line, "port %i", &port) == 1 && port != 0) {
574 	DBG (10, "New Escl_Device PORT [%d].", port);
575 	if (escl_device != NULL) {
576 	    DBG (10, "New Escl_Device PORT Affected.");
577 	    escl_device->port_nb = port;
578 	}
579     }
580     else if (strncmp(line, "model", 5) == 0) {
581 	const char *model_space = sanei_config_skip_whitespace(line + 5);
582 	DBG (10, "New Escl_Device MODEL [%s].", (model_space ? model_space : "VIDE"));
583 	if (escl_device != NULL && model_space != NULL) {
584 	    DBG (10, "New Escl_Device MODEL Affected.");
585 	    escl_device->model_name = strdup(model_space);
586 	}
587     }
588     else if (strncmp(line, "type", 4) == 0) {
589 	const char *type_space = sanei_config_skip_whitespace(line + 4);
590 	DBG (10, "New Escl_Device TYPE [%s].", (type_space ? type_space : "VIDE"));
591 	if (escl_device != NULL && type_space != NULL) {
592 	    DBG (10, "New Escl_Device TYPE Affected.");
593 	    escl_device->type = strdup(type_space);
594 	}
595     }
596     escl_device->is = strdup("flatbed or ADF scanner");
597     escl_device->uuid = NULL;
598     char url_port[512] = { 0 };
599     snprintf(url_port, sizeof(url_port), "https://%s:%d", escl_device->ip_address, escl_device->port_nb);
600     escl_device->tls = escl_is_tls(url_port, escl_device->type);
601     status = escl_check_and_add_device(escl_device);
602     if (status == SANE_STATUS_GOOD)
603        escl_device = NULL;
604     return status;
605 }
606 
607 /**
608  * \fn SANE_Status sane_get_devices(const SANE_Device ***device_list, SANE_Bool local_only)
609  * \brief Function that searches for connected devices and places them in our 'device_list'. ('for' loop)
610  *        If the attribute 'local_only' is worth SANE_FALSE, we only returns the connected devices locally.
611  *
612  * \return SANE_STATUS_GOOD if devlist != NULL ; SANE_STATUS_NO_MEM otherwise.
613  */
614 SANE_Status
sane_get_devices(const SANE_Device *** device_list,SANE_Bool local_only)615 sane_get_devices(const SANE_Device ***device_list, SANE_Bool local_only)
616 {
617     if (local_only)             /* eSCL is a network-only protocol */
618 	return (device_list ? SANE_STATUS_GOOD : SANE_STATUS_INVAL);
619 
620     DBG (10, "escl sane_get_devices\n");
621     ESCL_Device *dev = NULL;
622     static const SANE_Device **devlist = 0;
623     SANE_Status status;
624     SANE_Status status2;
625 
626     if (device_list == NULL)
627 	return (SANE_STATUS_INVAL);
628     status2 = sanei_configure_attach(ESCL_CONFIG_FILE, NULL,
629 				    attach_one_config, NULL);
630     escl_devices(&status);
631     if (status != SANE_STATUS_GOOD && status2 != SANE_STATUS_GOOD)
632     {
633        if (status2 != SANE_STATUS_GOOD)
634                return (status2);
635        if (status != SANE_STATUS_GOOD)
636                return (status);
637     }
638     if (devlist)
639 	free(devlist);
640     devlist = (const SANE_Device **) calloc (num_devices + 1, sizeof (devlist[0]));
641     if (devlist == NULL)
642 	return (SANE_STATUS_NO_MEM);
643     int i = 0;
644     for (dev = list_devices_primary; i < num_devices; dev = dev->next) {
645 	SANE_Device *s_dev = convertFromESCLDev(dev);
646 	devlist[i] = s_dev;
647 	i++;
648     }
649     devlist[i] = 0;
650     *device_list = devlist;
651     return (devlist) ? SANE_STATUS_GOOD : SANE_STATUS_NO_MEM;
652 }
653 
654 /* Returns the length of the longest string, including the terminating
655  * character. */
656 static size_t
_source_size_max(SANE_String_Const * sources)657 _source_size_max (SANE_String_Const * sources)
658 {
659   size_t size = 0;
660 
661   while(*sources)
662    {
663       size_t t = strlen (*sources) + 1;
664       if (t > size)
665           size = t;
666       sources++;
667    }
668   return size;
669 }
670 
671 static int
_get_resolution(escl_sane_t * handler,int resol)672 _get_resolution(escl_sane_t *handler, int resol)
673 {
674     int x = 1;
675     int n = handler->scanner->caps[handler->scanner->source].SupportedResolutions[0] + 1;
676     int old = -1;
677     for (; x < n; x++) {
678       DBG(10, "SEARCH RESOLUTION [ %d | %d]\n", resol, (int)handler->scanner->caps[handler->scanner->source].SupportedResolutions[x]);
679       if (resol == handler->scanner->caps[handler->scanner->source].SupportedResolutions[x])
680          return resol;
681       else if (resol < handler->scanner->caps[handler->scanner->source].SupportedResolutions[x])
682       {
683           if (old == -1)
684              return handler->scanner->caps[handler->scanner->source].SupportedResolutions[1];
685           else
686              return old;
687       }
688       else
689           old = handler->scanner->caps[handler->scanner->source].SupportedResolutions[x];
690     }
691     return old;
692 }
693 
694 
695 /**
696  * \fn static SANE_Status init_options(SANE_String_Const name, escl_sane_t *s)
697  * \brief Function thzt initializes all the needed options of the received scanner
698  *        (the resolution / the color / the margins) thanks to the information received with
699  *        the 'escl_capabilities' function, called just before.
700  *
701  * \return status (if everything is OK, status = SANE_STATUS_GOOD)
702  */
703 static SANE_Status
init_options_small(SANE_String_Const name_source,escl_sane_t * s)704 init_options_small(SANE_String_Const name_source, escl_sane_t *s)
705 {
706     int found = 0;
707     DBG (10, "escl init_options\n");
708 
709     SANE_Status status = SANE_STATUS_GOOD;
710     if (!s->scanner) return SANE_STATUS_INVAL;
711     if (name_source) {
712 	   int source = s->scanner->source;
713 	   if (!strcmp(name_source, SANE_I18N ("ADF Duplex")))
714 	       s->scanner->source = ADFDUPLEX;
715 	   else if (!strncmp(name_source, "A", 1) ||
716 	            !strcmp(name_source, SANE_I18N ("ADF")))
717 	       s->scanner->source = ADFSIMPLEX;
718 	   else
719 	       s->scanner->source = PLATEN;
720 	   if (source == s->scanner->source) return status;
721            s->scanner->caps[s->scanner->source].default_color =
722                 strdup(s->scanner->caps[source].default_color);
723            s->scanner->caps[s->scanner->source].default_resolution =
724                 _get_resolution(s, s->scanner->caps[source].default_resolution);
725     }
726     if (s->scanner->caps[s->scanner->source].ColorModes == NULL) {
727         if (s->scanner->caps[PLATEN].ColorModes)
728             s->scanner->source = PLATEN;
729         else if (s->scanner->caps[ADFSIMPLEX].ColorModes)
730             s->scanner->source = ADFSIMPLEX;
731         else if (s->scanner->caps[ADFDUPLEX].ColorModes)
732             s->scanner->source = ADFDUPLEX;
733         else
734             return SANE_STATUS_INVAL;
735     }
736     if (s->scanner->source == PLATEN) {
737         DBG (10, "SOURCE PLATEN.\n");
738     }
739     else if (s->scanner->source == ADFDUPLEX) {
740         DBG (10, "SOURCE ADFDUPLEX.\n");
741     }
742     else if (s->scanner->source == ADFSIMPLEX) {
743         DBG (10, "SOURCE ADFSIMPLEX.\n");
744     }
745     s->x_range1.min = 0;
746     s->x_range1.max =
747 	    PIXEL_TO_MM((s->scanner->caps[s->scanner->source].MaxWidth -
748 		         s->scanner->caps[s->scanner->source].MinWidth),
749 			300.0);
750     s->x_range1.quant = 0;
751     s->x_range2.min = PIXEL_TO_MM(s->scanner->caps[s->scanner->source].MinWidth, 300.0);
752     s->x_range2.max = PIXEL_TO_MM(s->scanner->caps[s->scanner->source].MaxWidth, 300.0);
753     s->x_range2.quant = 0;
754     s->y_range1.min = 0;
755     s->y_range1.max =
756 	    PIXEL_TO_MM((s->scanner->caps[s->scanner->source].MaxHeight -
757 	                 s->scanner->caps[s->scanner->source].MinHeight),
758 			300.0);
759     s->y_range1.quant = 0;
760     s->y_range2.min = PIXEL_TO_MM(s->scanner->caps[s->scanner->source].MinHeight, 300.0);
761     s->y_range2.max = PIXEL_TO_MM(s->scanner->caps[s->scanner->source].MaxHeight, 300.0);
762     s->y_range2.quant = 0;
763 
764     s->opt[OPT_MODE].constraint.string_list = s->scanner->caps[s->scanner->source].ColorModes;
765     if (s->val[OPT_MODE].s)
766         free(s->val[OPT_MODE].s);
767     s->val[OPT_MODE].s = NULL;
768 
769     if (s->scanner->caps[s->scanner->source].default_color) {
770         int x = 0;
771         if (!strcmp(s->scanner->caps[s->scanner->source].default_color, "Grayscale8"))
772            s->val[OPT_MODE].s = (char *)strdup(SANE_VALUE_SCAN_MODE_GRAY);
773         else if (!strcmp(s->scanner->caps[s->scanner->source].default_color, "BlackAndWhite1"))
774            s->val[OPT_MODE].s = (char *)strdup(SANE_VALUE_SCAN_MODE_LINEART);
775         else
776            s->val[OPT_MODE].s = (char *)strdup(SANE_VALUE_SCAN_MODE_COLOR);
777         for (x = 0; s->scanner->caps[s->scanner->source].ColorModes[x]; x++) {
778             if (s->scanner->caps[s->scanner->source].ColorModes[x] &&
779               !strcasecmp(s->scanner->caps[s->scanner->source].ColorModes[x], s->val[OPT_MODE].s)) {
780               found = 1;
781               break;
782             }
783         }
784     }
785     if (!s->scanner->caps[s->scanner->source].default_color || found == 0) {
786         if (s->scanner->caps[s->scanner->source].default_color)
787            free(s->scanner->caps[s->scanner->source].default_color);
788         s->val[OPT_MODE].s = strdup(s->scanner->caps[s->scanner->source].ColorModes[0]);
789         if (!strcasecmp(s->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_GRAY))
790             s->scanner->caps[s->scanner->source].default_color = strdup("Grayscale8");
791         else if (!strcasecmp(s->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_LINEART))
792             s->scanner->caps[s->scanner->source].default_color = strdup("BlackAndWhite1");
793         else
794             s->scanner->caps[s->scanner->source].default_color = strdup("RGB24");
795     }
796     if (!s->val[OPT_MODE].s) {
797        DBG (10, "Color Mode Default allocation failure.\n");
798        return (SANE_STATUS_NO_MEM);
799     }
800     if (!s->scanner->caps[s->scanner->source].default_color) {
801        DBG (10, "Color Mode Default allocation failure.\n");
802        return (SANE_STATUS_NO_MEM);
803     }
804     s->val[OPT_RESOLUTION].w = s->scanner->caps[s->scanner->source].default_resolution;
805     s->opt[OPT_TL_X].constraint.range = &s->x_range1;
806     s->opt[OPT_TL_Y].constraint.range = &s->y_range1;
807     s->opt[OPT_BR_X].constraint.range = &s->x_range2;
808     s->opt[OPT_BR_Y].constraint.range = &s->y_range2;
809 
810     if (s->val[OPT_SCAN_SOURCE].s)
811       free (s->val[OPT_SCAN_SOURCE].s);
812     s->val[OPT_SCAN_SOURCE].s = strdup (s->scanner->Sources[s->scanner->source]);
813 
814     return (SANE_STATUS_GOOD);
815 }
816 
817 /**
818  * \fn static SANE_Status init_options(SANE_String_Const name, escl_sane_t *s)
819  * \brief Function thzt initializes all the needed options of the received scanner
820  *        (the resolution / the color / the margins) thanks to the information received with
821  *        the 'escl_capabilities' function, called just before.
822  *
823  * \return status (if everything is OK, status = SANE_STATUS_GOOD)
824  */
825 static SANE_Status
init_options(SANE_String_Const name_source,escl_sane_t * s)826 init_options(SANE_String_Const name_source, escl_sane_t *s)
827 {
828     DBG (10, "escl init_options\n");
829 
830     SANE_Status status = SANE_STATUS_GOOD;
831     int i = 0;
832     if (!s->scanner) return SANE_STATUS_INVAL;
833     if (name_source) {
834 	   int source = s->scanner->source;
835 	   DBG (10, "escl init_options name [%s]\n", name_source);
836 	   if (!strcmp(name_source, SANE_I18N ("ADF Duplex")))
837 	       s->scanner->source = ADFDUPLEX;
838 	   else if (!strncmp(name_source, "A", 1) ||
839 	            !strcmp(name_source, SANE_I18N ("ADF")))
840 	       s->scanner->source = ADFSIMPLEX;
841 	   else
842 	       s->scanner->source = PLATEN;
843 	   if (source == s->scanner->source) return status;
844     }
845     if (s->scanner->caps[s->scanner->source].ColorModes == NULL) {
846         if (s->scanner->caps[PLATEN].ColorModes)
847             s->scanner->source = PLATEN;
848         else if (s->scanner->caps[ADFSIMPLEX].ColorModes)
849             s->scanner->source = ADFSIMPLEX;
850         else if (s->scanner->caps[ADFDUPLEX].ColorModes)
851             s->scanner->source = ADFDUPLEX;
852         else
853             return SANE_STATUS_INVAL;
854     }
855     if (s->scanner->source == PLATEN) {
856         DBG (10, "SOURCE PLATEN.\n");
857     }
858     else if (s->scanner->source == ADFDUPLEX) {
859         DBG (10, "SOURCE ADFDUPLEX.\n");
860     }
861     else if (s->scanner->source == ADFSIMPLEX) {
862         DBG (10, "SOURCE ADFSIMPLEX.\n");
863     }
864     memset (s->opt, 0, sizeof (s->opt));
865     memset (s->val, 0, sizeof (s->val));
866     for (i = 0; i < NUM_OPTIONS; ++i) {
867 	   s->opt[i].size = sizeof (SANE_Word);
868 	   s->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
869     }
870     s->x_range1.min = 0;
871     s->x_range1.max =
872 	    PIXEL_TO_MM((s->scanner->caps[s->scanner->source].MaxWidth -
873 		         s->scanner->caps[s->scanner->source].MinWidth),
874 			300.0);
875     s->x_range1.quant = 0;
876     s->x_range2.min = PIXEL_TO_MM(s->scanner->caps[s->scanner->source].MinWidth, 300.0);
877     s->x_range2.max = PIXEL_TO_MM(s->scanner->caps[s->scanner->source].MaxWidth, 300.0);
878     s->x_range2.quant = 0;
879     s->y_range1.min = 0;
880     s->y_range1.max =
881 	    PIXEL_TO_MM((s->scanner->caps[s->scanner->source].MaxHeight -
882 	                 s->scanner->caps[s->scanner->source].MinHeight),
883 			300.0);
884     s->y_range1.quant = 0;
885     s->y_range2.min = PIXEL_TO_MM(s->scanner->caps[s->scanner->source].MinHeight, 300.0);
886     s->y_range2.max = PIXEL_TO_MM(s->scanner->caps[s->scanner->source].MaxHeight, 300.0);
887     s->y_range2.quant = 0;
888     s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS;
889     s->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS;
890     s->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT;
891     s->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT;
892     s->val[OPT_NUM_OPTS].w = NUM_OPTIONS;
893 
894     s->opt[OPT_MODE_GROUP].title = SANE_TITLE_SCAN_MODE;
895     s->opt[OPT_MODE_GROUP].desc = "";
896     s->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP;
897     s->opt[OPT_MODE_GROUP].cap = 0;
898     s->opt[OPT_MODE_GROUP].size = 0;
899     s->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
900 
901     s->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE;
902     s->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE;
903     s->opt[OPT_MODE].desc = SANE_DESC_SCAN_MODE;
904     s->opt[OPT_MODE].type = SANE_TYPE_STRING;
905     s->opt[OPT_MODE].unit = SANE_UNIT_NONE;
906     s->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
907     s->opt[OPT_MODE].constraint.string_list = s->scanner->caps[s->scanner->source].ColorModes;
908     if (s->scanner->caps[s->scanner->source].default_color) {
909         if (!strcasecmp(s->scanner->caps[s->scanner->source].default_color, "Grayscale8"))
910            s->val[OPT_MODE].s = (char *)strdup(SANE_VALUE_SCAN_MODE_GRAY);
911         else if (!strcasecmp(s->scanner->caps[s->scanner->source].default_color, "BlackAndWhite1"))
912            s->val[OPT_MODE].s = (char *)strdup(SANE_VALUE_SCAN_MODE_LINEART);
913         else
914            s->val[OPT_MODE].s = (char *)strdup(SANE_VALUE_SCAN_MODE_COLOR);
915     }
916     else {
917         s->val[OPT_MODE].s = (char *)strdup(s->scanner->caps[s->scanner->source].ColorModes[0]);
918         if (!strcasecmp(s->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_GRAY)) {
919            s->scanner->caps[s->scanner->source].default_color = strdup("Grayscale8");
920         }
921         else if (!strcasecmp(s->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_LINEART)) {
922            s->scanner->caps[s->scanner->source].default_color =
923                 strdup("BlackAndWhite1");
924         }
925         else {
926            s->scanner->caps[s->scanner->source].default_color =
927                strdup("RGB24");
928        }
929     }
930     if (!s->val[OPT_MODE].s) {
931        DBG (10, "Color Mode Default allocation failure.\n");
932        return (SANE_STATUS_NO_MEM);
933     }
934     DBG (10, "++ Color Mode Default allocation [%s].\n", s->scanner->caps[s->scanner->source].default_color);
935     s->opt[OPT_MODE].size = max_string_size(s->scanner->caps[s->scanner->source].ColorModes);
936     if (!s->scanner->caps[s->scanner->source].default_color) {
937        DBG (10, "Color Mode Default allocation failure.\n");
938        return (SANE_STATUS_NO_MEM);
939     }
940     DBG (10, "Color Mode Default allocation (%s).\n", s->scanner->caps[s->scanner->source].default_color);
941 
942     s->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;
943     s->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
944     s->opt[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION;
945     s->opt[OPT_RESOLUTION].type = SANE_TYPE_INT;
946     s->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI;
947     s->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST;
948     s->opt[OPT_RESOLUTION].constraint.word_list = s->scanner->caps[s->scanner->source].SupportedResolutions;
949     s->val[OPT_RESOLUTION].w = s->scanner->caps[s->scanner->source].SupportedResolutions[1];
950     s->scanner->caps[s->scanner->source].default_resolution = s->scanner->caps[s->scanner->source].SupportedResolutions[1];
951 
952     s->opt[OPT_PREVIEW].name = SANE_NAME_PREVIEW;
953     s->opt[OPT_PREVIEW].title = SANE_TITLE_PREVIEW;
954     s->opt[OPT_PREVIEW].desc = SANE_DESC_PREVIEW;
955     s->opt[OPT_PREVIEW].cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT;
956     s->opt[OPT_PREVIEW].type = SANE_TYPE_BOOL;
957     s->val[OPT_PREVIEW].w = SANE_FALSE;
958 
959     s->opt[OPT_GRAY_PREVIEW].name = SANE_NAME_GRAY_PREVIEW;
960     s->opt[OPT_GRAY_PREVIEW].title = SANE_TITLE_GRAY_PREVIEW;
961     s->opt[OPT_GRAY_PREVIEW].desc = SANE_DESC_GRAY_PREVIEW;
962     s->opt[OPT_GRAY_PREVIEW].type = SANE_TYPE_BOOL;
963     s->val[OPT_GRAY_PREVIEW].w = SANE_FALSE;
964 
965     s->opt[OPT_GEOMETRY_GROUP].title = SANE_TITLE_GEOMETRY;
966     s->opt[OPT_GEOMETRY_GROUP].desc = SANE_DESC_GEOMETRY;
967     s->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP;
968     s->opt[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED;
969     s->opt[OPT_GEOMETRY_GROUP].size = 0;
970     s->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
971 
972     s->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X;
973     s->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X;
974     s->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X;
975     s->opt[OPT_TL_X].type = SANE_TYPE_FIXED;
976     s->opt[OPT_TL_X].size = sizeof(SANE_Fixed);
977     s->opt[OPT_TL_X].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
978     s->opt[OPT_TL_X].unit = SANE_UNIT_MM;
979     s->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
980     s->opt[OPT_TL_X].constraint.range = &s->x_range1;
981     s->val[OPT_TL_X].w = s->x_range1.min;
982 
983     s->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y;
984     s->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
985     s->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y;
986     s->opt[OPT_TL_Y].type = SANE_TYPE_FIXED;
987     s->opt[OPT_TL_Y].size = sizeof(SANE_Fixed);
988     s->opt[OPT_TL_Y].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
989     s->opt[OPT_TL_Y].unit = SANE_UNIT_MM;
990     s->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
991     s->opt[OPT_TL_Y].constraint.range = &s->y_range1;
992     s->val[OPT_TL_Y].w = s->y_range1.min;
993 
994     s->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X;
995     s->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X;
996     s->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X;
997     s->opt[OPT_BR_X].type = SANE_TYPE_FIXED;
998     s->opt[OPT_BR_X].size = sizeof(SANE_Fixed);
999     s->opt[OPT_BR_X].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
1000     s->opt[OPT_BR_X].unit = SANE_UNIT_MM;
1001     s->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
1002     s->opt[OPT_BR_X].constraint.range = &s->x_range2;
1003     s->val[OPT_BR_X].w = s->x_range2.max;
1004 
1005     s->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y;
1006     s->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
1007     s->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y;
1008     s->opt[OPT_BR_Y].type = SANE_TYPE_FIXED;
1009     s->opt[OPT_BR_Y].size = sizeof(SANE_Fixed);
1010     s->opt[OPT_BR_Y].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
1011     s->opt[OPT_BR_Y].unit = SANE_UNIT_MM;
1012     s->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
1013     s->opt[OPT_BR_Y].constraint.range = &s->y_range2;
1014     s->val[OPT_BR_Y].w = s->y_range2.max;
1015 
1016 	/* OPT_SCAN_SOURCE */
1017     s->opt[OPT_SCAN_SOURCE].name = SANE_NAME_SCAN_SOURCE;
1018     s->opt[OPT_SCAN_SOURCE].title = SANE_TITLE_SCAN_SOURCE;
1019     s->opt[OPT_SCAN_SOURCE].desc = SANE_DESC_SCAN_SOURCE;
1020     s->opt[OPT_SCAN_SOURCE].type = SANE_TYPE_STRING;
1021     s->opt[OPT_SCAN_SOURCE].size = _source_size_max(s->scanner->Sources);
1022     s->opt[OPT_SCAN_SOURCE].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
1023     s->opt[OPT_SCAN_SOURCE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
1024     s->opt[OPT_SCAN_SOURCE].constraint.string_list = s->scanner->Sources;
1025     if (s->val[OPT_SCAN_SOURCE].s)
1026        free (s->val[OPT_SCAN_SOURCE].s);
1027     s->val[OPT_SCAN_SOURCE].s = strdup (s->scanner->Sources[s->scanner->source]);
1028 
1029     /* "Enhancement" group: */
1030     s->opt[OPT_ENHANCEMENT_GROUP].title = SANE_I18N ("Enhancement");
1031     s->opt[OPT_ENHANCEMENT_GROUP].desc = "";    /* not valid for a group */
1032     s->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP;
1033     s->opt[OPT_ENHANCEMENT_GROUP].cap = SANE_CAP_ADVANCED;
1034     s->opt[OPT_ENHANCEMENT_GROUP].size = 0;
1035     s->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE;
1036 
1037 
1038     s->opt[OPT_BRIGHTNESS].name = SANE_NAME_BRIGHTNESS;
1039     s->opt[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS;
1040     s->opt[OPT_BRIGHTNESS].desc = SANE_DESC_BRIGHTNESS;
1041     s->opt[OPT_BRIGHTNESS].type = SANE_TYPE_INT;
1042     s->opt[OPT_BRIGHTNESS].unit = SANE_UNIT_NONE;
1043     s->opt[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE;
1044     if (s->scanner->brightness) {
1045        s->opt[OPT_BRIGHTNESS].constraint.range = &s->brightness_range;
1046        s->val[OPT_BRIGHTNESS].w = s->scanner->brightness->value;
1047        s->brightness_range.quant=1;
1048        s->brightness_range.min=s->scanner->brightness->min;
1049        s->brightness_range.max=s->scanner->brightness->max;
1050     }
1051     else{
1052       SANE_Range range = { 0, 255, 0 };
1053       s->opt[OPT_BRIGHTNESS].constraint.range = &range;
1054       s->val[OPT_BRIGHTNESS].w = 0;
1055       s->opt[OPT_BRIGHTNESS].cap |= SANE_CAP_INACTIVE;
1056     }
1057     s->opt[OPT_CONTRAST].name = SANE_NAME_CONTRAST;
1058     s->opt[OPT_CONTRAST].title = SANE_TITLE_CONTRAST;
1059     s->opt[OPT_CONTRAST].desc = SANE_DESC_CONTRAST;
1060     s->opt[OPT_CONTRAST].type = SANE_TYPE_INT;
1061     s->opt[OPT_CONTRAST].unit = SANE_UNIT_NONE;
1062     s->opt[OPT_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE;
1063     if (s->scanner->contrast) {
1064        s->opt[OPT_CONTRAST].constraint.range = &s->contrast_range;
1065        s->val[OPT_CONTRAST].w = s->scanner->contrast->value;
1066        s->contrast_range.quant=1;
1067        s->contrast_range.min=s->scanner->contrast->min;
1068        s->contrast_range.max=s->scanner->contrast->max;
1069     }
1070     else{
1071       SANE_Range range = { 0, 255, 0 };
1072       s->opt[OPT_CONTRAST].constraint.range = &range;
1073       s->val[OPT_CONTRAST].w = 0;
1074       s->opt[OPT_CONTRAST].cap |= SANE_CAP_INACTIVE;
1075     }
1076     s->opt[OPT_SHARPEN].name = SANE_NAME_SHARPEN;
1077     s->opt[OPT_SHARPEN].title = SANE_TITLE_SHARPEN;
1078     s->opt[OPT_SHARPEN].desc = SANE_DESC_SHARPEN;
1079     s->opt[OPT_SHARPEN].type = SANE_TYPE_INT;
1080     s->opt[OPT_SHARPEN].unit = SANE_UNIT_NONE;
1081     s->opt[OPT_SHARPEN].constraint_type = SANE_CONSTRAINT_RANGE;
1082     if (s->scanner->sharpen) {
1083        s->opt[OPT_SHARPEN].constraint.range = &s->sharpen_range;
1084        s->val[OPT_SHARPEN].w = s->scanner->sharpen->value;
1085        s->sharpen_range.quant=1;
1086        s->sharpen_range.min=s->scanner->sharpen->min;
1087        s->sharpen_range.max=s->scanner->sharpen->max;
1088     }
1089     else{
1090       SANE_Range range = { 0, 255, 0 };
1091       s->opt[OPT_SHARPEN].constraint.range = &range;
1092       s->val[OPT_SHARPEN].w = 0;
1093       s->opt[OPT_SHARPEN].cap |= SANE_CAP_INACTIVE;
1094     }
1095     /*threshold*/
1096     s->opt[OPT_THRESHOLD].name = SANE_NAME_THRESHOLD;
1097     s->opt[OPT_THRESHOLD].title = SANE_TITLE_THRESHOLD;
1098     s->opt[OPT_THRESHOLD].desc = SANE_DESC_THRESHOLD;
1099     s->opt[OPT_THRESHOLD].type = SANE_TYPE_INT;
1100     s->opt[OPT_THRESHOLD].unit = SANE_UNIT_NONE;
1101     s->opt[OPT_THRESHOLD].constraint_type = SANE_CONSTRAINT_RANGE;
1102     if (s->scanner->threshold) {
1103       s->opt[OPT_THRESHOLD].constraint.range = &s->thresold_range;
1104       s->val[OPT_THRESHOLD].w = s->scanner->threshold->value;
1105       s->thresold_range.quant=1;
1106       s->thresold_range.min= s->scanner->threshold->min;
1107       s->thresold_range.max=s->scanner->threshold->max;
1108     }
1109     else{
1110       SANE_Range range = { 0, 255, 0 };
1111       s->opt[OPT_THRESHOLD].constraint.range = &range;
1112       s->val[OPT_THRESHOLD].w = 0;
1113       s->opt[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE;
1114     }
1115     if (!strcasecmp(s->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_LINEART)) {
1116        if (s->scanner->threshold)
1117        	  s->opt[OPT_THRESHOLD].cap  &= ~SANE_CAP_INACTIVE;
1118        if (s->scanner->brightness)
1119        	  s->opt[OPT_BRIGHTNESS].cap |= SANE_CAP_INACTIVE;
1120        if (s->scanner->contrast)
1121        	  s->opt[OPT_CONTRAST].cap |= SANE_CAP_INACTIVE;
1122        if (s->scanner->sharpen)
1123           s->opt[OPT_SHARPEN].cap |= SANE_CAP_INACTIVE;
1124     }
1125     else {
1126        if (s->scanner->threshold)
1127        	  s->opt[OPT_THRESHOLD].cap  |= SANE_CAP_INACTIVE;
1128        if (s->scanner->brightness)
1129           s->opt[OPT_BRIGHTNESS].cap &= ~SANE_CAP_INACTIVE;
1130        if (s->scanner->contrast)
1131           s->opt[OPT_CONTRAST].cap   &= ~SANE_CAP_INACTIVE;
1132        if (s->scanner->sharpen)
1133           s->opt[OPT_SHARPEN].cap   &= ~SANE_CAP_INACTIVE;
1134     }
1135     return (status);
1136 }
1137 
1138 SANE_Status
escl_parse_name(SANE_String_Const name,ESCL_Device * device)1139 escl_parse_name(SANE_String_Const name, ESCL_Device *device)
1140 {
1141     SANE_String_Const host = NULL;
1142     SANE_String_Const port_str = NULL;
1143     DBG(10, "escl_parse_name\n");
1144     if (name == NULL || device == NULL) {
1145         return SANE_STATUS_INVAL;
1146     }
1147 
1148     if (strncmp(name, "unix:", 5) == 0) {
1149         SANE_String_Const socket = name + 5;
1150         name = strchr(socket, ':');
1151         if (name == NULL)
1152             return SANE_STATUS_INVAL;
1153         device->unix_socket = strndup(socket, name - socket);
1154         name++;
1155     }
1156 
1157     if (strncmp(name, "https://", 8) == 0) {
1158         device->https = SANE_TRUE;
1159         device->type = strdup("https");
1160         host = name + 8;
1161     } else if (strncmp(name, "http://", 7) == 0) {
1162         device->https = SANE_FALSE;
1163         device->type = strdup("http");
1164         host = name + 7;
1165     } else {
1166         DBG(1, "Unknown URL scheme in %s", name);
1167         return SANE_STATUS_INVAL;
1168     }
1169 
1170     port_str = strchr(host, ':');
1171     if (port_str == NULL) {
1172         DBG(1, "Port missing from URL: %s", name);
1173         return SANE_STATUS_INVAL;
1174     }
1175     port_str++;
1176     device->port_nb = atoi(port_str);
1177     if (device->port_nb < 1 || device->port_nb > 65535) {
1178         DBG(1, "Invalid port number in URL: %s", name);
1179         return SANE_STATUS_INVAL;
1180     }
1181 
1182     device->ip_address = strndup(host, port_str - host - 1);
1183     return SANE_STATUS_GOOD;
1184 }
1185 
1186 static void
_get_hack(SANE_String_Const name,ESCL_Device * device)1187 _get_hack(SANE_String_Const name, ESCL_Device *device)
1188 {
1189   FILE *fp;
1190   SANE_Char line[PATH_MAX];
1191   DBG (3, "_get_hack: start\n");
1192   if (device->model_name &&
1193       (strcasestr(device->model_name, "LaserJet FlowMFP M578") ||
1194        strcasestr(device->model_name, "LaserJet MFP M630"))) {
1195        device->hack = curl_slist_append(NULL, "Host: localhost");
1196        DBG (3, "_get_hack: finish\n");
1197        return;
1198   }
1199 
1200   /* open configuration file */
1201   fp = sanei_config_open (ESCL_CONFIG_FILE);
1202   if (!fp)
1203     {
1204       DBG (2, "_get_hack: couldn't access %s\n", ESCL_CONFIG_FILE);
1205       DBG (3, "_get_hack: exit\n");
1206     }
1207 
1208   /* loop reading the configuration file, all line beginning by "option " are
1209    * parsed for value to store in configuration structure, other line are
1210    * used are device to try to attach
1211    */
1212   while (sanei_config_read (line, PATH_MAX, fp))
1213     {
1214        if (strstr(line, name)) {
1215           DBG (3, "_get_hack: idevice found\n");
1216 	  if (strstr(line, "hack=localhost")) {
1217               DBG (3, "_get_hack: device found\n");
1218 	      device->hack = curl_slist_append(NULL, "Host: localhost");
1219 	  }
1220 	  goto finish_hack;
1221        }
1222     }
1223 finish_hack:
1224   DBG (3, "_get_hack: finish\n");
1225   fclose(fp);
1226 }
1227 
1228 static char*
_get_blacklist_pdf(void)1229 _get_blacklist_pdf(void)
1230 {
1231   FILE *fp;
1232   char *blacklist = NULL;
1233   SANE_Char line[PATH_MAX];
1234 
1235   /* open configuration file */
1236   fp = sanei_config_open (ESCL_CONFIG_FILE);
1237   if (!fp)
1238     {
1239       DBG (2, "_get_blacklit: couldn't access %s\n", ESCL_CONFIG_FILE);
1240       DBG (3, "_get_blacklist: exit\n");
1241     }
1242 
1243   /* loop reading the configuration file, all line beginning by "option " are
1244    * parsed for value to store in configuration structure, other line are
1245    * used are device to try to attach
1246    */
1247   while (sanei_config_read (line, PATH_MAX, fp))
1248     {
1249        if (!strncmp(line, "pdfblacklist", 12)) {
1250           blacklist = strdup(line);
1251 	  goto finish_;
1252        }
1253     }
1254 finish_:
1255   DBG (3, "_get_blacklist_pdf: finish\n");
1256   fclose(fp);
1257   return blacklist;
1258 }
1259 
1260 
1261 /**
1262  * \fn SANE_Status sane_open(SANE_String_Const name, SANE_Handle *h)
1263  * \brief Function that establishes a connection with the device named by 'name',
1264  *        and returns a 'handler' using 'SANE_Handle *h', representing it.
1265  *        Thus, it's this function that calls the 'escl_status' function firstly,
1266  *        then the 'escl_capabilities' function, and, after, the 'init_options' function.
1267  *
1268  * \return status (if everything is OK, status = SANE_STATUS_GOOD, otherwise, SANE_STATUS_NO_MEM/SANE_STATUS_INVAL)
1269  */
1270 SANE_Status
sane_open(SANE_String_Const name,SANE_Handle * h)1271 sane_open(SANE_String_Const name, SANE_Handle *h)
1272 {
1273     char *blacklist = NULL;
1274     DBG (10, "escl sane_open\n");
1275     SANE_Status status;
1276     escl_sane_t *handler = NULL;
1277 
1278     if (name == NULL)
1279         return (SANE_STATUS_INVAL);
1280 
1281     ESCL_Device *device = calloc(1, sizeof(ESCL_Device));
1282     if (device == NULL) {
1283         DBG (10, "Handle device allocation failure.\n");
1284         return SANE_STATUS_NO_MEM;
1285     }
1286     status = escl_parse_name(name, device);
1287     if (status != SANE_STATUS_GOOD) {
1288         escl_free_device(device);
1289         return status;
1290     }
1291 
1292     handler = (escl_sane_t *)calloc(1, sizeof(escl_sane_t));
1293     if (handler == NULL) {
1294         escl_free_device(device);
1295         return (SANE_STATUS_NO_MEM);
1296     }
1297     handler->device = device;  // Handler owns device now.
1298     blacklist = _get_blacklist_pdf();
1299     handler->scanner = escl_capabilities(device, blacklist, &status);
1300     if (status != SANE_STATUS_GOOD) {
1301         escl_free_handler(handler);
1302         return (status);
1303     }
1304     _get_hack(name, device);
1305 
1306     status = init_options(NULL, handler);
1307     if (status != SANE_STATUS_GOOD) {
1308         escl_free_handler(handler);
1309         return (status);
1310     }
1311     handler->ps.depth = 8;
1312     handler->ps.last_frame = SANE_TRUE;
1313     handler->ps.format = SANE_FRAME_RGB;
1314     handler->ps.pixels_per_line = MM_TO_PIXEL(handler->val[OPT_BR_X].w, 300.0);
1315     handler->ps.lines = MM_TO_PIXEL(handler->val[OPT_BR_Y].w, 300.0);
1316     handler->ps.bytes_per_line = handler->ps.pixels_per_line * 3;
1317     status = sane_get_parameters(handler, 0);
1318     if (status != SANE_STATUS_GOOD) {
1319         escl_free_handler(handler);
1320         return (status);
1321     }
1322     handler->cancel = SANE_FALSE;
1323     handler->write_scan_data = SANE_FALSE;
1324     handler->decompress_scan_data = SANE_FALSE;
1325     handler->end_read = SANE_FALSE;
1326     *h = handler;
1327     return (status);
1328 }
1329 
1330 /**
1331  * \fn void sane_cancel(SANE_Handle h)
1332  * \brief Function that's used to, immediately or as quickly as possible, cancel the currently
1333  *        pending operation of the device represented by 'SANE_Handle h'.
1334  *        This functions calls the 'escl_scanner' functions, that resets the scan operations.
1335  */
1336 void
sane_cancel(SANE_Handle h)1337 sane_cancel(SANE_Handle h)
1338 {
1339     DBG (10, "escl sane_cancel\n");
1340     escl_sane_t *handler = h;
1341     if (handler->scanner->tmp)
1342     {
1343       fclose(handler->scanner->tmp);
1344       handler->scanner->tmp = NULL;
1345     }
1346     handler->scanner->work = SANE_FALSE;
1347     handler->cancel = SANE_TRUE;
1348     escl_scanner(handler->device, handler->scanner->scanJob, handler->result);
1349     free(handler->result);
1350     handler->result = NULL;
1351     free(handler->scanner->scanJob);
1352     handler->scanner->scanJob = NULL;
1353 }
1354 
1355 /**
1356  * \fn void sane_close(SANE_Handle h)
1357  * \brief Function that closes the communication with the device represented by 'SANE_Handle h'.
1358  *        This function must release the resources that were allocated to the opening of 'h'.
1359  */
1360 void
sane_close(SANE_Handle h)1361 sane_close(SANE_Handle h)
1362 {
1363     DBG (10, "escl sane_close\n");
1364     if (h != NULL) {
1365         escl_free_handler(h);
1366         h = NULL;
1367     }
1368 }
1369 
1370 /**
1371  * \fn const SANE_Option_Descriptor *sane_get_option_descriptor(SANE_Handle h, SANE_Int n)
1372  * \brief Function that retrieves a descriptor from the n number option of the scanner
1373  *        represented by 'h'.
1374  *        The descriptor remains valid until the machine is closed.
1375  *
1376  * \return s->opt + n
1377  */
1378 const SANE_Option_Descriptor *
sane_get_option_descriptor(SANE_Handle h,SANE_Int n)1379 sane_get_option_descriptor(SANE_Handle h, SANE_Int n)
1380 {
1381     DBG (10, "escl sane_get_option_descriptor\n");
1382     escl_sane_t *s = h;
1383 
1384     if ((unsigned) n >= NUM_OPTIONS || n < 0)
1385 	return (0);
1386     return (&s->opt[n]);
1387 }
1388 
1389 /**
1390  * \fn SANE_Status sane_control_option(SANE_Handle h, SANE_Int n, SANE_Action a, void *v, SANE_Int *i)
1391  * \brief Function that defines the actions to perform for the 'n' option of the machine,
1392  *        represented by 'h', if the action is 'a'.
1393  *        There are 3 types of possible actions :
1394  *        --> SANE_ACTION_GET_VALUE: 'v' must be used to provide the value of the option.
1395  *        --> SANE_ACTION_SET_VALUE: The option must take the 'v' value.
1396  *        --> SANE_ACTION_SET_AUTO: The backend or machine must affect the option with an appropriate value.
1397  *        Moreover, the parameter 'i' is used to provide additional information about the state of
1398  *        'n' option if SANE_ACTION_SET_VALUE has been performed.
1399  *
1400  * \return SANE_STATUS_GOOD if everything is OK, otherwise, SANE_STATUS_NO_MEM/SANE_STATUS_INVAL
1401  */
1402 SANE_Status
sane_control_option(SANE_Handle h,SANE_Int n,SANE_Action a,void * v,SANE_Int * i)1403 sane_control_option(SANE_Handle h, SANE_Int n, SANE_Action a, void *v, SANE_Int *i)
1404 {
1405     DBG (10, "escl sane_control_option\n");
1406     escl_sane_t *handler = h;
1407 
1408     if (i)
1409 	*i = 0;
1410     if (n >= NUM_OPTIONS || n < 0)
1411 	return (SANE_STATUS_INVAL);
1412     if (a == SANE_ACTION_GET_VALUE) {
1413 	switch (n) {
1414 	case OPT_TL_X:
1415 	case OPT_TL_Y:
1416 	case OPT_BR_X:
1417 	case OPT_BR_Y:
1418 	case OPT_NUM_OPTS:
1419 	case OPT_PREVIEW:
1420 	case OPT_GRAY_PREVIEW:
1421 	case OPT_RESOLUTION:
1422         case OPT_BRIGHTNESS:
1423         case OPT_CONTRAST:
1424         case OPT_SHARPEN:
1425 	    *(SANE_Word *) v = handler->val[n].w;
1426 	    break;
1427 	case OPT_SCAN_SOURCE:
1428 	case OPT_MODE:
1429 	    strcpy (v, handler->val[n].s);
1430 	    break;
1431 	case OPT_MODE_GROUP:
1432 	default:
1433 	    break;
1434 	}
1435 	return (SANE_STATUS_GOOD);
1436     }
1437     if (a == SANE_ACTION_SET_VALUE) {
1438 	switch (n) {
1439 	case OPT_TL_X:
1440 	case OPT_TL_Y:
1441 	case OPT_BR_X:
1442 	case OPT_BR_Y:
1443 	case OPT_NUM_OPTS:
1444 	case OPT_PREVIEW:
1445 	case OPT_GRAY_PREVIEW:
1446         case OPT_BRIGHTNESS:
1447         case OPT_CONTRAST:
1448         case OPT_SHARPEN:
1449 	    handler->val[n].w = *(SANE_Word *) v;
1450 	    if (i)
1451 		*i |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS | SANE_INFO_INEXACT;
1452 	    break;
1453 	case OPT_SCAN_SOURCE:
1454 	    DBG(10, "SET OPT_SCAN_SOURCE(%s)\n", (SANE_String_Const)v);
1455 	    init_options_small((SANE_String_Const)v, handler);
1456 	    if (i)
1457 		*i |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS | SANE_INFO_INEXACT;
1458 	    break;
1459 	case OPT_MODE:
1460 	    if (handler->val[n].s)
1461 		free (handler->val[n].s);
1462 	    handler->val[n].s = strdup (v);
1463 	    if (!handler->val[n].s) {
1464 	      DBG (10, "OPT_MODE allocation failure.\n");
1465 	      return (SANE_STATUS_NO_MEM);
1466 	    }
1467 	    DBG(10, "SET OPT_MODE(%s)\n", (SANE_String_Const)v);
1468 
1469             if (!strcasecmp(handler->val[n].s, SANE_VALUE_SCAN_MODE_GRAY)) {
1470               handler->scanner->caps[handler->scanner->source].default_color = strdup("Grayscale8");
1471 	    DBG(10, "SET OPT_MODE(Grayscale8)\n");
1472             }
1473             else if (!strcasecmp(handler->val[n].s, SANE_VALUE_SCAN_MODE_LINEART)) {
1474               handler->scanner->caps[handler->scanner->source].default_color =
1475                  strdup("BlackAndWhite1");
1476 	    DBG(10, "SET OPT_MODE(BlackAndWhite1)\n");
1477             }
1478             else {
1479               handler->scanner->caps[handler->scanner->source].default_color =
1480                  strdup("RGB24");
1481 	         DBG(10, "SET OPT_MODE(RGB24)\n");
1482             }
1483             DBG (10, "Color Mode allocation (%s).\n", handler->scanner->caps[handler->scanner->source].default_color);
1484 	    if (i)
1485 		*i |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS | SANE_INFO_INEXACT;
1486             if (handler->scanner->brightness)
1487                 handler->opt[OPT_BRIGHTNESS].cap |= SANE_CAP_INACTIVE;
1488             if (handler->scanner->contrast)
1489                 handler->opt[OPT_CONTRAST].cap   |= SANE_CAP_INACTIVE;
1490             if (handler->scanner->threshold)
1491                 handler->opt[OPT_THRESHOLD].cap  |= SANE_CAP_INACTIVE;
1492             if (handler->scanner->sharpen)
1493                 handler->opt[OPT_SHARPEN].cap  |= SANE_CAP_INACTIVE;
1494             if (!strcasecmp(handler->val[n].s, SANE_VALUE_SCAN_MODE_LINEART)) {
1495                if (handler->scanner->threshold)
1496                   handler->opt[OPT_THRESHOLD].cap  &= ~SANE_CAP_INACTIVE;
1497             }
1498             else {
1499                if (handler->scanner->brightness)
1500                   handler->opt[OPT_BRIGHTNESS].cap &= ~SANE_CAP_INACTIVE;
1501                if (handler->scanner->contrast)
1502                   handler->opt[OPT_CONTRAST].cap   &= ~SANE_CAP_INACTIVE;
1503                if (handler->scanner->sharpen)
1504                   handler->opt[OPT_SHARPEN].cap   &= ~SANE_CAP_INACTIVE;
1505             }
1506 	    break;
1507 	case OPT_RESOLUTION:
1508             handler->val[n].w = _get_resolution(handler, (int)(*(SANE_Word *) v));
1509 	    handler->scanner->caps[handler->scanner->source].default_resolution = handler->val[n].w;
1510 	    if (i)
1511 		*i |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS | SANE_INFO_INEXACT;
1512 	    break;
1513 	default:
1514 	    break;
1515 	}
1516     }
1517     return (SANE_STATUS_GOOD);
1518 }
1519 
1520 static SANE_Bool
_go_next_page(SANE_Status status,SANE_Status job)1521 _go_next_page(SANE_Status status,
1522               SANE_Status job)
1523 {
1524    // Thank's Alexander Pevzner (pzz@apevzner.com)
1525    SANE_Status st = SANE_STATUS_NO_DOCS;
1526    switch (status) {
1527       case SANE_STATUS_GOOD:
1528       case SANE_STATUS_UNSUPPORTED:
1529       case SANE_STATUS_DEVICE_BUSY: {
1530          DBG(10, "eSCL : Test next page\n");
1531          if (job != SANE_STATUS_GOOD) {
1532             DBG(10, "eSCL : Go next page\n");
1533             st = SANE_STATUS_GOOD;
1534          }
1535          break;
1536       }
1537       default:
1538          DBG(10, "eSCL : No next page\n");
1539    }
1540    return st;
1541 }
1542 
1543 /**
1544  * \fn SANE_Status sane_start(SANE_Handle h)
1545  * \brief Function that initiates acquisition of an image from the device represented by handle 'h'.
1546  *        This function calls the "escl_newjob" function and the "escl_scan" function.
1547  *
1548  * \return status (if everything is OK, status = SANE_STATUS_GOOD, otherwise, SANE_STATUS_NO_MEM/SANE_STATUS_INVAL)
1549  */
1550 SANE_Status
sane_start(SANE_Handle h)1551 sane_start(SANE_Handle h)
1552 {
1553     DBG (10, "escl sane_start\n");
1554     SANE_Status status = SANE_STATUS_GOOD;
1555     escl_sane_t *handler = h;
1556     int w = 0;
1557     int he = 0;
1558     int bps = 0;
1559 
1560     if (handler->device == NULL) {
1561         DBG(1, "Missing handler device.\n");
1562         return (SANE_STATUS_INVAL);
1563     }
1564     handler->cancel = SANE_FALSE;
1565     handler->write_scan_data = SANE_FALSE;
1566     handler->decompress_scan_data = SANE_FALSE;
1567     handler->end_read = SANE_FALSE;
1568     if (handler->scanner->work == SANE_FALSE) {
1569        SANE_Status st = escl_status(handler->device,
1570                                     handler->scanner->source,
1571                                     NULL,
1572                                     NULL);
1573        if (st != SANE_STATUS_GOOD)
1574           return st;
1575        if (handler->val[OPT_PREVIEW].w == SANE_TRUE)
1576        {
1577           int i = 0, val = 9999;
1578 
1579           if(handler->scanner->caps[handler->scanner->source].default_color)
1580              free(handler->scanner->caps[handler->scanner->source].default_color);
1581 
1582           if (handler->val[OPT_GRAY_PREVIEW].w == SANE_TRUE ||
1583 	      !strcasecmp(handler->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_GRAY))
1584 	     handler->scanner->caps[handler->scanner->source].default_color =
1585 	          strdup("Grayscale8");
1586           else
1587 	     handler->scanner->caps[handler->scanner->source].default_color =
1588 	          strdup("RGB24");
1589           if (!handler->scanner->caps[handler->scanner->source].default_color) {
1590 	     DBG (10, "Default Color allocation failure.\n");
1591 	     return (SANE_STATUS_NO_MEM);
1592 	  }
1593           for (i = 1; i < handler->scanner->caps[handler->scanner->source].SupportedResolutionsSize; i++)
1594           {
1595 	     if (val > handler->scanner->caps[handler->scanner->source].SupportedResolutions[i])
1596 	         val = handler->scanner->caps[handler->scanner->source].SupportedResolutions[i];
1597           }
1598           handler->scanner->caps[handler->scanner->source].default_resolution = val;
1599        }
1600        else
1601        {
1602           handler->scanner->caps[handler->scanner->source].default_resolution =
1603 	     handler->val[OPT_RESOLUTION].w;
1604           if (!handler->scanner->caps[handler->scanner->source].default_color) {
1605              if (!strcasecmp(handler->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_GRAY))
1606 	        handler->scanner->caps[handler->scanner->source].default_color = strdup("Grayscale8");
1607              else if (!strcasecmp(handler->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_LINEART))
1608 	        handler->scanner->caps[handler->scanner->source].default_color =
1609 	            strdup("BlackAndWhite1");
1610              else
1611 	        handler->scanner->caps[handler->scanner->source].default_color =
1612 	            strdup("RGB24");
1613           }
1614        }
1615        DBG (10, "Before newjob Color Mode allocation (%s).\n", handler->scanner->caps[handler->scanner->source].default_color);
1616        handler->scanner->caps[handler->scanner->source].height =
1617             MM_TO_PIXEL(handler->val[OPT_BR_Y].w, 300.0);
1618        handler->scanner->caps[handler->scanner->source].width =
1619             MM_TO_PIXEL(handler->val[OPT_BR_X].w, 300.0);;
1620        if (handler->x_range1.min == handler->val[OPT_TL_X].w)
1621            handler->scanner->caps[handler->scanner->source].pos_x = 0;
1622        else
1623            handler->scanner->caps[handler->scanner->source].pos_x =
1624                MM_TO_PIXEL((handler->val[OPT_TL_X].w - handler->x_range1.min),
1625                300.0);
1626        if (handler->y_range1.min == handler->val[OPT_TL_X].w)
1627            handler->scanner->caps[handler->scanner->source].pos_y = 0;
1628        else
1629            handler->scanner->caps[handler->scanner->source].pos_y =
1630                MM_TO_PIXEL((handler->val[OPT_TL_Y].w - handler->y_range1.min),
1631                300.0);
1632        DBG(10, "Calculate Size Image [%dx%d|%dx%d]\n",
1633 	        handler->scanner->caps[handler->scanner->source].pos_x,
1634 	        handler->scanner->caps[handler->scanner->source].pos_y,
1635 	        handler->scanner->caps[handler->scanner->source].width,
1636 	        handler->scanner->caps[handler->scanner->source].height);
1637        if (!handler->scanner->caps[handler->scanner->source].default_color) {
1638           DBG (10, "Default Color allocation failure.\n");
1639           return (SANE_STATUS_NO_MEM);
1640        }
1641 
1642        if (handler->scanner->threshold) {
1643           DBG(10, "Have Thresold\n");
1644           if (IS_ACTIVE(OPT_THRESHOLD)) {
1645             DBG(10, "Use Thresold [%d]\n", handler->val[OPT_THRESHOLD].w);
1646             handler->scanner->val_threshold = handler->val[OPT_THRESHOLD].w;
1647             handler->scanner->use_threshold = 1;
1648          }
1649          else  {
1650             DBG(10, "Not use Thresold\n");
1651             handler->scanner->use_threshold = 0;
1652          }
1653        }
1654        else
1655           DBG(10, "Don't have Thresold\n");
1656 
1657        if (handler->scanner->sharpen) {
1658           DBG(10, "Have Sharpen\n");
1659            if (IS_ACTIVE(OPT_SHARPEN)) {
1660              DBG(10, "Use Sharpen [%d]\n", handler->val[OPT_SHARPEN].w);
1661              handler->scanner->val_sharpen = handler->val[OPT_SHARPEN].w;
1662              handler->scanner->use_sharpen = 1;
1663           }
1664          else  {
1665             DBG(10, "Not use Sharpen\n");
1666             handler->scanner->use_sharpen = 0;
1667          }
1668        }
1669        else
1670           DBG(10, "Don't have Sharpen\n");
1671 
1672        if (handler->scanner->contrast) {
1673           DBG(10, "Have Contrast\n");
1674           if (IS_ACTIVE(OPT_CONTRAST)) {
1675              DBG(10, "Use Contrast [%d]\n", handler->val[OPT_CONTRAST].w);
1676              handler->scanner->val_contrast = handler->val[OPT_CONTRAST].w;
1677              handler->scanner->use_contrast = 1;
1678           }
1679           else  {
1680              DBG(10, "Not use Contrast\n");
1681              handler->scanner->use_contrast = 0;
1682           }
1683        }
1684        else
1685           DBG(10, "Don't have Contrast\n");
1686 
1687        if (handler->scanner->brightness) {
1688           DBG(10, "Have Brightness\n");
1689           if (IS_ACTIVE(OPT_BRIGHTNESS)) {
1690              DBG(10, "Use Brightness [%d]\n", handler->val[OPT_BRIGHTNESS].w);
1691              handler->scanner->val_brightness = handler->val[OPT_BRIGHTNESS].w;
1692              handler->scanner->use_brightness = 1;
1693           }
1694           else  {
1695              DBG(10, "Not use Brightness\n");
1696              handler->scanner->use_brightness = 0;
1697           }
1698        }
1699        else
1700           DBG(10, "Don't have Brightness\n");
1701 
1702        handler->result = escl_newjob(handler->scanner, handler->device, &status);
1703        if (status != SANE_STATUS_GOOD)
1704           return (status);
1705     }
1706     else
1707     {
1708        SANE_Status job = SANE_STATUS_UNSUPPORTED;
1709        SANE_Status st = escl_status(handler->device,
1710                                        handler->scanner->source,
1711                                        handler->result,
1712                                        &job);
1713        DBG(10, "eSCL : command returned status %s\n", sane_strstatus(st));
1714        if (_go_next_page(st, job) != SANE_STATUS_GOOD)
1715        {
1716          handler->scanner->work = SANE_FALSE;
1717          return SANE_STATUS_NO_DOCS;
1718        }
1719     }
1720     status = escl_scan(handler->scanner, handler->device, handler->scanner->scanJob, handler->result);
1721     if (status != SANE_STATUS_GOOD)
1722        return (status);
1723     if (!strcmp(handler->scanner->caps[handler->scanner->source].default_format, "image/jpeg"))
1724     {
1725        status = get_JPEG_data(handler->scanner, &w, &he, &bps);
1726     }
1727     else if (!strcmp(handler->scanner->caps[handler->scanner->source].default_format, "image/png"))
1728     {
1729        status = get_PNG_data(handler->scanner, &w, &he, &bps);
1730     }
1731     else if (!strcmp(handler->scanner->caps[handler->scanner->source].default_format, "image/tiff"))
1732     {
1733        status = get_TIFF_data(handler->scanner, &w, &he, &bps);
1734     }
1735     else if (!strcmp(handler->scanner->caps[handler->scanner->source].default_format, "application/pdf"))
1736     {
1737        status = get_PDF_data(handler->scanner, &w, &he, &bps);
1738     }
1739     else {
1740        DBG(10, "Unknown image format\n");
1741        return SANE_STATUS_INVAL;
1742     }
1743 
1744     DBG(10, "2-Size Image (%ld)[%dx%d|%dx%d]\n", handler->scanner->img_size, 0, 0, w, he);
1745 
1746     if (status != SANE_STATUS_GOOD)
1747        return (status);
1748     handler->ps.depth = 8;
1749     handler->ps.pixels_per_line = w;
1750     handler->ps.lines = he;
1751     handler->ps.bytes_per_line = w * bps;
1752     handler->ps.last_frame = SANE_TRUE;
1753     handler->ps.format = SANE_FRAME_RGB;
1754     handler->scanner->work = SANE_FALSE;
1755 //    DBG(10, "NEXT Frame [%s]\n", (handler->ps.last_frame ? "Non" : "Oui"));
1756     DBG(10, "Real Size Image [%dx%d|%dx%d]\n", 0, 0, w, he);
1757     return (status);
1758 }
1759 
1760 /**
1761  * \fn SANE_Status sane_get_parameters(SANE_Handle h, SANE_Parameters *p)
1762  * \brief Function that retrieves the device parameters represented by 'h' and stores them in 'p'.
1763  *        This function is normally used after "sane_start".
1764  *        It's in this function that we choose to assign the default color. (Color or Monochrome)
1765  *
1766  * \return status (if everything is OK, status = SANE_STATUS_GOOD, otherwise, SANE_STATUS_NO_MEM/SANE_STATUS_INVAL)
1767  */
1768 SANE_Status
sane_get_parameters(SANE_Handle h,SANE_Parameters * p)1769 sane_get_parameters(SANE_Handle h, SANE_Parameters *p)
1770 {
1771     DBG (10, "escl sane_get_parameters\n");
1772     SANE_Status status = SANE_STATUS_GOOD;
1773     escl_sane_t *handler = h;
1774 
1775     if (status != SANE_STATUS_GOOD)
1776         return (status);
1777     if (p != NULL) {
1778         p->depth = 8;
1779         p->last_frame = handler->ps.last_frame;
1780         p->format = SANE_FRAME_RGB;
1781         p->pixels_per_line = handler->ps.pixels_per_line;
1782         p->lines = handler->ps.lines;
1783         p->bytes_per_line = handler->ps.bytes_per_line;
1784     }
1785     return (status);
1786 }
1787 
1788 
1789 /**
1790  * \fn SANE_Status sane_read(SANE_Handle h, SANE_Byte *buf, SANE_Int maxlen, SANE_Int *len)
1791  * \brief Function that's used to read image data from the device represented by handle 'h'.
1792  *        The argument 'buf' is a pointer to a memory area that is at least 'maxlen' bytes long.
1793  *        The number of bytes returned is stored in '*len'.
1794  *        --> When the call succeeds, the number of bytes returned can be anywhere in the range from 0 to 'maxlen' bytes.
1795  *
1796  * \return SANE_STATUS_GOOD (if everything is OK, otherwise, SANE_STATUS_NO_MEM/SANE_STATUS_INVAL)
1797  */
1798 SANE_Status
sane_read(SANE_Handle h,SANE_Byte * buf,SANE_Int maxlen,SANE_Int * len)1799 sane_read(SANE_Handle h, SANE_Byte *buf, SANE_Int maxlen, SANE_Int *len)
1800 {
1801     DBG (10, "escl sane_read\n");
1802     escl_sane_t *handler = h;
1803     SANE_Status status = SANE_STATUS_GOOD;
1804     long readbyte;
1805 
1806     if (!handler | !buf | !len)
1807         return (SANE_STATUS_INVAL);
1808 
1809     if (handler->cancel)
1810         return (SANE_STATUS_CANCELLED);
1811     if (!handler->write_scan_data)
1812         handler->write_scan_data = SANE_TRUE;
1813     if (!handler->decompress_scan_data) {
1814         if (status != SANE_STATUS_GOOD)
1815             return (status);
1816         handler->decompress_scan_data = SANE_TRUE;
1817     }
1818     if (handler->scanner->img_data == NULL)
1819         return (SANE_STATUS_INVAL);
1820     if (!handler->end_read) {
1821         readbyte = min((handler->scanner->img_size - handler->scanner->img_read), maxlen);
1822         memcpy(buf, handler->scanner->img_data + handler->scanner->img_read, readbyte);
1823         handler->scanner->img_read = handler->scanner->img_read + readbyte;
1824         *len = readbyte;
1825         if (handler->scanner->img_read == handler->scanner->img_size)
1826             handler->end_read = SANE_TRUE;
1827         else if (handler->scanner->img_read > handler->scanner->img_size) {
1828             *len = 0;
1829             handler->end_read = SANE_TRUE;
1830             free(handler->scanner->img_data);
1831             handler->scanner->img_data = NULL;
1832             return (SANE_STATUS_INVAL);
1833         }
1834     }
1835     else {
1836         SANE_Status job = SANE_STATUS_UNSUPPORTED;
1837         *len = 0;
1838         free(handler->scanner->img_data);
1839         handler->scanner->img_data = NULL;
1840         if (handler->scanner->source != PLATEN) {
1841 	      SANE_Bool next_page = SANE_FALSE;
1842           SANE_Status st = escl_status(handler->device,
1843                                        handler->scanner->source,
1844                                        handler->result,
1845                                        &job);
1846           DBG(10, "eSCL : command returned status %s\n", sane_strstatus(st));
1847           if (_go_next_page(st, job) == SANE_STATUS_GOOD)
1848 	     next_page = SANE_TRUE;
1849           handler->scanner->work = SANE_TRUE;
1850           handler->ps.last_frame = !next_page;
1851         }
1852         return SANE_STATUS_EOF;
1853     }
1854     return (SANE_STATUS_GOOD);
1855 }
1856 
1857 SANE_Status
sane_get_select_fd(SANE_Handle __sane_unused__ h,SANE_Int __sane_unused__ * fd)1858 sane_get_select_fd(SANE_Handle __sane_unused__ h, SANE_Int __sane_unused__ *fd)
1859 {
1860     return (SANE_STATUS_UNSUPPORTED);
1861 }
1862 
1863 SANE_Status
sane_set_io_mode(SANE_Handle __sane_unused__ handle,SANE_Bool __sane_unused__ non_blocking)1864 sane_set_io_mode(SANE_Handle __sane_unused__ handle, SANE_Bool __sane_unused__ non_blocking)
1865 {
1866     return (SANE_STATUS_UNSUPPORTED);
1867 }
1868 
1869 /**
1870  * \fn void escl_curl_url(CURL *handle, const ESCL_Device *device, SANE_String_Const path)
1871  * \brief Uses the device info in 'device' and the path from 'path' to construct
1872  *        a full URL.  Sets this URL and any necessary connection options into
1873  *        'handle'.
1874  */
1875 void
escl_curl_url(CURL * handle,const ESCL_Device * device,SANE_String_Const path)1876 escl_curl_url(CURL *handle, const ESCL_Device *device, SANE_String_Const path)
1877 {
1878     int url_len;
1879     char *url;
1880 
1881     url_len = snprintf(NULL, 0, "%s://%s:%d%s",
1882                        (device->https ? "https" : "http"), device->ip_address,
1883                        device->port_nb, path);
1884     url_len++;
1885     url = (char *)malloc(url_len);
1886     snprintf(url, url_len, "%s://%s:%d%s",
1887              (device->https ? "https" : "http"), device->ip_address,
1888              device->port_nb, path);
1889 
1890     DBG( 1, "escl_curl_url: URL: %s\n", url );
1891     curl_easy_setopt(handle, CURLOPT_URL, url);
1892     free(url);
1893     DBG( 1, "Before use hack\n");
1894     if (device->hack) {
1895         DBG( 1, "Use hack\n");
1896         curl_easy_setopt(handle, CURLOPT_HTTPHEADER, device->hack);
1897     }
1898     DBG( 1, "After use hack\n");
1899     if (device->https) {
1900         DBG( 1, "Ignoring safety certificates, use https\n");
1901         curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0L);
1902         curl_easy_setopt(handle, CURLOPT_SSL_VERIFYHOST, 0L);
1903         if (device->tls > 0)
1904            curl_easy_setopt(handle, CURLOPT_SSLVERSION, device->tls);
1905     }
1906     if (device->unix_socket != NULL) {
1907         DBG( 1, "Using local socket %s\n", device->unix_socket );
1908         curl_easy_setopt(handle, CURLOPT_UNIX_SOCKET_PATH,
1909                          device->unix_socket);
1910     }
1911 }
1912