Tizen 2.1 base
[platform/upstream/hplip.git] / prnt / hpijs / hpijs.cpp
1 /*****************************************************************************\
2     hpijs.cpp : HP Inkjet Server
3
4     Copyright (c) 2001 - 2008, 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 extern void SendDbusMessage (const char *dev, const char *printer, int code, 
47                              const char *username, const int jobid, const char *title);
48
49 #ifdef HAVE_LIBHPIP
50 extern  int hpijsFaxServer (int argc, char **argv);
51 #endif
52
53 #if 0
54 int bug(const char *fmt, ...)
55 {
56    char buf[256];
57    va_list args;
58    int n;
59
60    va_start(args, fmt);
61
62    if ((n = vsnprintf(buf, 256, fmt, args)) == -1)
63       buf[255] = 0;     /* output was truncated */
64
65    fprintf(stderr, buf);
66    syslog(LOG_WARNING, buf);
67
68    fflush(stderr);
69    va_end(args);
70    return n;
71 }
72 #endif
73
74 void setLogLevel(UXServices *pSS)
75 {
76     FILE    *fp;
77     char    str[258];
78     char    *p;
79     fp = fopen ("/etc/cups/cupsd.conf", "r");
80     if (fp == NULL)
81         return;
82     while (!feof (fp))
83     {
84         if (!fgets (str, 256, fp))
85         {
86             break;
87         }
88         if ((p = strstr (str, "hpLogLevel")))
89         {
90             p += strlen ("hpLogLevel") + 1;
91             pSS->m_iLogLevel = atoi (p);
92             break;
93         }
94     }
95     fclose (fp);
96
97     if (pSS->m_iLogLevel & SAVE_PCL_FILE)
98     {
99         char    szFileName[32];
100         sprintf (szFileName, "/tmp/hpijs_%d.out", getpid());
101         pSS->outfp = fopen (szFileName, "w");
102         if (pSS->outfp)
103         {
104             chmod (szFileName, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
105         }
106     }
107 }
108
109 /* Set Print Context. */
110 int hpijs_set_context(UXServices *pSS)
111 {
112    int r;
113
114    if (pSS->PenSet != DUMMY_PEN)
115    {
116      if ((r = pSS->pPC->SetPenSet((PEN_TYPE)pSS->PenSet)) != NO_ERROR)
117         BUG("unable to SetPenSet set=%d, err=%d\n", pSS->PenSet, r);
118    }
119
120    if ((r = pSS->pPC->SelectPrintMode((QUALITY_MODE)pSS->Quality, (MEDIATYPE)pSS->MediaType, (COLORMODE)pSS->ColorMode)) !=  NO_ERROR)
121    {
122       BOOL        bDevText;
123       BUG("unable to set Quality=%d, ColorMode=%d, MediaType=%d, err=%d\n", pSS->Quality, pSS->ColorMode, pSS->MediaType, r);
124       pSS->pPC->GetPrintModeSettings((QUALITY_MODE &)pSS->Quality, (MEDIATYPE &)pSS->MediaType, (COLORMODE &)pSS->ColorMode, bDevText);
125       BUG("following will be used Quality=%d, ColorMode=%d, MediaType=%d\n", pSS->Quality, pSS->ColorMode, pSS->MediaType);
126    }
127
128    /* Map ghostscript paper size to APDK paper size. */
129    pSS->MapPaperSize(pSS->PaperWidth, pSS->PaperHeight); 
130
131    /* Do duplex stuff now, since we have a valid print mode. */
132    if (pSS->Duplex && !pSS->Tumble)
133    {
134       if (pSS->pPC->SelectDuplexPrinting(DUPLEXMODE_BOOK) != TRUE)
135          BUG("unable to set duplex mode=book\n");
136    }
137    else if (pSS->Duplex && pSS->Tumble)
138    {
139       if (pSS->pPC->SelectDuplexPrinting(DUPLEXMODE_TABLET) != TRUE)
140          BUG("unable to set duplex mode=tablet\n");
141    }
142    else
143    {
144       pSS->pPC->SelectDuplexPrinting(DUPLEXMODE_NONE);
145    }
146
147    if (pSS->MediaPosition != sourceTrayAuto)
148    {
149       if (pSS->pPC->SetMediaSource((MediaSource)pSS->MediaPosition) != NO_ERROR)
150          BUG("unable to set MediaPosition=%d\n", pSS->MediaPosition);
151    }
152
153    return 0;
154 }
155
156 int hpijs_status_cb(void *status_cb_data, IjsServerCtx *ctx, IjsJobId job_id)
157 {
158    return 0;
159 }
160
161 int hpijs_list_cb(void *list_cb_data, IjsServerCtx *ctx, IjsJobId job_id,
162         char *val_buf, int val_size)
163 {
164    return snprintf(val_buf, val_size, "OutputFD,DeviceManufacturer,DeviceModel,PageImageFormat,Dpi,Width,Height,BitsPerSample,ColorSpace,PaperSize,PrintableArea,PrintableTopLeft,DryTime,PS:Duplex,PS:Tumble,Quality:Quality,Quality:MediaType,Quality:ColorMode,Quality:PenSet,Quality:FullBleed,PS:MediaPosition");
165 }
166
167 int hpijs_enum_cb(void *enum_cb_data, IjsServerCtx *ctx, IjsJobId job_id,
168        const char *key, char *val_buf, int val_size)
169 {
170    UXServices *pSS = (UXServices*)enum_cb_data;
171
172    if (!strcmp (key, "ColorSpace"))
173    {
174       if (pSS->pPC->SupportSeparateBlack())
175          return snprintf(val_buf, val_size, "sRGB,KRGB");
176       else
177          return snprintf(val_buf, val_size, "sRGB");
178    }
179    else if (!strcmp (key, "DeviceManufacturer"))
180       return snprintf(val_buf, val_size, "HEWLETT-PACKARD,APOLLO,HP");
181    else if (!strcmp (key, "PageImageFormat"))
182       return snprintf(val_buf, val_size, "Raster");
183    else if (!strcmp (key, "BitsPerSample"))
184       return snprintf(val_buf, val_size, "8");
185    else if (!strcmp (key, "PS:Duplex"))
186    {
187       if (pSS->pPC->SelectDuplexPrinting(DUPLEXMODE_BOOK) == TRUE)
188          return snprintf(val_buf, val_size, "true");
189       else
190          return snprintf(val_buf, val_size, "false");
191       pSS->pPC->SelectDuplexPrinting(DUPLEXMODE_NONE);
192    }
193    else if (!strcmp (key, "PS:Tumble"))
194    {
195       if (pSS->pPC->SelectDuplexPrinting(DUPLEXMODE_TABLET) == TRUE)
196          return snprintf(val_buf, val_size, "true");
197       else
198          return snprintf(val_buf, val_size, "false");
199       pSS->pPC->SelectDuplexPrinting(DUPLEXMODE_NONE);
200    }
201    else
202       BUG("unable to enum key=%s\n", key);    
203   return IJS_ERANGE;
204 }
205
206 /*
207  * Set parameter (in the server) call back. Note, OutputFD is the only call that can be
208  * preceded by set DeviceManufacturer and DeviceModel.
209  */
210 int hpijs_set_cb (void *set_cb_data, IjsServerCtx *ctx, IjsJobId job_id,
211                   const char *key, const char *value, int value_size)
212 {
213     UXServices  *pSS = (UXServices*)set_cb_data;
214     int         fd, r;
215     char        *tail;
216     int         status = 0;
217     char        svalue[IJS_MAX_PARAM+1];   
218     float       w, h, dx, dy;
219     int         iVal;
220
221     /* Sanity check input value. */
222     if (value_size > IJS_MAX_PARAM)
223     {
224         memcpy(svalue, value, IJS_MAX_PARAM);
225         svalue[IJS_MAX_PARAM] = 0;
226     }
227     else
228     {
229         memcpy(svalue, value, value_size);
230         svalue[value_size] = 0;
231     }
232
233     if (!strcmp (key, "OutputFD"))
234     {
235         fd = strtol(svalue, &tail, 10);
236         pSS->OutputPath = fd;   /* set prn_stream as output of SS::ToDevice */
237     }
238     else if (!strcmp (key, "DeviceManufacturer"))
239     {
240         if ((strncasecmp(svalue, "HEWLETT-PACKARD", 15) != 0) &&
241             (strncasecmp(svalue, "APOLLO", 6) != 0) && (strncasecmp(svalue, "HP", 2) != 0))
242         {
243             BUG("unable to set DeviceManufacturer=%s\n", svalue);
244             status = -1;
245         }
246     }
247     else if (!strcmp (key, "DeviceModel"))
248     {
249         if ((r = pSS->pPC->SelectDevice(svalue)) != NO_ERROR)
250         {
251             if (r == PLUGIN_LIBRARY_MISSING)
252             {
253                 // call dbus here
254                 const char    *user_name = " ";
255                 const char    *title     = " ";
256                 const char *device_uri = getenv ("DEVICE_URI");
257                 const char *printer = getenv ("PRINTER");
258                 int     job_id = 0;
259
260                 if (device_uri == NULL)
261                     device_uri = "";
262                 if (printer == NULL)
263                     printer = "";
264
265                 SendDbusMessage (device_uri, printer,
266                                  EVENT_PRINT_FAILED_MISSING_PLUGIN,
267                                  user_name, job_id, title);
268                 BUG("unable to set device=%s, err=%d\n", svalue, r);
269                 status = -1;
270             }
271             else
272             {
273                 /* OfficeJet LX is not very unique, do separate check here. */
274                 if (!strncmp(svalue,"OfficeJet", 10))
275                 r = pSS->pPC->SelectDevice("DESKJET 540");
276             }
277         }
278
279         if (r == NO_ERROR)
280         {
281             pSS->Model = 1;
282
283             /* Got a valid device class, let's set some print mode defaults. */
284             BOOL        bDevText;
285             pSS->pPC->GetPrintModeSettings((QUALITY_MODE &)pSS->Quality, (MEDIATYPE &)pSS->MediaType, (COLORMODE &)pSS->ColorMode, bDevText);
286         }
287         else
288         {
289             BUG("unable to set device=%s, err=%d\n", svalue, r);
290             status = -1;
291         }
292     }
293     else if ((strcmp (key, "PS:Duplex") == 0) || (strcmp (key, "Duplex") == 0))
294     {
295         if (strncmp(svalue, "true", 4) == 0)
296             pSS->Duplex = 1;
297         else
298             pSS->Duplex = 0;
299     }
300     else if ((strcmp (key, "PS:Tumble") == 0) || (strcmp (key, "Tumble") == 0))
301     {
302         if (strncmp(svalue, "true", 4) == 0)
303             pSS->Tumble = 1;
304         else
305             pSS->Tumble = 0;
306     }
307     else if (!strcmp (key, "PaperSize"))
308     {
309         w = (float)strtod(svalue, &tail);
310         h = (float)strtod(tail+1, &tail);
311
312         if (pSS->FirstRaster)
313         {
314             /* Normal start of print Job. */
315             pSS->PaperWidth = w;
316             pSS->PaperHeight = h;
317             hpijs_set_context(pSS);
318         }
319         else
320         {
321
322             dx = w > pSS->PaperWidth ? w - pSS->PaperWidth : pSS->PaperWidth - w;
323             dy = h > pSS->PaperHeight ? h - pSS->PaperHeight :  pSS->PaperHeight - h;
324
325             /* Middle of print Job, ignore paper size if same. */
326             if ((dx > 0.25) || (dy > 0.25))
327             {
328                 pSS->FirstRaster = 1;  /* force new Job */
329                 pSS->PaperWidth = w;   /* set new paper size */
330                 pSS->PaperHeight = h;
331                 hpijs_set_context(pSS);
332             }
333         }
334     }
335     else if (!strcmp (key, "TopLeft"))
336     {
337         /* not currently used */
338     }
339     else if (!strcmp (key, "Quality:Quality"))
340     {
341         pSS->Quality = (QUALITY_MODE) strtol(svalue, &tail, 10);
342     }
343     else if (!strcmp (key, "Quality:MediaType"))
344     {
345         pSS->MediaType = (MEDIATYPE) strtol(svalue, &tail, 10);
346     }
347     else if (!strcmp (key, "Quality:ColorMode"))
348     {
349         pSS->ColorMode = (COLORMODE) strtol(svalue, &tail, 10);
350     }
351     else if (!strcmp (key, "Quality:PenSet"))
352     {
353         pSS->PenSet = (PEN_TYPE) strtol(svalue, &tail, 10);
354     }
355     else if (!strcmp (key, "Quality:FullBleed"))
356     {
357         pSS->FullBleed = strtol(svalue, &tail, 10);
358     }
359     else if (!strcmp (key, "PS:MediaPosition"))
360     {
361         pSS->MediaPosition = strtol(svalue, &tail, 10);
362     }
363     else if (!strcmp (key, "DryTime"))
364     {
365         iVal = strtol (svalue, &tail, 10);
366         pSS->pPC->SetPrinterHint (EXTRA_DRYTIME_HINT, iVal);
367     }
368     else if (!strcmp (key, "RedEye"))
369     {
370         iVal = strtol (svalue, &tail, 10);
371         pSS->pPC->SetPrinterHint (RED_EYE_REMOVAL_HINT, iVal);
372     }
373     else if (!strcmp (key, "PhotoFix"))
374     {
375         iVal = strtol (svalue, &tail, 10);
376         pSS->pPC->SetPrinterHint (PHOTO_FIX_HINT, iVal);
377     }
378     else if (!strcmp (key, "MaxJpegFileSize"))
379     {
380         iVal = strtol (svalue, &tail, 10);
381         pSS->pPC->SetPrinterHint (MAX_FILE_SIZE_HINT, iVal);
382     }  
383     else if (!strcmp (key, "Quality:SpeedMech") && !pSS->Duplex)
384     {
385         pSS->pPC->SetPrinterHint (PAGES_IN_DOC_HINT, 512);
386         pSS->EnableSpeedMech (TRUE);
387     }
388     else if (!strcmp (key, "Quality:MediaSubtype"))
389     {
390         iVal = strtol (svalue, &tail, 10);
391         pSS->pPC->SetMediaSubtype (iVal);
392     }
393 //  The next 5 values are passed in as inch * 1000
394     else if (!strcmp (key, "Margin:TopPadding"))
395     {
396         iVal = strtol (svalue, &tail, 10);
397         pSS->pPC->SetMechOffset (iVal);
398     }
399     else if (!strcmp (key, "Overspray:Left"))
400     {
401         iVal = strtol (svalue, &tail, 10);
402         pSS->pPC->SetPrinterHint (LEFT_OVERSPRAY_HINT, iVal);
403     }
404     else if (!strcmp (key, "Overspray:Top"))
405     {
406         iVal = strtol (svalue, &tail, 10);
407         pSS->pPC->SetPrinterHint (TOP_OVERSPRAY_HINT, iVal);
408     }
409     else if (!strcmp (key, "Overspray:Right"))
410     {
411         iVal = strtol (svalue, &tail, 10);
412         pSS->pPC->SetPrinterHint (RIGHT_OVERSPRAY_HINT, iVal);
413     }
414     else if (!strcmp (key, "Overspray:Bottom"))
415     {
416         iVal = strtol (svalue, &tail, 10);
417         pSS->pPC->SetPrinterHint (BOTTOM_OVERSPRAY_HINT, iVal);
418     }
419     else
420         BUG("unable to set key=%s, value=%s\n", key, svalue);    
421
422     return status;
423 }
424
425 /* Get parameter (from the server) call back. Note, all calls must be preceded by set DeviceName. */
426 int hpijs_get_cb(void *get_cb_data, IjsServerCtx *ctx, IjsJobId job_id, const char *key, char *value_buf, int value_size)
427 {
428    UXServices *pSS = (UXServices*)get_cb_data;
429    float        fX;
430    float        fY;
431
432    if (!strcmp (key, "PrintableArea"))
433    {
434        fY = pSS->pPC->PrintableHeight ();
435       /* If duplexing, adjust printable height to 1/2 inch top/bottom margins, except laserjets. */
436       if ((pSS->pPC->QueryDuplexMode() != DUPLEXMODE_NONE) && pSS->pPC->RotateImageForBackPage() && (FALSE == pSS->pPC->IsBorderless()))
437       {
438           // User has requested fullbleed printing and printer supports 4-sided fullbleed or
439           // top and bottom margin are equal (0.125"), then
440           // don't need top and bottom margins to be 0.5" each. In other words, if physical page size -
441           // printable height is more than 0.25 inches, adjustment is required for symmetry.
442           // Update - 11/22/05: Not so, the autoduplexer still requires a half inch margin.
443 #if 0
444          if ((pSS->pPC->PrintableHeight () + 0.28) < pSS->pPC->PhysicalPageSizeY ())
445          {
446              fY = pSS->pPC->PhysicalPageSizeY () - 1.0;
447          }
448 #endif
449          fY = pSS->pPC->PhysicalPageSizeY () - 1.0;
450
451          // SuperB size paper requires larger margins
452          if (pSS->pPC->PhysicalPageSizeY () > 18.0)
453          {
454              fY = 1.5;
455          }
456
457       }
458
459 /*
460  *      Fullbleed printing is requested and printer supports it, then
461  *      return the unadjusted physical width and height.
462  */
463
464       if ((fX = pSS->pPC->PrintableWidth ()) > pSS->PaperWidth)
465       {
466           fX = pSS->PaperWidth;
467           fY = pSS->PaperHeight;
468       }
469
470       return (snprintf (value_buf, value_size, "%.4fx%.4f", fX, fY));
471    }
472    else if (!strcmp (key, "PrintableTopLeft"))
473    {
474        fY = pSS->pPC->PrintableStartY (); 
475       /* If duplexing, adjust printable top to 1/2 inch top margin, except laserjets. */
476       if ((pSS->pPC->QueryDuplexMode() != DUPLEXMODE_NONE) && pSS->pPC->RotateImageForBackPage() && (FALSE == pSS->pPC->IsBorderless()))
477       {
478 #if 0
479          if ((pSS->pPC->PrintableHeight () + 0.28) < pSS->pPC->PhysicalPageSizeY ())
480          {
481              fY = 0.5;
482          }
483 #endif
484          fY = 0.5;
485          // SuperB size paper requires larger margins
486          if (pSS->pPC->PhysicalPageSizeY () > 18.0)
487          {
488              fY = 0.75;
489          }
490
491       }
492
493       return snprintf (value_buf, value_size, "%.4fx%.4f", pSS->pPC->PrintableStartX (), fY);
494    }
495    else if ((!strcmp (key, "Duplex")) || (!strcmp (key, "PS:Duplex")))
496    {
497       if (pSS->pPC->QueryDuplexMode() == DUPLEXMODE_NONE)
498          return snprintf(value_buf, value_size, "false");
499       else
500          return snprintf(value_buf, value_size, "true");
501    }
502    else if ((!strcmp (key, "Tumble")) || (!strcmp (key, "PS:Tumble")))
503    {
504       if (pSS->pPC->QueryDuplexMode() == DUPLEXMODE_TABLET)
505          return snprintf(value_buf, value_size, "true");
506       else
507          return snprintf(value_buf, value_size, "false");
508    }
509    else if (!strcmp (key, "PaperSize"))
510    {
511       return snprintf(value_buf, value_size, "%.4fx%.4f", pSS->pPC->PhysicalPageSizeX(), pSS->pPC->PhysicalPageSizeY());
512    }
513    else if (!strcmp (key, "Dpi"))
514    {
515       return snprintf(value_buf, value_size, "%dx%d", pSS->pPC->EffectiveResolutionX(), pSS->pPC->EffectiveResolutionY());
516    }
517    else if (!strcmp (key, "DeviceModel"))
518    {
519       return snprintf(value_buf, value_size, "%s", pSS->pPC->PrinterModel());
520    }
521    else if (!strcmp (key, "Quality:Quality"))
522    {
523       return snprintf(value_buf, value_size, "%d", pSS->Quality);
524    }
525    else if (!strcmp (key, "Quality:ColorMode"))
526    {
527       return snprintf(value_buf, value_size, "%d", pSS->ColorMode);
528    }
529    else if (!strcmp (key, "Quality:MediaType"))
530    {
531       return snprintf(value_buf, value_size, "%d", pSS->MediaType);
532    }
533    else if (!strcmp (key, "ColorSpace"))
534    {
535       return snprintf(value_buf, value_size, "%s", pSS->ph.cs);
536    }
537    else if (!strcmp (key, "PageImageFormat"))
538    {
539       return snprintf(value_buf, value_size, "Raster");
540    }
541    else if (!strcmp (key, "BitsPerSample"))
542    {
543       return snprintf(value_buf, value_size, "8");
544    }
545    else if (!strcmp (key, "PS:MediaPosition"))
546    {
547       return snprintf(value_buf, value_size, "%d", pSS->MediaPosition);
548    }
549    else
550       BUG("unable to get key=%s\n", key);    
551
552    return IJS_EUNKPARAM;
553 }
554
555 /* Get raster from the client. */
556 int hpijs_get_client_raster(IjsServerCtx *ctx, char *buf, int size, char white)
557 {
558    int status, clean=1, i;
559
560    status = ijs_server_get_data(ctx, (char *)buf, size);
561
562    if (status < 0)
563       return status;  /* error */
564
565    /* Check for blank raster. */
566    for (i = 0; i < size; i++)
567    {
568       if (buf[i] != white)
569       {
570          clean = 0;
571          break;
572       }
573    }
574
575    if (clean)
576       return 0;
577
578    return size;
579 }
580
581 int main (int argc, char *argv[], char *evenp[])
582 {
583    UXServices *pSS = NULL;
584    IjsServerCtx *ctx = NULL;
585    char *raster = NULL, *k_raster = NULL;
586    int status = EXIT_FAILURE;
587    int ret, n, i, kn=0, width, k_width;
588
589    openlog("hpijs", LOG_PID,  LOG_DAEMON);
590
591    if (argc > 1)
592    {
593       const char *arg = argv[1];
594       if ((arg[0] == '-') && (arg[1] == 'h'))
595       {
596          fprintf(stdout, "\nHewlett-Packard Co. Inkjet Server %s\n", VERSION);
597          fprintf(stdout, "Copyright (c) 2001-2004, Hewlett-Packard Co.\n");
598          exit(0);
599       }
600    }
601
602 #ifdef HAVE_LIBHPIP
603    char *pDev;
604    if ((pDev = getenv ("DEVICE_URI")) &&
605        ((strncmp (pDev, "hpfax:", 6)) == 0))
606    {
607        exit ( hpijsFaxServer (argc, argv));
608    }
609 #endif
610
611    ctx = ijs_server_init();
612    if (ctx == NULL)
613    {
614       BUG("unable to init hpijs server\n");
615       goto BUGOUT;
616    }
617
618    pSS = new UXServices();
619    if (pSS->constructor_error != NO_ERROR)
620    {
621       BUG("unable to open Services object err=%d\n", pSS->constructor_error);
622       goto BUGOUT;
623    }
624
625    setLogLevel(pSS);
626
627 #ifdef CAPTURE
628    if ((pSS->InitScript("/tmp/capout", TRUE)) != NO_ERROR)
629       BUG("unable to init capture");
630 #endif
631
632    
633    pSS->pPC = new PrintContext (pSS, 0, 0);
634
635    /* Ignore JOB_CANCELED. This a bi-di hack that allows the job to continue even if bi-di communication failed. */
636    if (pSS->pPC->constructor_error > 0 && pSS->DisplayStatus != DISPLAY_PRINTING_CANCELED)
637    {
638       BUG("unable to open PrintContext object err=%d\n", pSS->pPC->constructor_error);
639       goto BUGOUT;
640    }
641
642 /*
643  *  Ignore the WARN_MODE_MISMATCH warning. This will happen if we are talking to a monochrome printer.
644  *  We will select the correct printmode later.
645  */
646
647     if (pSS->pPC->constructor_error < 0 &&
648         pSS->pPC->constructor_error != WARN_MODE_MISMATCH)
649     {
650         BUG ("WARNING: %s\n", pSS->GetDriverMessage (pSS->pPC->constructor_error));
651                 switch (pSS->pPC->constructor_error)
652                 {
653                         case WARN_LOW_INK_BOTH_PENS:
654                         case WARN_LOW_INK_BLACK:
655                         case WARN_LOW_INK_COLOR:
656                         case WARN_LOW_INK_PHOTO:
657                         case WARN_LOW_INK_GREY:
658                         case WARN_LOW_INK_BLACK_PHOTO:
659                         case WARN_LOW_INK_COLOR_PHOTO:
660                         case WARN_LOW_INK_GREY_PHOTO:
661                         case WARN_LOW_INK_COLOR_GREY:
662                         case WARN_LOW_INK_COLOR_GREY_PHOTO:
663                         case WARN_LOW_INK_COLOR_BLACK_PHOTO:
664                         case WARN_LOW_INK_CYAN:
665                         case WARN_LOW_INK_MAGENTA:
666                         case WARN_LOW_INK_YELLOW:
667                         case WARN_LOW_INK_MULTIPLE_PENS:
668                         {
669                            fputs("STATE: +marker-supply-low-warning\n", stderr);
670                            break;
671                         }
672                         default:
673                            fputs("STATE: +marker-supply-low-warning\n", stderr);
674                 }
675     }
676
677 #if 0
678    BUG("device model=%s\n", pSS->pPC->PrinterModel());
679    BUG("device class=%s\n",  pSS->pPC->PrintertypeToString(pSS->pPC->SelectedDevice()));
680    BUG("default pen=%d\n",  pSS->pPC->GetDefaultPenSet());
681    BUG("installed pen=%d\n",  pSS->pPC->GetInstalledPens());
682 #endif
683
684    ijs_server_install_status_cb (ctx, hpijs_status_cb, pSS);
685    ijs_server_install_list_cb (ctx, hpijs_list_cb, pSS);
686    ijs_server_install_enum_cb (ctx, hpijs_enum_cb, pSS);
687    ijs_server_install_set_cb (ctx, hpijs_set_cb, pSS);
688    ijs_server_install_get_cb (ctx, hpijs_get_cb, pSS);
689
690    while (1)
691    {
692       if ((ret = ijs_server_get_page_header(ctx, &pSS->ph)) < 0)
693       {
694          BUG("unable to read client data err=%d\n", ret);
695          goto BUGOUT;
696       }
697
698       if (pSS->Model == -1)
699          goto BUGOUT;      /* no device selected */
700
701       if (ret)
702       {
703          status = 0; /* normal exit */
704          break;
705       }
706
707       if (pSS->FirstRaster)
708       {
709           char  *pEnv = getenv ("COPY_COUNT");
710           if (pEnv)
711           {
712               i = atoi (pEnv);
713               pSS->pPC->SetCopyCount (i);
714           }
715
716          pSS->FirstRaster = 0;
717
718          width = (int)(pSS->ph.xres * pSS->pPC->PrintableWidth() + 0.5);
719
720          /* Desensitize input width, may be off by one due to paper size conversions. */
721          if (pSS->ph.width < width)
722             width = pSS->ph.width;
723
724          if ((ret = pSS->pPC->SetPixelsPerRow(width, width)) != NO_ERROR)
725          {
726             BUG("unable to SetPixelsPerRow width=%d, err=%d\n", pSS->ph.width, ret);
727          }
728
729          /* Turn off any bi-di support. Allow bi-di for printer capabilities only. */
730 //         pSS->IOMode.bDevID = pSS->IOMode.bStatus = FALSE;
731          pSS->ResetIOMode (FALSE, FALSE);
732
733 //       Turn off SpeedMech in duplex printing mode
734          if (pSS->Duplex)
735          {
736              pSS->EnableSpeedMech (FALSE);
737          }
738
739          if (pSS->IsSpeedMechEnabled ())
740          {
741              pSS->InitSpeedMechBuffer ();
742          }
743
744          if (pSS->pJob != NULL)
745             delete pSS->pJob;
746          pSS->pJob = new Job(pSS->pPC);
747          if (pSS->pJob->constructor_error != NO_ERROR)
748          {
749             BUG("unable to create Job object err=%d\n", pSS->pJob->constructor_error);
750             goto BUGOUT;
751          }
752
753          if (pSS->pPC->QueryDuplexMode() != DUPLEXMODE_NONE)
754          {
755             if ((pSS->pPC->QueryDuplexMode() == DUPLEXMODE_BOOK) && pSS->pPC->RotateImageForBackPage())
756                pSS->InitDuplexBuffer();
757             pSS->BackPage = FALSE;
758          }
759
760          pSS->KRGB=0;
761          if (strcmp(pSS->ph.cs, "KRGB") == 0)
762             pSS->KRGB=1;
763          
764 #if 0
765          BUG("papersize=%d\n", pSS->pPC->GetPaperSize());
766          BUG("width=%d, height=%d\n", pSS->ph.width, pSS->ph.height);
767          BUG("EffResX=%d, EffResY=%d, InPixelsPerRow=%d, OutPixelsPerRow=%d\n", 
768             pSS->pPC->EffectiveResolutionX(), pSS->pPC->EffectiveResolutionY(), 
769             pSS->pPC->InputPixelsPerRow(), pSS->pPC->OutputPixelsPerRow());
770          BUG("device=%s\n", pSS->pPC->PrinterModel());
771 #endif
772       } // pSS->FirstRaster
773
774       if ((raster = (char *)malloc(pSS->ph.width*3)) == NULL)
775       {
776          BUG("unable to allocate raster buffer size=%d: %m\n", pSS->ph.width*3);
777          goto BUGOUT;
778       }
779
780       k_width = (pSS->ph.width + 7) >> 3;  /* width of k plane in bytes, byte aligned */
781
782       if ((k_raster = (char *)malloc(k_width)) == NULL)
783       {
784          BUG("unable to allocate black raster buffer size=%d: %m\n", k_width);
785          goto BUGOUT;
786       }
787       memset(k_raster, 0, k_width);
788
789       pSS->SendPreviousPage ();
790       for (i=0; i < pSS->ph.height; i++)      
791       {
792          if ((n = hpijs_get_client_raster(ctx, raster, pSS->ph.width*3, 0xff)) < 0)
793             break;    /* error */
794          if (pSS->KRGB)
795          {
796             if ((kn = hpijs_get_client_raster(ctx, k_raster, k_width, 0)) < 0)
797                break;    /* error */
798          }
799          if (n == 0 && kn == 0)
800             pSS->ProcessRaster((char *)0, (char *)0);  /* blank raster */
801          else if (kn == 0)
802             pSS->ProcessRaster(raster, (char *)0);
803          else if (n == 0)
804             pSS->ProcessRaster((char *)0, k_raster);
805          else 
806             pSS->ProcessRaster(raster, k_raster);
807       }
808
809       free(raster);
810       raster = NULL;
811       free(k_raster);
812       k_raster = NULL;
813
814       if (pSS->pPC->QueryDuplexMode() != DUPLEXMODE_NONE)
815       {
816          if ((pSS->pPC->QueryDuplexMode() == DUPLEXMODE_BOOK) && pSS->pPC->RotateImageForBackPage() && pSS->BackPage)
817          {
818             pSS->SendBackPage();
819          }
820          pSS->BackPage = (BOOL)((int)pSS->BackPage + 1) % 2;
821       }
822
823       pSS->pJob->NewPage();
824
825       
826    } /* end while (1) */
827
828    if (pSS->pPC->QueryDuplexMode() != DUPLEXMODE_NONE)
829    {
830       if (pSS->BackPage)
831       {
832          /* Send extra blank line & newpage to eject the page. (for VIP printers). */
833          /* For malibu send enough blank lines to cause at least two blank rasters in Job::sendrasters(). 5/1/03, des */
834          //         for (int i = 0; i < 201; i++)
835          for (int i = 0; i < 401; i++)
836             pSS->pJob->SendRasters((unsigned char *)0);
837          pSS->pJob->NewPage();
838       }
839    }
840
841 BUGOUT:
842    if (pSS != NULL)
843    {
844       if (pSS->pJob != NULL)
845          delete pSS->pJob;
846       if (pSS->pPC != NULL)
847          delete pSS->pPC;
848 #ifdef CAPTURE
849       pSS->EndScript();
850 #endif
851       delete pSS;
852    }
853    if (raster != NULL)
854       free(raster);
855    if (k_raster != NULL)
856       free(k_raster);
857    if (ctx != NULL)
858       ijs_server_done(ctx);
859
860    exit(status);
861 }
862