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