Tizen 2.1 base
[platform/upstream/hplip.git] / prnt / hpijs / services.cpp
1 /*****************************************************************************\
2     services.cpp : HP Inkjet Server
3
4     Copyright (c) 2001 - 2004, Hewlett-Packard Co.
5     All rights reserved.
6
7     Redistribution and use in source and binary forms, with or without
8     modification, are permitted provided that the following conditions
9     are met:
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.
18
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 \*****************************************************************************/
31
32 #include <sys/stat.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <stdarg.h>
36 #include <syslog.h>
37 #include <string.h>
38 #include <unistd.h>
39 #include <fcntl.h>
40 #include "header.h"
41 #include "ijs.h"
42 #include "ijs_server.h"
43 #include "hpijs.h"
44 #include "services.h"
45
46 #if defined(HAVE_LIBHPIP) && defined(HAVE_DBUS) 
47 #include <dbus/dbus.h>
48 #define DBUS_INTERFACE "com.hplip.StatusService"
49 #define DBUS_PATH "/"
50 static DBusError dbus_err;
51 static DBusConnection *dbus_conn;
52 void InitDbus (void);
53 void SendDbusMessage (const char *dev, const char *printer, int code, 
54                       const char *username, const int jobid, const char *title);
55 #else
56 void SendDbusMessage (const char *dev, const char *printer, int code, 
57                       const char *username, const int jobid, const char *title)
58 {
59 }
60 #endif
61
62 int UXServices::InitDuplexBuffer()
63 {
64     /* Free buffer if new page size in middle of print job. */
65     if (RastersOnPage)
66        delete [] RastersOnPage;
67     if (KRastersOnPage)
68        delete [] KRastersOnPage;
69
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++)
75     {
76        RastersOnPage[i] = NULL;
77        KRastersOnPage[i] = NULL;
78     }
79     return 0;
80 }
81
82 int UXServices::SendBackPage()
83 {
84     DRIVER_ERROR    err;
85     int i = CurrentRaster+1;
86
87     while (i < ph.height)
88     {
89        if (KRGB)
90        {
91           if ((err = pJob->SendRasters(KRastersOnPage[i], RastersOnPage[i])) != NO_ERROR)
92             return err;
93        }
94        else
95        {
96           if ((err = pJob->SendRasters(RastersOnPage[i])) != NO_ERROR)
97             return err;
98        }
99
100        if (RastersOnPage[i])
101            delete [] RastersOnPage[i];
102        if (KRastersOnPage[i])
103            delete [] KRastersOnPage[i];
104        i++;
105     }
106
107     CurrentRaster = ph.height - 1;   /* reset raster index */
108
109     return 0;
110 }
111
112 static unsigned char xmask[] =
113 {
114    0x80,    /* x=0 */
115    0x40,    /* 1 */
116    0x20,    /* 2 */
117    0x10,    /* 3 */
118    0x08,    /* 4 */
119    0x04,    /* 5 */
120    0x02,    /* 6 */
121    0x01     /* 7 */
122 };
123
124 int UXServices::ProcessRaster(char *raster, char *k_raster)
125 {
126     if (!((pPC->QueryDuplexMode() == DUPLEXMODE_BOOK) && pPC->RotateImageForBackPage() && BackPage))
127     {
128        if (KRGB)
129           return pJob->SendRasters((unsigned char *)k_raster, (unsigned char *)raster);
130        else
131           return pJob->SendRasters((unsigned char *)raster);
132     }
133     else
134     {
135         if (CurrentRaster < 0)
136            return -1;
137
138         BYTE   *new_raster;
139         int    new_raster_size;
140         int    i,w;
141
142         if (raster == NULL)
143         {
144            RastersOnPage[CurrentRaster] = NULL;
145         }
146         else
147         {
148            new_raster_size = pPC->InputPixelsPerRow() * 3;
149            new_raster = new BYTE[new_raster_size];
150            if (new_raster == 0)
151            {
152                BUG("unable to create duplex buffer, size=%d: %m\n", new_raster_size);
153                return -1;
154            }
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)
159            {
160                memcpy (p, raster+i, 3);  /* rotate rgb image */
161                p -= 3;
162            }
163         }
164
165         if (k_raster == NULL)
166         {
167            KRastersOnPage[CurrentRaster] = NULL;
168         }
169         else
170         {
171            new_raster_size = (pPC->InputPixelsPerRow() + 7) >> 3;
172            new_raster = new BYTE[new_raster_size];
173            if (new_raster == 0)
174            {
175                BUG("unable to create black duplex buffer, size=%d: %m\n", new_raster_size);
176                return -1;
177            }
178            memset(new_raster, 0, new_raster_size);
179            KRastersOnPage[CurrentRaster] = new_raster;
180            w = pPC->InputPixelsPerRow();
181            for (i=0; i<w; i++)
182            {
183                if (k_raster[i>>3] & xmask[i&7])
184                   new_raster[(w-i)>>3] |= xmask[(w-i)&7];  /* rotate k image */
185            }
186            int    k = ((w + 7) / 8) * 8 - w;
187            BYTE   c = 0xff << k;
188            if (k != 0)
189                new_raster[0] = c & k_raster[new_raster_size-1];
190         }
191
192         CurrentRaster--;
193
194         return 0;
195     }
196 }
197
198
199 #ifdef HAVE_LIBHPIP
200
201 /*
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.
205  *
206  */
207 BOOL UXServices::CanDoBiDi ()
208 {
209     char            *hpDev;
210     struct hpmud_model_attributes ma;
211     char            strDevID[512];
212
213     // Check for CUPS environment
214
215     if ((hpDev = getenv ("DEVICE_URI")) == NULL)
216     {
217         return FALSE;
218     }
219
220     // Check for HP Backend
221
222     if (strncmp (hpDev, "hp:", 3))
223     {
224         return FALSE;
225     }
226
227     // Check io-mode in models.xml for this device
228
229     hpmud_query_model(hpDev, &ma);
230
231     if (ma.prt_mode == HPMUD_UNI_MODE)
232     {
233         return FALSE;
234     }
235     if (hpmud_open_device(hpDev, ma.prt_mode, &hpFD) != HPMUD_R_OK)
236     {
237         return FALSE;
238     }
239     memset (strDevID, 0, 512);
240     if ((ReadDeviceID ((BYTE *) strDevID, 512)) != NO_ERROR)
241     {
242         return FALSE;
243     }
244
245     // Check if this is a laser device
246     if (strstr (strDevID, "Laser") || strstr (strDevID, "laser"))
247     {
248         return TRUE;
249     }
250
251     // Check if device id is complete
252     if (!(strstr (strDevID, ";S:")) && !(strstr (strDevID, "VSTATUS")))
253     {
254         return FALSE;
255     }
256     return TRUE;
257 }
258
259 #else
260
261 BOOL UXServices::CanDoBiDi ()
262 {
263     return FALSE;
264 }
265
266 #endif  // HAVE_LIBHPIP
267
268 UXServices::UXServices():SystemServices()
269 {
270    constructor_error = NO_ERROR;
271    hpFD = -1;
272
273    // instead of InitDeviceComm(), just do...
274    IOMode.bDevID = IOMode.bStatus = FALSE;   /* uni-di support is default */
275
276 #if 0 // Old code
277
278    /* Check for CUPS environment and HP backend. */
279    if ((hpDev = getenv("DEVICE_URI")) != NULL)
280    {
281       if (strncmp(hpDev, "hp:", 3) == 0)
282       {
283          hplip_Init();
284          hplip_ModelQuery(hpDev, &ma);      /* check io-mode in models.xml for this device */  
285          if (ma.prt_mode != UNI_MODE)
286          {
287             if ((hpFD = hplip_OpenHP(hpDev, &ma)) >= 0)
288             {
289                 InitDeviceComm();            /* lets try bi-di support */
290             }
291             if(IOMode.bDevID == FALSE)
292                BUG("unable to set bi-di for hp backend\n");
293          }
294       }
295    }
296
297 #endif // Old code
298
299    if (CanDoBiDi ())
300    {
301        InitDeviceComm ();
302        if (IOMode.bDevID == FALSE)
303        {
304            BUG ("Unable to set bi-di for hp backend\n");
305        }
306    }
307
308    Quality = QUALITY_NORMAL;
309    MediaType = MEDIA_PLAIN;
310    ColorMode = COLOR;
311    PenSet = DUMMY_PEN;
312    
313    RastersOnPage = 0;
314    KRastersOnPage = 0;
315    pPC = NULL;
316    pJob = NULL;
317    Duplex = 0;
318    Tumble = 0;
319    FullBleed = 0;
320    FirstRaster = 1;
321    MediaPosition = sourceTrayAuto;
322    Model = -1;
323    strcpy(ph.cs, "sRGB");
324    VertAlign = -1;
325    DisplayStatus = NODISPLAYSTATUS;
326    OutputPath = -1;
327    outfp = NULL;
328    m_iLogLevel = 0;
329
330    m_pbyPclBuffer      = NULL;
331    m_iPclBufferSize    = BUFFER_CHUNK_SIZE;
332    m_iCurPclBufferPos  = 0;
333    m_iPageCount        = 0;
334    m_bSpeedMechEnabled = FALSE;
335 }
336
337 UXServices::~UXServices()
338 {
339    if (m_bSpeedMechEnabled)
340    {
341        SendLastPage ();
342    }
343
344    if (RastersOnPage)
345       delete [] RastersOnPage;
346    if (KRastersOnPage)
347       delete [] KRastersOnPage;
348 #ifdef HAVE_LIBHPIP
349    if (hpFD >= 0)
350       hpmud_close_device(hpFD);  
351 #endif
352     if (outfp)
353     {
354         fclose (outfp);
355     }
356 }
357
358 DRIVER_ERROR UXServices::ToDevice(const BYTE * pBuffer, DWORD * Count)
359 {
360     if (OutputPath == -1)
361     {
362         return IO_ERROR;
363     }
364
365    if (m_bSpeedMechEnabled)
366    {
367        if ((CopyData (pBuffer, *Count)) == 0)
368        {
369            *Count = 0;
370            return NO_ERROR;
371        }
372    }
373
374     if (outfp)
375     {
376         fwrite (pBuffer, 1, *Count, outfp);
377         if (!(m_iLogLevel & SEND_TO_PRINTER))
378         {
379             *Count = 0;
380             return NO_ERROR;
381         }
382     }
383
384    /* Write must be not-buffered, don't use streams */
385    if (write(OutputPath, pBuffer, *Count) != (ssize_t)*Count) 
386    {
387       static int cnt=0;
388       if (cnt++ < 5)
389          BUG("unable to write to output, fd=%d, count=%d: %m\n", OutputPath, *Count);
390       return IO_ERROR;
391    }
392
393    *Count = 0;
394    return NO_ERROR;
395 }
396
397 BOOL UXServices::GetStatusInfo (BYTE * bStatReg)
398 {
399 #ifdef HAVE_LIBHPIP
400    unsigned int s;
401    if (hpmud_get_device_status(hpFD, &s) == HPMUD_R_OK)
402    {
403       *bStatReg = (BYTE)s;
404       return TRUE;
405    }
406 #endif
407    return FALSE;
408 }
409
410 DRIVER_ERROR UXServices::ReadDeviceID (BYTE * strID, int iSize)
411 {
412 #ifdef HAVE_LIBHPIP
413    int len;
414    hpmud_get_device_id(hpFD, (char *)strID, iSize, &len);
415    if (len < 3)
416       return IO_ERROR;
417 #endif
418    return NO_ERROR;
419 }
420
421 #ifdef HP_PRINTVIEW
422 const char *szPJLHeader = "@PJL SET JOBATTR=\"JobAcct7=HPPrintView.exe\"\012";
423 int UXServices::GetPJLHeaderBuffer (char **szPJLBuffer)
424 {
425     *szPJLBuffer = (char *) szPJLHeader;
426     return strlen (szPJLHeader);
427 }
428 #endif // HP_PRINTVIEW
429
430 BOOL UXServices::GetVerticalAlignmentValue(BYTE* cVertAlignVal)
431 {
432    if (VertAlign == -1)
433       return FALSE;
434
435    *cVertAlignVal = (BYTE)VertAlign;
436    return TRUE;
437 }
438
439 BOOL UXServices::GetVertAlignFromDevice()
440 {
441 #ifdef HAVE_LIBHPIP
442    if ((VertAlign = ReadHPVertAlign(hpFD)) == -1)
443       return FALSE;
444 #endif
445    return TRUE;
446 }
447
448 void UXServices::DisplayPrinterStatus (DISPLAY_STATUS ePrinterStatus)
449 {
450    DisplayStatus = ePrinterStatus;
451 }
452
453 DRIVER_ERROR UXServices::BusyWait (DWORD msec)
454 {
455    switch (DisplayStatus)
456    {
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 */
469       default:
470          break;
471    }
472    return NO_ERROR;
473 }
474
475 const char * UXServices::GetDriverMessage (DRIVER_ERROR err)
476 {
477    const char *p=NULL;
478
479         /* Map driver error to text message. TODO: text needs to be localized. */
480    switch(err)
481    {
482       case(WARN_MODE_MISMATCH):
483          p = "printmode mismatch with pen, tray, etc.";
484          break;
485       case(WARN_LOW_INK_BOTH_PENS):
486          p = "both pens have low ink";
487          break;
488       case(WARN_LOW_INK_BLACK):
489          p = "black pen has low ink";
490          break;
491       case(WARN_LOW_INK_COLOR):
492          p = "color pen has low ink";
493          break;
494       case(WARN_LOW_INK_PHOTO):
495          p = "photo pen has low ink";
496          break;
497       case(WARN_LOW_INK_GREY):
498          p = "grey pen has low ink";
499          break;
500       case(WARN_LOW_INK_BLACK_PHOTO):
501          p = "black photo has low ink";
502          break;
503       case(WARN_LOW_INK_COLOR_PHOTO):
504          p = "color photo pen has low ink";
505          break;
506       case(WARN_LOW_INK_GREY_PHOTO):
507          p = "grey photo pen has low ink";
508          break;
509       case(WARN_LOW_INK_COLOR_GREY):
510          p = "grey pen has low ink";
511          break;
512       case(WARN_LOW_INK_COLOR_GREY_PHOTO):
513          p = "color grey photo pen has low ink";
514          break;
515       case(WARN_LOW_INK_COLOR_BLACK_PHOTO):
516          p = "color back pen has low ink";
517          break;
518       case(WARN_LOW_INK_CYAN):
519          p = "cyan has low ink";
520          break;
521       case(WARN_LOW_INK_MAGENTA):
522          p = "magenta has low ink";
523          break;
524       case(WARN_LOW_INK_YELLOW):
525          p = "yellow has low ink";
526          break;
527       case(WARN_LOW_INK_MULTIPLE_PENS):
528          p = "more that one ink is low";
529          break;
530       case(WARN_FULL_BLEED_UNSUPPORTED):
531          p = "fullbleed is not supported";
532          break;
533       case(WARN_FULL_BLEED_3SIDES):
534          p = "fullbleed is 3 sides";
535          break;
536       case(WARN_FULL_BLEED_PHOTOPAPER_ONLY):
537          p = "fullbleed photo paper only";
538          break;
539       case(WARN_FULL_BLEED_3SIDES_PHOTOPAPER_ONLY):
540          p = "fullbleed 3 sides photo paper only";
541          break;
542       case(WARN_ILLEGAL_PAPERSIZE):
543          p = "illegal paper size";
544          break;
545       case(WARN_INVALID_MEDIA_SOURCE):
546          p = "invalid media source";
547          break;
548       default:
549          p = "driver error";
550          BUG("driver error=%d\n", err);
551          break;
552    }
553    return p;
554 }
555
556 int UXServices::MapPaperSize (float width, float height)
557 {
558     int    i, r, size;
559     float  dx, dy;
560
561     /* Map gs paper sizes to APDK paper sizes, or do custom. */
562     size = CUSTOM_SIZE;
563     for (i=0; i<MAX_PAPER_SIZE; i++)
564     {
565         r = pPC->SetPaperSize ((PAPER_SIZE)i);
566
567         if (r != NO_ERROR)
568             continue;
569
570         dx = width  > pPC->PhysicalPageSizeX () ? width  - pPC->PhysicalPageSizeX () : pPC->PhysicalPageSizeX () - width;
571         dy = height > pPC->PhysicalPageSizeY () ? height - pPC->PhysicalPageSizeY () : pPC->PhysicalPageSizeY () - height;
572
573         if ((dx < 0.05) && (dy < 0.05))
574         {
575             size = i;   /* found standard paper size */
576             break;
577         }
578     }
579
580     if (size == CUSTOM_SIZE)
581         pPC->SetCustomSize (width, height);
582
583     if ((r = pPC->SetPaperSize ((PAPER_SIZE)size, FullBleed)) != NO_ERROR)
584     {
585         if (r > 0)
586         {
587             BUG("unable to set paper size=%d, err=%d, width=%0.5g, height=%0.5g\n", size, r, width, height);
588         }
589         else 
590         {
591             BUG("warning setting paper size=%d, err=%d, width=%0.5g, height=%0.5g\n", size, r, width, height);
592         }
593 /*
594  *      Call failed, reset our PaperWidth and PaperHeight values.
595  *      This ensures that we return correct values when gs queries for printable area.
596  */
597
598         PaperWidth  = pPC->PhysicalPageSizeX ();
599         PaperHeight = pPC->PhysicalPageSizeY ();
600         return -1;
601     }
602
603     PaperWidth  = pPC->PhysicalPageSizeX ();
604     PaperHeight = pPC->PhysicalPageSizeY ();
605
606     return 0; 
607 }
608
609 void UXServices::ResetIOMode (BOOL bDevID, BOOL bStatus)
610 {
611     if (pPC)
612     {
613         IOMode.bDevID  = bDevID;
614         IOMode.bStatus = bStatus;
615         pPC->ResetIOMode (bDevID, bStatus);
616     }
617 }
618
619 void UXServices::InitSpeedMechBuffer ()
620 {
621     if (m_pbyPclBuffer)
622     {
623         return;
624     }
625     m_pbyPclBuffer = new BYTE[m_iPclBufferSize + 2];
626     if (m_pbyPclBuffer)
627     {
628         iSendBufferSize = 0;
629     }
630 }
631
632 int UXServices::SendPreviousPage ()
633 {
634     DRIVER_ERROR    err;
635     if (m_bSpeedMechEnabled == FALSE)
636     {
637         return 0;
638     }
639     m_iPageCount++;
640     if (m_iPageCount == 1)
641     {
642         return 0;
643     }
644     m_bSpeedMechEnabled = FALSE;
645     err = ToDevice (m_pbyPclBuffer, (DWORD *) &m_iCurPclBufferPos);
646     if (err != NO_ERROR)
647     {
648         return 1;
649     }
650     m_bSpeedMechEnabled = TRUE;
651     m_iCurPclBufferPos = 0;
652
653 //  Request the printer to inject speed mech command. Also, let it know this is not the last page
654
655     pPC->SetPrinterHint (SPEED_MECH_HINT, 0);
656     return 0;
657 }
658
659 int UXServices::CopyData (const BYTE *pBuffer, DWORD iCount)
660 {
661     if (m_iCurPclBufferPos + (int) iCount < m_iPclBufferSize)
662     {
663         memcpy (m_pbyPclBuffer + m_iCurPclBufferPos, pBuffer, iCount);
664         m_iCurPclBufferPos += iCount;
665        return 0;
666     }
667     BYTE    *p = new BYTE[m_iPclBufferSize + BUFFER_CHUNK_SIZE + 2];
668     if (p == NULL)
669     {
670         m_bSpeedMechEnabled = FALSE;
671         return 1;
672     }
673     memcpy (p, m_pbyPclBuffer, m_iCurPclBufferPos);
674     delete [] m_pbyPclBuffer;
675     m_pbyPclBuffer = p;
676     memcpy (m_pbyPclBuffer + m_iCurPclBufferPos, pBuffer, iCount);
677     m_iCurPclBufferPos += iCount;
678     m_iPclBufferSize += BUFFER_CHUNK_SIZE;
679     return 0;
680 }
681
682 //  Note that this is good only for VIP printers
683 const char *pbySpeedMechCmd = "\x1B*o5W\x0D\x02\x00";
684
685 void UXServices::SendLastPage ()
686 {
687     if (m_pbyPclBuffer == NULL)
688     {
689         return;
690     }
691     // Look for speed mech command in the buffer, set the page count and last page flag
692     int    i = 0;
693     BYTE   *p = m_pbyPclBuffer;
694     while (i < m_iPclBufferSize)
695     {
696         if (*p == '\x1B')
697         {
698             if (!(memcmp (p, pbySpeedMechCmd, 8)))
699             {
700                 p += 8;
701                 *p++ = (BYTE) ((m_iPageCount & 0xFF00) >> 8);
702                 *p++ = (BYTE) ((m_iPageCount & 0x00FF));
703                 *(p + 9) = 1;
704                 break;
705             }
706         }
707         i++;
708         p++;
709     }
710     m_bSpeedMechEnabled = FALSE;
711     ToDevice (m_pbyPclBuffer, (DWORD *) &m_iCurPclBufferPos);
712     delete [] m_pbyPclBuffer;
713 }
714
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)
718 {
719     DBusMessage * msg = NULL;
720
721     InitDbus ();
722     if (dbus_conn == NULL)
723         return;
724     msg = dbus_message_new_signal(DBUS_PATH, DBUS_INTERFACE, "Event");
725
726     if (NULL == msg)
727     {
728         BUG("dbus message is NULL!\n");
729         return;
730     }
731
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, 
739         DBUS_TYPE_INVALID);
740
741     if (!dbus_connection_send(dbus_conn, msg, NULL))
742     {
743         BUG("dbus message send failed!\n");
744         return;
745     }
746
747     dbus_connection_flush(dbus_conn);
748     dbus_message_unref(msg);
749
750     return;
751 }
752
753 void InitDbus (void)
754 {
755    dbus_error_init (&dbus_err);
756    dbus_conn = dbus_bus_get (DBUS_BUS_SYSTEM, &dbus_err);
757     
758    if (dbus_error_is_set (&dbus_err))
759    { 
760       BUG ("dBus Connection Error (%s)!\n", dbus_err.message); 
761       dbus_error_free (&dbus_err); 
762    }
763
764    return;
765 }
766 #endif  /* HAVE_DBUS */
767
768