Tizen 2.0 Release
[platform/upstream/hplip.git] / prnt / backend / hp.c
1 /*****************************************************************************\
2
3   hp.c - hp cups backend 
4  
5   (c) 2004-2008 Copyright Hewlett-Packard Development Company, LP
6
7   Permission is hereby granted, free of charge, to any person obtaining a copy 
8   of this software and associated documentation files (the "Software"), to deal 
9   in the Software without restriction, including without limitation the rights 
10   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
11   of the Software, and to permit persons to whom the Software is furnished to do 
12   so, subject to the following conditions:
13
14   The above copyright notice and this permission notice shall be included in all
15   copies or substantial portions of the Software.
16
17   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
18   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 
19   FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 
20   COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 
21   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
22   WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
24 \*****************************************************************************/
25
26 #ifndef _GNU_SOURCE
27 #define _GNU_SOURCE
28 #endif
29
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <netinet/in.h>
33 #include <netdb.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <fcntl.h>
37 #include <string.h>
38 #include <unistd.h>
39 #include <stdarg.h>
40 #include <syslog.h>
41 #include <ctype.h>
42 #include <pthread.h>
43 #ifdef HAVE_DBUS
44 #include <dbus/dbus.h>
45 #endif
46 #include "hpmud.h"
47 #include <signal.h>
48
49 //#define HP_DEBUG
50
51 enum BACKEND_RESULT
52 {
53   BACKEND_OK = 0,
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 */
58 };
59
60 struct pjl_attributes
61 {
62    int pjl_device;   /* 0=disabled, 1=enabled */
63    int current_status;
64    int eoj_pages;        /* end-of-job pages */
65    int abort;         /* 0=no, 1=yes */
66    int done;          /* 0=no, 1=yes */
67    HPMUD_DEVICE dd;
68    HPMUD_CHANNEL cd;
69    pthread_t tid;
70    pthread_mutex_t mutex;
71    pthread_cond_t done_cond;
72 };
73
74 #define _STRINGIZE(x) #x
75 #define STRINGIZE(x) _STRINGIZE(x)
76
77 #define BUG(args...) bug(__FILE__ " " STRINGIZE(__LINE__) ": " args)
78
79 #ifdef HP_DEBUG
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)
83 #else
84    #define DBG(args...)
85    #define DBG_DUMP(data, size)
86    #define DBG_SZ(args...)
87 #endif
88
89 #define RETRY_TIMEOUT 30  /* seconds */
90 #define EXCEPTION_TIMEOUT 45 /* seconds */
91
92 #define NFAULT_BIT  0x08
93 #define PERROR_BIT  0x20
94
95 #define OOP             (NFAULT_BIT | PERROR_BIT)
96 #define JAMMED          (PERROR_BIT)
97 #define ERROR_TRAP      (0)
98
99 #define STATUS_MASK (NFAULT_BIT | PERROR_BIT)
100
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)
104
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'
108
109 /* Definitions for hpLogLevel in cupsd.conf. */
110 #define BASIC_LOG          1
111 #define SAVE_PCL_FILE      2
112 #define SAVE_INPUT_RASTERS 4
113 #define SEND_TO_PRINTER_ALSO    8
114
115 /* Actual vstatus codes are mapped to 1000+vstatus for DeviceError messages. */ 
116 typedef enum
117 {
118    VSTATUS_IDLE = 1000,
119    VSTATUS_BUSY,
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 */
140 } VSTATUS;
141
142 #define EVENT_START_JOB 500
143 #define EVENT_END_JOB 501
144
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";
149
150 #ifdef HAVE_DBUS
151 #define DBUS_INTERFACE "com.hplip.StatusService"
152 #define DBUS_PATH "/"
153 static DBusError dbus_err;
154 static DBusConnection *dbus_conn;
155 #endif
156
157 static int bug(const char *fmt, ...)
158 {
159    char buf[256];
160    va_list args;
161    int n;
162
163    va_start(args, fmt);
164
165    if ((n = vsnprintf(buf, 256, fmt, args)) == -1)
166       buf[255] = 0;     /* output was truncated */
167
168    fprintf(stderr, "%s", buf);
169    syslog(LOG_ERR, "%s", buf);
170
171    fflush(stderr);
172    va_end(args);
173    return n;
174 }
175
176 #ifdef HP_DEBUG
177 static void sysdump(const void *data, int size)
178 {
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.
181      */
182
183     unsigned char *p = (unsigned char *)data;
184     unsigned char c;
185     int n;
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++) {
191         if (n%16 == 1) {
192             /* store address for this line */
193             snprintf(addrstr, sizeof(addrstr), "%.4d", (int)((p-(unsigned char *)data) & 0xffff));
194         }
195             
196         c = *p;
197         if (isprint(c) == 0) {
198             c = '.';
199         }
200
201         /* store hex str (for left side) */
202         snprintf(bytestr, sizeof(bytestr), "%02X ", *p);
203         strncat(hexstr, bytestr, sizeof(hexstr)-strlen(hexstr)-1);
204
205         /* store char str (for right side) */
206         snprintf(bytestr, sizeof(bytestr), "%c", c);
207         strncat(charstr, bytestr, sizeof(charstr)-strlen(charstr)-1);
208
209         if(n%16 == 0) { 
210             /* line completed */
211             DBG_SZ("[%4.4s]   %-50.50s  %s\n", addrstr, hexstr, charstr);
212             hexstr[0] = 0;
213             charstr[0] = 0;
214         }
215         p++; /* next byte */
216     }
217
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);
221     }
222 }
223 #endif
224
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)
227 {
228    
229    if (status >= 1000 && status <= 1999)
230    {
231       /* inkjet vstatus */
232       switch (status)
233       {
234          case VSTATUS_IDLE:
235          case VSTATUS_PRNT:
236             *state_msg = "none";
237             break;
238          case VSTATUS_OOPA:
239             *state_msg = "media-empty-error";
240             break;
241          case(VSTATUS_PAJM):
242             *state_msg = "media-jam-error";
243             break;
244          default:
245             *state_msg = "other";
246             break;
247       }
248    }
249    else if (status >= 10000 && status <= 55999)
250    {
251       /* laserjet pjl status */
252       if (status >= 10000 && status <= 10999)
253          *state_msg = "none";
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";
262       else
263          *state_msg = "other";      /* 40017 - cartridge E-LABEL is unreadable (ie: ljp1005) */ 
264    }
265    else
266    {
267       /* Assume hpmud error */
268       *state_msg = "other";
269    }
270
271    return 0;
272 }
273
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)
275 {
276    enum HPMUD_RESULT stat;
277    int len;
278
279    *bytes_read = 0;
280
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)
284       goto bugout;
285
286    buf[len]=0;
287
288    DBG("pjl result len=%d\n", len);
289    DBG_DUMP(buf, len);
290
291    *bytes_read = len;
292
293    stat = HPMUD_R_OK;
294
295 bugout:
296    return stat;
297 }
298
299 static int parse_pjl_job_end(char *buf, int *pages)
300 {
301    char *p, *tail;
302    int stat=0;
303
304    if (buf[0] == 0)
305       goto bugout;
306
307    if ((p = strcasestr(buf, "ustatus job")) != NULL)
308    {
309       if (strncasecmp(p+13, "end", 3) == 0)
310       { 
311          stat = 1;   
312          if ((p = strcasestr(p+13+5, "pages=")) != NULL)
313             *pages = strtol(p+6, &tail, 10);
314       }
315    }
316
317 bugout:
318    return stat;
319 }
320
321 static int parse_pjl_device_status(char *buf, int *status)
322 {
323    char *p, *tail;
324    int stat=0;
325
326    if (buf[0] == 0)
327       goto bugout;
328
329    if ((p = strcasestr(buf, "code=")) != NULL)
330    {
331       *status = strtol(p+5, &tail, 10);
332       stat = 1;   
333    }
334
335 bugout:
336    return stat;
337 }
338
339 static void pjl_read_thread(struct pjl_attributes *pa)
340 {
341    enum HPMUD_RESULT stat;
342    int len, new_status, new_eoj;
343    char buf[1024];
344    
345    pthread_detach(pthread_self());
346
347    DBG("starting thread %d\n", (int)pa->tid);
348
349    pa->current_status = 10001;       /* default is ready */
350    pa->eoj_pages = pa->abort = pa->done = 0;
351
352    while (!pa->abort)
353    {
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))
356       {
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);
361          break;
362       }
363
364       if (stat == HPMUD_R_OK)
365       {
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);
370          if (new_status)
371             BUG("read new pjl status: %d\n", pa->current_status);
372          if (new_eoj)
373             BUG("read pjl job_end: %d\n", pa->eoj_pages);
374       }
375       else
376          sleep(1);
377    }
378
379    DBG("exiting thread %d abort=%d stat=%d\n", (int)pa->tid, pa->abort, stat);
380
381    pa->done=1;
382    pthread_cond_signal(&pa->done_cond);
383
384    return;
385 }
386
387 /* 
388  * get_printer_status
389  *
390  * inputs:
391  *   dd - device descriptor
392  *   pa - see pjl_attributes definition
393  *
394  * outputs:
395  *   return - printer status, 1000 to 1999 = inkjet vstatus, 5000 to 5999 = hpmud error, 10000 to 55999 = pjl status code
396  *    
397  */
398 static int get_printer_status(HPMUD_DEVICE dd, HPMUD_CHANNEL cd, struct pjl_attributes *pa)
399 {
400    char id[1024];
401    char *pSf;
402    int status, ver, len;
403    enum HPMUD_RESULT r;
404
405    if (pa->pjl_device)
406    {
407       pthread_mutex_lock(&pa->mutex);
408       status = pa->current_status;
409       pthread_mutex_unlock(&pa->mutex);
410    }
411    else
412    {
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))
416       if (r != HPMUD_R_OK)
417       {
418          status = 5000+r;      /* no deviceid, return some error */
419          goto bugout;
420       }
421    
422       /* Check for valid S-field in device id string. */
423       if ((pSf = strstr(id, ";S:")) == NULL)
424       {
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))
429          if (r != HPMUD_R_OK)
430          {
431             status = 5000+r;      /* no 8-bit status, return some error */
432             goto bugout;
433          }
434
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;
441       }
442       else
443       {
444          /* Valid S-field, get version number. */
445          pSf+=3;
446          ver = 0; 
447          HEX2INT(*pSf, ver);
448          pSf++;
449          ver = ver << 4;
450          HEX2INT(*pSf, ver);
451          pSf++;
452
453          /* Position pointer to printer state subfield. */
454          switch (ver)
455          {
456             case 0:
457             case 1:
458             case 2:
459                pSf+=12;
460                break;
461             case 3:
462                pSf+=14;
463                break;
464             case 4:
465                pSf+=18;
466                break;
467             default:
468                BUG("WARNING: unknown S-field version=%d\n", ver);
469                pSf+=12;
470                break;            
471          }
472
473          /* Extract VStatus.*/
474          status = 0; 
475          HEX2INT(*pSf, status);
476          pSf++;
477          status = status << 4;
478          HEX2INT(*pSf, status);
479          status += 1000;
480       }
481    }
482
483 bugout:
484    return status;
485 }
486
487 static int device_discovery()
488 {
489    char buf[HPMUD_LINE_SIZE*64];
490    int cnt=0, bytes_read, r=1;  
491    enum HPMUD_RESULT stat;
492
493    stat = hpmud_probe_devices(HPMUD_BUS_ALL, buf, sizeof(buf), &cnt, &bytes_read);
494
495    if (stat != HPMUD_R_OK)
496       goto bugout;
497
498    if (cnt == 0)
499 #ifdef HAVE_CUPS11
500       fprintf(stdout, "direct hp:/no_device_found \"Unknown\" \"hp no_device_found\"\n");
501 #else
502       fprintf(stdout, "direct hp \"Unknown\" \"HP Printer (HPLIP)\"\n");
503 #endif
504    else
505       fprintf(stdout, "%s", buf);
506
507    r = 0;
508
509 bugout:
510    return r;
511 }
512
513 #ifdef HAVE_DBUS
514 static int device_event(const char *dev, const char *printer, int code, 
515     const char *username, const char *jobid, const char *title)
516 {
517     DBusMessage * msg = NULL;
518     int id = atoi(jobid);
519
520     if (dbus_conn == NULL)
521       return 0;
522
523     msg = dbus_message_new_signal(DBUS_PATH, DBUS_INTERFACE, "Event");
524
525     if (NULL == msg)
526     {
527         BUG("dbus message is NULL!\n");
528         return 0;
529     }
530
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, 
538         DBUS_TYPE_INVALID);
539
540     if (!dbus_connection_send(dbus_conn, msg, NULL))
541     {
542         BUG("dbus message send failed!\n");
543         return 0;
544     }
545
546     dbus_connection_flush(dbus_conn);
547     dbus_message_unref(msg);
548
549     return 1;
550 }
551
552 int init_dbus(void)
553 {
554    dbus_error_init(&dbus_err);
555    dbus_conn = dbus_bus_get(DBUS_BUS_SYSTEM, &dbus_err);
556     
557    if (dbus_error_is_set(&dbus_err))
558    { 
559       BUG("dBus Connection Error (%s)!\n", dbus_err.message); 
560       dbus_error_free(&dbus_err); 
561    }
562
563    if (dbus_conn == NULL) 
564    { 
565       return 0; 
566    }
567
568    return 1;
569 }
570 #else
571 static int device_event(const char *dev, const char *printer, int code, 
572     const char *username, const char *jobid, const char *title)
573 {
574     return 1;
575 }
576 int init_dbus(void)
577 {
578    return 1;
579 }
580 #endif  /* HAVE_DBUS */
581
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)
585 {
586    int status, stat;
587    const char *pstate, *old_state=NULL;
588
589    while (1)
590    {
591       status = get_printer_status(dd, cd, pa);
592       map_ipp_printer_state_reason(status, &pstate);
593
594       /* Check for user intervention errors. */
595       if (strstr(pstate, "error"))
596       {
597          if (pstate != old_state)
598          {
599             if (old_state)
600             {
601                /* Clear old error. */
602 //               device_event(dev, printer, status, username, jobid, title);
603                fprintf(stderr, "STATE: -%s\n", old_state);
604             }
605
606             /* Display error. */
607             device_event(dev, printer, status, username, jobid, title);
608             fprintf(stderr, "STATE: +%s\n", pstate);
609             old_state = pstate;
610          }
611          BUG("ERROR: %d %s; will retry in %d seconds...\n", status, pstate, RETRY_TIMEOUT);
612          sleep(RETRY_TIMEOUT);
613          continue;
614       }
615
616       /* Clear any old state. */
617       if (old_state)
618          fprintf(stderr, "STATE: -%s\n", old_state);
619
620       /* Check for system errors. */
621       if (status >= 5000 && status <= 5999)
622       {
623          /* Display error. */
624          device_event(dev, printer, status, username, jobid, title);
625          BUG("ERROR: %d device communication error!\n", status);
626          stat = 1;
627       }
628       else
629          stat = 0;
630
631       break;   /* done */
632    }
633
634    return stat;
635 }
636
637 int main(int argc, char *argv[])
638 {
639    int fd;
640    int copies;
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;
645    HPMUD_DEVICE hd=-1;
646    HPMUD_CHANNEL cd=-1;
647    int n, total=0, retry=0, size, pages;
648    enum HPMUD_RESULT stat;
649    char *printer = getenv("PRINTER"); 
650    
651    //     0        1     2     3     4      5
652    // device_uri job-id user title copies options
653
654    openlog("hp", LOG_PID,  LOG_DAEMON);
655
656    pa.tid = 0;
657
658    if (argc > 1)
659    {
660       const char *arg = argv[1];
661       if ((arg[0] == '-') && (arg[1] == 'h'))
662       {
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");
665          exit(0);
666       }
667    }
668
669    if (argc == 1)
670       exit (device_discovery());
671
672    if (argc < 6 || argc > 7)
673    {
674       BUG("ERROR: invalid usage: device_uri job-id user title copies options [file]\n");
675       exit (1);
676    }
677
678    if (argc == 6)
679    {
680       fd = 0;         /* use stdin. */
681       copies = 1;
682    }
683    else
684    {
685       if ((fd = open(argv[6], O_RDONLY)) < 0)  /* use specified file */ 
686       {
687          BUG("ERROR: unable to open print file %s: %m\n", argv[6]);
688          exit (1);
689       }
690       copies = atoi(argv[4]);
691    }
692
693    signal(SIGTERM, SIG_IGN);
694    init_dbus();
695
696    /* Get any parameters needed for DeviceOpen. */
697    hpmud_query_model(argv[0], &ma);  
698
699    DBG("job start %s prt_mode=%d statustype=%d\n", argv[0], ma.prt_mode, ma.statustype); 
700
701    pa.pjl_device = 0;
702    if (strcasestr(argv[0], ":/net") == NULL && (ma.statustype==HPMUD_STATUSTYPE_PJL || ma.statustype==HPMUD_STATUSTYPE_PJLPML))
703       pa.pjl_device = 1;
704
705    device_event(argv[0], printer, EVENT_START_JOB, argv[2], argv[1], argv[3]);
706
707    /* Write print file. */
708    while (copies > 0)
709    {
710       copies--;
711
712       if (fd != 0)
713       {
714          fputs("PAGE: 1 1\n", stderr);
715          lseek(fd, 0, SEEK_SET);
716       }
717
718       while ((len = read(fd, buf, sizeof(buf))) > 0)
719       {
720          size=len;
721          total=0;
722
723          while (size > 0)
724          {
725             /* Got some data now open the hp device. This will handle any HPIJS device contention. */
726             if (hd <= 0)
727             {
728                fputs("STATE: +connecting-to-device\n", stderr);
729
730                /* Open hp device. */
731                while ((stat = hpmud_open_device(argv[0], ma.prt_mode, &hd)) != HPMUD_R_OK)
732                {
733                   if (getenv("CLASS") != NULL)
734                   {
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.
737                       */
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. */
740                      goto bugout;
741                   }
742
743                   if (stat != HPMUD_R_DEVICE_BUSY)
744                   {
745                      BUG("ERROR: open device failed stat=%d: %s\n", stat, argv[0]);
746                      goto bugout;
747                   }
748
749                   /* Display user error. */
750                   device_event(argv[0], printer, 5000+stat, argv[2], argv[1], argv[3]);
751
752                   BUG("INFO: open device failed stat=%d: %s; will retry in %d seconds...\n", stat, argv[0], RETRY_TIMEOUT);
753                   sleep(RETRY_TIMEOUT);
754                   retry = 1;
755                }
756
757                if (retry)
758                {
759                   /* Clear user error. */
760                   device_event(argv[0], printer, VSTATUS_PRNT, argv[2], argv[1], argv[3]);
761                   retry=0;
762                }
763
764                while ((stat = hpmud_open_channel(hd, HPMUD_S_PRINT_CHANNEL, &cd)) != HPMUD_R_OK)
765                {
766                   if (stat != HPMUD_R_DEVICE_BUSY)
767                   {
768                      BUG("ERROR: cannot open channel %s\n", HPMUD_S_PRINT_CHANNEL);
769                      goto bugout;
770                   }
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);
774                   retry = 1;
775                }
776
777                if (retry)
778                {
779                   /* Clear user error. */
780                   device_event(argv[0], printer, VSTATUS_PRNT, argv[2], argv[1], argv[3]);
781                   retry=0;
782                }          
783
784                fputs("STATE: -connecting-to-device\n", stderr);
785
786                if (pa.pjl_device)
787                {
788                   /* Enable unsolicited status. */
789                   hpmud_write_channel(hd, cd, pjl_ustatus_cmd, sizeof(pjl_ustatus_cmd)-1, 5, &len);
790                   pa.dd = hd;
791                   pa.cd = cd;
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);
795                }
796
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");
800
801             } /* if (hd <= 0) */
802
803             stat = hpmud_write_channel(hd, cd, buf+total, size, EXCEPTION_TIMEOUT, &n);
804
805             if (n != size)
806             {
807                /* IO error, get printer status. */
808                if (loop_test(hd, cd, &pa, argv[0], printer, argv[2], argv[1], argv[3]))
809                {
810                   exit_stat = BACKEND_STOP;  /* stop queue */
811                   goto bugout;
812                }
813             }
814             else
815             {
816                /* Data was sent to device successfully. */ 
817                if (pa.pjl_device)
818                {
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]))
821                   {
822                      exit_stat = BACKEND_STOP; /* stop queue */
823                      goto bugout;
824                   }
825                }
826             }
827             total+=n;
828             size-=n;
829          }   /* while (size > 0) */
830       }   /* while ((len = read(fd, buf, HPLIP_BUFFER_SIZE)) > 0) */
831    }   /* while (copies > 0) */
832
833    DBG("job end %s prt_mode=%d statustype=%d total=%d\n", argv[0], ma.prt_mode, ma.statustype, total); 
834
835    /* Note read() could return zero bytes. Check for bogus null print job. */
836    if (total==0)
837    {
838       exit_stat = BACKEND_OK; /* leave queue up */
839       BUG("ERROR: null print job total=%d\n", total);
840       goto bugout;
841    }
842
843    if (pa.pjl_device && pa.tid)
844    {
845       pthread_mutex_lock(&pa.mutex);
846       pa.eoj_pages=0;
847       pthread_mutex_unlock(&pa.mutex);
848       hpmud_write_channel(hd, cd, pjl_job_end_cmd, sizeof(pjl_job_end_cmd)-1, 5, &len);
849
850       /* Look for job end status. */
851       for (cnt=0; cnt<10; cnt++)
852       {
853          if (loop_test(hd, cd, &pa, argv[0], printer, argv[2], argv[1], argv[3]))
854          {
855             exit_stat = BACKEND_OK; /* leave queue up */
856             goto bugout;
857          }         
858          pthread_mutex_lock(&pa.mutex);
859          pages = pa.eoj_pages;
860          pthread_mutex_unlock(&pa.mutex);
861          if (pages > 0)
862          {
863             DBG("job end pages=%d\n", pages);
864             break;
865          }
866          DBG("waiting for job end status...\n");
867          sleep(2);
868       }
869
870       hpmud_write_channel(hd, cd, pjl_ustatus_off_cmd, sizeof(pjl_ustatus_off_cmd)-1, 5, &len);
871    }
872    else if ((ma.prt_mode != HPMUD_UNI_MODE) && (ma.statustype == HPMUD_STATUSTYPE_SFIELD))
873    {
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);
876       if (status < 5000)
877       {
878          /* Got valid status, wait for idle. */
879          cnt=0;
880          while ((status != VSTATUS_IDLE) && (status < 5000) && (cnt < 5))
881          {
882            sleep(2);
883            status = get_printer_status(hd, cd, &pa);
884            cnt++;
885          } 
886       }
887    }
888    else
889    {
890       /* Just use fixed delay for uni-di, VSTATUS devices and laserjets without pjl. */
891       sleep(8);
892    }
893     
894    exit_stat = BACKEND_OK;
895    fputs("INFO: ready to print\n", stderr);
896
897 bugout:
898
899    device_event(argv[0], printer, EVENT_END_JOB, argv[2], argv[1], argv[3]);
900
901    if (pa.pjl_device && pa.tid)
902    {
903       /* Gracefully kill the pjl_read_thread. */
904       pthread_mutex_lock(&pa.mutex);
905       pa.abort=1;
906       while (!pa.done)
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);
912    }
913
914    if (cd >= 0)
915       hpmud_close_channel(hd, cd);
916    if (hd >= 0)
917       hpmud_close_device(hd);   
918    if (fd != 0)
919       close(fd);
920
921    exit (exit_stat);
922 }
923