Tizen 2.1 base
[platform/upstream/hplip.git] / scan / sane / bb_ledm.c
1 /************************************************************************************\
2   bb_ledm.c - HP SANE backend support for ledm based multi-function peripherals
3   (c) 2010 Copyright Hewlett-Packard Development Company, LP
4
5   Primary Author: Naga Samrat Chowdary, Narla
6   Contributing Authors: Yashwant Kumar Sahu, Sarbeswar Meher
7 \************************************************************************************/
8
9 # ifndef _GNU_SOURCE
10 # define _GNU_SOURCE
11 # endif
12
13 # include <stdarg.h>
14 # include <syslog.h>
15 # include <stdio.h>
16 # include <string.h>
17 # include <fcntl.h>
18 # include <math.h>
19 # include "sane.h"
20 # include "saneopts.h"
21 # include "hpmud.h"
22 # include "hpip.h"
23 # include "common.h"
24 # include "ledm.h"
25 # include "ledmi.h"
26 # include "http.h"
27 # include "xml.h"
28 # include <stdlib.h>
29
30 # include <stdint.h>
31
32 # define _STRINGIZE(x) #x
33 # define STRINGIZE(x) _STRINGIZE(x)
34
35 # define _BUG(args...) syslog(LOG_ERR, __FILE__ " " STRINGIZE(__LINE__) ": " args)
36
37 # ifdef BB_LEDM_DEBUG
38    # define _DBG(args...) syslog(LOG_INFO, __FILE__ " " STRINGIZE(__LINE__) ": " args)
39 # else
40    # define _DBG(args...)
41 # endif
42
43 enum DOCUMENT_TYPE
44 {
45   DT_AUTO = 1,
46   DT_MAX,
47 };
48
49 enum SCANNER_STATE
50 {
51   SS_IDLE = 1,
52   SS_PROCESSING,
53   SS_STOPPED,
54 };
55
56 enum SCANNER_STATE_REASON
57 {
58   SSR_ATTENTION_REQUIRED = 1,
59   SSR_CALIBRATING,
60   SSR_COVER_OPEN,
61   SSR_INPUT_TRAY_EMPTY,
62   SSR_INTERNAL_STORAGE_FULL,
63   SSR_LAMP_ERROR,
64   SSR_LAMP_WARMING,
65   SSR_MEDIA_JAM,
66   SSR_BUSY,
67   SSR_NONE,
68 };
69
70 struct media_size
71 {
72   int width;                                   /* in 1/1000 of an inch */
73   int height;                                  /* in 1/1000 of an inch */
74 };
75
76 struct device_settings
77 {
78   enum COLOR_ENTRY color[CE_MAX];
79   enum SCAN_FORMAT formats[SF_MAX];
80   int jpeg_quality_factor_supported;           /* 0=false, 1=true */
81   enum DOCUMENT_TYPE docs[DT_MAX];
82   int document_size_auto_detect_supported;     /* 0=false, 1=true */
83   int feeder_capacity;
84 };
85
86 struct device_platen
87 {
88   int flatbed_supported;                       /* 0=false, 1=true */
89   struct media_size minimum_size;
90   struct media_size maximum_size;
91   struct media_size optical_resolution;
92   int platen_resolution_list[MAX_LIST_SIZE];
93 };
94
95 struct device_adf
96 {
97   int supported;                               /* 0=false, 1=true */
98   int duplex_supported;                        /* 0=false, 1=true */
99   struct media_size minimum_size;
100   struct media_size maximum_size;
101   struct media_size optical_resolution;
102   int adf_resolution_list[MAX_LIST_SIZE];
103 };
104
105 struct scanner_configuration
106 {
107   struct device_settings settings;
108   struct device_platen platen;
109   struct device_adf adf;
110 };
111
112 struct scanner_status
113 {
114   char *current_time;
115   enum SCANNER_STATE state;
116   enum SCANNER_STATE_REASON reason;
117   int paper_in_adf;                            /* 0=false, 1=true */
118   int scan_to_available;                       /* 0=false, 1=true */
119 };
120
121 struct wscn_scan_elements
122 {
123   struct scanner_configuration config;
124   struct scanner_status status;
125   char model_number[32];
126 };
127
128 struct wscn_create_scan_job_response
129 {
130   int jobid;
131   int pixels_per_line;
132   int lines;                                   /* number of lines */
133   int bytes_per_line;                          /* zero if jpeg */
134   enum SCAN_FORMAT format;
135   int jpeg_quality_factor;
136   int images_to_transfer;                      /* number of images to scan */
137   enum INPUT_SOURCE source;
138   enum DOCUMENT_TYPE doc;
139   struct media_size input_size;
140   int scan_region_xoffset;
141   int scan_region_yoffset;
142   int scan_region_width;
143   int scan_region_height;
144   enum COLOR_ENTRY color;
145   struct media_size resolution;
146 };
147
148 struct bb_ledm_session
149 {
150   struct wscn_create_scan_job_response job;    /* actual scan job attributes (valid after sane_start) */
151   struct wscn_scan_elements elements;          /* scanner elements (valid after sane_open and sane_start) */
152   HTTP_HANDLE http_handle;
153 };
154
155 /* Following elements must match their associated enum table. */
156 static const char *sf_element[SF_MAX] = { "", "raw", "jpeg" };  /* SCAN_FORMAT (compression) */
157 static const char *ce_element[CE_MAX] = { "", "K1", "Gray8", "Color8" };   /* COLOR_ENTRY */
158 static const char *is_element[IS_MAX] = { "", "Platen", "Adf", "ADFDuplex" };   /* INPUT_SOURCE */
159
160 # define POST_HEADER "POST /Scan/Jobs HTTP/1.1\r\nHost: localhost\r\nUser-Agent: \
161 hplip\r\nAccept: text/plain, */*\r\nAccept-Language: en-us,en\r\n\
162 Accept-Charset: ISO-8859-1,utf-8\r\nKeep-Alive: 1000\r\nProxy-Connection: keep-alive\r\n\
163 Content-Type: */*; charset=UTF-8\r\nX-Requested-With: XMLHttpRequest\r\n\
164 Content-Length: %d\r\nCookie: AccessCounter=new\r\n\
165 Pragma: no-cache\r\nCache-Control: no-cache\r\n\r\n" 
166
167 # define GET_SCANNER_ELEMENTS "GET /Scan/ScanCaps HTTP/1.1\r\n\
168 Host: localhost\r\nUser-Agent: hplip\r\n\
169 Accept: text/xml\r\n\
170 Accept-Language: en-us,en\r\n\
171 Accept-Charset:utf-8\r\n\
172 Keep-Alive: 20\r\nProxy-Connection: keep-alive\r\nCookie: AccessCounter=new\r\n0\r\n\r\n"
173
174 # define GET_SCANNER_STATUS "GET /Scan/Status HTTP/1.1\r\n\
175 Host: localhost\r\nUser-Agent: hplip\r\n\
176 Accept: text/xml\r\n\
177 Accept-Language: en-us,en\r\n\
178 Accept-Charset:utf-8\r\n\
179 Keep-Alive: 20\r\nProxy-Connection: keep-alive\r\nCookie: AccessCounter=new\r\n0\r\n\r\n"
180
181 # define CREATE_SCAN_JOB_REQUEST "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\
182 <ScanSettings xmlns=\"http://www.hp.com/schemas/imaging/con/cnx/scan/2008/08/19\">\
183 <XResolution>%d</XResolution>\
184 <YResolution>%d</YResolution>\
185 <XStart>%d</XStart>\
186 <Width>%d</Width>\
187 <YStart>%d</YStart>\
188 <Height>%d</Height>\
189 <Format>%s</Format>\
190 <CompressionQFactor>15</CompressionQFactor>\
191 <ColorSpace>%s</ColorSpace>\
192 <BitDepth>%d</BitDepth>\
193 <InputSource>%s</InputSource>\
194 <InputSourceType>%s</InputSourceType>%s\
195 <GrayRendering>NTSC</GrayRendering>\
196 <ToneMap>\
197 <Gamma>0</Gamma>\
198 <Brightness>1000</Brightness>\
199 <Contrast>1000</Contrast>\
200 <Highlite>0</Highlite>\
201 <Shadow>0</Shadow></ToneMap>\
202 <ContentType>Photo</ContentType></ScanSettings>" 
203
204 # define CANCEL_JOB_REQUEST "PUT %s HTTP/1.1\r\nHost: localhost\r\nUser-Agent: hplip\r\n\
205 Accept: text/plain\r\nAccept-Language: en-us,en\r\nAccept-Charset:utf-8\r\nKeep-Alive: 10\r\n\
206 Content-Type: text/xml\r\nProxy-Connection: Keep-alive\r\nX-Requested-With: XMLHttpRequest\r\nReferer: localhost\r\n\
207 Content-Length: %d\r\nCookie: AccessCounter=new\r\n\r\n"
208
209 #define CANCEL_JOB_DATA "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
210 <j:Job xmlns:j=\"http://www.hp.com/schemas/imaging/con/ledm/jobs/2009/04/30\" \
211 xmlns:dd=\"http://www.hp.com/schemas/imaging/con/dictionaries/1.0/\" \
212 xmlns:fax=\"http://www.hp.com/schemas/imaging/con/fax/2008/06/13\" \
213 xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" \
214 xsi:schemaLocation=\"http://www.hp.com/schemas/imaging/con/ledm/jobs/2009/04/30 ../schemas/Jobs.xsd\">\
215 <j:JobState>Canceled</j:JobState></j:Job>"
216
217 # define GET_SCAN_JOB_URL "GET %s HTTP/1.1\r\nHost: localhost\r\nUser-Agent: hplip\r\n\
218 Accept: text/plain\r\nAccept-Language: en-us,en\r\nAccept-Charset:utf-8\r\nX-Requested-With: XMLHttpRequest\r\n\
219 Keep-Alive: 300\r\nProxy-Connection: keep-alive\r\nCookie: AccessCounter=new\r\n0\r\n\r\n"
220
221 # define ZERO_FOOTER "\r\n0\r\n\r\n"
222
223 # define READY_TO_UPLOAD "<PageState>ReadyToUpload</PageState>"
224 # define CANCELED_BY_DEVICE "<PageState>CanceledByDevice</PageState>"
225 # define CANCELED_BY_CLIENT "<PageState>CanceledByClient</PageState>"
226 # define ADF_LOADED "<AdfState>Loaded</AdfState>"
227 # define ADF_EMPTY "<AdfState>Empty</AdfState>"
228 # define SCANNER_IDLE "<ScannerState>Idle</ScannerState>"
229 # define SCANNER_BUSY_WITH_SCAN_JOB "<ScannerState>BusyWithScanJob</ScannerState>"
230 # define JOBSTATE_PROCESSING "<j:JobState>Processing</j:JobState>"
231 # define JOBSTATE_CANCELED "<j:JobState>Canceled</j:JobState>"
232 # define JOBSTATE_COMPLETED "<j:JobState>Completed</j:JobState>"
233
234 static int parse_scan_elements(const char *payload, int size, struct wscn_scan_elements *elements)
235 {
236   char tag[512];
237   char value[128];
238   int i;
239   char *tail=(char *)payload;
240
241   memset(elements, 0, sizeof(struct wscn_scan_elements));
242
243   while (1)
244   {
245     get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
246
247     if (!tag[0])
248       break;     /* done */
249
250     if(strncmp(tag, "ColorEntries", 12) == 0)
251     {
252       int h=1;
253       while(h)
254       {
255         get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
256         if(strncmp(tag, "Platen", 6) ==0) break;
257         if(strncmp(tag, "/ColorEntries", 13) ==0) break;
258         if(strncmp(tag, "ColorType", 9)==0)
259         {
260           get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
261           if (strcmp(value, ce_element[CE_K1]) == 0)
262             elements->config.settings.color[CE_K1] = CE_K1;
263           else if (strcmp(value, ce_element[CE_GRAY8]) == 0)
264              elements->config.settings.color[CE_GRAY8] = CE_GRAY8;
265           else if (strcmp(value, ce_element[CE_COLOR8]) == 0)
266              elements->config.settings.color[CE_COLOR8] = CE_COLOR8;
267 //        else
268 //           _BUG("unknowned element=%s, sf_element[SF_JPEG]=%s, sf_element[SF_RAW]=%s\n", value, sf_element[SF_JPEG], sf_element[SF_RAW] );
269           _DBG("FormatSupported:%s\n", value);
270           get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
271           if(strncmp(tag, "/ColorEntries", 13) == 0) h=0; 
272          }
273          if(strncmp(tag, "/ColorEntries", 13) == 0) h=0; 
274        }   
275     }         
276
277     if(strncmp(tag, "Platen", 6) == 0)
278     {
279       elements->config.platen.flatbed_supported = 1;
280       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
281       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
282       get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
283       elements->config.platen.minimum_size.width=strtol(value, NULL, 10);
284       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
285       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
286       get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
287       elements->config.platen.minimum_size.height=strtol(value, NULL, 10);
288       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
289       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
290       get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
291       elements->config.platen.maximum_size.width=strtol(value, NULL, 10);
292       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
293       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
294       get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
295       elements->config.platen.maximum_size.height=strtol(value, NULL, 10);
296       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
297       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
298       get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
299       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
300       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
301       get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
302       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
303       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
304       get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
305       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
306       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
307       get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
308       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
309       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
310       get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
311       elements->config.platen.optical_resolution.width=strtol(value, NULL, 10);
312       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
313       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
314       get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
315       elements->config.platen.optical_resolution.height=strtol(value, NULL, 10);        
316       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
317       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
318       get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
319
320       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
321       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
322       i=1; 
323       elements->config.platen.platen_resolution_list[0]=0;
324       while(strcmp(tag, "/SupportedResolutions"))
325       {
326         get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
327         if(!strcmp(tag, "Resolution"))
328         {
329           get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
330           get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
331           _DBG ("parse_scan_elements platen_resolution_list value=%s\n", value);
332           if(strtol(value, NULL, 10) && elements->config.platen.platen_resolution_list[i-1] != strtol(value, NULL, 10))
333           
334             elements->config.platen.platen_resolution_list[i++]=strtol(value, NULL, 10);
335         }
336       }
337       elements->config.platen.platen_resolution_list[0]=i-1;
338     }
339
340     if(strncmp(tag, "Adf", 3) == 0 && strlen(tag) == 3)
341     {
342       elements->config.adf.supported = 1;
343       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
344       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
345       get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
346       elements->config.adf.minimum_size.width=strtol(value, NULL, 10);
347       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
348       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
349       get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
350       elements->config.adf.minimum_size.height=strtol(value, NULL, 10);
351       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
352       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
353       get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
354       elements->config.adf.maximum_size.width=strtol(value, NULL, 10);
355       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
356       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
357       get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
358       elements->config.adf.maximum_size.height=strtol(value, NULL, 10);
359       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
360       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
361       get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
362       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
363       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
364       get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
365       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
366       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
367       get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
368       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
369       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
370       get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
371       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
372       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
373       get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
374       elements->config.adf.optical_resolution.width=strtol(value, NULL, 10);
375       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
376       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
377       get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
378       elements->config.adf.optical_resolution.height=strtol(value, NULL, 10);
379       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
380       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
381       get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
382
383       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
384       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
385       i=1; 
386       elements->config.adf.adf_resolution_list[0]=0;
387       while(strcmp(tag, "/SupportedResolutions"))
388       {
389         get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
390         if(!strcmp(tag, "Resolution"))
391         {
392           get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
393           get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
394           _DBG ("parse_scan_elements adf_resolution_list value=%s", value);
395           if(strtol(value, NULL, 10) && elements->config.adf.adf_resolution_list[i-1] != strtol(value, NULL, 10))
396             elements->config.adf.adf_resolution_list[i++]=strtol(value, NULL, 10);
397         }
398       }
399       elements->config.adf.adf_resolution_list[0]=i-1;
400       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
401       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);//FeederCapacity
402       get_element(tail, size-(tail-payload), value, sizeof(value), &tail);
403       _DBG ("parse_scan_elements FeederCapacity=%s", value);
404       elements->config.settings.feeder_capacity = strtol(value, NULL, 10);
405       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
406       get_tag(tail, size-(tail-payload), tag, sizeof(tag), &tail);
407       if(!strcmp(tag, "AdfDuplexer"))
408       {
409          elements->config.adf.duplex_supported = 1;
410          _DBG ("parse_scan_elements duplex_supported");
411       }
412     }
413   }  /* end while (1) */
414   return 0;
415 } /* parse_scan_elements */
416
417 static struct bb_ledm_session* create_session()
418 {
419   struct bb_ledm_session* pbb;
420
421   if ((pbb = malloc(sizeof(struct bb_ledm_session))) == NULL)
422   {
423     return NULL;
424   }
425
426   memset(pbb, 0, sizeof(struct bb_ledm_session));
427   return pbb;
428 } /* create_session */
429
430 static int read_http_payload(struct ledm_session *ps, char *payload, int max_size, int sec_timeout, int *bytes_read)
431 {
432   struct bb_ledm_session *pbb = ps->bb_session;
433   int stat=1, total=0, len;
434   int tmo=sec_timeout;
435   enum HTTP_RESULT ret;
436   int payload_length=-1;
437   char *temp=NULL;
438
439   *bytes_read = 0;
440
441   if(http_read_header(pbb->http_handle, payload, max_size, tmo, &len) != HTTP_R_OK)
442       goto bugout;
443
444   _DBG("read_http_payload len=%d %s\n",len,payload);
445   temp = strstr(payload, "HTTP/1.1 201 Created");
446   if (temp)
447   {
448                 *bytes_read = total = len;
449                 stat=0;
450                 return stat ;
451   }
452   
453   temp=strstr(payload, "Content-Length:");
454   if (temp)
455   {
456                 temp=temp+16;
457                 temp=strtok(temp, "\r\n");
458                 payload_length=strtol(temp, NULL, 10);
459                 if (payload_length == 0)
460                 {
461                         *bytes_read = total = len;
462                         stat=0;
463                         return stat ;
464                 }
465   }
466   memset(payload, ' ', len);
467   if(payload_length==-1)
468   {
469     int i=10;
470     while(i)
471     {
472                 len = 0;
473                 ret = http_read(pbb->http_handle, payload+total, max_size-total, tmo, &len);
474                 total+=len;
475         tmo=1;
476         i--;
477                 if (ret == HTTP_R_EOF)
478         {
479          _DBG("read_http_payload1 DONE......\n");
480           break;    /* done */
481         }
482
483         if (!(ret == HTTP_R_OK || ret == HTTP_R_EOF))
484         {
485                 _DBG("read_http_payload1 ERROR......\n");
486                 goto bugout;
487         }
488     }//end while(i)
489   }//end if(payload_length==-1)
490   else
491   {
492           len=payload_length;
493           while (total < payload_length) 
494           {
495                   ret = http_read(pbb->http_handle, payload+total, max_size-total, tmo, &len);
496                   total+=len;
497                   tmo=1;
498                   if (ret == HTTP_R_EOF)
499                   {
500                      _DBG("read_http_payload2 DONE......\n");
501                      break;    /* done */
502                   } 
503
504                   if (!(ret == HTTP_R_OK || ret == HTTP_R_EOF))
505                   {
506                   _DBG("read_http_payload2 ERROR......\n");
507                   goto bugout;
508            }
509         }//end while()
510   }//end else
511
512  *bytes_read = total;
513   stat=0;
514
515 bugout:
516    return stat;
517 } /* read_http_payload */
518
519 static int get_scanner_elements(struct ledm_session *ps, struct wscn_scan_elements *elements)
520 {
521   struct bb_ledm_session *pbb = ps->bb_session;
522   int bytes_read = 0;
523   int stat=1, tmo=10;
524   char buf[8192];
525
526   if (http_open(ps->dd, HPMUD_S_LEDM_SCAN, &pbb->http_handle) != HTTP_R_OK)
527   {
528     _BUG("unable to open http connection %s\n", ps->uri);
529     goto bugout;
530   }
531
532   /* Write the xml payload. */
533   if (http_write(pbb->http_handle, GET_SCANNER_ELEMENTS, sizeof(GET_SCANNER_ELEMENTS)-1, tmo) != HTTP_R_OK)
534   {
535     _BUG("unable to get_scanner_elements %s\n", ps->uri);
536     goto bugout;
537   }
538
539   /* Read http response. */
540   if (read_http_payload(ps, buf, sizeof(buf), tmo, &bytes_read))
541     goto bugout;
542
543   _DBG("get_scanner_elements bytes_read=%d len=%d buf=%s\n", bytes_read, strlen(buf), buf);
544
545    http_unchunk_data(buf);
546    bytes_read=strlen(buf);
547   
548   _DBG("get_scanner_elements buf=%s\n", buf);
549   parse_scan_elements(buf, bytes_read, elements);
550   stat=0;
551
552 bugout:
553   if (pbb->http_handle)
554   {
555     http_close(pbb->http_handle);
556     pbb->http_handle = 0;
557   }
558   return stat;
559 } /* get_scanner_elements */
560
561 static int cancel_job(struct ledm_session *ps)
562 {
563   struct bb_ledm_session *pbb = ps->bb_session;
564   int len, stat=1, tmo=5/*EXCEPTION_TIMEOUT*/;
565   char buf[2048];
566   int bytes_read;
567
568   _DBG("cancel_job user_cancel=%d job_id=%d url=%s \n", ps->user_cancel, ps->job_id, ps->url);
569   if (ps->job_id == 0 || ps->user_cancel == 0)
570   {
571        ps->job_id = 0;
572        ps->page_id = 0;
573        return 0 ;
574   }
575   
576   if (http_open(ps->dd, HPMUD_S_LEDM_SCAN, &pbb->http_handle) != HTTP_R_OK)
577   {
578     _BUG("unable to open http connection %s\n", ps->uri);
579     goto bugout;
580   }
581
582   len = snprintf(buf, sizeof(buf), CANCEL_JOB_REQUEST, ps->url, strlen(CANCEL_JOB_DATA));
583   if (http_write(pbb->http_handle, buf, len, 1) != HTTP_R_OK)
584   {
585     _BUG("unable to cancel_job %s\n", ps->url);
586   }
587  
588   len = snprintf(buf, sizeof(buf), CANCEL_JOB_DATA);
589   if (http_write(pbb->http_handle, buf, len, 1) != HTTP_R_OK)
590   {
591     _BUG("unable to cancel_job %s\n", ps->url);
592   }
593
594   if (read_http_payload(ps, buf, sizeof(buf), tmo, &bytes_read))
595     goto bugout;
596
597   stat=0;
598
599 bugout:
600   if (pbb->http_handle)
601   {
602     http_close(pbb->http_handle);
603     pbb->http_handle = 0;
604   }
605   return stat;   
606 }; /* cancel_job */
607
608 /* --------------------------- LEDM API Calls -----------------------------*/
609
610 int bb_open(struct ledm_session *ps)
611 {
612   struct bb_ledm_session *pbb;
613   struct device_settings *ds;
614   int stat=1, i, j;
615
616   _DBG("bb_open()\n");
617
618   if ((ps->bb_session = create_session()) == NULL)
619     goto bugout;
620
621   pbb = ps->bb_session;
622
623   /* Get scanner elements from device. */
624   if (get_scanner_elements(ps, &pbb->elements))
625   {
626     goto bugout;
627   }
628
629   /* Determine supported Scan Modes. */
630   ds = &pbb->elements.config.settings;
631   for(i=0, j=0; i<CE_MAX; i++)
632   {
633     if (ds->color[i] == CE_K1)
634     {
635       ps->scanModeList[j] = SANE_VALUE_SCAN_MODE_LINEART;
636       ps->scanModeMap[j++] = CE_K1;
637     }
638     if (ds->color[i] == CE_GRAY8)
639     {
640        ps->scanModeList[j] = SANE_VALUE_SCAN_MODE_GRAY;
641        ps->scanModeMap[j++] = CE_GRAY8;
642     }
643     if (ds->color[i] == CE_COLOR8)
644     {
645       ps->scanModeList[j] = SANE_VALUE_SCAN_MODE_COLOR;
646       ps->scanModeMap[j++] = CE_COLOR8;
647     }
648   }
649    
650   /* Determine scan input sources. */
651   i=0;
652   if (pbb->elements.config.platen.flatbed_supported)
653   {
654     ps->inputSourceList[i] = STR_ADF_MODE_FLATBED;
655     ps->inputSourceMap[i++] = IS_PLATEN;
656   }
657   if (pbb->elements.config.adf.supported)
658   {
659     ps->inputSourceList[i] = STR_ADF_MODE_ADF;
660     ps->inputSourceMap[i++] = IS_ADF;
661   }
662   if (pbb->elements.config.adf.duplex_supported)
663   {
664     ps->inputSourceList[i] = STR_TITLE_DUPLEX;
665     ps->inputSourceMap[i++] = IS_ADF_DUPLEX;
666   }
667
668   /* Determine if jpeg quality factor is supported. */
669   if (pbb->elements.config.settings.jpeg_quality_factor_supported)
670     ps->option[LEDM_OPTION_JPEG_QUALITY].cap &= ~SANE_CAP_INACTIVE;
671   else
672     ps->option[LEDM_OPTION_JPEG_QUALITY].cap |= SANE_CAP_INACTIVE;
673
674
675   /* Set flatbed x,y extents. */
676   ps->platen_min_width = SANE_FIX(pbb->elements.config.platen.minimum_size.width/1000.0*MM_PER_INCH);
677   ps->platen_min_height = SANE_FIX(pbb->elements.config.platen.minimum_size.height/1000.0*MM_PER_INCH);
678   ps->platen_tlxRange.max = SANE_FIX(pbb->elements.config.platen.maximum_size.width/11.811023);
679   ps->platen_brxRange.max = ps->platen_tlxRange.max;
680   ps->platen_tlyRange.max = SANE_FIX(pbb->elements.config.platen.maximum_size.height/11.811023);
681   ps->platen_bryRange.max = ps->platen_tlyRange.max;
682
683   /* Set adf/duplex x,y extents. */
684   ps->adf_min_width = SANE_FIX(pbb->elements.config.adf.minimum_size.width/1000.0*MM_PER_INCH);
685   ps->adf_min_height = SANE_FIX(pbb->elements.config.adf.minimum_size.height/1000.0*MM_PER_INCH);
686   ps->adf_tlxRange.max = SANE_FIX(pbb->elements.config.adf.maximum_size.width/11.811023);
687   ps->adf_brxRange.max = ps->adf_tlxRange.max;
688   ps->adf_tlyRange.max = SANE_FIX(pbb->elements.config.adf.maximum_size.height/11.811023);
689   ps->adf_bryRange.max = ps->adf_tlyRange.max;
690
691   i = pbb->elements.config.platen.platen_resolution_list[0] + 1;
692   while(i--)
693   {
694   _DBG("bb_open platen_resolution_list = %d\n",  pbb->elements.config.platen.platen_resolution_list[i]);
695     ps->platen_resolutionList[i] = pbb->elements.config.platen.platen_resolution_list[i];
696     ps->resolutionList[i] = pbb->elements.config.platen.platen_resolution_list[i];
697   }
698
699   i = pbb->elements.config.adf.adf_resolution_list[0] + 1;
700   while(i--) ps->adf_resolutionList[i] = pbb->elements.config.adf.adf_resolution_list[i]; 
701
702   stat = 0;
703
704 bugout:
705   return stat;
706 } /* bb_open */
707
708 int bb_close(struct ledm_session *ps)
709 {
710   _DBG("bb_close()\n");
711   free(ps->bb_session);
712   ps->bb_session = NULL;
713   return 0;
714
715
716 /* Set scan parameters. If scan has started, use actual known parameters otherwise estimate. */
717 int bb_get_parameters(struct ledm_session *ps, SANE_Parameters *pp, int option)
718 {
719   struct bb_ledm_session *pbb = ps->bb_session;
720   pp->last_frame = SANE_TRUE;
721   int factor;
722
723   _DBG("bb_get_parameters(option=%d)\n", option);
724
725   switch(ps->currentScanMode)
726   {
727     case CE_K1:
728       pp->format = SANE_FRAME_GRAY;     /* lineart (GRAY8 converted to MONO by IP) */
729       pp->depth = 1;
730       factor = 1;
731       break;
732     case CE_GRAY8:
733       pp->format = SANE_FRAME_GRAY;     /* grayscale */
734       pp->depth = 8;
735       factor = 1;
736       break;
737     case CE_COLOR8:
738     default:
739       pp->format = SANE_FRAME_RGB;      /* color */
740       pp->depth = 8;
741       factor = 3;
742       break;
743   }
744
745   switch (option)
746   {
747     case SPO_STARTED:  /* called by xsane */
748       if (ps->currentCompression == SF_RAW && ps->currentScanMode != CE_GRAY8)
749       {
750          /* Set scan parameters based on scan job response values */
751         //pp->lines = pbb->job.lines;
752         pp->lines = (int)(SANE_UNFIX(ps->effectiveBry - ps->effectiveTly)/MM_PER_INCH*ps->currentResolution);
753         pp->pixels_per_line = pbb->job.pixels_per_line;
754         pp->bytes_per_line = pbb->job.bytes_per_line;
755       }
756       else  /* Must be SF_JFIF or ScanMode==CE_BLACK_AND_WHITE1. */
757       {
758         /* Set scan parameters based on IP. Note for Linart, use IP for hpraw and jpeg. */
759         //pp->lines = ps->image_traits.lNumRows;
760         pp->lines = (int)(SANE_UNFIX(ps->effectiveBry - ps->effectiveTly)/MM_PER_INCH*ps->currentResolution);
761         pp->pixels_per_line = ps->image_traits.iPixelsPerRow;
762         pp->bytes_per_line = BYTES_PER_LINE(pp->pixels_per_line, pp->depth * factor);
763       }
764       break;
765     case SPO_STARTED_JR: /* called by sane_start */
766       /* Set scan parameters based on scan job response values */
767       pp->lines = pbb->job.lines;
768       pp->pixels_per_line = pbb->job.pixels_per_line;
769       pp->bytes_per_line = pbb->job.bytes_per_line;
770       break;
771     case SPO_BEST_GUESS:  /* called by xsane & sane_start */
772       /* Set scan parameters based on best guess. */
773       pp->lines = (int)round(SANE_UNFIX(ps->effectiveBry - ps->effectiveTly)/MM_PER_INCH*ps->currentResolution);
774       pp->pixels_per_line = (int)round(SANE_UNFIX(ps->effectiveBrx -ps->effectiveTlx)/MM_PER_INCH*ps->currentResolution);
775       pp->bytes_per_line = BYTES_PER_LINE(pp->pixels_per_line, pp->depth * factor);
776       break;
777     default:
778       break;
779   }
780 return 0;
781 }
782
783 int bb_is_paper_in_adf(struct ledm_session *ps) /* 0 = no paper in adf, 1 = paper in adf, -1 = error */
784 {
785   char buf[1024];
786   int bytes_read;
787   struct bb_ledm_session *pbb = ps->bb_session;
788
789   if(http_open(ps->dd, HPMUD_S_LEDM_SCAN, &pbb->http_handle) != HTTP_R_OK)
790   {
791   }
792   if (http_write(pbb->http_handle, GET_SCANNER_STATUS, sizeof(GET_SCANNER_STATUS)-1, 10) != HTTP_R_OK)
793   {
794     //goto bugout;
795   }
796   read_http_payload(ps, buf, sizeof(buf), EXCEPTION_TIMEOUT, &bytes_read);
797
798   http_close(pbb->http_handle);   /* error, close http connection */
799   pbb->http_handle = 0;
800   _DBG("bb_is_paper_in_adf .job_id=%d buf=%s\n", ps->job_id, buf);
801   if(strstr(buf, ADF_LOADED)) return 1;
802   if(strstr(buf, ADF_EMPTY) && strstr(buf, SCANNER_BUSY_WITH_SCAN_JOB)) return 2;
803   else return 0;
804 }
805
806
807 SANE_Status bb_start_scan(struct ledm_session *ps)
808 {
809   char buf[4096] = {0};
810   char buf1[1024]={0};
811   int len, bytes_read;
812   int i, timeout = 10 ;
813   char szPage_ID[5] = {0};
814   char szJob_ID[5] = {0};
815   SANE_Status stat = SANE_STATUS_IO_ERROR;
816   struct bb_ledm_session *pbb = ps->bb_session;
817   
818   ps->user_cancel = 0;
819   _DBG("bb_start_scan() entering...job_id=%d\n", ps->job_id);
820   if (ps->job_id == 0)
821   {
822     if(http_open(ps->dd, HPMUD_S_LEDM_SCAN, &pbb->http_handle) != HTTP_R_OK)
823     {
824        // goto bugout;
825     }
826
827     if (http_write(pbb->http_handle, GET_SCANNER_STATUS, sizeof(GET_SCANNER_STATUS)-1, timeout) != HTTP_R_OK)
828     {
829        //goto bugout;
830     }
831  
832     read_http_payload(ps, buf, sizeof(buf), timeout, &bytes_read);
833      
834     if(!strstr(buf, SCANNER_IDLE)) 
835     {
836         stat = SANE_STATUS_DEVICE_BUSY;
837         goto bugout;
838     }
839
840     http_close(pbb->http_handle);
841         pbb->http_handle = 0;
842
843     if(http_open(ps->dd, HPMUD_S_LEDM_SCAN, &pbb->http_handle) != HTTP_R_OK)
844     {
845     }
846
847     len = snprintf(buf, sizeof(buf), CREATE_SCAN_JOB_REQUEST,
848                 ps->currentResolution,//<XResolution>
849                 ps->currentResolution,//<YResolution>
850         (int) (ps->currentTlx / 5548.7133),//<XStart>
851         (int) ((ps->currentBrx / 5548.7133) - (ps->currentTlx / 5548.7133)),//<Width>
852         (int) (ps->currentTly / 5548.7133),//<YStart>
853         (int) ((ps->currentBry / 5548.7133) - (ps->currentTly / 5548.7133)),//<Height>
854         "Jpeg",//<Format>
855         (! strcmp(ce_element[ps->currentScanMode], "Color8")) ? "Color" : (! strcmp(ce_element[ps->currentScanMode], "Gray8")) ? "Gray" : "Gray",//<ColorSpace>
856         ((! strcmp(ce_element[ps->currentScanMode], "Color8")) || (! strcmp(ce_element[ps->currentScanMode], "Gray8"))) ? 8: 8,//<BitDepth>
857         ps->currentInputSource == IS_PLATEN ? is_element[1] : is_element[2],//<InputSource>
858         ps->currentInputSource == IS_PLATEN ? is_element[1] : is_element[2],//<InputSourceType>
859         ps->currentInputSource != IS_ADF_DUPLEX ? "" : "<AdfOptions><AdfOption>Duplex</AdfOption></AdfOptions>");
860
861     len = len + strlen(ZERO_FOOTER);
862
863     len = snprintf(buf1, sizeof(buf1), POST_HEADER, len);
864     if (http_write(pbb->http_handle, buf1, strlen(buf1), timeout) != HTTP_R_OK)
865     {
866         //goto bugout;
867     }
868     
869     if (http_write(pbb->http_handle, buf, strlen(buf), 1) != HTTP_R_OK)
870     {
871         //goto bugout;
872     }
873
874     /* Write zero footer. */
875     if (http_write(pbb->http_handle, ZERO_FOOTER, sizeof(ZERO_FOOTER)-1, 1) != HTTP_R_OK)
876     {
877         //goto bugout;
878     }
879     memset(buf, 0, sizeof(buf));
880     /* Read response. */
881     if (read_http_payload(ps, buf, sizeof(buf), timeout, &bytes_read))
882        goto bugout;
883
884     http_close(pbb->http_handle);
885     pbb->http_handle = 0;
886
887     char joblist[64];
888     char* jl=strstr(buf, "Location:");
889     if (!jl) goto bugout;
890     jl=jl+10;
891         
892     int i=0;
893     while(*jl != '\r')
894     { 
895       joblist[i]=*jl; 
896       jl=jl+1; i++;
897     } 
898     joblist[i]='\0';
899
900     strcpy(ps->url, joblist);
901     char *c=ps->url;
902     c=strstr(c, "JobList"); 
903     if (c)
904     {
905       c=c+8;
906       int job_id=strtol(c, NULL, 10);
907       itoa(job_id, szJob_ID,10);
908       itoa(1, szPage_ID,10);
909       ps->page_id = 1;
910       ps->job_id = job_id;
911     }
912   }
913   else
914   {
915     if (ps->currentInputSource == IS_PLATEN)
916     {
917        stat = SANE_STATUS_INVAL;
918        goto bugout;
919     }
920
921     ps->page_id++;
922     itoa(ps->job_id,szJob_ID,10);
923     itoa(ps->page_id, szPage_ID,10);
924   }
925   _DBG("bb_start_scan() url=%s page_id=%d\n", ps->url, ps->page_id);
926   
927   memset(buf, 0, sizeof(buf)-1);
928
929   if(http_open(ps->dd, HPMUD_S_LEDM_SCAN, &pbb->http_handle) != HTTP_R_OK)
930   {
931   }
932   while(strstr(buf, READY_TO_UPLOAD) == NULL)
933   {
934      _DBG("bb_start_scan() ENTERING....buf=%s\n", buf);
935      len = snprintf(buf, sizeof(buf), GET_SCAN_JOB_URL, ps->url);
936
937      if (http_write(pbb->http_handle, buf, strlen(buf), 1) != HTTP_R_OK)
938      {
939         //goto bugout;
940         break ;
941      }
942      if (read_http_payload (ps, buf, sizeof(buf), 5, &len) != HTTP_R_OK)
943      {
944         //goto bugout
945         _DBG("bb_start_scan() read_http_payload FAILED len=%d buf=%s\n", len, buf);
946         break;
947      }
948      if (strstr(buf,JOBSTATE_CANCELED) || strstr(buf, CANCELED_BY_DEVICE) || strstr(buf, CANCELED_BY_CLIENT))
949      {
950         //_DBG("bb_start_scan() SCAN CANCELLED\n");
951         stat = SANE_STATUS_GOOD;
952         ps->user_cancel = 1;
953         goto bugout;
954      }
955      if (strstr(buf, JOBSTATE_COMPLETED))
956      {
957         stat = SANE_STATUS_GOOD;
958         goto bugout;
959      }
960      usleep(500000);//0.5 sec delay
961   }//end while()
962
963   char *c = strstr(buf, "<BinaryURL>");
964   _DBG("bb_start_scan() BinaryURL=%s \n", c);
965   
966   if (!c) goto bugout;
967   c +=11;
968   char BinaryURL[30];
969   i = 0;
970   while(*c != '<')
971   {
972      BinaryURL[i++] = *c ;
973      c++;
974   }
975   BinaryURL[i] = '\0';
976   //_DBG("bb_start_scan() BinaryURL=%s\n", BinaryURL);
977   len = snprintf(buf, sizeof(buf), GET_SCAN_JOB_URL, BinaryURL);
978  
979   if (http_write(pbb->http_handle, buf, strlen(buf), timeout) != HTTP_R_OK)
980   {
981         //goto bugout;
982   }
983  
984   if (http_read_header(pbb->http_handle, buf, sizeof(buf), timeout, &len) != HTTP_R_OK)
985   {
986          //goto bugout;
987   }
988
989   if(strstr(buf, "HTTP/1.1 400 Bad Request")) http_read_header(pbb->http_handle, buf, sizeof(buf), timeout, &len);
990   
991   stat = SANE_STATUS_GOOD;
992 bugout:
993   if (stat && pbb->http_handle)
994   {
995     http_close(pbb->http_handle);   /* error, close http connection */
996     pbb->http_handle = 0;
997   }
998   return stat;
999 } /* bb_start_scan */
1000
1001 int get_size(struct ledm_session* ps)
1002 {
1003   struct bb_ledm_session *pbb = ps->bb_session;
1004   char buffer[7];
1005   int i=0, tmo=50, len;
1006
1007   if(ps->currentResolution >= 1200) tmo *= 5;
1008   
1009   while(1)
1010   {
1011     if(http_read_size(pbb->http_handle, buffer+i, 1, tmo, &len) == 2) return 0;
1012     if( i && *(buffer+i) == '\n' && *(buffer+i-1) == '\r') break;
1013     i++;
1014   }
1015   *(buffer+i+1)='\0';
1016   return strtol(buffer, NULL, 16);
1017 }
1018
1019 int bb_get_image_data(struct ledm_session* ps, int maxLength) 
1020 {
1021   struct bb_ledm_session *pbb = ps->bb_session;
1022   int size=0, stat=1;
1023   char buf_size[2];
1024   int len=0, tmo=50;
1025   _DBG("bb_get_image_data http_handle=%p cnt=%d pbb=%p\n", pbb->http_handle, ps->cnt, pbb);
1026   if(ps->currentResolution >= 1200) tmo *= 5;
1027  
1028   if (ps->cnt == 0)
1029   {
1030     size = get_size(ps);
1031     if(size == 0) 
1032     { 
1033       http_read_size(pbb->http_handle, buf_size, 2, tmo, &len);
1034       http_read_size(pbb->http_handle, buf_size, -1, tmo, &len);
1035       return 0; 
1036     }
1037     http_read_size(pbb->http_handle, ps->buf, size, tmo, &len);
1038     ps->cnt += len;
1039     http_read_size(pbb->http_handle, buf_size, 2, tmo, &len);
1040   }
1041
1042   return stat=0;
1043 }
1044
1045 int bb_end_page(struct ledm_session *ps, int io_error)
1046 {
1047    struct bb_ledm_session *pbb = ps->bb_session;
1048
1049   _DBG("bb_end_page(error=%d)\n", io_error);
1050
1051    if (pbb->http_handle)
1052    {
1053       http_close(pbb->http_handle);
1054       pbb->http_handle = 0;
1055    }
1056    return 0;
1057 }
1058
1059 int bb_end_scan(struct ledm_session* ps, int io_error)
1060 {
1061   struct bb_ledm_session *pbb = ps->bb_session;
1062
1063   _DBG("bb_end_scan(error=%d)\n", io_error);
1064
1065   if (pbb->http_handle)
1066   {
1067     http_close(pbb->http_handle);
1068     pbb->http_handle = 0;
1069   }
1070   cancel_job(ps);
1071   memset(ps->url, 0, sizeof(ps->url));
1072   ps->job_id = 0;
1073   ps->page_id = 0;
1074   return 0;
1075 }