1 /*
2 * CUPS Backend common code
3 *
4 * Copyright (c) 2007-2019 Solomon Peachy <pizza@shaftnet.org>
5 *
6 * The latest version of this program can be found at:
7 *
8 * http://git.shaftnet.org/cgit/selphy_print.git
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the Free
12 * Software Foundation; either version 2 of the License, or (at your option)
13 * any later version.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 * for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 *
23 * [http://www.gnu.org/licenses/gpl-2.0.html]
24 *
25 * SPDX-License-Identifier: GPL-2.0+
26 *
27 */
28
29 #include "backend_common.h"
30 #include <errno.h>
31
32 #define BACKEND_VERSION "0.94G"
33 #ifndef URI_PREFIX
34 #error "Must Define URI_PREFIX"
35 #endif
36
37 #define URB_XFER_SIZE (64*1024)
38 #define XFER_TIMEOUT 15000
39
40 #define USB_SUBCLASS_PRINTER 0x1
41 #define USB_INTERFACE_PROTOCOL_BIDIR 0x2
42 #define USB_INTERFACE_PROTOCOL_IPP 0x4
43
44 /* Global Variables */
45 int dyesub_debug = 0;
46 int terminate = 0;
47 int fast_return = 0;
48 int extra_vid = -1;
49 int extra_pid = -1;
50 int extra_type = -1;
51 int ncopies = 1;
52 int collate = 0;
53 int test_mode = 0;
54 int old_uri = 0;
55 int quiet = 0;
56
57 static int max_xfer_size = URB_XFER_SIZE;
58 static int xfer_timeout = XFER_TIMEOUT;
59
60 /* Support Functions */
backend_claim_interface(struct libusb_device_handle * dev,int iface,int num_claim_attempts)61 int backend_claim_interface(struct libusb_device_handle *dev, int iface,
62 int num_claim_attempts)
63 {
64 int ret;
65 do {
66 ret = libusb_claim_interface(dev, iface);
67 if (!ret)
68 break;
69 if (ret != LIBUSB_ERROR_BUSY)
70 break;
71 if (--num_claim_attempts == 0)
72 break;
73 sleep(1);
74 } while (1);
75
76 if (ret)
77 ERROR("Failed to claim interface %d (%d)\n", iface, ret);
78
79 return ret;
80 }
81
lookup_printer_type(struct dyesub_backend * backend,uint16_t idVendor,uint16_t idProduct)82 static int lookup_printer_type(struct dyesub_backend *backend, uint16_t idVendor, uint16_t idProduct)
83 {
84 int i;
85 int type = P_UNKNOWN;
86
87 for (i = 0 ; backend->devices[i].vid ; i++) {
88 if (extra_pid != -1 &&
89 extra_vid != -1 &&
90 extra_type != -1) {
91 if (backend->devices[i].type == extra_type &&
92 extra_vid == idVendor &&
93 extra_pid == idProduct) {
94 return extra_type;
95 }
96 }
97 if (idVendor == backend->devices[i].vid &&
98 idProduct == backend->devices[i].pid) {
99 return backend->devices[i].type;
100 }
101 }
102
103 return type;
104 }
105
106 /* Interface **MUST** already be claimed! */
107 #define ID_BUF_SIZE 2048
get_device_id(struct libusb_device_handle * dev,int iface)108 static char *get_device_id(struct libusb_device_handle *dev, int iface)
109 {
110 int length;
111 char *buf = malloc(ID_BUF_SIZE + 1);
112
113 if (!buf) {
114 ERROR("Memory allocation failure (%d bytes)\n", ID_BUF_SIZE+1);
115 return NULL;
116 }
117
118 if (libusb_control_transfer(dev,
119 LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_ENDPOINT_IN |
120 LIBUSB_RECIPIENT_INTERFACE,
121 0, 0,
122 (iface << 8),
123 (unsigned char *)buf, ID_BUF_SIZE, 5000) < 0)
124 {
125 *buf = '\0';
126 goto done;
127 }
128
129 /* length is the first two bytes, MSB first */
130 length = (((unsigned)buf[0] & 255) << 8) |
131 ((unsigned)buf[1] & 255);
132
133 /* Sanity checks */
134 if (length > ID_BUF_SIZE || length < 14)
135 length = (((unsigned)buf[1] & 255) << 8) |
136 ((unsigned)buf[0] & 255);
137
138 if (length > ID_BUF_SIZE)
139 length = ID_BUF_SIZE;
140
141 if (length < 14) {
142 *buf = '\0';
143 goto done;
144 }
145
146 /* IEEE1284 length field includs the header! */
147 length -= 2;
148
149 /* Move, and terminate */
150 memmove(buf, buf + 2, length);
151 buf[length] = '\0';
152
153 done:
154 return buf;
155 }
156
157 /* Used with the IEEE1284 deviceid string parsing */
158 struct deviceid_dict {
159 char *key;
160 char *val;
161 };
162
163 #define MAX_DICT 32
164
parse1284_data(const char * device_id,struct deviceid_dict * dict)165 static int parse1284_data(const char *device_id, struct deviceid_dict* dict)
166 {
167 char *ptr;
168 char key[256];
169 char val[256];
170 int num = 0;
171
172 if (!device_id)
173 return 0;
174
175 //[whitespace]key[whitespace]:[whitespace]value[whitespace];
176 while (*device_id && num < MAX_DICT) {
177 /* Skip leading spaces */
178 if (*device_id == ' ')
179 device_id++;
180 if (!*device_id)
181 break;
182
183 /* Work out key */
184 for (ptr = key; *device_id && *device_id != ':'; device_id++)
185 *ptr++ = *device_id;
186 if (!*device_id)
187 break;
188 while (ptr > key && *(ptr-1) == ' ')
189 ptr--;
190 *ptr = 0;
191 device_id++;
192 if (!*device_id)
193 break;
194
195 /* Next up, value */
196 for (ptr = val; *device_id && *device_id != ';'; device_id++)
197 *ptr++ = *device_id;
198 if (!*device_id)
199 break;
200 while (ptr > val && *(ptr-1) == ' ')
201 ptr--;
202 *ptr = 0;
203 device_id++;
204
205 /* Add it to the dictionary */
206 dict[num].key = strdup(key);
207 dict[num].val = strdup(val);
208 num++;
209
210 if (!*device_id)
211 break;
212 }
213 return num;
214 }
215
dict_find(const char * key,int dlen,struct deviceid_dict * dict)216 static char *dict_find(const char *key, int dlen, struct deviceid_dict* dict)
217 {
218 while(dlen) {
219 if (!strcmp(key, dict->key))
220 return dict->val;
221 dlen--;
222 dict++;
223 }
224 return NULL;
225 }
226
227 /* I/O functions */
read_data(struct libusb_device_handle * dev,uint8_t endp,uint8_t * buf,int buflen,int * readlen)228 int read_data(struct libusb_device_handle *dev, uint8_t endp,
229 uint8_t *buf, int buflen, int *readlen)
230 {
231 int ret;
232
233 /* Clear buffer */
234 memset(buf, 0, buflen);
235
236 ret = libusb_bulk_transfer(dev, endp,
237 buf,
238 buflen,
239 readlen,
240 xfer_timeout);
241
242 if (ret < 0) {
243 ERROR("Failure to receive data from printer (libusb error %d: (%d/%d from 0x%02x))\n", ret, *readlen, buflen, endp);
244 goto done;
245 }
246
247 if (dyesub_debug) {
248 DEBUG("Received %d bytes from printer\n", *readlen);
249 }
250
251 if ((dyesub_debug > 1 && buflen < 4096) ||
252 dyesub_debug > 2) {
253 int i = *readlen;
254
255 DEBUG("<- ");
256 while(i > 0) {
257 if ((*readlen-i) != 0 &&
258 (*readlen-i) % 16 == 0) {
259 DEBUG2("\n");
260 DEBUG(" ");
261 }
262 DEBUG2("%02x ", buf[*readlen-i]);
263 i--;
264 }
265 DEBUG2("\n");
266 }
267
268 done:
269 return ret;
270 }
271
send_data(struct libusb_device_handle * dev,uint8_t endp,const uint8_t * buf,int len)272 int send_data(struct libusb_device_handle *dev, uint8_t endp,
273 const uint8_t *buf, int len)
274 {
275 int num = 0;
276
277 if (dyesub_debug) {
278 DEBUG("Sending %d bytes to printer\n", len);
279 }
280
281 while (len) {
282 int len2 = (len > max_xfer_size) ? max_xfer_size: len;
283 int ret = libusb_bulk_transfer(dev, endp,
284 (uint8_t*) buf, len2,
285 &num, xfer_timeout);
286
287 if ((dyesub_debug > 1 && len < 4096) ||
288 dyesub_debug > 2) {
289 int i = num;
290
291 DEBUG("-> ");
292 while(i > 0) {
293 if ((num-i) != 0 &&
294 (num-i) % 16 == 0) {
295 DEBUG2("\n");
296 DEBUG(" ");
297 }
298 DEBUG2("%02x ", buf[num-i]);
299 i--;
300 }
301 DEBUG2("\n");
302 }
303
304 if (ret < 0) {
305 ERROR("Failure to send data to printer (libusb error %d: (%d/%d to 0x%02x))\n", ret, num, len2, endp);
306 return ret;
307 }
308 len -= num;
309 buf += num;
310 }
311
312 return 0;
313 }
314
315 /* More stuff */
sigterm_handler(int signum)316 static void sigterm_handler(int signum) {
317 UNUSED(signum);
318
319 terminate = 1;
320 INFO("Job Cancelled");
321 }
322
sanitize_string(char * str)323 static char *sanitize_string(char *str) {
324 int len = strlen(str);
325
326 while(len && (str[len-1] <= 0x20)) {
327 str[len-1] = 0;
328 len--;
329 }
330 return str;
331 }
332
333 /*
334
335 These functions are Public Domain code obtained from:
336
337 http://www.geekhideout.com/urlcode.shtml
338
339 */
340 #include <ctype.h> /* for isalnum() */
to_hex(char code)341 static char to_hex(char code) {
342 static const char hex[] = "0123456789abcdef";
343 return hex[code & 15];
344 }
from_hex(char ch)345 static char from_hex(char ch) {
346 return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10;
347 }
348 /* Note -- caller must free returned pointer! */
url_encode(char * str)349 static char *url_encode(char *str) {
350 char *pstr = str, *buf = malloc(strlen(str) * 3 + 1), *pbuf = buf;
351
352 if (!buf) {
353 ERROR("Memory allocation failure (%d bytes)\n", (int) strlen(str)*3 + 1);
354 return NULL;
355 }
356
357 while (*pstr) {
358 if (isalnum(*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' || *pstr == '~')
359 *pbuf++ = *pstr;
360 else if (*pstr == ' ')
361 *pbuf++ = '+';
362 else
363 *pbuf++ = '%', *pbuf++ = to_hex(*pstr >> 4), *pbuf++ = to_hex(*pstr & 15);
364 pstr++;
365 }
366 *pbuf = '\0';
367 return buf;
368 }
url_decode(char * str)369 static char *url_decode(char *str) {
370 char *pstr = str, *buf = malloc(strlen(str) + 1), *pbuf = buf;
371
372 if (!buf) {
373 ERROR("Memory allocation failure (%d bytes)\n", (int) strlen(str) + 1);
374 return NULL;
375 }
376
377 while (*pstr) {
378 if (*pstr == '%') {
379 if (pstr[1] && pstr[2]) {
380 *pbuf++ = from_hex(pstr[1]) << 4 | from_hex(pstr[2]);
381 pstr += 2;
382 }
383 } else if (*pstr == '+') {
384 *pbuf++ = ' ';
385 } else {
386 *pbuf++ = *pstr;
387 }
388 pstr++;
389 }
390 *pbuf = '\0';
391 return buf;
392 }
393
394 /* And now back to our regularly-scheduled programming */
395
probe_device(struct libusb_device * device,struct libusb_device_descriptor * desc,const char * uri_prefix,const char * prefix,char * manuf_override,int found,int num_claim_attempts,int scan_only,char * match_serno,uint8_t * r_iface,uint8_t * r_altset,uint8_t * r_endp_up,uint8_t * r_endp_down,struct dyesub_backend * backend)396 static int probe_device(struct libusb_device *device,
397 struct libusb_device_descriptor *desc,
398 const char *uri_prefix,
399 const char *prefix, char *manuf_override,
400 int found, int num_claim_attempts,
401 int scan_only, char *match_serno,
402 uint8_t *r_iface, uint8_t *r_altset,
403 uint8_t *r_endp_up, uint8_t *r_endp_down,
404 struct dyesub_backend *backend)
405 {
406 struct libusb_device_handle *dev;
407 char buf[256];
408 char *product = NULL, *serial = NULL, *manuf = NULL, *descr = NULL;
409 uint8_t iface, altset;
410 struct libusb_config_descriptor *config = NULL;
411 int dlen = 0;
412 struct deviceid_dict dict[MAX_DICT];
413 char *ieee_id = NULL;
414 int i;
415 uint8_t endp_up, endp_down;
416
417 DEBUG("Probing VID: %04X PID: %04x\n", desc->idVendor, desc->idProduct);
418 STATE("+connecting-to-device\n");
419
420 if (libusb_open(device, &dev)) {
421 ERROR("Could not open device %04x:%04x (need to be root?)\n", desc->idVendor, desc->idProduct);
422 found = -1;
423 goto abort;
424 }
425
426 /* XXX FIXME: Iterate through possible configurations? */
427 if (libusb_get_active_config_descriptor(device, &config)) {
428 found = -1;
429 goto abort_close;
430 }
431
432 /* Loop through all interfaces and altsettings to find candidates */
433 for (iface = 0 ; iface < config->bNumInterfaces ; iface ++) {
434 for (altset = 0 ; altset < config->interface[iface].num_altsetting ; altset++) {
435 /* Skip interfaces that don't have enough endpoints */
436 if (config->interface[iface].altsetting[altset].bNumEndpoints < 2) {
437 continue;
438 }
439
440 #if 1
441 /* Explicitly exclude IPP-over-USB interfaces */
442 if (desc->bDeviceClass == LIBUSB_CLASS_PER_INTERFACE &&
443 config->interface[iface].altsetting[altset].bInterfaceClass == LIBUSB_CLASS_PRINTER &&
444 config->interface[iface].altsetting[altset].bInterfaceSubClass == USB_SUBCLASS_PRINTER &&
445 config->interface[iface].altsetting[altset].bInterfaceProtocol == USB_INTERFACE_PROTOCOL_IPP) {
446 continue;
447 }
448 #else
449 // Make sure it's a printer class device that supports bidir comms (XXX Is this necessarily true?)
450 if (desc->bDeviceClass == LIBUSB_CLASS_PRINTER ||
451 (desc->bDeviceClass == LIBUSB_CLASS_PER_INTERFACE &&
452 config->interface[iface].altsetting[altset].bInterfaceClass == LIBUSB_CLASS_PRINTER &&
453 config->interface[iface].altsetting[altset].bInterfaceSubClass == USB_SUBCLASS_PRINTER &&
454 config->interface[iface].altsetting[altset].bInterfaceProtocol != USB_INTERFACE_PROTOCOL_BIDIR)) {
455 continue;
456 }
457 #endif
458
459 /* Find the first set of endpoints! */
460 endp_up = endp_down = 0;
461 for (i = 0 ; i < config->interface[iface].altsetting[altset].bNumEndpoints ; i++) {
462 if ((config->interface[iface].altsetting[altset].endpoint[i].bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) == LIBUSB_TRANSFER_TYPE_BULK) {
463 if (config->interface[iface].altsetting[altset].endpoint[i].bEndpointAddress & LIBUSB_ENDPOINT_IN)
464 endp_up = config->interface[iface].altsetting[altset].endpoint[i].bEndpointAddress;
465 else
466 endp_down = config->interface[iface].altsetting[altset].endpoint[i].bEndpointAddress;
467 }
468 if (endp_up && endp_down)
469 goto candidate;
470 }
471 }
472 }
473
474 /* If we got here, we didn't find a match. */
475 found = -1;
476 goto abort_close;
477
478 candidate:
479
480 /* We've now found an interface/altset we need to query in more detail */
481 /* Detach the kernel driver */
482 if (libusb_kernel_driver_active(dev, iface))
483 libusb_detach_kernel_driver(dev, iface);
484
485 /* Claim the interface so we can start querying things! */
486 if (backend_claim_interface(dev, iface, num_claim_attempts)) {
487 found = -1;
488 goto abort_release;
489 }
490
491 /* Use the appropriate altesetting, but only if the
492 printer supports more than one. Some printers don't like
493 us unconditionally setting this. */
494 if (config->interface[iface].num_altsetting > 1) {
495 if (libusb_set_interface_alt_setting(dev, iface, altset)) {
496 ERROR("Failed to set alternative interface %d/%d\n", iface, altset);
497 found = -1;
498 goto abort_release;
499 }
500 }
501
502 /* Query IEEE1284 info only if it's a PRINTER class */
503 if (desc->bDeviceClass == LIBUSB_CLASS_PRINTER ||
504 (desc->bDeviceClass == LIBUSB_CLASS_PER_INTERFACE &&
505 config->interface[iface].altsetting[altset].bInterfaceClass == LIBUSB_CLASS_PRINTER &&
506 config->interface[iface].altsetting[altset].bInterfaceSubClass == USB_SUBCLASS_PRINTER)) {
507 ieee_id = get_device_id(dev, iface);
508 dlen = parse1284_data(ieee_id, dict);
509 }
510
511 /* Look up mfg string. */
512 if (manuf_override && strlen(manuf_override)) {
513 manuf = url_encode(manuf_override); /* Backend supplied */
514 } else if ((manuf = dict_find("MANUFACTURER", dlen, dict))) {
515 manuf = url_encode(manuf);
516 } else if ((manuf = dict_find("MFG", dlen, dict))) {
517 manuf = url_encode(manuf);
518 } else if ((manuf = dict_find("MFR", dlen, dict))) {
519 manuf = url_encode(manuf);
520 } else if (desc->iManufacturer) { /* Get from USB descriptor */
521 buf[0] = 0;
522 libusb_get_string_descriptor_ascii(dev, desc->iManufacturer, (unsigned char*)buf, STR_LEN_MAX);
523 sanitize_string(buf);
524 manuf = url_encode(buf);
525 }
526 if (!manuf || !strlen(manuf)) { /* Last-ditch */
527 if (manuf) free(manuf);
528 manuf = url_encode("Unknown"); // XXX use USB VID?
529 }
530
531 /* Look up model number */
532 if ((product = dict_find("MODEL", dlen, dict))) {
533 product = url_encode(product);
534 } else if ((product = dict_find("MDL", dlen, dict))) {
535 product = url_encode(product);
536 } else if (desc->iProduct) { /* Get from USB descriptor */
537 buf[0] = 0;
538 libusb_get_string_descriptor_ascii(dev, desc->iProduct, (unsigned char*)buf, STR_LEN_MAX);
539 sanitize_string(buf);
540 product = url_encode(buf);
541 }
542
543 if (!product || !strlen(product)) { /* Last-ditch */
544 if (!product) free(product);
545 product = url_encode("Unknown"); // XXX Use USB PID?
546 }
547
548 /* Look up description */
549 if ((descr = dict_find("DESCRIPTION", dlen, dict))) {
550 descr = strdup(descr);
551 } else if ((descr = dict_find("DES", dlen, dict))) {
552 descr = strdup(descr);
553 }
554 if (!descr || !strlen(descr)) { /* Last-ditch, generate */
555 char *product2 = url_decode(product);
556 char *manuf3 = url_decode(manuf);
557 descr = malloc(514); /* 256 + 256 + 1 + 1 */
558 if (!descr) {
559 ERROR("Memory allocation failure (%d bytes)\n", 514);
560 if (manuf3)
561 free(manuf3);
562 if (product2)
563 free(product2);
564 return -1;
565 }
566
567 snprintf(descr, 514, "%s %s", manuf3, product2);
568 free(product2);
569 free(manuf3);
570 }
571
572 /* Look up serial number */
573 if ((serial = dict_find("SERIALNUMBER", dlen, dict))) {
574 serial = url_encode(serial);
575 } else if ((serial = dict_find("SN", dlen, dict))) {
576 serial = url_encode(serial);
577 } else if ((serial = dict_find("SER", dlen, dict))) {
578 serial = url_encode(serial);
579 } else if ((serial = dict_find("SERN", dlen, dict))) {
580 serial = url_encode(serial);
581 } else if (desc->iSerialNumber) { /* Get from USB descriptor */
582 libusb_get_string_descriptor_ascii(dev, desc->iSerialNumber, (unsigned char*)buf, STR_LEN_MAX);
583 sanitize_string(buf);
584 serial = url_encode(buf);
585 } else if (backend->query_serno) { /* Get from backend hook */
586 buf[0] = 0;
587 /* Ignore result since a failure isn't critical here */
588 backend->query_serno(dev, endp_up, endp_down, buf, STR_LEN_MAX);
589 serial = url_encode(buf);
590 }
591
592 if (!serial || !strlen(serial)) { /* Last-ditch */
593 if (serial) free(serial);
594 WARNING("**** THIS PRINTER DOES NOT REPORT A SERIAL NUMBER!\n");
595 WARNING("**** If you intend to use multiple printers of this type, you\n");
596 WARNING("**** must only plug one in at a time or unexpected behavior will occur!\n");
597 serial = strdup("NONE_UNKNOWN");
598 }
599
600 if (scan_only) {
601 if (!old_uri) {
602 fprintf(stdout, "direct %s://%s/%s \"%s\" \"%s\" \"%s\" \"\"\n",
603 prefix, uri_prefix, serial,
604 descr, descr,
605 ieee_id ? ieee_id : "");
606 } else {
607 int k = 0;
608
609 /* URLify the manuf and model strings */
610 strncpy(buf, manuf, sizeof(buf) - 2);
611 k = strlen(buf);
612 buf[k++] = '/';
613 buf[k] = 0;
614
615 strncpy(buf + k, product, sizeof(buf)-k);
616
617 fprintf(stdout, "direct %s://%s?serial=%s&backend=%s \"%s\" \"%s\" \"%s\" \"\"\n",
618 prefix, buf, serial, uri_prefix,
619 descr, descr,
620 ieee_id? ieee_id : "");
621 }
622 }
623
624 /* If a serial number was passed down, use it. */
625 if (match_serno && strcmp(match_serno, (char*)serial)) {
626 found = -1;
627 }
628
629 if (dyesub_debug)
630 DEBUG("VID: %04X PID: %04X Manuf: '%s' Product: '%s' Serial: '%s' found: %d\n",
631 desc->idVendor, desc->idProduct, manuf, product, serial, found);
632
633 if (found != -1) {
634 if (r_iface) *r_iface = iface;
635 if (r_altset) *r_altset = altset;
636 if (r_endp_up) *r_endp_up = endp_up;
637 if (r_endp_up) *r_endp_down = endp_down;
638 }
639
640 /* Free things up */
641 if(serial) free(serial);
642 if(manuf) free(manuf);
643 if(product) free(product);
644 if(descr) free(descr);
645 if(ieee_id) free(ieee_id);
646
647 abort_release:
648
649 libusb_release_interface(dev, iface);
650
651 abort_close:
652
653 libusb_close(dev);
654
655 abort:
656 if (config) libusb_free_config_descriptor(config);
657
658 /* Clean up the dictionary */
659 while (dlen--) {
660 free (dict[dlen].key);
661 free (dict[dlen].val);
662 }
663
664 STATE("-connecting-to-device\n");
665
666 return found;
667 }
668
generic_teardown(void * vctx)669 void generic_teardown(void *vctx)
670 {
671 if (!vctx)
672 return;
673
674 free(vctx);
675 }
676
677 extern struct dyesub_backend sonyupd_backend;
678 extern struct dyesub_backend sonyupdneo_backend;
679 extern struct dyesub_backend kodak6800_backend;
680 extern struct dyesub_backend kodak605_backend;
681 extern struct dyesub_backend kodak1400_backend;
682 extern struct dyesub_backend shinkos1245_backend;
683 extern struct dyesub_backend shinkos2145_backend;
684 extern struct dyesub_backend shinkos6145_backend;
685 extern struct dyesub_backend shinkos6245_backend;
686 extern struct dyesub_backend canonselphy_backend;
687 extern struct dyesub_backend canonselphyneo_backend;
688 extern struct dyesub_backend mitsu70x_backend;
689 extern struct dyesub_backend mitsu9550_backend;
690 extern struct dyesub_backend mitsup95d_backend;
691 extern struct dyesub_backend dnpds40_backend;
692 extern struct dyesub_backend magicard_backend;
693 extern struct dyesub_backend mitsud90_backend;
694
695 static struct dyesub_backend *backends[] = {
696 &canonselphy_backend,
697 &canonselphyneo_backend,
698 &kodak6800_backend,
699 &kodak605_backend,
700 &kodak1400_backend,
701 &shinkos1245_backend,
702 &shinkos2145_backend,
703 &shinkos6145_backend,
704 &shinkos6245_backend,
705 &sonyupd_backend,
706 &mitsu70x_backend,
707 &mitsud90_backend,
708 &mitsu9550_backend,
709 &mitsup95d_backend,
710 &dnpds40_backend,
711 &magicard_backend,
712 NULL,
713 };
714
find_and_enumerate(struct libusb_context * ctx,struct libusb_device *** list,struct dyesub_backend * backend,char * match_serno,int scan_only,int num_claim_attempts,uint8_t * r_iface,uint8_t * r_altset,uint8_t * r_endp_up,uint8_t * r_endp_down)715 static int find_and_enumerate(struct libusb_context *ctx,
716 struct libusb_device ***list,
717 struct dyesub_backend *backend,
718 char *match_serno,
719 int scan_only, int num_claim_attempts,
720 uint8_t *r_iface, uint8_t *r_altset,
721 uint8_t *r_endp_up, uint8_t *r_endp_down)
722 {
723 int num;
724 int i, j = 0, k;
725 int found = -1;
726 const char *prefix = NULL;
727
728 if (test_mode >= TEST_MODE_NOATTACH) {
729 found = 1;
730 *r_endp_up = 0x82;
731 *r_endp_down = 0x01;
732 *r_iface = 0;
733 *r_altset = 0;
734 return found;
735 }
736
737 STATE("+org.gutenprint-searching-for-device\n");
738
739 /* Enumerate and find suitable device */
740 num = libusb_get_device_list(ctx, list);
741
742 for (i = 0 ; i < num ; i++) {
743 struct libusb_device_descriptor desc;
744 libusb_get_device_descriptor((*list)[i], &desc);
745
746 for (k = 0 ; backends[k] ; k++) {
747 if (backend && backend != backends[k])
748 continue;
749 for (j = 0 ; backends[k]->devices[j].vid ; j++) {
750 if (extra_pid != -1 &&
751 extra_vid != -1 &&
752 extra_type != -1) {
753 if (backends[k]->devices[j].type == extra_type &&
754 extra_vid == desc.idVendor &&
755 extra_pid == desc.idProduct) {
756 found = i;
757 prefix = backends[k]->uri_prefixes[0];
758 goto match;
759 }
760 }
761 if (desc.idVendor == backends[k]->devices[j].vid &&
762 (desc.idProduct == backends[k]->devices[j].pid ||
763 desc.idProduct == 0xffff)) {
764 prefix = backends[k]->devices[j].prefix;
765 found = i;
766 goto match;
767 }
768 }
769 }
770
771 continue;
772
773 match:
774 found = probe_device((*list)[i], &desc, prefix,
775 URI_PREFIX, backends[k]->devices[j].manuf_str,
776 found, num_claim_attempts,
777 scan_only, match_serno,
778 r_iface, r_altset,
779 r_endp_up, r_endp_down,
780 backends[k]);
781
782 if (found != -1 && !scan_only)
783 break;
784 }
785
786 STATE("-org.gutenprint-searching-for-device\n");
787 return found;
788 }
789
find_backend(char * uri_prefix)790 static struct dyesub_backend *find_backend(char *uri_prefix)
791 {
792 int i;
793
794 if (!uri_prefix)
795 return NULL;
796
797 for (i = 0; ; i++) {
798 struct dyesub_backend *backend = backends[i];
799 const char **alias;
800 if (!backend)
801 return NULL;
802 for (alias = backend->uri_prefixes ; alias && *alias ; alias++) {
803 if (!strcmp(uri_prefix, *alias))
804 return backend;
805 }
806 }
807 return NULL;
808 }
809
query_markers(struct dyesub_backend * backend,void * ctx,int full)810 static int query_markers(struct dyesub_backend *backend, void *ctx, int full)
811 {
812 struct marker *markers = NULL;
813 int marker_count = 0;
814 int ret;
815
816 if (!backend->query_markers)
817 return CUPS_BACKEND_OK;
818
819 if (test_mode >= TEST_MODE_NOPRINT)
820 return CUPS_BACKEND_OK;
821
822 ret = backend->query_markers(ctx, &markers, &marker_count);
823 if (ret)
824 return ret;
825
826 dump_markers(markers, marker_count, full);
827
828 return CUPS_BACKEND_OK;
829 }
830
print_license_blurb(void)831 void print_license_blurb(void)
832 {
833 const char *license = "\n\
834 Copyright 2007-2019 Solomon Peachy <pizza AT shaftnet DOT org>\n\
835 \n\
836 This program is free software; you can redistribute it and/or modify it\n\
837 under the terms of the GNU General Public License as published by the Free\n\
838 Software Foundation; either version 3 of the License, or (at your option)\n\
839 any later version.\n\
840 \n\
841 This program is distributed in the hope that it will be useful, but\n\
842 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n\
843 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License\n\
844 for more details.\n\
845 \n\
846 You should have received a copy of the GNU General Public License\n\
847 along with this program. If not, see https://www.gnu.org/licenses/.\n\
848 \n [http://www.gnu.org/licenses/gpl-2.0.html]\n\n";
849
850 fprintf(stderr, "%s", license);
851 }
852
print_help(char * argv0,struct dyesub_backend * backend)853 void print_help(char *argv0, struct dyesub_backend *backend)
854 {
855 struct libusb_context *ctx = NULL;
856 struct libusb_device **list = NULL;
857
858 char *ptr = strrchr(argv0, '/');
859 if (ptr)
860 ptr++;
861 else
862 ptr = argv0;
863
864 if (!backend)
865 backend = find_backend(ptr);
866
867 if (!backend) {
868 int i;
869 DEBUG("Environment variables:\n");
870 DEBUG(" DYESUB_DEBUG EXTRA_PID EXTRA_VID EXTRA_TYPE BACKEND SERIAL OLD_URI_SCHEME BACKEND_QUIET\n");
871 DEBUG("CUPS Usage:\n");
872 DEBUG("\tDEVICE_URI=someuri %s job user title num-copies options [ filename ]\n", URI_PREFIX);
873 DEBUG("\n");
874 DEBUG("Standalone Usage:\n");
875 DEBUG("\t%s\n", URI_PREFIX);
876 DEBUG(" [ -D ] [ -G ] [ -f ] [ -v ]\n");
877 DEBUG(" [ backend_specific_args ] \n");
878 DEBUG(" [ -d copies ] \n");
879 DEBUG(" [ - | infile ] \n");
880 for (i = 0; ; i++) {
881 const char **alias;
882
883 backend = backends[i];
884 if (!backend)
885 break;
886 DEBUG("\t# %s version %s\n",
887 backend->name, backend->version);
888 DEBUG(" BACKEND=");
889 for (alias = backend->uri_prefixes ; alias && *alias ; alias++)
890 DEBUG2("%s ", *alias);
891 DEBUG2("\n");
892
893 if (backend->cmdline_usage)
894 backend->cmdline_usage();
895 }
896 } else {
897 const char **alias;
898 DEBUG("Standalone %s backend version %s\n",
899 backend->name, backend->version);
900 DEBUG("\t supporting: ");
901 for (alias = backend->uri_prefixes ; alias && *alias ; alias++)
902 DEBUG2("%s ", *alias);
903 DEBUG2("\n");
904
905 DEBUG("\t[ -D ] [ -G ] [ -f ]\n");
906 if (backend->cmdline_usage)
907 backend->cmdline_usage();
908 DEBUG("\t[ -d copies ] [ infile | - ]\n");
909 }
910
911 /* Probe for printers */
912 find_and_enumerate(ctx, &list, backend, NULL, 1, 1, NULL, NULL, NULL, NULL);
913 libusb_free_device_list(list, 1);
914 }
915
parse_cmdstream(struct dyesub_backend * backend,void * backend_ctx,int fd)916 int parse_cmdstream(struct dyesub_backend *backend, void *backend_ctx, int fd)
917 {
918 FILE *fp = stdin;
919 char line[128];
920 char *lp;
921
922 if (fd != fileno(stdin)) {
923 fp = fdopen(fd, "r");
924 if (!fp) {
925 ERROR("Can't open data stream!\n");
926 return CUPS_BACKEND_FAILED;
927 }
928 }
929 while (fgets(line, sizeof(line), fp) != NULL) {
930 /* Strip trailing newline */
931 lp = line + strlen(line) - 1;
932 if (*lp == '\n')
933 *lp = '\0';
934 /* And leading spaces */
935 for (lp = line; isspace(*lp); lp++);
936 /* And comments and blank lines */
937 if (*lp == '#' || !*lp)
938 continue;
939
940 /* Parse command! */
941 if (strncasecmp(lp, "ReportLevels", 12) == 0) {
942 query_markers(backend, backend_ctx, 1);
943 /* XXX TODO: ReportStatus, AutoConfigure, PrintSelfTestPage? What about others, eg reset or cancel job? */
944 } else {
945 WARNING("Invalid printer command \"%s\"!\n", lp);
946 }
947 }
948
949 /* Clean up */
950 if (fp != stdin)
951 fclose(fp);
952
953 return CUPS_BACKEND_OK;
954 };
955
main(int argc,char ** argv)956 int main (int argc, char **argv)
957 {
958 struct libusb_context *ctx = NULL;
959 struct libusb_device **list = NULL;
960 struct libusb_device_handle *dev;
961
962 struct dyesub_backend *backend = NULL;
963 void * backend_ctx = NULL;
964
965 uint8_t endp_up, endp_down;
966 uint8_t iface, altset;
967
968 int data_fd = fileno(stdin);
969
970 const void *job = NULL;
971
972 int i;
973
974 int ret = CUPS_BACKEND_OK;
975
976 int found = -1;
977 int jobid = 0;
978 int current_page = 0;
979
980 char *uri;
981 char *type;
982 char *fname = NULL;
983 char *use_serno = NULL;
984 int printer_type;
985
986 /* Handle environment variables */
987 if (getenv("BACKEND_QUIET"))
988 quiet = atoi(getenv("BACKEND_QUIET"));
989 if (getenv("DYESUB_DEBUG"))
990 dyesub_debug = atoi(getenv("DYESUB_DEBUG"));
991 if (getenv("EXTRA_PID"))
992 extra_pid = strtol(getenv("EXTRA_PID"), NULL, 16);
993 if (getenv("EXTRA_VID"))
994 extra_vid = strtol(getenv("EXTRA_VID"), NULL, 16);
995 if (getenv("EXTRA_TYPE"))
996 extra_type = atoi(getenv("EXTRA_TYPE"));
997 if (getenv("BACKEND"))
998 backend = find_backend(getenv("BACKEND"));
999 if (getenv("FAST_RETURN"))
1000 fast_return++;
1001 if (getenv("MAX_XFER_SIZE"))
1002 max_xfer_size = atoi(getenv("MAX_XFER_SIZE"));
1003 if (getenv("XFER_TIMEOUT"))
1004 xfer_timeout = atoi(getenv("XFER_TIMEOUT"));
1005 if (getenv("TEST_MODE"))
1006 test_mode = atoi(getenv("TEST_MODE"));
1007 if (getenv("OLD_URI_SCHEME"))
1008 old_uri = atoi(getenv("OLD_URI_SCHEME"));
1009
1010 if (test_mode >= TEST_MODE_NOATTACH && (extra_vid == -1 || extra_pid == -1)) {
1011 ERROR("Must specify EXTRA_VID, EXTRA_PID in test mode > 1!\n");
1012 exit(1);
1013 }
1014
1015 DEBUG("Multi-Call Dye-sublimation CUPS Backend version %s\n",
1016 BACKEND_VERSION);
1017 DEBUG("Copyright 2007-2019 Solomon Peachy\n");
1018 DEBUG("This free software comes with ABSOLUTELY NO WARRANTY! \n");
1019 DEBUG("Licensed under the GNU GPL. Run with '-G' for more details.\n");
1020 DEBUG("\n");
1021
1022 use_serno = getenv("SERIAL");
1023 uri = getenv("DEVICE_URI"); /* CUPS backend mode! */
1024 type = getenv("FINAL_CONTENT_TYPE"); /* CUPS content type -- ie raster or command */
1025
1026 if (uri) {
1027 /* CUPS backend mode */
1028 int base = optind; /* ie 1 */
1029 if (argc < 6) {
1030 ERROR("Insufficient arguments\n");
1031 exit(1);
1032 }
1033 if (argv[base])
1034 jobid = atoi(argv[base]);
1035 if (argv[base + 3])
1036 ncopies = atoi(argv[base + 3]);
1037 if (argc > 6)
1038 fname = argv[base + 5];
1039 else
1040 fname = "-";
1041
1042 /* Figure out backend based on URI */
1043 {
1044 char *ptr = strstr(uri, "backend="), *ptr2;
1045 if (ptr) { /* Original format */
1046 ptr += 8;
1047 ptr2 = strchr(ptr, '&');
1048 if (ptr2)
1049 *ptr2 = 0;
1050
1051 backend = find_backend(ptr);
1052 if (!backend) {
1053 ERROR("Invalid backend (%s)\n", ptr);
1054 exit(1);
1055 }
1056 if (ptr2)
1057 *ptr2 = '&';
1058
1059 use_serno = strchr(uri, '=');
1060 if (!use_serno || !*(use_serno+1)) {
1061 ERROR("Invalid URI (%s)\n", uri);
1062 exit(1);
1063 }
1064 use_serno++;
1065 ptr = strchr(use_serno, '&');
1066 if (ptr)
1067 *ptr = 0;
1068 } else { /* New format */
1069 // prefix://backend/serno
1070 ptr = strchr(uri, '/');
1071 ptr += 2;
1072 use_serno = strchr(ptr, '/');
1073 if (!use_serno || !*(use_serno+1)) {
1074 ERROR("Invalid URI (%s)\n", uri);
1075 exit(1);
1076 }
1077 *use_serno = 0;
1078 use_serno++;
1079
1080 backend = find_backend(ptr);
1081 if (!backend) {
1082 ERROR("Invalid backend (%s)\n", ptr);
1083 exit(1);
1084 }
1085
1086 ptr = strchr(ptr, '?');
1087 if (ptr)
1088 *ptr = 0;
1089 }
1090 }
1091
1092 /* Always enable fast return in CUPS mode */
1093 fast_return++;
1094 } else {
1095 /* Standalone mode */
1096
1097 /* Try to guess backend from executable name */
1098 if (!backend) {
1099 char *ptr = strrchr(argv[0], '/');
1100 if (ptr)
1101 ptr++;
1102 else
1103 ptr = argv[0];
1104 backend = find_backend(ptr);
1105 }
1106
1107 srand(getpid());
1108 jobid = rand();
1109 }
1110
1111 #ifndef LIBUSB_PRE_1_0_10
1112 if (dyesub_debug) {
1113 const struct libusb_version *ver;
1114 ver = libusb_get_version();
1115 DEBUG(" ** running with libusb %d.%d.%d%s (%d)\n",
1116 ver->major, ver->minor, ver->micro, (ver->rc? ver->rc : ""), ver->nano );
1117 }
1118 #endif
1119
1120 /* Libusb setup */
1121 ret = libusb_init(&ctx);
1122 if (ret) {
1123 ERROR("Failed to initialize libusb (%d)\n", ret);
1124 ret = CUPS_BACKEND_RETRY_CURRENT;
1125 goto done;
1126 }
1127
1128 /* If we don't have a valid backend, print help and terminate */
1129 if (!backend) {
1130 print_help(argv[0], NULL); // probes all devices
1131 ret = CUPS_BACKEND_OK;
1132 goto done;
1133 }
1134
1135 /* If we're in standalone mode, print help only if no args */
1136 if (!uri) {
1137 if (argc < 2) {
1138 print_help(argv[0], backend); // probes all devices
1139 ret = CUPS_BACKEND_OK;
1140 goto done;
1141 }
1142 }
1143
1144 /* Enumerate devices */
1145 found = find_and_enumerate(ctx, &list, backend, use_serno, 0, NUM_CLAIM_ATTEMPTS, &iface, &altset, &endp_up, &endp_down);
1146
1147 if (found == -1) {
1148 ERROR("Printer open failure (No matching printers found!)\n");
1149 ret = CUPS_BACKEND_RETRY;
1150 goto done;
1151 }
1152
1153 if (test_mode) {
1154 WARNING("**** TEST MODE %d!\n", test_mode);
1155 if (test_mode >= TEST_MODE_NOATTACH)
1156 goto bypass;
1157 }
1158
1159 /* Open an appropriate device */
1160 ret = libusb_open(list[found], &dev);
1161 if (ret) {
1162 ERROR("Printer open failure (Need to be root?) (%d)\n", ret);
1163 ret = CUPS_BACKEND_RETRY_CURRENT;
1164 goto done;
1165 }
1166
1167 /* Detach the kernel driver */
1168 if (libusb_kernel_driver_active(dev, iface)) {
1169 ret = libusb_detach_kernel_driver(dev, iface);
1170 if (ret) {
1171 ERROR("Printer open failure (Could not detach printer from kernel) (%d)\n", ret);
1172 ret = CUPS_BACKEND_RETRY_CURRENT;
1173 goto done_close;
1174 }
1175 }
1176
1177 /* Claim the interface so we can start using this! */
1178 ret = backend_claim_interface(dev, iface, NUM_CLAIM_ATTEMPTS);
1179 if (ret) {
1180 ERROR("Printer open failure (Unable to claim interface) (%d)\n", ret);
1181 ret = CUPS_BACKEND_RETRY;
1182 goto done_close;
1183 }
1184
1185 /* Use the appropriate altesetting! */
1186 if (altset != 0) {
1187 ret = libusb_set_interface_alt_setting(dev, iface, altset);
1188 if (ret) {
1189 ERROR("Printer open failure (Unable to issue altsettinginterface) (%d)\n", ret);
1190 ret = CUPS_BACKEND_RETRY;
1191 goto done_close;
1192 }
1193 }
1194
1195 bypass:
1196 /* Initialize backend */
1197 DEBUG("Initializing '%s' backend (version %s)\n",
1198 backend->name, backend->version);
1199 backend_ctx = backend->init();
1200
1201 if (test_mode < TEST_MODE_NOATTACH) {
1202 struct libusb_device *device;
1203 struct libusb_device_descriptor desc;
1204
1205 device = libusb_get_device(dev);
1206 libusb_get_device_descriptor(device, &desc);
1207
1208 printer_type = lookup_printer_type(backend,
1209 desc.idVendor, desc.idProduct);
1210 } else {
1211 printer_type = lookup_printer_type(backend,
1212 extra_vid, extra_pid);
1213 }
1214
1215 if (printer_type <= P_UNKNOWN) {
1216 ERROR("Unable to lookup printer type\n");
1217 ret = CUPS_BACKEND_FAILED;
1218 goto done_close;
1219 }
1220
1221 /* Attach backend to device */
1222 if (backend->attach(backend_ctx, dev, printer_type, endp_up, endp_down, jobid)) {
1223 ERROR("Unable to attach to printer!");
1224 ret = CUPS_BACKEND_FAILED;
1225 goto done_close;
1226 }
1227
1228 // STATE("+org.gutenprint-attached-to-device\n");
1229
1230 if (!uri) {
1231 if (backend->cmdline_arg(backend_ctx, argc, argv) < 0)
1232 goto done_claimed;
1233
1234 /* Grab the filename */
1235 fname = argv[optind]; // XXX do this a smarter way?
1236 }
1237
1238 if (!fname) {
1239 if (uri)
1240 ERROR("ERROR: No input file specified\n");
1241 goto done_claimed;
1242 }
1243
1244 if (ncopies < 1) {
1245 ERROR("ERROR: need to have at least 1 copy!\n");
1246 ret = CUPS_BACKEND_FAILED;
1247 goto done_claimed;
1248 }
1249
1250 /* Open file if not STDIN */
1251 if (strcmp("-", fname)) {
1252 data_fd = open(fname, O_RDONLY);
1253 if (data_fd < 0) {
1254 perror("ERROR:Can't open input file");
1255 ret = CUPS_BACKEND_FAILED;
1256 goto done_claimed;
1257 }
1258 }
1259
1260 /* Ensure we're using BLOCKING I/O */
1261 i = fcntl(data_fd, F_GETFL, 0);
1262 if (i < 0) {
1263 perror("ERROR:Can't open input");
1264 ret = CUPS_BACKEND_FAILED;
1265 goto done;
1266 }
1267 i &= ~O_NONBLOCK;
1268 i = fcntl(data_fd, F_SETFL, i);
1269 if (i < 0) {
1270 perror("ERROR:Can't open input");
1271 ret = CUPS_BACKEND_FAILED;
1272 goto done_claimed;
1273 }
1274
1275 /* Ignore SIGPIPE */
1276 signal(SIGPIPE, SIG_IGN);
1277 signal(SIGTERM, sigterm_handler);
1278
1279 /* Time for the main processing loop */
1280 INFO("Printing started (%d copies)\n", ncopies);
1281
1282 /* See if it's a CUPS command stream, and if yes, handle it! */
1283 if (type && !strcmp("application/vnd.cups-command", type))
1284 {
1285 ret = parse_cmdstream(backend, backend_ctx, data_fd);
1286 goto done_claimed;
1287 }
1288
1289 newpage:
1290
1291 /* Read in data */
1292 if ((ret = backend->read_parse(backend_ctx, &job, data_fd, ncopies))) {
1293 if (current_page)
1294 goto done_multiple;
1295 else
1296 goto done_claimed;
1297 }
1298
1299 /* The backend parser might not return a job due to job dependencies.
1300 Try and read another page. */
1301 if (!job)
1302 goto newpage;
1303
1304 /* Create our own joblist if necessary */
1305 if (!(backend->flags & BACKEND_FLAG_JOBLIST)) {
1306 struct dyesub_joblist *jlist = dyesub_joblist_create(backend, backend_ctx);
1307 if (!list)
1308 goto done_claimed;
1309 dyesub_joblist_addjob(jlist, job);
1310 job = jlist;
1311 }
1312
1313 /* Dump the full marker dump */
1314 ret = query_markers(backend, backend_ctx, !current_page);
1315 if (ret)
1316 goto done_claimed;
1317
1318 INFO("Printing page %d\n", ++current_page);
1319
1320 if (test_mode >= TEST_MODE_NOPRINT ) {
1321 WARNING("**** TEST MODE, bypassing printing!\n");
1322 } else {
1323 ret = dyesub_joblist_print(job);
1324 }
1325
1326 dyesub_joblist_cleanup(job);
1327
1328 if (ret)
1329 goto done_claimed;
1330
1331 /* Log the completed page */
1332 if (!uri)
1333 PAGE("%d %d\n", current_page, ncopies);
1334
1335 /* Dump a marker status update */
1336 ret = query_markers(backend, backend_ctx, !current_page);
1337 if (ret)
1338 goto done_claimed;
1339
1340 /* Since we have no way of telling if there's more data remaining
1341 to be read (without actually trying to read it), always assume
1342 multiple print jobs. */
1343 goto newpage;
1344
1345 done_multiple:
1346 close(data_fd);
1347
1348 /* Done printing, log the total number of pages */
1349 if (!uri)
1350 PAGE("total %d\n", current_page * ncopies);
1351 ret = CUPS_BACKEND_OK;
1352
1353 done_claimed:
1354 if (test_mode < TEST_MODE_NOATTACH)
1355 libusb_release_interface(dev, iface);
1356
1357 done_close:
1358 if (test_mode < TEST_MODE_NOATTACH)
1359 libusb_close(dev);
1360 done:
1361
1362 if (backend && backend_ctx) {
1363 if (backend->teardown)
1364 backend->teardown(backend_ctx);
1365 else
1366 generic_teardown(backend_ctx);
1367 // STATE("-org.gutenprint-attached-to-device");
1368 }
1369
1370 if (list)
1371 libusb_free_device_list(list, 1);
1372
1373 libusb_exit(ctx);
1374
1375 return ret;
1376 }
1377
dump_markers(struct marker * markers,int marker_count,int full)1378 void dump_markers(struct marker *markers, int marker_count, int full)
1379 {
1380 int i;
1381
1382 if (!full)
1383 goto minimal;
1384
1385 ATTR("marker-colors=");
1386 for (i = 0 ; i < marker_count; i++) {
1387 DEBUG2("%s", markers[i].color);
1388 if ((i+1) < marker_count)
1389 DEBUG2(",");
1390 }
1391 DEBUG2("\n");
1392
1393 ATTR("marker-high-levels=");
1394 for (i = 0 ; i < marker_count; i++) {
1395 DEBUG2("%d", 100);
1396 if ((i+1) < marker_count)
1397 DEBUG2(",");
1398 }
1399 DEBUG2("\n");
1400
1401 ATTR("marker-low-levels=");
1402 for (i = 0 ; i < marker_count; i++) {
1403 DEBUG2("%d", 10);
1404 if ((i+1) < marker_count)
1405 DEBUG2(",");
1406 }
1407 DEBUG2("\n");
1408
1409 ATTR("marker-names=");
1410 for (i = 0 ; i < marker_count; i++) {
1411 DEBUG2("'\"%s\"'", markers[i].name);
1412 if ((i+1) < marker_count)
1413 DEBUG2(",");
1414 }
1415 DEBUG2("\n");
1416
1417 ATTR("marker-types=");
1418 for (i = 0 ; i < marker_count; i++) {
1419 DEBUG2("ribbonWax");
1420 if ((i+1) < marker_count)
1421 DEBUG2(",");
1422 }
1423 DEBUG2("\n");
1424
1425 minimal:
1426 ATTR("marker-levels=");
1427 for (i = 0 ; i < marker_count; i++) {
1428 int val;
1429 if (markers[i].levelmax <= 0 || markers[i].levelnow < 0)
1430 val = (markers[i].levelnow <= 0) ? markers[i].levelnow : -1;
1431 else if (markers[i].levelmax == 100)
1432 val = markers[i].levelnow;
1433 else
1434 val = markers[i].levelnow * 100 / markers[i].levelmax;
1435 DEBUG2("%d", val);
1436 if ((i+1) < marker_count)
1437 DEBUG2(",");
1438 }
1439 DEBUG2("\n");
1440
1441 /* Only dump a message if the marker is not a percentage */
1442 if (markers[0].levelmax != 100) {
1443 ATTR("marker-message=");
1444 for (i = 0 ; i < marker_count; i++) {
1445 switch (markers[i].levelnow) {
1446 case -1:
1447 DEBUG2("'\"Unable to query remaining prints on %s media\"'", markers[i].name);
1448 break;
1449 case -2:
1450 DEBUG2("'\"Unknown remaining prints on %s media\"'", markers[i].name);
1451 break;
1452 case -3:
1453 DEBUG2("'\"One or more remaining prints on %s media\"'", markers[i].name);
1454 break;
1455 default:
1456 DEBUG2("'\"%d native prints remaining on %s media\"'", markers[i].levelnow, markers[i].name);
1457 break;
1458 }
1459 if ((i+1) < marker_count)
1460 DEBUG2(",");
1461 }
1462 DEBUG2("\n");
1463 }
1464 }
1465
dyesub_read_file(char * filename,void * databuf,int datalen,int * actual_len)1466 int dyesub_read_file(char *filename, void *databuf, int datalen,
1467 int *actual_len)
1468 {
1469 int len;
1470 int fd = open(filename, O_RDONLY);
1471
1472 if (fd < 0) {
1473 ERROR("Unable to open '%s'\n", filename);
1474 return CUPS_BACKEND_FAILED;
1475 }
1476 len = read(fd, databuf, datalen);
1477 if (len < 0) {
1478 ERROR("Bad Read! (%d/%d)\n", len, errno);
1479 close(fd);
1480 return CUPS_BACKEND_FAILED;
1481 }
1482 if (!actual_len && (datalen != len)) {
1483 ERROR("Read mismatch (%d vs %d)\n", len, datalen);
1484 close(fd);
1485 return CUPS_BACKEND_FAILED;
1486 }
1487 close(fd);
1488
1489 if (actual_len)
1490 *actual_len = len;
1491
1492 return CUPS_BACKEND_OK;
1493 }
1494
uint16_to_packed_bcd(uint16_t val)1495 uint16_t uint16_to_packed_bcd(uint16_t val)
1496 {
1497 uint16_t bcd;
1498 uint16_t i;
1499
1500 /* Handle from 0-9999 */
1501 i = val % 10;
1502 bcd = i;
1503 val /= 10;
1504 i = val % 10;
1505 bcd |= (i << 4);
1506 val /= 10;
1507 i = val % 10;
1508 bcd |= (i << 8);
1509 val /= 10;
1510 i = val % 10;
1511 bcd |= (i << 12);
1512
1513 return bcd;
1514 }
1515
packed_bcd_to_uint32(char * in,int len)1516 uint32_t packed_bcd_to_uint32(char *in, int len)
1517 {
1518 uint32_t out = 0;
1519
1520 while (len--) {
1521 out *= 10;
1522 out += (*in >> 4);
1523 out *= 10;
1524 out += (*in & 0xf);
1525 in++;
1526 }
1527 return out;
1528 }
1529
1530 /* Job list manipulation */
dyesub_joblist_create(struct dyesub_backend * backend,void * ctx)1531 struct dyesub_joblist *dyesub_joblist_create(struct dyesub_backend *backend, void *ctx)
1532 {
1533 struct dyesub_joblist *list;
1534
1535 list = malloc(sizeof(struct dyesub_joblist));
1536 if (!list) {
1537 ERROR("Memory allocation failure\n");
1538 return NULL;
1539 }
1540 list->backend = backend;
1541 list->ctx = ctx;
1542 list->num_entries = 0;
1543
1544 if (collate)
1545 list->copies = ncopies;
1546 else
1547 list->copies = 1;
1548
1549 return list;
1550 }
1551
dyesub_joblist_cleanup(const struct dyesub_joblist * list)1552 void dyesub_joblist_cleanup(const struct dyesub_joblist *list)
1553 {
1554 int i;
1555 for (i = 0; i < list->num_entries ; i++) {
1556 if (list->entries[i])
1557 list->backend->cleanup_job(list->entries[i]);
1558 }
1559 free((void*)list);
1560 }
1561
dyesub_joblist_addjob(struct dyesub_joblist * list,const void * job)1562 int dyesub_joblist_addjob(struct dyesub_joblist *list, const void *job)
1563 {
1564 if (list->num_entries >= DYESUB_MAX_JOB_ENTRIES)
1565 return 1;
1566
1567 list->entries[list->num_entries++] = job;
1568
1569 return 0;
1570 }
1571
dyesub_joblist_print(const struct dyesub_joblist * list)1572 int dyesub_joblist_print(const struct dyesub_joblist *list)
1573 {
1574 int i, j;
1575 int ret;
1576 for (i = 0 ; i < list->copies ; i++) {
1577 for (j = 0 ; j < list->num_entries ; j++) {
1578 if (list->entries[j]) {
1579 ret = list->backend->main_loop(list->ctx, list->entries[j]);
1580 if (ret)
1581 return ret;
1582
1583 #if 0
1584 /* Free up the job as we go along
1585 if we're on the final copy */
1586 if (i + 1 == list->copies) {
1587 list->backend->cleanup_job(list->entries[j]);
1588 list->entries[j] = NULL;
1589 }
1590 #endif
1591 }
1592 }
1593 }
1594 return CUPS_BACKEND_OK;
1595 }
1596