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