1 /*****************************************************************************\
5 (c) 2004-2008 Copyright Hewlett-Packard Development Company, LP
7 Permission is hereby granted, free of charge, to any person obtaining a copy
8 of this software and associated documentation files (the "Software"), to deal
9 in the Software without restriction, including without limitation the rights
10 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
11 of the Software, and to permit persons to whom the Software is furnished to do
12 so, subject to the following conditions:
14 The above copyright notice and this permission notice shall be included in all
15 copies or substantial portions of the Software.
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19 FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 \*****************************************************************************/
30 #include <sys/types.h>
32 #include <netinet/in.h>
44 #include <dbus/dbus.h>
54 BACKEND_FAILED = 1, /* use error-policy */
55 BACKEND_HOLD = 3, /* hold job */
56 BACKEND_STOP = 4, /* stop queue */
57 BACKEND_CANCEL = 5 /* cancel job */
62 int pjl_device; /* 0=disabled, 1=enabled */
64 int eoj_pages; /* end-of-job pages */
65 int abort; /* 0=no, 1=yes */
66 int done; /* 0=no, 1=yes */
70 pthread_mutex_t mutex;
71 pthread_cond_t done_cond;
74 #define _STRINGIZE(x) #x
75 #define STRINGIZE(x) _STRINGIZE(x)
77 #define BUG(args...) bug(__FILE__ " " STRINGIZE(__LINE__) ": " args)
80 #define DBG(args...) syslog(LOG_INFO, __FILE__ " " STRINGIZE(__LINE__) ": " args)
81 #define DBG_DUMP(data, size) sysdump((data), (size))
82 #define DBG_SZ(args...) syslog(LOG_INFO, args)
85 #define DBG_DUMP(data, size)
86 #define DBG_SZ(args...)
89 #define RETRY_TIMEOUT 30 /* seconds */
90 #define EXCEPTION_TIMEOUT 45 /* seconds */
92 #define NFAULT_BIT 0x08
93 #define PERROR_BIT 0x20
95 #define OOP (NFAULT_BIT | PERROR_BIT)
96 #define JAMMED (PERROR_BIT)
97 #define ERROR_TRAP (0)
99 #define STATUS_MASK (NFAULT_BIT | PERROR_BIT)
101 #define DEVICE_IS_OOP(reg) ((reg & STATUS_MASK) == OOP)
102 #define DEVICE_PAPER_JAMMED(reg) ((reg & STATUS_MASK) == JAMMED)
103 #define DEVICE_IO_TRAP(reg) ((reg & STATUS_MASK) == ERROR_TRAP)
105 #define HEX2INT(x, i) if (x >= '0' && x <= '9') i |= x - '0'; \
106 else if (x >= 'A' && x <= 'F') i |= 0xA + x - 'A'; \
107 else if (x >= 'a' && x <= 'f') i |= 0xA + x - 'a'
109 /* Definitions for hpLogLevel in cupsd.conf. */
111 #define SAVE_PCL_FILE 2
112 #define SAVE_INPUT_RASTERS 4
113 #define SEND_TO_PRINTER_ALSO 8
115 /* Actual vstatus codes are mapped to 1000+vstatus for DeviceError messages. */
120 VSTATUS_PRNT, /* io printing */
121 VSTATUS_OFFF, /* turning off */
122 VSTATUS_RPRT, /* report printing */
123 VSTATUS_CNCL, /* canceling */
124 VSTATUS_IOST, /* io stall */
125 VSTATUS_DRYW, /* dry time wait */
126 VSTATUS_PENC, /* pen change */
127 VSTATUS_OOPA, /* out of paper */
128 VSTATUS_BNEJ, /* banner eject needed */
129 VSTATUS_BNMZ, /* banner mismatch */
130 VSTATUS_PHMZ, /* photo mismatch */
131 VSTATUS_DPMZ, /* duplex mismatch */
132 VSTATUS_PAJM, /* media jam */
133 VSTATUS_CARS, /* carriage stall */
134 VSTATUS_PAPS, /* paper stall */
135 VSTATUS_PENF, /* pen failure */
136 VSTATUS_ERRO, /* hard error */
137 VSTATUS_PWDN, /* power down */
138 VSTATUS_FPTS, /* front panel test */
139 VSTATUS_CLNO /* clean out tray missing */
142 #define EVENT_START_JOB 500
143 #define EVENT_END_JOB 501
145 //const char pjl_status_cmd[] = "\e%-12345X@PJL INFO STATUS \r\n\e%-12345X";
146 static const char pjl_ustatus_cmd[] = "\e%-12345X@PJL USTATUS DEVICE = ON \r\n@PJL USTATUS JOB = ON \r\n@PJL JOB \r\n\e%-12345X";
147 static const char pjl_job_end_cmd[] = "\e%-12345X@PJL EOJ \r\n\e%-12345X";
148 static const char pjl_ustatus_off_cmd[] = "\e%-12345X@PJL USTATUSOFF \r\n\e%-12345X";
151 #define DBUS_INTERFACE "com.hplip.StatusService"
152 #define DBUS_PATH "/"
153 static DBusError dbus_err;
154 static DBusConnection *dbus_conn;
157 static int bug(const char *fmt, ...)
165 if ((n = vsnprintf(buf, 256, fmt, args)) == -1)
166 buf[255] = 0; /* output was truncated */
168 fprintf(stderr, "%s", buf);
169 syslog(LOG_ERR, "%s", buf);
177 static void sysdump(const void *data, int size)
179 /* Dump size bytes of *data. Output looks like:
180 * [0000] 75 6E 6B 6E 6F 77 6E 20 30 FF 00 00 00 00 39 00 unknown 0.....9.
183 unsigned char *p = (unsigned char *)data;
186 char bytestr[4] = {0};
187 char addrstr[10] = {0};
188 char hexstr[16*3 + 5] = {0};
189 char charstr[16*1 + 5] = {0};
190 for(n=1;n<=size;n++) {
192 /* store address for this line */
193 snprintf(addrstr, sizeof(addrstr), "%.4d", (int)((p-(unsigned char *)data) & 0xffff));
197 if (isprint(c) == 0) {
201 /* store hex str (for left side) */
202 snprintf(bytestr, sizeof(bytestr), "%02X ", *p);
203 strncat(hexstr, bytestr, sizeof(hexstr)-strlen(hexstr)-1);
205 /* store char str (for right side) */
206 snprintf(bytestr, sizeof(bytestr), "%c", c);
207 strncat(charstr, bytestr, sizeof(charstr)-strlen(charstr)-1);
211 DBG_SZ("[%4.4s] %-50.50s %s\n", addrstr, hexstr, charstr);
218 if (strlen(hexstr) > 0) {
219 /* print rest of buffer if not empty */
220 DBG_SZ("[%4.4s] %-50.50s %s\n", addrstr, hexstr, charstr);
225 /* Map printer status to IPP printer-state-reasons (see RFC-2911). */
226 static int map_ipp_printer_state_reason(int status, const char **state_msg)
229 if (status >= 1000 && status <= 1999)
239 *state_msg = "media-empty-error";
242 *state_msg = "media-jam-error";
245 *state_msg = "other";
249 else if (status >= 10000 && status <= 55999)
251 /* laserjet pjl status */
252 if (status >= 10000 && status <= 10999)
254 else if (status >= 41000 && status <= 41999)
255 *state_msg = "media-empty-error";
256 else if ((status >= 42000 && status <= 42999) || (status >= 44000 && status <= 44999) || (status == 40022))
257 *state_msg = "media-jam-error";
258 else if (status == 40021)
259 *state_msg = "cover-open-error";
260 else if (status == 40600)
261 *state_msg = "toner-empty-error";
263 *state_msg = "other"; /* 40017 - cartridge E-LABEL is unreadable (ie: ljp1005) */
267 /* Assume hpmud error */
268 *state_msg = "other";
274 static enum HPMUD_RESULT get_pjl_input(HPMUD_DEVICE dd, HPMUD_CHANNEL cd, char *buf, int buf_size, int sec_timeout, int *bytes_read)
276 enum HPMUD_RESULT stat;
281 /* Read unsolicited status from device. */
282 stat = hpmud_read_channel(dd, cd, buf, buf_size, sec_timeout, &len);
283 if (stat != HPMUD_R_OK)
288 DBG("pjl result len=%d\n", len);
299 static int parse_pjl_job_end(char *buf, int *pages)
307 if ((p = strcasestr(buf, "ustatus job")) != NULL)
309 if (strncasecmp(p+13, "end", 3) == 0)
312 if ((p = strcasestr(p+13+5, "pages=")) != NULL)
313 *pages = strtol(p+6, &tail, 10);
321 static int parse_pjl_device_status(char *buf, int *status)
329 if ((p = strcasestr(buf, "code=")) != NULL)
331 *status = strtol(p+5, &tail, 10);
339 static void pjl_read_thread(struct pjl_attributes *pa)
341 enum HPMUD_RESULT stat;
342 int len, new_status, new_eoj;
345 pthread_detach(pthread_self());
347 DBG("starting thread %d\n", (int)pa->tid);
349 pa->current_status = 10001; /* default is ready */
350 pa->eoj_pages = pa->abort = pa->done = 0;
354 stat = get_pjl_input(pa->dd, pa->cd, buf, sizeof(buf), 0, &len);
355 if (!(stat == HPMUD_R_OK || stat == HPMUD_R_IO_TIMEOUT))
357 BUG("exiting thread %d error=%d\n", (int)pa->tid, stat);
358 pthread_mutex_lock(&pa->mutex);
359 pa->current_status = 5000+stat; /* io error */
360 pthread_mutex_unlock(&pa->mutex);
364 if (stat == HPMUD_R_OK)
366 pthread_mutex_lock(&pa->mutex);
367 new_status = parse_pjl_device_status(buf, &pa->current_status);
368 new_eoj = parse_pjl_job_end(buf, &pa->eoj_pages);
369 pthread_mutex_unlock(&pa->mutex);
371 BUG("read new pjl status: %d\n", pa->current_status);
373 BUG("read pjl job_end: %d\n", pa->eoj_pages);
379 DBG("exiting thread %d abort=%d stat=%d\n", (int)pa->tid, pa->abort, stat);
382 pthread_cond_signal(&pa->done_cond);
391 * dd - device descriptor
392 * pa - see pjl_attributes definition
395 * return - printer status, 1000 to 1999 = inkjet vstatus, 5000 to 5999 = hpmud error, 10000 to 55999 = pjl status code
398 static int get_printer_status(HPMUD_DEVICE dd, HPMUD_CHANNEL cd, struct pjl_attributes *pa)
402 int status, ver, len;
407 pthread_mutex_lock(&pa->mutex);
408 status = pa->current_status;
409 pthread_mutex_unlock(&pa->mutex);
413 status = VSTATUS_IDLE; /* set default */
414 r = hpmud_get_device_id(dd, id, sizeof(id), &len);
415 // if (!(r == HPMUD_R_OK || r == HPMUD_R_DEVICE_BUSY))
418 status = 5000+r; /* no deviceid, return some error */
422 /* Check for valid S-field in device id string. */
423 if ((pSf = strstr(id, ";S:")) == NULL)
425 /* No S-field, use status register instead of device id. */
426 unsigned int bit_status;
427 r = hpmud_get_device_status(dd, &bit_status);
428 // if (!(r == HPMUD_R_OK || r == HPMUD_R_DEVICE_BUSY))
431 status = 5000+r; /* no 8-bit status, return some error */
435 if (DEVICE_IS_OOP(bit_status))
436 status = VSTATUS_OOPA;
437 else if (DEVICE_PAPER_JAMMED(bit_status))
438 status = VSTATUS_PAJM;
439 else if (DEVICE_IO_TRAP(bit_status))
440 status = VSTATUS_CARS;
444 /* Valid S-field, get version number. */
453 /* Position pointer to printer state subfield. */
468 BUG("WARNING: unknown S-field version=%d\n", ver);
473 /* Extract VStatus.*/
475 HEX2INT(*pSf, status);
477 status = status << 4;
478 HEX2INT(*pSf, status);
487 static int device_discovery()
489 char buf[HPMUD_LINE_SIZE*64];
490 int cnt=0, bytes_read, r=1;
491 enum HPMUD_RESULT stat;
493 stat = hpmud_probe_devices(HPMUD_BUS_ALL, buf, sizeof(buf), &cnt, &bytes_read);
495 if (stat != HPMUD_R_OK)
500 fprintf(stdout, "direct hp:/no_device_found \"Unknown\" \"hp no_device_found\"\n");
502 fprintf(stdout, "direct hp \"Unknown\" \"HP Printer (HPLIP)\"\n");
505 fprintf(stdout, "%s", buf);
514 static int device_event(const char *dev, const char *printer, int code,
515 const char *username, const char *jobid, const char *title)
517 DBusMessage * msg = NULL;
518 int id = atoi(jobid);
520 if (dbus_conn == NULL)
523 msg = dbus_message_new_signal(DBUS_PATH, DBUS_INTERFACE, "Event");
527 BUG("dbus message is NULL!\n");
531 dbus_message_append_args(msg,
532 DBUS_TYPE_STRING, &dev,
533 DBUS_TYPE_STRING, &printer,
534 DBUS_TYPE_UINT32, &code,
535 DBUS_TYPE_STRING, &username,
536 DBUS_TYPE_UINT32, &id,
537 DBUS_TYPE_STRING, &title,
540 if (!dbus_connection_send(dbus_conn, msg, NULL))
542 BUG("dbus message send failed!\n");
546 dbus_connection_flush(dbus_conn);
547 dbus_message_unref(msg);
554 dbus_error_init(&dbus_err);
555 dbus_conn = dbus_bus_get(DBUS_BUS_SYSTEM, &dbus_err);
557 if (dbus_error_is_set(&dbus_err))
559 BUG("dBus Connection Error (%s)!\n", dbus_err.message);
560 dbus_error_free(&dbus_err);
563 if (dbus_conn == NULL)
571 static int device_event(const char *dev, const char *printer, int code,
572 const char *username, const char *jobid, const char *title)
580 #endif /* HAVE_DBUS */
582 /* Check printer status, if a valid error state, loop until error condition is cleared. */
583 static int loop_test(HPMUD_DEVICE dd, HPMUD_CHANNEL cd, struct pjl_attributes *pa,
584 const char *dev, const char *printer, const char *username, const char *jobid, const char *title)
587 const char *pstate, *old_state=NULL;
591 status = get_printer_status(dd, cd, pa);
592 map_ipp_printer_state_reason(status, &pstate);
594 /* Check for user intervention errors. */
595 if (strstr(pstate, "error"))
597 if (pstate != old_state)
601 /* Clear old error. */
602 // device_event(dev, printer, status, username, jobid, title);
603 fprintf(stderr, "STATE: -%s\n", old_state);
607 device_event(dev, printer, status, username, jobid, title);
608 fprintf(stderr, "STATE: +%s\n", pstate);
611 BUG("ERROR: %d %s; will retry in %d seconds...\n", status, pstate, RETRY_TIMEOUT);
612 sleep(RETRY_TIMEOUT);
616 /* Clear any old state. */
618 fprintf(stderr, "STATE: -%s\n", old_state);
620 /* Check for system errors. */
621 if (status >= 5000 && status <= 5999)
624 device_event(dev, printer, status, username, jobid, title);
625 BUG("ERROR: %d device communication error!\n", status);
637 int main(int argc, char *argv[])
641 int len, status, cnt, exit_stat=BACKEND_FAILED;
642 char buf[HPMUD_BUFFER_SIZE];
643 struct hpmud_model_attributes ma;
644 struct pjl_attributes pa;
647 int n, total=0, retry=0, size, pages;
648 enum HPMUD_RESULT stat;
649 char *printer = getenv("PRINTER");
652 // device_uri job-id user title copies options
654 openlog("hp", LOG_PID, LOG_DAEMON);
660 const char *arg = argv[1];
661 if ((arg[0] == '-') && (arg[1] == 'h'))
663 fprintf(stdout, "HP Linux Imaging and Printing System\nCUPS Backend %s\n", VERSION);
664 fprintf(stdout, "(c) 2003-2008 Copyright Hewlett-Packard Development Company, LP\n");
670 exit (device_discovery());
672 if (argc < 6 || argc > 7)
674 BUG("ERROR: invalid usage: device_uri job-id user title copies options [file]\n");
680 fd = 0; /* use stdin. */
685 if ((fd = open(argv[6], O_RDONLY)) < 0) /* use specified file */
687 BUG("ERROR: unable to open print file %s: %m\n", argv[6]);
690 copies = atoi(argv[4]);
693 signal(SIGTERM, SIG_IGN);
696 /* Get any parameters needed for DeviceOpen. */
697 hpmud_query_model(argv[0], &ma);
699 DBG("job start %s prt_mode=%d statustype=%d\n", argv[0], ma.prt_mode, ma.statustype);
702 if (strcasestr(argv[0], ":/net") == NULL && (ma.statustype==HPMUD_STATUSTYPE_PJL || ma.statustype==HPMUD_STATUSTYPE_PJLPML))
705 device_event(argv[0], printer, EVENT_START_JOB, argv[2], argv[1], argv[3]);
707 /* Write print file. */
714 fputs("PAGE: 1 1\n", stderr);
715 lseek(fd, 0, SEEK_SET);
718 while ((len = read(fd, buf, sizeof(buf))) > 0)
725 /* Got some data now open the hp device. This will handle any HPIJS device contention. */
728 fputs("STATE: +connecting-to-device\n", stderr);
730 /* Open hp device. */
731 while ((stat = hpmud_open_device(argv[0], ma.prt_mode, &hd)) != HPMUD_R_OK)
733 if (getenv("CLASS") != NULL)
735 /* The job was submitted to a class and not a specific queue. Abort to
736 * give another class member a chance to print the job.
738 BUG("INFO: open device failed stat=%d: %s; trying next printer in class...\n", stat, argv[0]);
739 sleep (5); /* Prevent job requeuing too quickly. */
743 if (stat != HPMUD_R_DEVICE_BUSY)
745 BUG("ERROR: open device failed stat=%d: %s\n", stat, argv[0]);
749 /* Display user error. */
750 device_event(argv[0], printer, 5000+stat, argv[2], argv[1], argv[3]);
752 BUG("INFO: open device failed stat=%d: %s; will retry in %d seconds...\n", stat, argv[0], RETRY_TIMEOUT);
753 sleep(RETRY_TIMEOUT);
759 /* Clear user error. */
760 device_event(argv[0], printer, VSTATUS_PRNT, argv[2], argv[1], argv[3]);
764 while ((stat = hpmud_open_channel(hd, HPMUD_S_PRINT_CHANNEL, &cd)) != HPMUD_R_OK)
766 if (stat != HPMUD_R_DEVICE_BUSY)
768 BUG("ERROR: cannot open channel %s\n", HPMUD_S_PRINT_CHANNEL);
771 device_event(argv[0], printer, 5000+stat, argv[2], argv[1], argv[3]);
772 BUG("INFO: open print channel failed stat=%d; will retry in %d seconds...\n", stat, RETRY_TIMEOUT);
773 sleep(RETRY_TIMEOUT);
779 /* Clear user error. */
780 device_event(argv[0], printer, VSTATUS_PRNT, argv[2], argv[1], argv[3]);
784 fputs("STATE: -connecting-to-device\n", stderr);
788 /* Enable unsolicited status. */
789 hpmud_write_channel(hd, cd, pjl_ustatus_cmd, sizeof(pjl_ustatus_cmd)-1, 5, &len);
792 pthread_mutex_init(&pa.mutex, NULL);
793 pthread_cond_init(&pa.done_cond, NULL);
794 pthread_create(&pa.tid, NULL, (void *(*)(void*))pjl_read_thread, (void *)&pa);
797 /* Clear any errors left over from a previous job. */
798 fprintf(stderr, "STATE: -%s\n", "media-empty-error,media-jam-error,hplip.plugin-error,"
799 "cover-open-error,toner-empty-error,other");
803 stat = hpmud_write_channel(hd, cd, buf+total, size, EXCEPTION_TIMEOUT, &n);
807 /* IO error, get printer status. */
808 if (loop_test(hd, cd, &pa, argv[0], printer, argv[2], argv[1], argv[3]))
810 exit_stat = BACKEND_STOP; /* stop queue */
816 /* Data was sent to device successfully. */
819 /* Laserjets have a large data buffer, so manually check for operator intervention condition. */
820 if (loop_test(hd, cd, &pa, argv[0], printer, argv[2], argv[1], argv[3]))
822 exit_stat = BACKEND_STOP; /* stop queue */
829 } /* while (size > 0) */
830 } /* while ((len = read(fd, buf, HPLIP_BUFFER_SIZE)) > 0) */
831 } /* while (copies > 0) */
833 DBG("job end %s prt_mode=%d statustype=%d total=%d\n", argv[0], ma.prt_mode, ma.statustype, total);
835 /* Note read() could return zero bytes. Check for bogus null print job. */
838 exit_stat = BACKEND_OK; /* leave queue up */
839 BUG("ERROR: null print job total=%d\n", total);
843 if (pa.pjl_device && pa.tid)
845 pthread_mutex_lock(&pa.mutex);
847 pthread_mutex_unlock(&pa.mutex);
848 hpmud_write_channel(hd, cd, pjl_job_end_cmd, sizeof(pjl_job_end_cmd)-1, 5, &len);
850 /* Look for job end status. */
851 for (cnt=0; cnt<10; cnt++)
853 if (loop_test(hd, cd, &pa, argv[0], printer, argv[2], argv[1], argv[3]))
855 exit_stat = BACKEND_OK; /* leave queue up */
858 pthread_mutex_lock(&pa.mutex);
859 pages = pa.eoj_pages;
860 pthread_mutex_unlock(&pa.mutex);
863 DBG("job end pages=%d\n", pages);
866 DBG("waiting for job end status...\n");
870 hpmud_write_channel(hd, cd, pjl_ustatus_off_cmd, sizeof(pjl_ustatus_off_cmd)-1, 5, &len);
872 else if ((ma.prt_mode != HPMUD_UNI_MODE) && (ma.statustype == HPMUD_STATUSTYPE_SFIELD))
874 /* Wait for printer to receive all data before closing print channel. Otherwise data can be truncated. */
875 status = get_printer_status(hd, cd, &pa);
878 /* Got valid status, wait for idle. */
880 while ((status != VSTATUS_IDLE) && (status < 5000) && (cnt < 5))
883 status = get_printer_status(hd, cd, &pa);
890 /* Just use fixed delay for uni-di, VSTATUS devices and laserjets without pjl. */
894 exit_stat = BACKEND_OK;
895 fputs("INFO: ready to print\n", stderr);
899 device_event(argv[0], printer, EVENT_END_JOB, argv[2], argv[1], argv[3]);
901 if (pa.pjl_device && pa.tid)
903 /* Gracefully kill the pjl_read_thread. */
904 pthread_mutex_lock(&pa.mutex);
907 pthread_cond_wait(&pa.done_cond, &pa.mutex);
908 pthread_mutex_unlock(&pa.mutex);
909 pthread_cancel(pa.tid);
910 pthread_mutex_destroy(&pa.mutex);
911 pthread_cond_destroy(&pa.done_cond);
915 hpmud_close_channel(hd, cd);
917 hpmud_close_device(hd);