1 /************************************************************************************\
2
3 hpaio.c - HP SANE backend for multi-function peripherals (libsane-hpaio)
4
5 (c) 2001-2008 Copyright HP Development Company, LP
6
7 Permission is hereby granted, free of charge, to any person obtaining a copy
8 of this software and associated documentation files (the "Software"), to deal
9 in the Software without restriction, including without limitation the rights
10 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
11 of the Software, and to permit persons to whom the Software is furnished to do
12 so, subject to the following conditions:
13
14 The above copyright notice and this permission notice shall be included in all
15 copies or substantial portions of the Software.
16
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19 FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
24 Contributing Authors: David Paschal, Don Welch, David Suffield, Narla Naga Samrat Chowdary,
25 Yashwant Sahu, Sarbeswar Meher
26
27 \************************************************************************************/
28
29
30 #ifndef _GNU_SOURCE
31 #define _GNU_SOURCE
32 #endif
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <cups/cups.h>
38 #include "hpmud.h"
39 #include "hp_ipp.h"
40 #include "soap.h"
41 #include "soapht.h"
42 #include "marvell.h"
43 #include "hpaio.h"
44 #include "ledm.h"
45 #include "sclpml.h"
46 #include "escl.h"
47 #include "io.h"
48 #include "orblitei.h"
49
50
51 #define DEBUG_DECLARE_ONLY
52 #include "sanei_debug.h"
53
54 static SANE_Device **DeviceList = NULL;
55
AddDeviceList(char * uri,char * model,SANE_Device *** pd)56 static int AddDeviceList(char *uri, char *model, SANE_Device ***pd)
57 {
58 int i = 0, uri_length = 0;
59
60 if (*pd == NULL)
61 {
62 /* Allocate array of pointers. */
63 *pd = malloc(sizeof(SANE_Device *) * MAX_DEVICE);
64 memset(*pd, 0, sizeof(SANE_Device *) * MAX_DEVICE);
65 }
66
67 uri += 3; /* Skip "hp:" */
68 uri_length = strlen(uri);
69 if(strstr(uri, "&queue=false"))
70 uri_length -= 12; // Last 12 bytes of URI i.e "&queue=false"
71
72 /* Find empty slot in array of pointers. */
73 for (i=0; i < MAX_DEVICE; i++)
74 {
75 if ((*pd)[i] == NULL)
76 {
77 /* Allocate Sane_Device and members. */
78 (*pd)[i] = malloc(sizeof(SANE_Device));
79 (*pd)[i]->name = malloc(strlen(uri)+1);
80 strcpy((char *)(*pd)[i]->name, uri);
81 (*pd)[i]->model = strdup(model);
82 (*pd)[i]->vendor = "Hewlett-Packard";
83 (*pd)[i]->type = "all-in-one";
84 break;
85 }
86
87 //Check for Duplicate URI. If URI is added already then don't add it again.
88 if( strncasecmp((*pd)[i]->name, uri, uri_length) == 0 )
89 break;
90 }
91
92 return 0;
93 }
94
ResetDeviceList(SANE_Device *** pd)95 static int ResetDeviceList(SANE_Device ***pd)
96 {
97 int i;
98
99 if (*pd)
100 {
101 for (i=0; (*pd)[i] && i<MAX_DEVICE; i++)
102 {
103 if ((*pd)[i]->name)
104 free((void *)(*pd)[i]->name);
105 if ((*pd)[i]->model)
106 free((void *)(*pd)[i]->model);
107 free((*pd)[i]);
108 }
109 free(*pd);
110 *pd = NULL;
111 }
112
113 return 0;
114 }
115
116 /* Parse URI record from buf. Assumes one record per line. All returned strings are zero terminated. */
GetUriLine(char * buf,char * uri,char ** tail)117 static int GetUriLine(char *buf, char *uri, char **tail)
118 {
119 int i=0, j;
120 int maxBuf = HPMUD_LINE_SIZE*64;
121
122 uri[0] = 0;
123
124 if (strncasecmp(&buf[i], "direct ", 7) == 0)
125 {
126 i = 7;
127 j = 0;
128 for (; buf[i] == ' ' && i < maxBuf; i++); /* eat white space before string */
129 while ((buf[i] != ' ') && (i < maxBuf) && (j < HPMUD_LINE_SIZE))
130 uri[j++] = buf[i++];
131 uri[j] = 0;
132
133 for (; buf[i] != '\n' && i < maxBuf; i++); /* eat rest of line */
134 }
135 else
136 {
137 for (; buf[i] != '\n' && i < maxBuf; i++); /* eat line */
138 }
139
140 i++; /* bump past '\n' */
141
142 if (tail != NULL)
143 *tail = buf + i; /* tail points to next line */
144
145 return i;
146 }
147
AddCupsList(char * uri,char *** printer)148 static int AddCupsList(char *uri, char ***printer)
149 {
150 int i, stat=1;
151
152 /* Look for hp network URIs only. */
153 if (strncasecmp(uri, "hp:/net/", 8) !=0)
154 goto bugout;
155
156 if (*printer == NULL)
157 {
158 /* Allocate array of string pointers. */
159 *printer = malloc(sizeof(char *) * MAX_DEVICE);
160 memset(*printer, 0, sizeof(char *) * MAX_DEVICE);
161 }
162
163 /* Ignor duplicates (ie: printer queues using the same device). */
164 for (i=0; (*printer)[i] != NULL && i<MAX_DEVICE; i++)
165 {
166 if (strcmp((*printer)[i], uri) == 0)
167 goto bugout;
168 }
169
170 /* Find empty slot in array of pointers. */
171 for (i=0; i<MAX_DEVICE; i++)
172 {
173 if ((*printer)[i] == NULL)
174 {
175 (*printer)[i] = strdup(uri);
176 break;
177 }
178 }
179
180 stat = 0;
181
182 bugout:
183
184 return stat;
185 }
186
187
GetCupsPrinters(char *** printer)188 static int GetCupsPrinters(char ***printer)
189 {
190 http_t *http=NULL; /* HTTP object */
191 ipp_t *request=NULL; /* IPP request object */
192 ipp_t *response=NULL; /* IPP response object */
193 ipp_attribute_t *attr; /* Current IPP attribute */
194 int cnt=0;
195
196 /* Connect to the HTTP server */
197 if ((http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption())) == NULL)
198 goto bugout;
199
200 /* Assemble the IPP request */
201 request = ippNew();
202
203 ippSetOperation( request, CUPS_GET_PRINTERS );
204 ippSetRequestId( request, 1 );
205
206 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, "attributes-charset", NULL, "utf-8");
207 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, "attributes-natural-language", NULL, "en");
208 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", NULL, "device-uri");
209
210 /* Send the request and get a response. */
211 if ((response = cupsDoRequest(http, request, "/")) == NULL)
212 goto bugout;
213
214 for (attr = ippFirstAttribute ( response ); attr != NULL; attr = ippNextAttribute( response ))
215 {
216 /* Skip leading attributes until we hit a printer. */
217 while (attr != NULL && ippGetGroupTag( attr ) != IPP_TAG_PRINTER)
218 attr = ippNextAttribute( response );
219
220 if (attr == NULL)
221 break;
222
223 while (attr != NULL && ippGetGroupTag( attr ) == IPP_TAG_PRINTER)
224 {
225 if (strcmp(ippGetName( attr ), "device-uri") == 0 && ippGetValueTag( attr ) == IPP_TAG_URI && AddCupsList(ippGetString( attr, 0, NULL ), printer) == 0)
226 cnt++;
227 attr = ippNextAttribute( response );
228 }
229
230 if (attr == NULL)
231 break;
232 }
233
234 ippDelete(response);
235
236 bugout:
237 return cnt;
238 }
239
AddDevice(char * uri)240 static int AddDevice(char *uri)
241 {
242 struct hpmud_model_attributes ma;
243 char model[HPMUD_LINE_SIZE];
244 char new_uri[256];
245 int len = 0, i = 0, j = 0;
246 int scan_type;
247 int device_added = 0;
248
249 hpmud_query_model(uri, &ma);
250 if (ma.scantype > 0)
251 {
252 hpmud_get_uri_model(uri, model, sizeof(model));
253 AddDeviceList(uri, model, &DeviceList);
254 device_added = 1;
255 }
256 else
257 {
258 // This is added to make the uri hp:/net/hp_model_name?ip-xxx.xxx.xxx.xxx&queue=false
259 // For some of the devices the scan MDL recevied would be model_name instead of hp_model_name
260 len = strlen(uri);
261 strncpy(new_uri, uri, 9);
262 new_uri[8] = 'h';
263 new_uri[9] = 'p';
264 new_uri[10] = '_';
265 for (i = 11,j = 8; j<=len; ++i, ++j)
266 new_uri[i] = uri[j];
267
268 hpmud_query_model(new_uri, &ma);
269 DBG(6,"scantype=%d %s\n", ma.scantype, new_uri);
270
271 if(ma.scantype>0)
272 {
273 hpmud_get_uri_model(new_uri, model, sizeof(model));
274 AddDeviceList(new_uri, model, &DeviceList);
275 device_added = 1;
276 }
277 else
278 {
279 DBG(6,"unsupported scantype=%d %s\n", ma.scantype, new_uri);
280 }
281 }
282
283 return device_added;
284 }
285
DevDiscovery(int localOnly)286 static int DevDiscovery(int localOnly)
287 {
288 char message[HPMUD_LINE_SIZE*64];
289 char uri[HPMUD_LINE_SIZE];
290 char *tail = message;
291 int i, scan_type, cnt=0, total=0, bytes_read;
292 char **cups_printer=NULL; /* list of printers */
293 char* token = NULL;
294 enum HPMUD_RESULT stat;
295
296 stat = hpmud_probe_devices(HPMUD_BUS_ALL, message, sizeof(message), &cnt, &bytes_read);
297 if (stat != HPMUD_R_OK)
298 goto bugout;
299
300 /* Look for local all-in-one scan devices (defined by hpmud). */
301 for (i=0; i<cnt; i++)
302 {
303 GetUriLine(tail, uri, &tail);
304 total += AddDevice(uri);
305 }
306 memset(message, 0, sizeof(message));
307 /* Look for Network Scan devices if localonly flag if FALSE. */
308 if (!localOnly)
309 {
310 /* Look for all-in-one scan devices for which print queue created */
311 cnt = GetCupsPrinters(&cups_printer);
312 for (i=0; i<cnt; i++)
313 {
314 total += AddDevice(cups_printer[i]);
315 free(cups_printer[i]);
316 }
317 if (cups_printer)
318 free(cups_printer);
319 #ifdef HAVE_LIBNETSNMP
320 /* Discover NW scanners using Bonjour*/
321 bytes_read = mdns_probe_nw_scanners(message, sizeof(message), &cnt);
322 token = strtok(message, ";");
323 while (token)
324 {
325 total += AddDevice(token);
326 token = strtok(NULL, ";");
327 }
328 #endif
329 if(!total)
330 {
331 SendScanEvent("hpaio:/net/HP_Scan_Devices?ip=1.1.1.1", EVENT_ERROR_NO_PROBED_DEVICES_FOUND);
332 }
333 }
334
335 bugout:
336 return total;
337 }
338
339 /******************************************************* SANE API *******************************************************/
340
sane_hpaio_init(SANE_Int * pVersionCode,SANE_Auth_Callback authorize)341 extern SANE_Status sane_hpaio_init(SANE_Int * pVersionCode, SANE_Auth_Callback authorize)
342 {
343 int stat;
344
345 DBG_INIT();
346 InitDbus();
347
348 DBG(8, "sane_hpaio_init(): %s %d\n", __FILE__, __LINE__);
349
350 if( pVersionCode )
351 {
352 *pVersionCode = SANE_VERSION_CODE( 1, 0, 0 );
353 }
354
355
356 stat = orblite_init(pVersionCode, authorize);
357
358 return stat;
359 } /* sane_hpaio_init() */
360
sane_hpaio_exit(void)361 extern void sane_hpaio_exit(void)
362 {
363 DBG(8, "sane_hpaio_exit(): %s %d\n", __FILE__, __LINE__);
364 ResetDeviceList(&DeviceList);
365 }
366
sane_hpaio_get_devices(const SANE_Device *** deviceList,SANE_Bool localOnly)367 extern SANE_Status sane_hpaio_get_devices(const SANE_Device ***deviceList, SANE_Bool localOnly)
368 {
369 DBG(8, "sane_hpaio_get_devices(local=%d): %s %d\n", localOnly, __FILE__, __LINE__);
370 ResetDeviceList(&DeviceList);
371 DevDiscovery(localOnly);
372 *deviceList = (const SANE_Device **)DeviceList;
373 SANE_Device*** devList;
374 orblite_get_devices(devList, localOnly);
375
376 return SANE_STATUS_GOOD;
377 }
378
sane_hpaio_open(SANE_String_Const devicename,SANE_Handle * pHandle)379 extern SANE_Status sane_hpaio_open(SANE_String_Const devicename, SANE_Handle * pHandle)
380 {
381 struct hpmud_model_attributes ma;
382 char devname[256];
383
384 /* Get device attributes and determine what backend to call. */
385 snprintf(devname, sizeof(devname)-1, "hp:%s", devicename); /* prepend "hp:" */
386 hpmud_query_model(devname, &ma);
387 DBG(8, "sane_hpaio_open(%s): %s %d scan_type=%d scansrc=%d\n", devicename, __FILE__, __LINE__, ma.scantype, ma.scansrc);
388
389 if ((ma.scantype == HPMUD_SCANTYPE_MARVELL) || (ma.scantype == HPMUD_SCANTYPE_MARVELL2))
390 return marvell_open(devicename, pHandle);
391 if (ma.scantype == HPMUD_SCANTYPE_SOAP)
392 return soap_open(devicename, pHandle);
393 if (ma.scantype == HPMUD_SCANTYPE_SOAPHT)
394 return soapht_open(devicename, pHandle);
395 if (ma.scantype == HPMUD_SCANTYPE_LEDM)
396 return ledm_open(devicename, pHandle);
397 if ((ma.scantype == HPMUD_SCANTYPE_SCL) || (ma.scantype == HPMUD_SCANTYPE_SCL_DUPLEX) ||(ma.scantype == HPMUD_SCANTYPE_PML))
398 return sclpml_open(devicename, pHandle);
399 if (ma.scantype == HPMUD_SCANTYPE_ESCL)
400 return escl_open(devicename, pHandle);
401 if (ma.scantype == HPMUD_SCANTYPE_ORBLITE)
402 return orblite_open(devicename, pHandle);
403 else
404 return SANE_STATUS_UNSUPPORTED;
405 } /* sane_hpaio_open() */
406
sane_hpaio_close(SANE_Handle handle)407 extern void sane_hpaio_close(SANE_Handle handle)
408 {
409 if (strcmp(*((char **)handle), "MARVELL") == 0)
410 return marvell_close(handle);
411 if (strcmp(*((char **)handle), "SOAP") == 0)
412 return soap_close(handle);
413 if (strcmp(*((char **)handle), "SOAPHT") == 0)
414 return soapht_close(handle);
415 if (strcmp(*((char **)handle), "LEDM") == 0)
416 return ledm_close(handle);
417 if (strcmp(*((char **)handle), "SCL-PML") == 0)
418 return sclpml_close(handle);
419 if (strcmp(*((char **)handle), "ESCL") == 0)
420 return escl_close(handle);
421 if (strcmp(*((char **)handle), "ORBLITE") == 0)
422 orblite_close(handle);
423 } /* sane_hpaio_close() */
424
sane_hpaio_get_option_descriptor(SANE_Handle handle,SANE_Int option)425 extern const SANE_Option_Descriptor * sane_hpaio_get_option_descriptor(SANE_Handle handle, SANE_Int option)
426 {
427 if (strcmp(*((char **)handle), "MARVELL") == 0)
428 return marvell_get_option_descriptor(handle, option);
429 if (strcmp(*((char **)handle), "SOAP") == 0)
430 return soap_get_option_descriptor(handle, option);
431 if (strcmp(*((char **)handle), "SOAPHT") == 0)
432 return soapht_get_option_descriptor(handle, option);
433 if (strcmp(*((char **)handle), "LEDM") == 0)
434 return ledm_get_option_descriptor(handle, option);
435 if (strcmp(*((char **)handle), "SCL-PML") == 0)
436 return sclpml_get_option_descriptor(handle, option);
437 if (strcmp(*((char **)handle), "ESCL") == 0)
438 return escl_get_option_descriptor(handle, option);
439 if (strcmp(*((char **)handle), "ORBLITE") == 0)
440 {
441 struct t_SANE* h = (struct t_SANE*)handle;
442 if (option < optCount || option < optLast)
443 {
444 DBG(8, "1. sane_hpaio_get_option_descriptor optCount = %d, option = %d, optLast = %d \n",(int)optCount,option,(int)optLast );
445 return &h->Options[option];
446 }
447 else
448 {
449 DBG(8, "2. sane_hpaio_get_option_descriptor optCount = %d, option = %d, optLast = %d \n",(int)optCount,option,(int)optLast );
450 return NULL;
451 }
452 }
453 else
454 return NULL;
455 } /* sane_hpaio_get_option_descriptor() */
456
sane_hpaio_control_option(SANE_Handle handle,SANE_Int option,SANE_Action action,void * pValue,SANE_Int * pInfo)457 extern SANE_Status sane_hpaio_control_option(SANE_Handle handle, SANE_Int option, SANE_Action action, void * pValue, SANE_Int * pInfo )
458 {
459 if (strcmp(*((char **)handle), "MARVELL") == 0)
460 return marvell_control_option(handle, option, action, pValue, pInfo);
461 if (strcmp(*((char **)handle), "SOAP") == 0)
462 return soap_control_option(handle, option, action, pValue, pInfo);
463 if (strcmp(*((char **)handle), "SOAPHT") == 0)
464 return soapht_control_option(handle, option, action, pValue, pInfo);
465 if (strcmp(*((char **)handle), "LEDM") == 0)
466 return ledm_control_option(handle, option, action, pValue, pInfo);
467 if (strcmp(*((char **)handle), "SCL-PML") == 0)
468 return sclpml_control_option(handle, option, action, pValue, pInfo);
469 if (strcmp(*((char **)handle), "ESCL") == 0)
470 return escl_control_option(handle, option, action, pValue, pInfo);
471 if (strcmp(*((char **)handle), "ORBLITE") == 0)
472 return orblite_control_option(handle, option, action, pValue, pInfo);
473 else
474 return SANE_STATUS_UNSUPPORTED;
475 } /* sane_hpaio_control_option() */
476
sane_hpaio_get_parameters(SANE_Handle handle,SANE_Parameters * pParams)477 extern SANE_Status sane_hpaio_get_parameters(SANE_Handle handle, SANE_Parameters *pParams)
478 {
479 if (strcmp(*((char **)handle), "MARVELL") == 0)
480 return marvell_get_parameters(handle, pParams);
481 if (strcmp(*((char **)handle), "SOAP") == 0)
482 return soap_get_parameters(handle, pParams);
483 if (strcmp(*((char **)handle), "SOAPHT") == 0)
484 return soapht_get_parameters(handle, pParams);
485 if (strcmp(*((char **)handle), "LEDM") == 0)
486 return ledm_get_parameters(handle, pParams);
487 if (strcmp(*((char **)handle), "SCL-PML") == 0)
488 return sclpml_get_parameters(handle, pParams);
489 if (strcmp(*((char **)handle), "ESCL") == 0)
490 return escl_get_parameters(handle, pParams);
491 if (strcmp(*((char **)handle), "ORBLITE") == 0)
492 return orblite_get_parameters(handle, pParams);
493 else
494 return SANE_STATUS_UNSUPPORTED;
495 } /* sane_hpaio_get_parameters() */
496
sane_hpaio_start(SANE_Handle handle)497 extern SANE_Status sane_hpaio_start(SANE_Handle handle)
498 {
499 if (strcmp(*((char **)handle), "MARVELL") == 0)
500 return marvell_start(handle);
501 if (strcmp(*((char **)handle), "SOAP") == 0)
502 return soap_start(handle);
503 if (strcmp(*((char **)handle), "SOAPHT") == 0)
504 return soapht_start(handle);
505 if (strcmp(*((char **)handle), "LEDM") == 0)
506 return ledm_start(handle);
507 if (strcmp(*((char **)handle), "SCL-PML") == 0)
508 return sclpml_start(handle);
509 if (strcmp(*((char **)handle), "ESCL") == 0)
510 return escl_start(handle);
511 if (strcmp(*((char **)handle), "ORBLITE") == 0)
512 return orblite_start(handle);
513 else
514 return SANE_STATUS_UNSUPPORTED;
515 } /* sane_hpaio_start() */
516
517
sane_hpaio_read(SANE_Handle handle,SANE_Byte * data,SANE_Int maxLength,SANE_Int * pLength)518 extern SANE_Status sane_hpaio_read(SANE_Handle handle, SANE_Byte *data, SANE_Int maxLength, SANE_Int *pLength)
519 {
520 if (strcmp(*((char **)handle), "LEDM") == 0)
521 return ledm_read(handle, data, maxLength, pLength);
522 if (strcmp(*((char **)handle), "MARVELL") == 0)
523 return marvell_read(handle, data, maxLength, pLength);
524 if (strcmp(*((char **)handle), "SOAP") == 0)
525 return soap_read(handle, data, maxLength, pLength);
526 if (strcmp(*((char **)handle), "SOAPHT") == 0)
527 return soapht_read(handle, data, maxLength, pLength);
528 if (strcmp(*((char **)handle), "SCL-PML") == 0)
529 return sclpml_read(handle, data, maxLength, pLength);
530 if (strcmp(*((char **)handle), "ESCL") == 0)
531 return escl_read(handle, data, maxLength, pLength);
532 if (strcmp(*((char **)handle), "ORBLITE") == 0)
533 return orblite_read(handle, data, maxLength, pLength);
534 else
535 return SANE_STATUS_UNSUPPORTED;
536
537 } /* sane_hpaio_read() */
538
539 /* Note, sane_cancel is called normally not just during IO abort situations. */
sane_hpaio_cancel(SANE_Handle handle)540 extern void sane_hpaio_cancel( SANE_Handle handle )
541 {
542 if (strcmp(*((char **)handle), "MARVELL") == 0)
543 return marvell_cancel(handle);
544 if (strcmp(*((char **)handle), "SOAP") == 0)
545 return soap_cancel(handle);
546 if (strcmp(*((char **)handle), "SOAPHT") == 0)
547 return soapht_cancel(handle);
548 if (strcmp(*((char **)handle), "LEDM") == 0)
549 return ledm_cancel(handle);
550 if (strcmp(*((char **)handle), "SCL-PML") == 0)
551 return sclpml_cancel(handle);
552 if (strcmp(*((char **)handle), "ESCL") == 0)
553 return escl_cancel(handle);
554 if (strcmp(*((char **)handle), "ORBLITE") == 0)
555 orblite_cancel(handle);
556 } /* sane_hpaio_cancel() */
557
sane_hpaio_set_io_mode(SANE_Handle handle,SANE_Bool nonBlocking)558 extern SANE_Status sane_hpaio_set_io_mode(SANE_Handle handle, SANE_Bool nonBlocking)
559 {
560 return SANE_STATUS_UNSUPPORTED;
561 }
562
sane_hpaio_get_select_fd(SANE_Handle handle,SANE_Int * pFd)563 extern SANE_Status sane_hpaio_get_select_fd(SANE_Handle handle, SANE_Int *pFd)
564 {
565 return SANE_STATUS_UNSUPPORTED;
566 }
567
568
569