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 = ⦥
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 = ⦥
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 = ⦥
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 = ⦥
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