1 /*****************************************************************************\
2 services.cpp : HP Inkjet Server
4 Copyright (c) 2001 - 2004, Hewlett-Packard Co.
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
10 1. Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
15 3. Neither the name of the Hewlett-Packard nor the names of its
16 contributors may be used to endorse or promote products derived
17 from this software without specific prior written permission.
19 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 NOT LIMITED TO, PATENT INFRINGEMENT; PROCUREMENT OF SUBSTITUTE GOODS OR
25 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
28 IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 POSSIBILITY OF SUCH DAMAGE.
30 \*****************************************************************************/
42 #include "ijs_server.h"
46 #if defined(HAVE_LIBHPIP) && defined(HAVE_DBUS)
47 #include <dbus/dbus.h>
48 #define DBUS_INTERFACE "com.hplip.StatusService"
50 static DBusError dbus_err;
51 static DBusConnection *dbus_conn;
53 void SendDbusMessage (const char *dev, const char *printer, int code,
54 const char *username, const int jobid, const char *title);
56 void SendDbusMessage (const char *dev, const char *printer, int code,
57 const char *username, const int jobid, const char *title)
62 int UXServices::InitDuplexBuffer()
64 /* Free buffer if new page size in middle of print job. */
66 delete [] RastersOnPage;
68 delete [] KRastersOnPage;
70 /* Calculate duplex page buffer */
71 CurrentRaster = ph.height - 1; /* Height = physical page in pixels */
72 RastersOnPage = (BYTE **) new BYTE[(ph.height) * sizeof (BYTE *)];
73 KRastersOnPage = (BYTE **) new BYTE[(ph.height) * sizeof (BYTE *)];
74 for (int i = 0; i < ph.height; i++)
76 RastersOnPage[i] = NULL;
77 KRastersOnPage[i] = NULL;
82 int UXServices::SendBackPage()
85 int i = CurrentRaster+1;
91 if ((err = pJob->SendRasters(KRastersOnPage[i], RastersOnPage[i])) != NO_ERROR)
96 if ((err = pJob->SendRasters(RastersOnPage[i])) != NO_ERROR)
100 if (RastersOnPage[i])
101 delete [] RastersOnPage[i];
102 if (KRastersOnPage[i])
103 delete [] KRastersOnPage[i];
107 CurrentRaster = ph.height - 1; /* reset raster index */
112 static unsigned char xmask[] =
124 int UXServices::ProcessRaster(char *raster, char *k_raster)
126 if (!((pPC->QueryDuplexMode() == DUPLEXMODE_BOOK) && pPC->RotateImageForBackPage() && BackPage))
129 return pJob->SendRasters((unsigned char *)k_raster, (unsigned char *)raster);
131 return pJob->SendRasters((unsigned char *)raster);
135 if (CurrentRaster < 0)
144 RastersOnPage[CurrentRaster] = NULL;
148 new_raster_size = pPC->InputPixelsPerRow() * 3;
149 new_raster = new BYTE[new_raster_size];
152 BUG("unable to create duplex buffer, size=%d: %m\n", new_raster_size);
155 memset(new_raster, 0xFF, new_raster_size);
156 RastersOnPage[CurrentRaster] = new_raster;
157 BYTE *p = new_raster + new_raster_size - 3;
158 for (i = 0; i < new_raster_size; i += 3)
160 memcpy (p, raster+i, 3); /* rotate rgb image */
165 if (k_raster == NULL)
167 KRastersOnPage[CurrentRaster] = NULL;
171 new_raster_size = (pPC->InputPixelsPerRow() + 7) >> 3;
172 new_raster = new BYTE[new_raster_size];
175 BUG("unable to create black duplex buffer, size=%d: %m\n", new_raster_size);
178 memset(new_raster, 0, new_raster_size);
179 KRastersOnPage[CurrentRaster] = new_raster;
180 w = pPC->InputPixelsPerRow();
183 if (k_raster[i>>3] & xmask[i&7])
184 new_raster[(w-i)>>3] |= xmask[(w-i)&7]; /* rotate k image */
186 int k = ((w + 7) / 8) * 8 - w;
189 new_raster[0] = c & k_raster[new_raster_size-1];
202 * Check models.xml for bi-di flag and also check the
203 * device id string for integrity. Some devices return
204 * device id without some expected fields.
207 BOOL UXServices::CanDoBiDi ()
210 struct hpmud_model_attributes ma;
213 // Check for CUPS environment
215 if ((hpDev = getenv ("DEVICE_URI")) == NULL)
220 // Check for HP Backend
222 if (strncmp (hpDev, "hp:", 3))
227 // Check io-mode in models.xml for this device
229 hpmud_query_model(hpDev, &ma);
231 if (ma.prt_mode == HPMUD_UNI_MODE)
235 if (hpmud_open_device(hpDev, ma.prt_mode, &hpFD) != HPMUD_R_OK)
239 memset (strDevID, 0, 512);
240 if ((ReadDeviceID ((BYTE *) strDevID, 512)) != NO_ERROR)
245 // Check if this is a laser device
246 if (strstr (strDevID, "Laser") || strstr (strDevID, "laser"))
251 // Check if device id is complete
252 if (!(strstr (strDevID, ";S:")) && !(strstr (strDevID, "VSTATUS")))
261 BOOL UXServices::CanDoBiDi ()
266 #endif // HAVE_LIBHPIP
268 UXServices::UXServices():SystemServices()
270 constructor_error = NO_ERROR;
273 // instead of InitDeviceComm(), just do...
274 IOMode.bDevID = IOMode.bStatus = FALSE; /* uni-di support is default */
278 /* Check for CUPS environment and HP backend. */
279 if ((hpDev = getenv("DEVICE_URI")) != NULL)
281 if (strncmp(hpDev, "hp:", 3) == 0)
284 hplip_ModelQuery(hpDev, &ma); /* check io-mode in models.xml for this device */
285 if (ma.prt_mode != UNI_MODE)
287 if ((hpFD = hplip_OpenHP(hpDev, &ma)) >= 0)
289 InitDeviceComm(); /* lets try bi-di support */
291 if(IOMode.bDevID == FALSE)
292 BUG("unable to set bi-di for hp backend\n");
302 if (IOMode.bDevID == FALSE)
304 BUG ("Unable to set bi-di for hp backend\n");
308 Quality = QUALITY_NORMAL;
309 MediaType = MEDIA_PLAIN;
321 MediaPosition = sourceTrayAuto;
323 strcpy(ph.cs, "sRGB");
325 DisplayStatus = NODISPLAYSTATUS;
330 m_pbyPclBuffer = NULL;
331 m_iPclBufferSize = BUFFER_CHUNK_SIZE;
332 m_iCurPclBufferPos = 0;
334 m_bSpeedMechEnabled = FALSE;
337 UXServices::~UXServices()
339 if (m_bSpeedMechEnabled)
345 delete [] RastersOnPage;
347 delete [] KRastersOnPage;
350 hpmud_close_device(hpFD);
358 DRIVER_ERROR UXServices::ToDevice(const BYTE * pBuffer, DWORD * Count)
360 if (OutputPath == -1)
365 if (m_bSpeedMechEnabled)
367 if ((CopyData (pBuffer, *Count)) == 0)
376 fwrite (pBuffer, 1, *Count, outfp);
377 if (!(m_iLogLevel & SEND_TO_PRINTER))
384 /* Write must be not-buffered, don't use streams */
385 if (write(OutputPath, pBuffer, *Count) != (ssize_t)*Count)
389 BUG("unable to write to output, fd=%d, count=%d: %m\n", OutputPath, *Count);
397 BOOL UXServices::GetStatusInfo (BYTE * bStatReg)
401 if (hpmud_get_device_status(hpFD, &s) == HPMUD_R_OK)
410 DRIVER_ERROR UXServices::ReadDeviceID (BYTE * strID, int iSize)
414 hpmud_get_device_id(hpFD, (char *)strID, iSize, &len);
422 const char *szPJLHeader = "@PJL SET JOBATTR=\"JobAcct7=HPPrintView.exe\"\012";
423 int UXServices::GetPJLHeaderBuffer (char **szPJLBuffer)
425 *szPJLBuffer = (char *) szPJLHeader;
426 return strlen (szPJLHeader);
428 #endif // HP_PRINTVIEW
430 BOOL UXServices::GetVerticalAlignmentValue(BYTE* cVertAlignVal)
435 *cVertAlignVal = (BYTE)VertAlign;
439 BOOL UXServices::GetVertAlignFromDevice()
442 if ((VertAlign = ReadHPVertAlign(hpFD)) == -1)
448 void UXServices::DisplayPrinterStatus (DISPLAY_STATUS ePrinterStatus)
450 DisplayStatus = ePrinterStatus;
453 DRIVER_ERROR UXServices::BusyWait (DWORD msec)
455 switch (DisplayStatus)
457 case DISPLAY_ERROR_TRAP:
458 case DISPLAY_COMM_PROBLEM:
459 case DISPLAY_PRINTER_NOT_SUPPORTED:
460 case DISPLAY_OUT_OF_PAPER:
461 case DISPLAY_PHOTOTRAY_MISMATCH:
462 case DISPLAY_TOP_COVER_OPEN:
463 case DISPLAY_NO_COLOR_PEN:
464 case DISPLAY_NO_BLACK_PEN:
465 case DISPLAY_NO_PENS:
466 BUG("WARNING: printer bi-di error=%d\n", DisplayStatus);
467 DisplayStatus = DISPLAY_PRINTING_CANCELED;
468 return JOB_CANCELED; /* bail-out otherwise APDK will wait forever */
475 const char * UXServices::GetDriverMessage (DRIVER_ERROR err)
479 /* Map driver error to text message. TODO: text needs to be localized. */
482 case(WARN_MODE_MISMATCH):
483 p = "printmode mismatch with pen, tray, etc.";
485 case(WARN_LOW_INK_BOTH_PENS):
486 p = "both pens have low ink";
488 case(WARN_LOW_INK_BLACK):
489 p = "black pen has low ink";
491 case(WARN_LOW_INK_COLOR):
492 p = "color pen has low ink";
494 case(WARN_LOW_INK_PHOTO):
495 p = "photo pen has low ink";
497 case(WARN_LOW_INK_GREY):
498 p = "grey pen has low ink";
500 case(WARN_LOW_INK_BLACK_PHOTO):
501 p = "black photo has low ink";
503 case(WARN_LOW_INK_COLOR_PHOTO):
504 p = "color photo pen has low ink";
506 case(WARN_LOW_INK_GREY_PHOTO):
507 p = "grey photo pen has low ink";
509 case(WARN_LOW_INK_COLOR_GREY):
510 p = "grey pen has low ink";
512 case(WARN_LOW_INK_COLOR_GREY_PHOTO):
513 p = "color grey photo pen has low ink";
515 case(WARN_LOW_INK_COLOR_BLACK_PHOTO):
516 p = "color back pen has low ink";
518 case(WARN_LOW_INK_CYAN):
519 p = "cyan has low ink";
521 case(WARN_LOW_INK_MAGENTA):
522 p = "magenta has low ink";
524 case(WARN_LOW_INK_YELLOW):
525 p = "yellow has low ink";
527 case(WARN_LOW_INK_MULTIPLE_PENS):
528 p = "more that one ink is low";
530 case(WARN_FULL_BLEED_UNSUPPORTED):
531 p = "fullbleed is not supported";
533 case(WARN_FULL_BLEED_3SIDES):
534 p = "fullbleed is 3 sides";
536 case(WARN_FULL_BLEED_PHOTOPAPER_ONLY):
537 p = "fullbleed photo paper only";
539 case(WARN_FULL_BLEED_3SIDES_PHOTOPAPER_ONLY):
540 p = "fullbleed 3 sides photo paper only";
542 case(WARN_ILLEGAL_PAPERSIZE):
543 p = "illegal paper size";
545 case(WARN_INVALID_MEDIA_SOURCE):
546 p = "invalid media source";
550 BUG("driver error=%d\n", err);
556 int UXServices::MapPaperSize (float width, float height)
561 /* Map gs paper sizes to APDK paper sizes, or do custom. */
563 for (i=0; i<MAX_PAPER_SIZE; i++)
565 r = pPC->SetPaperSize ((PAPER_SIZE)i);
570 dx = width > pPC->PhysicalPageSizeX () ? width - pPC->PhysicalPageSizeX () : pPC->PhysicalPageSizeX () - width;
571 dy = height > pPC->PhysicalPageSizeY () ? height - pPC->PhysicalPageSizeY () : pPC->PhysicalPageSizeY () - height;
573 if ((dx < 0.05) && (dy < 0.05))
575 size = i; /* found standard paper size */
580 if (size == CUSTOM_SIZE)
581 pPC->SetCustomSize (width, height);
583 if ((r = pPC->SetPaperSize ((PAPER_SIZE)size, FullBleed)) != NO_ERROR)
587 BUG("unable to set paper size=%d, err=%d, width=%0.5g, height=%0.5g\n", size, r, width, height);
591 BUG("warning setting paper size=%d, err=%d, width=%0.5g, height=%0.5g\n", size, r, width, height);
594 * Call failed, reset our PaperWidth and PaperHeight values.
595 * This ensures that we return correct values when gs queries for printable area.
598 PaperWidth = pPC->PhysicalPageSizeX ();
599 PaperHeight = pPC->PhysicalPageSizeY ();
603 PaperWidth = pPC->PhysicalPageSizeX ();
604 PaperHeight = pPC->PhysicalPageSizeY ();
609 void UXServices::ResetIOMode (BOOL bDevID, BOOL bStatus)
613 IOMode.bDevID = bDevID;
614 IOMode.bStatus = bStatus;
615 pPC->ResetIOMode (bDevID, bStatus);
619 void UXServices::InitSpeedMechBuffer ()
625 m_pbyPclBuffer = new BYTE[m_iPclBufferSize + 2];
632 int UXServices::SendPreviousPage ()
635 if (m_bSpeedMechEnabled == FALSE)
640 if (m_iPageCount == 1)
644 m_bSpeedMechEnabled = FALSE;
645 err = ToDevice (m_pbyPclBuffer, (DWORD *) &m_iCurPclBufferPos);
650 m_bSpeedMechEnabled = TRUE;
651 m_iCurPclBufferPos = 0;
653 // Request the printer to inject speed mech command. Also, let it know this is not the last page
655 pPC->SetPrinterHint (SPEED_MECH_HINT, 0);
659 int UXServices::CopyData (const BYTE *pBuffer, DWORD iCount)
661 if (m_iCurPclBufferPos + (int) iCount < m_iPclBufferSize)
663 memcpy (m_pbyPclBuffer + m_iCurPclBufferPos, pBuffer, iCount);
664 m_iCurPclBufferPos += iCount;
667 BYTE *p = new BYTE[m_iPclBufferSize + BUFFER_CHUNK_SIZE + 2];
670 m_bSpeedMechEnabled = FALSE;
673 memcpy (p, m_pbyPclBuffer, m_iCurPclBufferPos);
674 delete [] m_pbyPclBuffer;
676 memcpy (m_pbyPclBuffer + m_iCurPclBufferPos, pBuffer, iCount);
677 m_iCurPclBufferPos += iCount;
678 m_iPclBufferSize += BUFFER_CHUNK_SIZE;
682 // Note that this is good only for VIP printers
683 const char *pbySpeedMechCmd = "\x1B*o5W\x0D\x02\x00";
685 void UXServices::SendLastPage ()
687 if (m_pbyPclBuffer == NULL)
691 // Look for speed mech command in the buffer, set the page count and last page flag
693 BYTE *p = m_pbyPclBuffer;
694 while (i < m_iPclBufferSize)
698 if (!(memcmp (p, pbySpeedMechCmd, 8)))
701 *p++ = (BYTE) ((m_iPageCount & 0xFF00) >> 8);
702 *p++ = (BYTE) ((m_iPageCount & 0x00FF));
710 m_bSpeedMechEnabled = FALSE;
711 ToDevice (m_pbyPclBuffer, (DWORD *) &m_iCurPclBufferPos);
712 delete [] m_pbyPclBuffer;
715 #if defined(HAVE_LIBHPIP) && defined(HAVE_DBUS)
716 void SendDbusMessage (const char *dev, const char *printer, int code,
717 const char *username, const int jobid, const char *title)
719 DBusMessage * msg = NULL;
722 if (dbus_conn == NULL)
724 msg = dbus_message_new_signal(DBUS_PATH, DBUS_INTERFACE, "Event");
728 BUG("dbus message is NULL!\n");
732 dbus_message_append_args(msg,
733 DBUS_TYPE_STRING, &dev,
734 DBUS_TYPE_STRING, &printer,
735 DBUS_TYPE_UINT32, &code,
736 DBUS_TYPE_STRING, &username,
737 DBUS_TYPE_UINT32, &jobid,
738 DBUS_TYPE_STRING, &title,
741 if (!dbus_connection_send(dbus_conn, msg, NULL))
743 BUG("dbus message send failed!\n");
747 dbus_connection_flush(dbus_conn);
748 dbus_message_unref(msg);
755 dbus_error_init (&dbus_err);
756 dbus_conn = dbus_bus_get (DBUS_BUS_SYSTEM, &dbus_err);
758 if (dbus_error_is_set (&dbus_err))
760 BUG ("dBus Connection Error (%s)!\n", dbus_err.message);
761 dbus_error_free (&dbus_err);
766 #endif /* HAVE_DBUS */