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 #define DEBUG_DECLARE_ONLY
25 #include "../include/sane/config.h"
26
27 #include "escl.h"
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 #include <libxml/parser.h>
34
35 #include "../include/sane/saneopts.h"
36
37 struct cap
38 {
39 char *memory;
40 size_t size;
41 };
42
43 static size_t
header_callback(void *str, size_t size, size_t nmemb, void *userp)44 header_callback(void *str, size_t size, size_t nmemb, void *userp)
45 {
46 struct cap *header = (struct cap *)userp;
47 size_t realsize = size * nmemb;
48 char *content = realloc(header->memory, header->size + realsize + 1);
49
50 if (content == NULL) {
51 DBG( 1, "Not enough memory (realloc returned NULL)\n");
52 return (0);
53 }
54 header->memory = content;
55 memcpy(&(header->memory[header->size]), str, realsize);
56 header->size = header->size + realsize;
57 header->memory[header->size] = 0;
58 return (realsize);
59 }
60
61
62 /**
63 * \fn static SANE_String_Const convert_elements(SANE_String_Const str)
64 * \brief Function that converts the 'color modes' of the scanner (color/gray) to be understood by SANE.
65 *
66 * \return SANE_VALUE_SCAN_MODE_GRAY / SANE_VALUE_SCAN_MODE_COLOR / SANE_VALUE_SCAN_MODE_LINEART; NULL otherwise
67 */
68 static SANE_String_Const
convert_elements(SANE_String_Const str)69 convert_elements(SANE_String_Const str)
70 {
71 if (strcmp(str, "Grayscale8") == 0)
72 return (SANE_VALUE_SCAN_MODE_GRAY);
73 else if (strcmp(str, "RGB24") == 0)
74 return (SANE_VALUE_SCAN_MODE_COLOR);
75 #if(defined HAVE_POPPLER_GLIB)
76 else if (strcmp(str, "BlackAndWhite1") == 0)
77 return (SANE_VALUE_SCAN_MODE_LINEART);
78 #endif
79 return (NULL);
80 }
81
82 /**
83 * \fn static SANE_String_Const *char_to_array(SANE_String_Const *tab, int *tabsize, SANE_String_Const mode, int good_array)
84 * \brief Function that creates the character arrays to put inside :
85 * the 'color modes', the 'content types', the 'document formats' and the 'supported intents'.
86 *
87 * \return board (the allocated array)
88 */
89 static SANE_String_Const *
char_to_array(SANE_String_Const *tab, int *tabsize, SANE_String_Const mode, int good_array)90 char_to_array(SANE_String_Const *tab, int *tabsize, SANE_String_Const mode, int good_array)
91 {
92 SANE_String_Const *board = NULL;
93 int i = 0;
94 SANE_String_Const convert = NULL;
95
96 if (mode == NULL)
97 return (tab);
98 if (good_array != 0) {
99 convert = convert_elements(mode);
100 if (convert == NULL)
101 return (tab);
102 }
103 else
104 convert = mode;
105 for (i = 0; i < (*tabsize); i++) {
106 if (strcmp(tab[i], convert) == 0)
107 return (tab);
108 }
109 (*tabsize)++;
110 if (*tabsize == 1)
111 board = (SANE_String_Const *)malloc(sizeof(SANE_String_Const) * ((*tabsize) + 1));
112 else
113 board = (SANE_String_Const *)realloc(tab, sizeof(SANE_String_Const) * ((*tabsize) + 1));
114 board[*tabsize - 1] = (SANE_String_Const)strdup(convert);
115 board[*tabsize] = NULL;
116 return (board);
117 }
118
119 /**
120 * \fn static SANE_Int *int_to_array(SANE_Int *tab, int *tabsize, int cont)
121 * \brief Function that creates the integer array to put inside the 'supported resolutions'.
122 *
123 * \return board (the allocated array)
124 */
125 static SANE_Int *
int_to_array(SANE_Int *tab, int *tabsize, int cont)126 int_to_array(SANE_Int *tab, int *tabsize, int cont)
127 {
128 SANE_Int *board = NULL;
129 int i = 0;
130
131 for (i = 0; i < (*tabsize); i++) {
132 if (tab[i] == cont)
133 return (tab);
134 }
135 (*tabsize)++;
136 if (*tabsize == 1) {
137 (*tabsize)++;
138 board = malloc(sizeof(SANE_Int *) * (*tabsize) + 1);
139 }
140 else
141 board = realloc(tab, sizeof(SANE_Int *) * (*tabsize) + 1);
142 board[0] = *tabsize - 1;
143 board[*tabsize - 1] = cont;
144 board[*tabsize] = -1;
145 return (board);
146 }
147
148 /**
149 * \fn static size_t memory_callback_c(void *contents, size_t size, size_t nmemb, void *userp)
150 * \brief Callback function that stocks in memory the content of the scanner capabilities.
151 *
152 * \return realsize (size of the content needed -> the scanner capabilities)
153 */
154 static size_t
memory_callback_c(void *contents, size_t size, size_t nmemb, void *userp)155 memory_callback_c(void *contents, size_t size, size_t nmemb, void *userp)
156 {
157 size_t realsize = size * nmemb;
158 struct cap *mem = (struct cap *)userp;
159
160 char *str = realloc(mem->memory, mem->size + realsize + 1);
161 if (str == NULL) {
162 DBG(10, "not enough memory (realloc returned NULL)\n");
163 return (0);
164 }
165 mem->memory = str;
166 memcpy(&(mem->memory[mem->size]), contents, realsize);
167 mem->size = mem->size + realsize;
168 mem->memory[mem->size] = 0;
169 return (realsize);
170 }
171
172 /**
173 * \fn static int find_nodes_c(xmlNode *node)
174 * \brief Function that browses the xml file and parses it, to find the xml children node.
175 * --> to recover the scanner capabilities.
176 *
177 * \return 0 if a xml child node is found, 1 otherwise
178 */
179 static int
find_nodes_c(xmlNode *node)180 find_nodes_c(xmlNode *node)
181 {
182 xmlNode *child = node->children;
183
184 while (child) {
185 if (child->type == XML_ELEMENT_NODE)
186 return (0);
187 child = child->next;
188 }
189 return (1);
190 }
191
192 /**
193 * \fn static int find_valor_of_array_variables(xmlNode *node, capabilities_t *scanner)
194 * \brief Function that searches in the xml file if a scanner capabilitie stocked
195 * in one of the created array (character/integer array) is found.
196 *
197 * \return 0
198 */
199 static int
find_valor_of_array_variables(xmlNode *node, capabilities_t *scanner, int type)200 find_valor_of_array_variables(xmlNode *node, capabilities_t *scanner, int type)
201 {
202 const char *name = (const char *)node->name;
203 if (strcmp(name, "ColorMode") == 0) {
204 const char *color = (SANE_String_Const)xmlNodeGetContent(node);
205 if (type == PLATEN || strcmp(color, "BlackAndWhite1"))
206 scanner->caps[type].ColorModes = char_to_array(scanner->caps[type].ColorModes, &scanner->caps[type].ColorModesSize, (SANE_String_Const)xmlNodeGetContent(node), 1);
207 }
208 else if (strcmp(name, "ContentType") == 0)
209 scanner->caps[type].ContentTypes = char_to_array(scanner->caps[type].ContentTypes, &scanner->caps[type].ContentTypesSize, (SANE_String_Const)xmlNodeGetContent(node), 0);
210 else if (strcmp(name, "DocumentFormat") == 0)
211 {
212 int i = 0;
213 SANE_Bool have_jpeg = SANE_FALSE, have_png = SANE_FALSE, have_tiff = SANE_FALSE, have_pdf = SANE_FALSE;
214 scanner->caps[type].DocumentFormats = char_to_array(scanner->caps[type].DocumentFormats, &scanner->caps[type].DocumentFormatsSize, (SANE_String_Const)xmlNodeGetContent(node), 0);
215 scanner->caps[type].have_jpeg = -1;
216 scanner->caps[type].have_png = -1;
217 scanner->caps[type].have_tiff = -1;
218 scanner->caps[type].have_pdf = -1;
219 for(; i < scanner->caps[type].DocumentFormatsSize; i++)
220 {
221 if (!strcmp(scanner->caps[type].DocumentFormats[i], "image/jpeg"))
222 {
223 have_jpeg = SANE_TRUE;
224 scanner->caps[type].have_jpeg = i;
225 }
226 #if(defined HAVE_LIBPNG)
227 else if(!strcmp(scanner->caps[type].DocumentFormats[i], "image/png"))
228 {
229 have_png = SANE_TRUE;
230 scanner->caps[type].have_png = i;
231 }
232 #endif
233 #if(defined HAVE_TIFFIO_H)
234 else if(type == PLATEN && !strcmp(scanner->caps[type].DocumentFormats[i], "image/tiff"))
235 {
236 have_tiff = SANE_TRUE;
237 scanner->caps[type].have_tiff = i;
238 }
239 #endif
240 #if(defined HAVE_POPPLER_GLIB)
241 else if(type == PLATEN && !strcmp(scanner->caps[type].DocumentFormats[i], "application/pdf"))
242 {
243 have_pdf = SANE_TRUE;
244 scanner->caps[type].have_pdf = i;
245 }
246 #endif
247 }
248 if (have_pdf)
249 scanner->caps[type].default_format = strdup("application/pdf");
250 else if (have_tiff)
251 scanner->caps[type].default_format = strdup("image/tiff");
252 else if (have_png)
253 scanner->caps[type].default_format = strdup("image/png");
254 else if (have_jpeg)
255 scanner->caps[type].default_format = strdup("image/jpeg");
256 }
257 else if (strcmp(name, "DocumentFormatExt") == 0)
258 scanner->caps[type].format_ext = 1;
259 else if (strcmp(name, "Intent") == 0)
260 scanner->caps[type].SupportedIntents = char_to_array(scanner->caps[type].SupportedIntents, &scanner->caps[type].SupportedIntentsSize, (SANE_String_Const)xmlNodeGetContent(node), 0);
261 else if (strcmp(name, "XResolution") == 0)
262 scanner->caps[type].SupportedResolutions = int_to_array(scanner->caps[type].SupportedResolutions, &scanner->caps[type].SupportedResolutionsSize, atoi((const char *)xmlNodeGetContent(node)));
263 return (0);
264 }
265
266 /**
267 * \fn static int find_value_of_int_variables(xmlNode *node, capabilities_t *scanner)
268 * \brief Function that searches in the xml file if a integer scanner capabilitie is found.
269 * The integer scanner capabilities that are interesting are :
270 * MinWidth, MaxWidth, MaxHeight, MinHeight, MaxScanRegions, MaxOpticalXResolution,
271 * RiskyLeftMargin, RiskyRightMargin, RiskyTopMargin, RiskyBottomMargin.
272 *
273 * \return 0
274 */
275 static int
find_value_of_int_variables(xmlNode *node, capabilities_t *scanner, int type)276 find_value_of_int_variables(xmlNode *node, capabilities_t *scanner, int type)
277 {
278 int MaxWidth = 0;
279 int MaxHeight = 0;
280 const char *name = (const char *)node->name;
281
282 if (strcmp(name, "MinWidth") == 0)
283 scanner->caps[type].MinWidth = atoi((const char*)xmlNodeGetContent(node));
284 else if (strcmp(name, "MaxWidth") == 0) {
285 MaxWidth = atoi((const char*)xmlNodeGetContent(node));
286 if (scanner->caps[type].MaxWidth == 0 || MaxWidth < scanner->caps[type].MaxWidth)
287 scanner->caps[type].MaxWidth = atoi((const char *)xmlNodeGetContent(node));
288 }
289 else if (strcmp(name, "MinHeight") == 0)
290 scanner->caps[type].MinHeight = atoi((const char*)xmlNodeGetContent(node));
291 else if (strcmp(name, "MaxHeight") == 0) {
292 MaxHeight = atoi((const char*)xmlNodeGetContent(node));
293 if (scanner->caps[type].MaxHeight == 0 || MaxHeight < scanner->caps[type].MaxHeight)
294 scanner->caps[type].MaxHeight = atoi((const char *)xmlNodeGetContent(node));
295 }
296 else if (strcmp(name, "MaxScanRegions") == 0)
297 scanner->caps[type].MaxScanRegions = atoi((const char *)xmlNodeGetContent(node));
298 else if (strcmp(name, "MaxOpticalXResolution") == 0)
299 scanner->caps[type].MaxOpticalXResolution = atoi((const char *)xmlNodeGetContent(node));
300 else if (strcmp(name, "RiskyLeftMargin") == 0)
301 scanner->caps[type].RiskyLeftMargin = atoi((const char *)xmlNodeGetContent(node));
302 else if (strcmp(name, "RiskyRightMargin") == 0)
303 scanner->caps[type].RiskyRightMargin = atoi((const char *)xmlNodeGetContent(node));
304 else if (strcmp(name, "RiskyTopMargin") == 0)
305 scanner->caps[type].RiskyTopMargin = atoi((const char *)xmlNodeGetContent(node));
306 else if (strcmp(name, "RiskyBottomMargin") == 0)
307 scanner->caps[type].RiskyBottomMargin = atoi((const char *)xmlNodeGetContent(node));
308 find_valor_of_array_variables(node, scanner, type);
309 return (0);
310 }
311
312 static support_t*
print_support(xmlNode *node)313 print_support(xmlNode *node)
314 {
315 support_t *sup = (support_t*)calloc(1, sizeof(support_t));
316 int cpt = 0;
317 int have_norm = 0;
318 while (node) {
319 if (!strcmp((const char *)node->name, "Min")){
320 sup->min = atoi((const char *)xmlNodeGetContent(node));
321 cpt++;
322 }
323 else if (!strcmp((const char *)node->name, "Max")) {
324 sup->max = atoi((const char *)xmlNodeGetContent(node));
325 cpt++;
326 }
327 else if (!strcmp((const char *)node->name, "Normal")) {
328 sup->value = atoi((const char *)xmlNodeGetContent(node));
329 sup->normal = sup->value;
330 cpt++;
331 have_norm = 1;
332 }
333 else if (!strcmp((const char *)node->name, "Step")) {
334 sup->step = atoi((const char *)xmlNodeGetContent(node));
335 cpt++;
336 }
337 node = node->next;
338 }
339 if (cpt == 4)
340 return sup;
341 if (cpt == 3 && have_norm == 0) {
342 sup->value = (sup->max / 2 );
343 sup->normal = sup->value;
344 return sup;
345 }
346 free(sup);
347 return NULL;
348 }
349
350 static int
find_struct_variables(xmlNode *node, capabilities_t *scanner)351 find_struct_variables(xmlNode *node, capabilities_t *scanner)
352 {
353 const char *name = (const char *)node->name;
354 if (strcmp(name, "BrightnessSupport") == 0) {
355 scanner->brightness =
356 print_support(node->children);
357 return 1;
358 }
359 else if (strcmp(name, "ContrastSupport") == 0) {
360 scanner->contrast =
361 print_support(node->children);
362 return 1;
363 }
364 else if (strcmp(name, "SharpenSupport") == 0) {
365 scanner->sharpen =
366 print_support(node->children);
367 return 1;
368 }
369 else if (strcmp(name, "ThresholdSupport") == 0) {
370 scanner->threshold =
371 print_support(node->children);
372 return 1;
373 }
374 return (0);
375 }
376
377 /**
378 * \fn static int find_true_variables(xmlNode *node, capabilities_t *scanner)
379 * \brief Function that searches in the xml file if we find a scanner capability stored
380 * in one of the created array (character/integer array),
381 * or, if we find a integer scanner capability.
382 *
383 * \return 0
384 */
385 static int
find_true_variables(xmlNode *node, capabilities_t *scanner, int type)386 find_true_variables(xmlNode *node, capabilities_t *scanner, int type)
387 {
388 const char *name = (const char *)node->name;
389 if (strcmp(name, "MinWidth") == 0 ||
390 strcmp(name, "MaxWidth") == 0 ||
391 strcmp(name, "MinHeight") == 0 ||
392 strcmp(name, "MaxHeight") == 0 ||
393 strcmp(name, "MaxScanRegions") == 0 ||
394 strcmp(name, "ColorMode") == 0 ||
395 strcmp(name, "ContentType") == 0 ||
396 strcmp(name, "DocumentFormat") == 0 ||
397 strcmp(name, "XResolution") == 0 ||
398 strcmp(name, "Intent") == 0 ||
399 strcmp(name, "MaxOpticalXResolution") == 0 ||
400 strcmp(name, "RiskyLeftMargin") == 0 ||
401 strcmp(name, "RiskyRightMargin") == 0 ||
402 strcmp(name, "RiskyTopMargin") == 0 ||
403 strcmp(name, "RiskyBottomMargin") == 0 ||
404 strcmp(name, "DocumentFormatExt") == 0)
405 find_value_of_int_variables(node, scanner, type);
406 return (0);
407 }
408
409 static char*
replace_char(char* str, char find, char replace)410 replace_char(char* str, char find, char replace){
411 char *current_pos = strchr(str,find);
412 while (current_pos) {
413 *current_pos = replace;
414 current_pos = strchr(current_pos,find);
415 }
416 return str;
417 }
418
419 /**
420 * \fn static int print_xml_c(xmlNode *node, capabilities_t *scanner)
421 * \brief Function that browses the xml file, node by node.
422 *
423 * \return 0
424 */
425 static int
print_xml_c(xmlNode *node, ESCL_Device *device, capabilities_t *scanner, int type)426 print_xml_c(xmlNode *node, ESCL_Device *device, capabilities_t *scanner, int type)
427 {
428 while (node) {
429 if (node->type == XML_ELEMENT_NODE) {
430 if (find_nodes_c(node) && type != -1)
431 find_true_variables(node, scanner, type);
432 }
433 if (!strcmp((const char *)node->name, "Version")&& node->ns && node->ns->prefix){
434 if (!strcmp((const char*)node->ns->prefix, "pwg"))
435 device->version = atof ((const char *)xmlNodeGetContent(node));
436 }
437 if (!strcmp((const char *)node->name, "MakeAndModel")){
438 device->model_name = strdup((const char *)xmlNodeGetContent(node));
439 }
440 else if (!strcmp((const char *)node->name, "PlatenInputCaps")) {
441 scanner->Sources[PLATEN] = (SANE_String_Const)strdup(SANE_I18N ("Flatbed"));
442 scanner->SourcesSize++;
443 scanner->source = PLATEN;
444 print_xml_c(node->children, device, scanner, PLATEN);
445 scanner->caps[PLATEN].duplex = 0;
446 }
447 else if (!strcmp((const char *)node->name, "AdfSimplexInputCaps")) {
448 scanner->Sources[ADFSIMPLEX] = (SANE_String_Const)strdup(SANE_I18N("ADF"));
449 scanner->SourcesSize++;
450 if (scanner->source == -1) scanner->source = ADFSIMPLEX;
451 print_xml_c(node->children, device, scanner, ADFSIMPLEX);
452 scanner->caps[ADFSIMPLEX].duplex = 0;
453 }
454 else if (!strcmp((const char *)node->name, "AdfDuplexInputCaps")) {
455 scanner->Sources[ADFDUPLEX] = (SANE_String_Const)strdup(SANE_I18N ("ADF Duplex"));
456 scanner->SourcesSize++;
457 if (scanner->source == -1) scanner->source = ADFDUPLEX;
458 print_xml_c(node->children, device, scanner, ADFDUPLEX);
459 scanner->caps[ADFDUPLEX].duplex = 1;
460 }
461 else if (find_struct_variables(node, scanner) == 0)
462 print_xml_c(node->children, device, scanner, type);
463 node = node->next;
464 }
465 return (0);
466 }
467
468 static void
_reduce_color_modes(capabilities_t *scanner)469 _reduce_color_modes(capabilities_t *scanner)
470 {
471 int type = 0;
472 for (type = 0; type < 3; type++) {
473 if (scanner->caps[type].ColorModesSize) {
474 if (scanner->caps[type].default_format &&
475 strcmp(scanner->caps[type].default_format, "application/pdf")) {
476 if (scanner->caps[type].ColorModesSize == 3) {
477 free(scanner->caps[type].ColorModes);
478 scanner->caps[type].ColorModes = NULL;
479 scanner->caps[type].ColorModesSize = 0;
480 scanner->caps[type].ColorModes = char_to_array(scanner->caps[type].ColorModes,
481 &scanner->caps[type].ColorModesSize,
482 (SANE_String_Const)SANE_VALUE_SCAN_MODE_GRAY, 0);
483 scanner->caps[type].ColorModes = char_to_array(scanner->caps[type].ColorModes,
484 &scanner->caps[type].ColorModesSize,
485 (SANE_String_Const)SANE_VALUE_SCAN_MODE_COLOR, 0);
486 }
487 }
488 }
489 }
490 }
491
492 static void
_delete_pdf(capabilities_t *scanner)493 _delete_pdf(capabilities_t *scanner)
494 {
495 int type = 0;
496 for (type = 0; type < 3; type++) {
497 if (scanner->caps[type].ColorModesSize) {
498 if (scanner->caps[type].default_format) {
499 scanner->caps[type].have_pdf = -1;
500 if (!strcmp(scanner->caps[type].default_format, "application/pdf")) {
501 free(scanner->caps[type].default_format);
502 if (scanner->caps[type].have_tiff > -1)
503 scanner->caps[type].default_format = strdup("image/tiff");
504 else if (scanner->caps[type].have_png > -1)
505 scanner->caps[type].default_format = strdup("image/png");
506 else if (scanner->caps[type].have_jpeg > -1)
507 scanner->caps[type].default_format = strdup("image/jpeg");
508 }
509 free(scanner->caps[type].ColorModes);
510 scanner->caps[type].ColorModes = NULL;
511 scanner->caps[type].ColorModesSize = 0;
512 scanner->caps[type].ColorModes = char_to_array(scanner->caps[type].ColorModes,
513 &scanner->caps[type].ColorModesSize,
514 (SANE_String_Const)SANE_VALUE_SCAN_MODE_GRAY, 0);
515 scanner->caps[type].ColorModes = char_to_array(scanner->caps[type].ColorModes,
516 &scanner->caps[type].ColorModesSize,
517 (SANE_String_Const)SANE_VALUE_SCAN_MODE_COLOR, 0);
518 }
519 }
520 }
521 }
522
523 /**
524 * \fn capabilities_t *escl_capabilities(const ESCL_Device *device, SANE_Status *status)
525 * \brief Function that finally recovers all the capabilities of the scanner, using curl.
526 * This function is called in the 'sane_open' function and it's the equivalent of
527 * the following curl command : "curl http(s)://'ip':'port'/eSCL/ScannerCapabilities".
528 *
529 * \return scanner (the structure that stocks all the capabilities elements)
530 */
531 capabilities_t *
escl_capabilities(ESCL_Device *device, char *blacklist, SANE_Status *status)532 escl_capabilities(ESCL_Device *device, char *blacklist, SANE_Status *status)
533 {
534 capabilities_t *scanner = (capabilities_t*)calloc(1, sizeof(capabilities_t));
535 CURL *curl_handle = NULL;
536 struct cap *var = NULL;
537 struct cap *header = NULL;
538 xmlDoc *data = NULL;
539 xmlNode *node = NULL;
540 int i = 0;
541 const char *scanner_capabilities = "/eSCL/ScannerCapabilities";
542 SANE_Bool use_pdf = SANE_TRUE;
543
544 *status = SANE_STATUS_GOOD;
545 if (device == NULL)
546 *status = SANE_STATUS_NO_MEM;
547 var = (struct cap *)calloc(1, sizeof(struct cap));
548 if (var == NULL)
549 *status = SANE_STATUS_NO_MEM;
550 var->memory = malloc(1);
551 var->size = 0;
552 header = (struct cap *)calloc(1, sizeof(struct cap));
553 if (header == NULL)
554 *status = SANE_STATUS_NO_MEM;
555 header->memory = malloc(1);
556 header->size = 0;
557 curl_handle = curl_easy_init();
558 escl_curl_url(curl_handle, device, scanner_capabilities);
559 curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, memory_callback_c);
560 curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)var);
561 curl_easy_setopt(curl_handle, CURLOPT_HEADERFUNCTION, header_callback);
562 curl_easy_setopt(curl_handle, CURLOPT_HEADERDATA, (void *)header);
563 curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L);
564 curl_easy_setopt(curl_handle, CURLOPT_MAXREDIRS, 3L);
565 CURLcode res = curl_easy_perform(curl_handle);
566 if (res == CURLE_OK)
567 DBG( 1, "Create NewJob : the scanner header responded : [%s]\n", header->memory);
568 if (res != CURLE_OK) {
569 DBG( 1, "The scanner didn't respond: %s\n", curl_easy_strerror(res));
570 *status = SANE_STATUS_INVAL;
571 goto clean_data;
572 }
573 DBG( 10, "XML Capabilities[\n%s\n]\n", var->memory);
574 data = xmlReadMemory(var->memory, var->size, "file.xml", NULL, 0);
575 if (data == NULL) {
576 *status = SANE_STATUS_NO_MEM;
577 goto clean_data;
578 }
579 node = xmlDocGetRootElement(data);
580 if (node == NULL) {
581 *status = SANE_STATUS_NO_MEM;
582 goto clean;
583 }
584
585 if (device->hack &&
586 header &&
587 header->memory &&
588 strstr(header->memory, "Server: HP_Compact_Server"))
589 device->hack = curl_slist_append(NULL, "Host: localhost");
590
591 device->version = 0.0;
592 scanner->source = 0;
593 scanner->Sources = (SANE_String_Const *)malloc(sizeof(SANE_String_Const) * 4);
594 for (i = 0; i < 4; i++)
595 scanner->Sources[i] = NULL;
596 print_xml_c(node, device, scanner, -1);
597 DBG (3, "1-blacklist_pdf: %s\n", (use_pdf ? "TRUE" : "FALSE") );
598 if (device->model_name != NULL) {
599 if (strcasestr(device->model_name, "MFC-J985DW")) {
600 DBG (3, "blacklist_pdf: device not support PDF\n");
601 use_pdf = SANE_FALSE;
602 }
603 else if (blacklist) {
604 char *model = strdup(device->model_name);
605 replace_char(model, ' ', '_');
606 if (strcasestr(blacklist, model)) {
607 use_pdf = SANE_FALSE;
608 }
609 free(model);
610 }
611 }
612 DBG (3, "1-blacklist_pdf: %s\n", (use_pdf ? "TRUE" : "FALSE") );
613 if (use_pdf)
614 _reduce_color_modes(scanner);
615 else
616 _delete_pdf(scanner);
617 clean:
618 xmlFreeDoc(data);
619 clean_data:
620 xmlCleanupParser();
621 xmlMemoryDump();
622 curl_easy_cleanup(curl_handle);
623 if (header)
624 free(header->memory);
625 free(header);
626 if (var)
627 free(var->memory);
628 free(var);
629 return (scanner);
630 }
631