• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *   Function to apply IPP options to a CUPS/PWG Raster header.
3  *
4  *   Copyright 2013 by Till Kamppeter.
5  *
6  *   Distribution and use rights are outlined in the file "COPYING"
7  *   which should have been included with this file.
8  *
9  * Contents:
10  *
11  *   cupsRasterParseIPPOptions() - Parse IPP options from the command line
12  *                                 and apply them to the CUPS Raster header.
13  */
14 
15 #include <config.h>
16 #include <cups/cups.h>
17 #include <cups/ppd.h>
18 #if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 6)
19 #define HAVE_CUPS_1_7 1
20 #endif
21 
22 /*
23  * Include necessary headers.
24  */
25 
26 #include "driver.h"
27 #include <string.h>
28 #include <ctype.h>
29 #ifdef HAVE_CUPS_1_7
30 #include <cups/pwg.h>
31 #endif /* HAVE_CUPS_1_7 */
32 
33 /*
34  * '_strlcpy()' - Safely copy two strings.
35  */
36 
37 size_t					/* O - Length of string */
_strlcpy(char * dst,const char * src,size_t size)38 _strlcpy(char       *dst,		/* O - Destination string */
39 	 const char *src,		/* I - Source string */
40 	 size_t      size)		/* I - Size of destination string buffer */
41 {
42   size_t	srclen;			/* Length of source string */
43 
44 
45  /*
46   * Figure out how much room is needed...
47   */
48 
49   size --;
50 
51   srclen = strlen(src);
52 
53  /*
54   * Copy the appropriate amount...
55   */
56 
57   if (srclen > size)
58     srclen = size;
59 
60   memcpy(dst, src, srclen);
61   dst[srclen] = '\0';
62 
63   return (srclen);
64 }
65 
66 /*
67  * 'cupsRasterParseIPPOptions()' - Parse IPP options from the command line
68  *                                 and apply them to the CUPS Raster header.
69  */
70 
71 int                                          /* O - -1 on error, 0 on success */
cupsRasterParseIPPOptions(cups_page_header2_t * h,int num_options,cups_option_t * options,int pwg_raster,int set_defaults)72 cupsRasterParseIPPOptions(cups_page_header2_t *h, /* I - Raster header */
73 			  int num_options,        /* I - Number of options */
74 			  cups_option_t *options, /* I - Options */
75 			  int pwg_raster,         /* I - 1 if PWG Raster */
76 			  int set_defaults)       /* I - If 1, se default values
77 						     for all fields for which
78 						     we did not get an option */
79 {
80 #ifdef HAVE_CUPS_1_7
81   int		i;			/* Looping var */
82   char		*ptr,			/* Pointer into string */
83 		s[255];			/* Temporary string */
84   const char	*val,			/* Pointer into value */
85                 *media;			/* media option */
86   char		*page_size,		/* PageSize option */
87                 *media_source,          /* Media source */
88                 *media_type;		/* Media type */
89   pwg_media_t   *size_found;            /* page size found for given name */
90   float         size;                   /* page size dimension */
91   int           num_non_ppd_options = 0;/* Number of options which are not
92                                            in the PPD */
93   cups_option_t *non_ppd_options = NULL;/* Options not in the PPD */
94   ppd_file_t    *ppd = NULL;
95 
96  /*
97   * Range check input...
98   */
99 
100   if (!h)
101     return (-1);
102 
103  /*
104   * If we have a PPD file (PPD environment variable), take it into
105   * account, by not parsing options which are in the PPD file here.
106   *
107   * They should get parsed and applied separately via the
108   * ppdRasterInterpretPPD() as that function parses the embedded
109   * PostScript code. This way weird things like Gutenprint's
110   * "Resolution" option (choice name is something odd, like
111   * 301x300dpi, and actual resolution can be completely different)
112   * will get treated correctly.
113   *
114   * We mark the option settings in the PPD and call
115   * ppdRasterInterpretPPD() only when we are called with set_defaults
116   * = 1. In any case we replace the option list we parse by a copy
117   * without the options of the PPD file.
118   */
119 
120   ptr = getenv("PPD");
121   if (ptr && ptr[0] != '\0' && (ppd = ppdOpenFile(ptr)) != NULL)
122   {
123     if (set_defaults)
124     {
125       cupsMarkOptions(ppd, num_options, options);
126       cupsRasterInterpretPPD(h, ppd, num_options, options, NULL);
127     }
128     for (i = 0; i < num_options; i ++)
129       if (ppdFindOption(ppd, options[i].name) == NULL)
130 	num_non_ppd_options =
131 	  cupsAddOption(options[i].name, options[i].value,
132 			num_non_ppd_options, &non_ppd_options);
133     num_options = num_non_ppd_options;
134     options = non_ppd_options;
135   }
136 
137  /*
138   * Check if the supplied "media" option is a comma-separated list of any
139   * combination of page size ("media"), media source ("media-position"),
140   * and media type ("media-type") and if so, put these list elements into
141   * their dedicated options.
142   */
143 
144   page_size = NULL;
145   media_source = NULL;
146   media_type = NULL;
147   if ((media = cupsGetOption("media", num_options, options)) != NULL)
148   {
149    /*
150     * Loop through the option string, separating it at commas and marking each
151     * individual option as long as the corresponding PPD option (PageSize,
152     * InputSlot, etc.) is not also set.
153     *
154     * For PageSize, we also check for an empty option value since some versions
155     * of MacOS X use it to specify auto-selection of the media based solely on
156     * the size.
157     */
158 
159     for (val = media; *val;)
160     {
161      /*
162       * Extract the sub-option from the string...
163       */
164 
165       for (ptr = s; *val && *val != ',' && (ptr - s) < (sizeof(s) - 1);)
166 	*ptr++ = *val++;
167       *ptr++ = '\0';
168 
169       if (*val == ',')
170 	val ++;
171 
172      /*
173       * Identify it...
174       */
175 
176       size_found = NULL;
177       if ((size_found = pwgMediaForPWG(s)) == NULL)
178 	if ((size_found = pwgMediaForPPD(s)) == NULL)
179 	  if ((size_found = pwgMediaForPPD(s)) == NULL)
180 	  {
181 	    if (strcasestr(s, "tray") ||
182 		strcasestr(s, "feed") ||
183 		strcasestr(s, "capacity") ||
184 		strcasestr(s, "upper") ||
185 		strcasestr(s, "top") ||
186 		strcasestr(s, "middle") ||
187 		strcasestr(s, "lower") ||
188 		strcasestr(s, "bottom") ||
189 		strcasestr(s, "left") ||
190 		strcasestr(s, "right") ||
191 		strcasestr(s, "side") ||
192 		strcasestr(s, "main"))
193             {
194               if (media_source == NULL)
195 	        media_source = strdup(s);
196             }
197 	    else
198 	      media_type = strdup(s);
199 	  }
200       if (page_size == NULL && size_found)
201 	page_size = strdup(size_found->pwg);
202     }
203   }
204 
205   if (pwg_raster)
206     strcpy(h->MediaClass, "PwgRaster");
207   else if ((val = cupsGetOption("media-class", num_options, options)) != NULL ||
208 	   (val = cupsGetOption("MediaClass", num_options, options)) != NULL)
209     _strlcpy(h->MediaClass, val, sizeof(h->MediaClass));
210   else if (set_defaults)
211     strcpy(h->MediaClass, "");
212 
213   if ((val = cupsGetOption("media-color", num_options, options)) != NULL ||
214       (val = cupsGetOption("MediaColor", num_options, options)) != NULL)
215     _strlcpy(h->MediaColor, val, sizeof(h->MediaColor));
216   else if (set_defaults)
217     h->MediaColor[0] = '\0';
218 
219   if ((val = cupsGetOption("media-type", num_options, options)) != NULL ||
220       (val = cupsGetOption("MediaType", num_options, options)) != NULL ||
221       (val = media_type) != NULL)
222     _strlcpy(h->MediaType, val, sizeof(h->MediaType));
223   else if (set_defaults)
224     h->MediaType[0] = '\0';
225 
226   if ((val = cupsGetOption("print-content-optimize", num_options,
227 			   options)) != NULL ||
228       (val = cupsGetOption("output-type", num_options, options)) != NULL ||
229       (val = cupsGetOption("OutputType", num_options, options)) != NULL)
230   {
231     if (!strcasecmp(val, "automatic"))
232       _strlcpy(h->OutputType, "Automatic",
233 	      sizeof(h->OutputType));
234     else if (!strcasecmp(val, "graphics"))
235       _strlcpy(h->OutputType, "Graphics", sizeof(h->OutputType));
236     else if (!strcasecmp(val, "photo"))
237       _strlcpy(h->OutputType, "Photo", sizeof(h->OutputType));
238     else if (!strcasecmp(val, "text"))
239       _strlcpy(h->OutputType, "Text", sizeof(h->OutputType));
240     else if (!strcasecmp(val, "text-and-graphics") ||
241 	     !strcasecmp(val, "TextAndGraphics"))
242       _strlcpy(h->OutputType, "TextAndGraphics",
243 	      sizeof(h->OutputType));
244     else if (pwg_raster)
245       fprintf(stderr, "DEBUG: Unsupported print-content-type \"%s\".\n", val);
246     else
247       _strlcpy(h->OutputType, val, sizeof(h->OutputType));
248   }
249   else if (set_defaults)
250     _strlcpy(h->OutputType, "Automatic", sizeof(h->OutputType));
251 
252   if (pwg_raster)
253   {
254     /* Set "reserved" fields to 0 */
255     h->AdvanceDistance = 0;
256     h->AdvanceMedia = CUPS_ADVANCE_NONE;
257     h->Collate = CUPS_FALSE;
258   }
259   else
260   {
261     /* TODO - Support for advance distance and advance media */
262     if (set_defaults)
263     {
264       h->AdvanceDistance = 0;
265       h->AdvanceMedia = CUPS_ADVANCE_NONE;
266     }
267     if ((val = cupsGetOption("Collate", num_options, options)) != NULL &&
268 	(!strcasecmp(val, "true") || !strcasecmp(val, "on") ||
269 	 !strcasecmp(val, "yes")))
270       h->Collate = CUPS_TRUE;
271     else if ((val = cupsGetOption("Collate", num_options, options)) != NULL &&
272 	     (!strcasecmp(val, "false") || !strcasecmp(val, "off") ||
273 	      !strcasecmp(val, "no")))
274       h->Collate = CUPS_FALSE;
275     else if (set_defaults)
276       h->Collate = CUPS_FALSE;
277   }
278 
279   if (set_defaults)
280     h->CutMedia = CUPS_CUT_NONE;
281 
282   if (set_defaults)
283     h->Tumble = CUPS_FALSE;
284   if ((val = cupsGetOption("sides", num_options, options)) != NULL ||
285       (val = cupsGetOption("Duplex", num_options, options)) != NULL)
286   {
287     if (!strcasecmp(val, "None") || !strcasecmp(val, "Off") ||
288 	!strcasecmp(val, "False") || !strcasecmp(val, "No") ||
289 	!strcasecmp(val, "one-sided") || !strcasecmp(val, "OneSided"))
290       h->Duplex = CUPS_FALSE;
291     else if (!strcasecmp(val, "On") ||
292 	     !strcasecmp(val, "True") || !strcasecmp(val, "Yes") ||
293 	     !strncasecmp(val, "two-sided", 9) ||
294 	     !strncasecmp(val, "TwoSided", 8) ||
295 	     !strncasecmp(val, "Duplex", 6))
296     {
297       h->Duplex = CUPS_TRUE;
298       if (!strncasecmp(val, "DuplexTumble", 12))
299 	h->Tumble = CUPS_TRUE;
300       if (!strncasecmp(val, "DuplexNoTumble", 12))
301 	h->Tumble = CUPS_FALSE;
302     }
303     else if (set_defaults)
304       h->Duplex = CUPS_FALSE;
305   }
306   else if (set_defaults)
307     h->Duplex = CUPS_FALSE;
308 
309   if ((val = cupsGetOption("printer-resolution", num_options,
310 			   options)) != NULL ||
311       (val = cupsGetOption("Resolution", num_options, options)) != NULL)
312   {
313     int	        xres,		/* X resolution */
314                 yres;		/* Y resolution */
315     char	*ptr;		/* Pointer into value */
316 
317     xres = yres = strtol(val, (char **)&ptr, 10);
318     if (ptr > val && xres > 0)
319     {
320       if (*ptr == 'x')
321 	yres = strtol(ptr + 1, (char **)&ptr, 10);
322     }
323 
324     if (ptr <= val || xres <= 0 || yres <= 0 || !ptr ||
325 	(*ptr != '\0' &&
326 	 strcasecmp(ptr, "dpi") &&
327 	 strcasecmp(ptr, "dpc") &&
328 	 strcasecmp(ptr, "dpcm")))
329     {
330       fprintf(stderr, "DEBUG: Bad resolution value \"%s\".\n", val);
331       if (set_defaults)
332       {
333 	h->HWResolution[0] = 600;
334 	h->HWResolution[1] = 600;
335       }
336     }
337     else
338     {
339       if (!strcasecmp(ptr, "dpc") ||
340 	  !strcasecmp(ptr, "dpcm"))
341       {
342 	xres = xres * 254 / 100;
343 	yres = yres * 254 / 100;
344       }
345       h->HWResolution[0] = xres;
346       h->HWResolution[1] = yres;
347     }
348   }
349   else if (set_defaults)
350   {
351     h->HWResolution[0] = 600;
352     h->HWResolution[1] = 600;
353   }
354 
355   if (set_defaults)
356   {
357     /* TODO - Support for insert sheets */
358     h->InsertSheet = CUPS_FALSE;
359   }
360 
361   if (set_defaults)
362   {
363     /* TODO - Support for jog */
364     h->Jog = CUPS_JOG_NONE;
365   }
366 
367   if ((val = cupsGetOption("feed-orientation", num_options,
368 			   options)) != NULL ||
369       (val = cupsGetOption("feed-direction", num_options, options)) != NULL ||
370       (val = cupsGetOption("LeadingEdge", num_options, options)) != NULL)
371   {
372     if (!strcasecmp(val, "ShortEdgeFirst"))
373       h->LeadingEdge = CUPS_EDGE_TOP;
374     else if (!strcasecmp(val, "LongEdgeFirst"))
375       h->LeadingEdge = CUPS_EDGE_RIGHT;
376     else
377       fprintf(stderr, "DEBUG: Unsupported feed-orientation \"%s\".\n", val);
378   }
379   else if (set_defaults)
380     h->LeadingEdge = CUPS_EDGE_TOP;
381 
382   if (pwg_raster || set_defaults)
383   {
384     /* TODO - Support for manual feed */
385     h->ManualFeed = CUPS_FALSE;
386   }
387 
388   if ((val = cupsGetOption("media-position", num_options, options)) != NULL ||
389       (val = cupsGetOption("MediaPosition", num_options, options)) != NULL ||
390       (val = cupsGetOption("media-source", num_options, options)) != NULL ||
391       (val = cupsGetOption("MediaSource", num_options, options)) != NULL ||
392       (val = cupsGetOption("InputSlot", num_options, options)) != NULL ||
393       (val = media_source) != NULL)
394   {
395     if (!strncasecmp(val, "Auto", 4) ||
396 	!strncasecmp(val, "Default", 7))
397       h->MediaPosition = 0;
398     else if (!strcasecmp(val, "Main"))
399       h->MediaPosition = 1;
400     else if (!strcasecmp(val, "Alternate"))
401       h->MediaPosition = 2;
402     else if (!strcasecmp(val, "LargeCapacity"))
403       h->MediaPosition = 3;
404     else if (!strcasecmp(val, "Manual"))
405       h->MediaPosition = 4;
406     else if (!strcasecmp(val, "Envelope"))
407       h->MediaPosition = 5;
408     else if (!strcasecmp(val, "Disc"))
409       h->MediaPosition = 6;
410     else if (!strcasecmp(val, "Photo"))
411       h->MediaPosition = 7;
412     else if (!strcasecmp(val, "Hagaki"))
413       h->MediaPosition = 8;
414     else if (!strcasecmp(val, "MainRoll"))
415       h->MediaPosition = 9;
416     else if (!strcasecmp(val, "AlternateRoll"))
417       h->MediaPosition = 10;
418     else if (!strcasecmp(val, "Top"))
419       h->MediaPosition = 11;
420     else if (!strcasecmp(val, "Middle"))
421       h->MediaPosition = 12;
422     else if (!strcasecmp(val, "Bottom"))
423       h->MediaPosition = 13;
424     else if (!strcasecmp(val, "Side"))
425       h->MediaPosition = 14;
426     else if (!strcasecmp(val, "Left"))
427       h->MediaPosition = 15;
428     else if (!strcasecmp(val, "Right"))
429       h->MediaPosition = 16;
430     else if (!strcasecmp(val, "Center"))
431       h->MediaPosition = 17;
432     else if (!strcasecmp(val, "Rear"))
433       h->MediaPosition = 18;
434     else if (!strcasecmp(val, "ByPassTray"))
435       h->MediaPosition = 19;
436     else if (!strcasecmp(val, "Tray1"))
437       h->MediaPosition = 20;
438     else if (!strcasecmp(val, "Tray2"))
439       h->MediaPosition = 21;
440     else if (!strcasecmp(val, "Tray3"))
441       h->MediaPosition = 22;
442     else if (!strcasecmp(val, "Tray4"))
443       h->MediaPosition = 23;
444     else if (!strcasecmp(val, "Tray5"))
445       h->MediaPosition = 24;
446     else if (!strcasecmp(val, "Tray6"))
447       h->MediaPosition = 25;
448     else if (!strcasecmp(val, "Tray7"))
449       h->MediaPosition = 26;
450     else if (!strcasecmp(val, "Tray8"))
451       h->MediaPosition = 27;
452     else if (!strcasecmp(val, "Tray9"))
453       h->MediaPosition = 28;
454     else if (!strcasecmp(val, "Tray10"))
455       h->MediaPosition = 29;
456     else if (!strcasecmp(val, "Tray11"))
457       h->MediaPosition = 30;
458     else if (!strcasecmp(val, "Tray12"))
459       h->MediaPosition = 31;
460     else if (!strcasecmp(val, "Tray13"))
461       h->MediaPosition = 32;
462     else if (!strcasecmp(val, "Tray14"))
463       h->MediaPosition = 33;
464     else if (!strcasecmp(val, "Tray15"))
465       h->MediaPosition = 34;
466     else if (!strcasecmp(val, "Tray16"))
467       h->MediaPosition = 35;
468     else if (!strcasecmp(val, "Tray17"))
469       h->MediaPosition = 36;
470     else if (!strcasecmp(val, "Tray18"))
471       h->MediaPosition = 37;
472     else if (!strcasecmp(val, "Tray19"))
473       h->MediaPosition = 38;
474     else if (!strcasecmp(val, "Tray20"))
475       h->MediaPosition = 39;
476     else if (!strcasecmp(val, "Roll1"))
477       h->MediaPosition = 40;
478     else if (!strcasecmp(val, "Roll2"))
479       h->MediaPosition = 41;
480     else if (!strcasecmp(val, "Roll3"))
481       h->MediaPosition = 42;
482     else if (!strcasecmp(val, "Roll4"))
483       h->MediaPosition = 43;
484     else if (!strcasecmp(val, "Roll5"))
485       h->MediaPosition = 44;
486     else if (!strcasecmp(val, "Roll6"))
487       h->MediaPosition = 45;
488     else if (!strcasecmp(val, "Roll7"))
489       h->MediaPosition = 46;
490     else if (!strcasecmp(val, "Roll8"))
491       h->MediaPosition = 47;
492     else if (!strcasecmp(val, "Roll9"))
493       h->MediaPosition = 48;
494     else if (!strcasecmp(val, "Roll10"))
495       h->MediaPosition = 49;
496     else
497       fprintf(stderr, "DEBUG: Unsupported media source \"%s\".\n", val);
498   }
499   else if (set_defaults)
500     h->MediaPosition = 0; /* Auto */
501 
502   if ((val = cupsGetOption("media-weight", num_options, options)) != NULL ||
503       (val = cupsGetOption("MediaWeight", num_options, options)) != NULL ||
504       (val = cupsGetOption("media-weight-metric", num_options,
505 			   options)) != NULL ||
506       (val = cupsGetOption("MediaWeightMetric", num_options, options)) != NULL)
507     h->MediaWeight = atol(val);
508   else if (set_defaults)
509     h->MediaWeight = 0;
510 
511   if (pwg_raster)
512   {
513     /* Set "reserved" fields to 0 */
514     h->MirrorPrint = CUPS_FALSE;
515     h->NegativePrint = CUPS_FALSE;
516   }
517   else
518   {
519     if ((val = cupsGetOption("mirror-print", num_options, options)) != NULL ||
520 	(val = cupsGetOption("MirrorPrint", num_options, options)) != NULL)
521     {
522       if (!strcasecmp(val, "true") || !strcasecmp(val, "on") ||
523 	  !strcasecmp(val, "yes"))
524 	h->MirrorPrint = CUPS_TRUE;
525       else if (!strcasecmp(val, "false") ||
526 	       !strcasecmp(val, "off") ||
527 	       !strcasecmp(val, "no"))
528 	h->MirrorPrint = CUPS_FALSE;
529       else if (set_defaults)
530 	h->MirrorPrint = CUPS_FALSE;
531     }
532     if ((val = cupsGetOption("negative-print", num_options, options)) != NULL ||
533 	(val = cupsGetOption("NegativePrint", num_options, options)) != NULL)
534     {
535       if (!strcasecmp(val, "true") || !strcasecmp(val, "on") ||
536 	  !strcasecmp(val, "yes"))
537 	h->NegativePrint = CUPS_TRUE;
538       else if (!strcasecmp(val, "false") ||
539 	       !strcasecmp(val, "off") ||
540 	       !strcasecmp(val, "no"))
541 	h->NegativePrint = CUPS_FALSE;
542       else if (set_defaults)
543 	h->NegativePrint = CUPS_FALSE;
544     }
545   }
546 
547   if ((val = cupsGetOption("copies", num_options, options)) != NULL ||
548       (val = cupsGetOption("Copies", num_options, options)) != NULL ||
549       (val = cupsGetOption("num-copies", num_options, options)) != NULL ||
550       (val = cupsGetOption("NumCopies", num_options, options)) != NULL)
551     h->NumCopies = atol(val);
552   else if (set_defaults)
553     h->NumCopies = 1; /* 0 = Printer default */
554 
555   if ((val = cupsGetOption("orientation-requested", num_options,
556 			   options)) != NULL ||
557       (val = cupsGetOption("OrientationRequested", num_options,
558 			   options)) != NULL ||
559       (val = cupsGetOption("Orientation", num_options, options)) != NULL)
560   {
561     if (!strcasecmp(val, "Portrait") ||
562 	!strcasecmp(val, "3"))
563       h->Orientation = CUPS_ORIENT_0;
564     else if (!strcasecmp(val, "Landscape") ||
565 	     !strcasecmp(val, "4"))
566       h->Orientation = CUPS_ORIENT_90;
567     else if (!strcasecmp(val, "reverse-portrait") ||
568 	     !strcasecmp(val, "ReversePortrait") ||
569 	     !strcasecmp(val, "5"))
570       h->Orientation = CUPS_ORIENT_180;
571     else if (!strcasecmp(val, "reverse-landscape") ||
572 	     !strcasecmp(val, "ReverseLandscape") ||
573 	     !strcasecmp(val, "6"))
574       h->Orientation = CUPS_ORIENT_270;
575     else
576       fprintf(stderr, "DEBUG: Unsupported Orientation \"%s\".\n", val);
577   }
578   else if (set_defaults)
579     h->Orientation = CUPS_ORIENT_0;
580 
581   if (pwg_raster)
582   {
583     /* Set "reserved" fields to 0 */
584     h->OutputFaceUp = CUPS_FALSE;
585   }
586   else
587   {
588     if ((val = cupsGetOption("OutputFaceUp", num_options, options)) != NULL ||
589 	(val = cupsGetOption("output-face-up", num_options, options)) != NULL)
590     {
591       if (!strcasecmp(val, "true") || !strcasecmp(val, "on") ||
592 	  !strcasecmp(val, "yes"))
593 	h->OutputFaceUp = CUPS_TRUE;
594       else if (!strcasecmp(val, "false") ||
595 	       !strcasecmp(val, "off") ||
596 	       !strcasecmp(val, "no"))
597 	h->OutputFaceUp = CUPS_FALSE;
598       else if (set_defaults)
599 	h->OutputFaceUp = CUPS_FALSE;
600     }
601   }
602 
603   if ((val = cupsGetOption("media-size", num_options, options)) != NULL ||
604       (val = cupsGetOption("MediaSize", num_options, options)) != NULL ||
605       (val = cupsGetOption("page-size", num_options, options)) != NULL ||
606       (val = cupsGetOption("PageSize", num_options, options)) != NULL ||
607       (val = page_size) != NULL)
608   {
609     size_found = NULL;
610     if ((size_found = pwgMediaForPWG(val)) == NULL)
611       if ((size_found = pwgMediaForPPD(val)) == NULL)
612 	size_found = pwgMediaForLegacy(val);
613     if (size_found != NULL)
614     {
615       h->PageSize[0] = size_found->width * 72 / 2540;
616       h->PageSize[1] = size_found->length * 72 / 2540;
617       _strlcpy(h->cupsPageSizeName, size_found->pwg,
618 	      sizeof(h->cupsPageSizeName));
619       if (pwg_raster)
620       {
621 	h->cupsPageSize[0] = 0.0;
622 	h->cupsPageSize[1] = 0.0;
623       }
624       else
625       {
626 	h->cupsPageSize[0] = size_found->width * 72.0 / 2540.0;
627 	h->cupsPageSize[1] = size_found->length * 72.0 / 2540.0;
628       }
629     }
630     else
631       fprintf(stderr, "DEBUG: Unsupported page size %s.\n", val);
632   }
633   else if (set_defaults)
634   {
635     /* TODO: Automatic A4/Letter, like in scheduler/conf.c in CUPS. */
636     h->cupsPageSize[0] = 612.0f;
637     h->cupsPageSize[1] = 792.0f;
638 
639     h->PageSize[0] = 612;
640     h->PageSize[1] = 792;
641     _strlcpy(h->cupsPageSizeName, "na_letter_8.5x11in",
642 	    sizeof(h->cupsPageSizeName));
643     if (pwg_raster)
644     {
645       h->cupsPageSize[0] = 0.0;
646       h->cupsPageSize[1] = 0.0;
647     }
648   }
649   else if (pwg_raster)
650   {
651     h->cupsPageSize[0] = 0.0;
652     h->cupsPageSize[1] = 0.0;
653   }
654 
655   if (pwg_raster)
656   {
657     /* Set "reserved" fields to 0 */
658     h->Margins[0] = 0;
659     h->Margins[1] = 0;
660     h->ImagingBoundingBox[0] = 0;
661     h->ImagingBoundingBox[1] = 0;
662     h->ImagingBoundingBox[2] = 0;
663     h->ImagingBoundingBox[3] = 0;
664     h->cupsImagingBBox[0] = 0.0;
665     h->cupsImagingBBox[1] = 0.0;
666     h->cupsImagingBBox[2] = 0.0;
667     h->cupsImagingBBox[3] = 0.0;
668   }
669   else
670   {
671     if ((val = cupsGetOption("media-left-margin", num_options, options))
672 	!= NULL)
673     {
674       size = atol(val) * 72.0 / 2540.0;
675       h->Margins[0] = (int)size;
676       h->ImagingBoundingBox[0] = (int)size;
677       h->cupsImagingBBox[0] = size;
678     }
679     else if (set_defaults)
680     {
681       h->Margins[0] = 0;
682       h->ImagingBoundingBox[0] = 0;
683       h->cupsImagingBBox[0] = 18.0f;
684     }
685     if ((val = cupsGetOption("media-bottom-margin", num_options, options))
686 	!= NULL)
687     {
688       size = atol(val) * 72.0 / 2540.0;
689       h->Margins[1] = (int)size;
690       h->ImagingBoundingBox[1] = (int)size;
691       h->cupsImagingBBox[1] = size;
692     }
693     else if (set_defaults)
694     {
695       h->Margins[1] = 0;
696       h->ImagingBoundingBox[1] = 0;
697       h->cupsImagingBBox[1] = 36.0f;
698     }
699     if ((val = cupsGetOption("media-right-margin", num_options, options))
700 	!= NULL)
701     {
702       size = atol(val) * 72.0 / 2540.0;
703       h->ImagingBoundingBox[2] = h->PageSize[0] - (int)size;
704       h->cupsImagingBBox[2] = h->cupsPageSize[0] - size;
705     }
706     else if (set_defaults)
707     {
708       h->ImagingBoundingBox[2] = h->PageSize[0];
709       h->cupsImagingBBox[2] = 594.0f;
710     }
711     if ((val = cupsGetOption("media-top-margin", num_options, options))
712 	!= NULL)
713     {
714       size = atol(val) * 72.0 / 2540.0;
715       h->ImagingBoundingBox[3] = h->PageSize[1] - (int)size;
716       h->cupsImagingBBox[3] = h->cupsPageSize[1] - size;
717     }
718     else if (set_defaults)
719     {
720       h->ImagingBoundingBox[3] = h->PageSize[1];
721       h->cupsImagingBBox[3] = 756.0f;
722     }
723   }
724 
725   if (pwg_raster)
726   {
727     /* Set "reserved" fields to 0 */
728     h->Separations = CUPS_FALSE;
729     h->TraySwitch = CUPS_FALSE;
730   }
731   else
732   {
733     if ((val = cupsGetOption("separations", num_options, options)) != NULL ||
734 	(val = cupsGetOption("Separations", num_options, options)) != NULL)
735     {
736       if (!strcasecmp(val, "true") || !strcasecmp(val, "on") ||
737 	  !strcasecmp(val, "yes"))
738 	h->Separations = CUPS_TRUE;
739       else if (!strcasecmp(val, "false") ||
740 	       !strcasecmp(val, "off") ||
741 	       !strcasecmp(val, "no"))
742 	h->Separations = CUPS_FALSE;
743       else if (set_defaults)
744 	h->Separations = CUPS_FALSE;
745     }
746     if ((val = cupsGetOption("tray-switch", num_options, options)) != NULL ||
747 	(val = cupsGetOption("TraySwitch", num_options, options)) != NULL)
748     {
749       if (!strcasecmp(val, "true") || !strcasecmp(val, "on") ||
750 	  !strcasecmp(val, "yes"))
751 	h->TraySwitch = CUPS_TRUE;
752       else if (!strcasecmp(val, "false") ||
753 	       !strcasecmp(val, "off") ||
754 	       !strcasecmp(val, "no"))
755 	h->TraySwitch = CUPS_FALSE;
756       else if (set_defaults)
757 	h->TraySwitch = CUPS_FALSE;
758     }
759   }
760 
761   if ((val = cupsGetOption("sides", num_options, options)) != NULL ||
762       (val = cupsGetOption("Tumble", num_options, options)) != NULL)
763   {
764     if (!strcasecmp(val, "None") || !strcasecmp(val, "Off") ||
765 	!strcasecmp(val, "False") || !strcasecmp(val, "No") ||
766 	!strcasecmp(val, "one-sided") || !strcasecmp(val, "OneSided") ||
767 	!strcasecmp(val, "two-sided-long-edge") ||
768 	!strcasecmp(val, "TwoSidedLongEdge") ||
769 	!strcasecmp(val, "DuplexNoTumble"))
770       h->Tumble = CUPS_FALSE;
771     else if (!strcasecmp(val, "On") ||
772 	     !strcasecmp(val, "True") || !strcasecmp(val, "Yes") ||
773 	     !strcasecmp(val, "two-sided-short-edge") ||
774 	     !strcasecmp(val, "TwoSidedShortEdge") ||
775 	     !strcasecmp(val, "DuplexTumble"))
776       h->Tumble = CUPS_TRUE;
777   }
778 
779   h->cupsWidth = h->HWResolution[0] * h->PageSize[0] / 72;
780   h->cupsHeight = h->HWResolution[1] * h->PageSize[1] / 72;
781 
782   if (pwg_raster || set_defaults)
783   {
784     /* TODO - Support for MediaType number */
785     h->cupsMediaType = 0;
786   }
787 
788   if ((val = cupsGetOption("pwg-raster-document-type", num_options,
789 			   options)) != NULL ||
790       (val = cupsGetOption("PwgRasterDocumentType", num_options,
791 			   options)) != NULL ||
792       (val = cupsGetOption("print-color-mode", num_options,
793 			   options)) != NULL ||
794       (val = cupsGetOption("PrintColorMode", num_options, options)) != NULL ||
795       (val = cupsGetOption("color-space", num_options, options)) != NULL ||
796       (val = cupsGetOption("ColorSpace", num_options, options)) != NULL ||
797       (val = cupsGetOption("color-model", num_options, options)) != NULL ||
798       (val = cupsGetOption("ColorModel", num_options, options)) != NULL)
799   {
800     int	        bitspercolor,	/* Bits per color */
801                 bitsperpixel,   /* Bits per pixel */
802                 colorspace,     /* CUPS/PWG raster color space */
803                 numcolors;	/* Number of colorants */
804     const char	*ptr;		/* Pointer into value */
805 
806     ptr = NULL;
807     numcolors = 0;
808     bitspercolor = 8;
809     if (!strncasecmp(val, "AdobeRgb", 8))
810     {
811       if (*(val + 8) == '_' || *(val + 8) == '-')
812 	ptr = val + 9;
813       colorspace = 20;
814       numcolors = 3;
815     }
816     else if (!strncasecmp(val, "adobe-rgb", 9))
817     {
818       if (*(val + 9) == '_' || *(val + 9) == '-')
819 	ptr = val + 10;
820       colorspace = 20;
821       numcolors = 3;
822     }
823     else if (!strcasecmp(val, "auto-monochrome"))
824     {
825       colorspace = 18;
826       numcolors = 1;
827     }
828     else if (!strcasecmp(val, "bi-level") ||
829 	     !strcasecmp(val, "process-bi-level"))
830     {
831       bitspercolor = 1;
832       colorspace = 3;
833       numcolors = 1;
834     }
835     else if (!strncasecmp(val, "Black", 5))
836     {
837       if (*(val + 5) == '_' || *(val + 5) == '-')
838 	ptr = val + 6;
839       bitspercolor = 1;
840       colorspace = 3;
841       numcolors = 1;
842     }
843     else if (!strcasecmp(val, "process-monochrome"))
844     {
845       colorspace = 18;
846       numcolors = 1;
847     }
848     else if (!strncasecmp(val, "Monochrome", 10))
849     {
850       if (*(val + 10) == '_' || *(val + 10) == '-')
851 	ptr = val + 11;
852       colorspace = 18;
853       numcolors = 1;
854     }
855     else if (!strncasecmp(val, "Mono", 4))
856     {
857       if (*(val + 4) == '_' || *(val + 4) == '-')
858 	ptr = val + 5;
859       colorspace = 18;
860       numcolors = 1;
861     }
862     else if (!strcasecmp(val, "color"))
863     {
864       colorspace = 19;
865       numcolors = 3;
866     }
867     else if (!strncasecmp(val, "Cmyk", 4))
868     {
869       if (*(val + 4) == '_' || *(val + 4) == '-')
870 	ptr = val + 5;
871       colorspace = 6;
872       numcolors = 4;
873     }
874     else if (!strncasecmp(val, "Cmy", 3))
875     {
876       if (*(val + 3) == '_' || *(val + 3) == '-')
877 	ptr = val + 4;
878       colorspace = 4;
879       numcolors = 3;
880     }
881     else if (!strncasecmp(val, "Device", 6))
882     {
883       ptr = val + 6;
884       numcolors = strtol(ptr, (char **)&ptr, 10);
885       if (*ptr == '_' || *ptr == '-')
886       {
887 	ptr ++;
888 	colorspace = 47 + numcolors;
889       }
890       else
891       {
892 	numcolors = 0;
893 	ptr = NULL;
894       }
895     }
896     else if (!strncasecmp(val, "Sgray", 5))
897     {
898       if (*(val + 5) == '_' || *(val + 5) == '-')
899 	ptr = val + 6;
900       colorspace = 18;
901       numcolors = 1;
902     }
903     else if (!strncasecmp(val, "Gray", 4))
904     {
905       if (*(val + 4) == '_' || *(val + 4) == '-')
906 	ptr = val + 5;
907       colorspace = 18;
908       numcolors = 1;
909     }
910     else if (!strncasecmp(val, "Srgb", 4))
911     {
912       if (*(val + 4) == '_' || *(val + 4) == '-')
913 	ptr = val + 5;
914       colorspace = 19;
915       numcolors = 3;
916     }
917     else if (!strncasecmp(val, "Rgbw", 4))
918     {
919       if (*(val + 4) == '_' || *(val + 4) == '-')
920 	ptr = val + 5;
921       colorspace = 17;
922       numcolors = 4;
923     }
924     else if (!strncasecmp(val, "Rgb", 3))
925     {
926       if (*(val + 3) == '_' || *(val + 3) == '-')
927 	ptr = val + 4;
928       colorspace = 1;
929       numcolors = 3;
930     }
931     else if (!strcasecmp(val, "auto"))
932     {
933       /* Let "auto" not look like an error */
934       if (set_defaults)
935       {
936 	fprintf(stderr,
937 		"DEBUG: \"Auto\" mode, using default RGB color space.\n");
938 	colorspace = 19;
939 	numcolors = 3;
940       }
941     }
942     if (numcolors > 0)
943     {
944       if (ptr)
945 	bitspercolor = strtol(ptr, (char **)&ptr, 10);
946       bitsperpixel = bitspercolor * numcolors;
947       /* In 1-bit-per-color RGB modes we add a forth bit to each pixel
948 	 to align the pixels with bytes */
949       if (bitsperpixel == 3 &&
950 	  strcasestr(val, "Rgb"))
951 	bitsperpixel = 4;
952       h->cupsBitsPerColor = bitspercolor;
953       h->cupsBitsPerPixel = bitsperpixel;
954       h->cupsColorSpace = colorspace;
955       h->cupsNumColors = numcolors;
956     }
957     else
958     {
959       fprintf(stderr, "DEBUG: Bad color space value \"%s\".\n", val);
960       if (set_defaults)
961       {
962 	h->cupsBitsPerColor = 8;
963 	h->cupsBitsPerPixel = 24;
964 	h->cupsColorSpace = 19;
965 	h->cupsNumColors = 3;
966       }
967     }
968   }
969   else if (set_defaults)
970   {
971     h->cupsBitsPerColor = 8;
972     h->cupsBitsPerPixel = 24;
973     h->cupsColorSpace = 19;
974     h->cupsNumColors = 3;
975   }
976 
977   h->cupsBytesPerLine = (h->cupsWidth * h->cupsBitsPerPixel + 7) / 8;
978 
979   if (pwg_raster || set_defaults)
980   {
981     /* TODO - Support for color orders 1 (banded) and 2 (planar) */
982     h->cupsColorOrder = 0;
983   }
984 
985   if (pwg_raster || set_defaults)
986   {
987     /* TODO - Support for these parameters */
988     h->cupsCompression = 0;
989     h->cupsRowCount = 0;
990     h->cupsRowFeed = 0;
991     h->cupsRowStep = 0;
992   }
993 
994   if (pwg_raster || set_defaults)
995   {
996     /* TODO - Support for cupsBorderlessScalingFactor */
997     h->cupsBorderlessScalingFactor = 0.0;
998   }
999 
1000   if (pwg_raster || set_defaults)
1001   {
1002     /* TODO - Support for custom values in CUPS Raster mode */
1003     for (i = 0; i < 16; i ++)
1004     {
1005       h->cupsInteger[i] = 0;
1006       h->cupsReal[i] = 0.0;
1007       memset(h->cupsString[i], 0, 64);
1008     }
1009   }
1010 
1011   if (pwg_raster)
1012   {
1013 
1014     if ((val = cupsGetOption("job-impressions", num_options,
1015 			     options)) != NULL ||
1016 	(val = cupsGetOption("JobImpressions", num_options, options)) != NULL ||
1017 	(val = cupsGetOption("Impressions", num_options, options)) != NULL)
1018     {
1019       int impressions = atoi(val);
1020       if (impressions >= 0)
1021 	h->cupsInteger[0] = impressions;
1022     }
1023 
1024     if ((val = cupsGetOption("pwg-raster-document-sheet-back", num_options,
1025 			     options)) != NULL ||
1026 	(val = cupsGetOption("PwgRasterDocumentSheetBack", num_options,
1027 			     options)) != NULL)
1028     {
1029       /* Set CrossFeedTransform and FeedTransform */
1030       if (h->Duplex == CUPS_FALSE)
1031       {
1032 	h->cupsInteger[1] = 1;
1033 	h->cupsInteger[2] = 1;
1034       }
1035       else if (h->Duplex == CUPS_TRUE)
1036       {
1037 	if (h->Tumble == CUPS_FALSE)
1038 	{
1039 	  if (!strcasecmp(val, "Flipped"))
1040 	  {
1041 	    h->cupsInteger[1] =  1;
1042 	    h->cupsInteger[2] = -1;
1043 	  }
1044 	  else if (!strncasecmp(val, "Manual", 6))
1045 	  {
1046 	    h->cupsInteger[1] =  1;
1047 	    h->cupsInteger[2] =  1;
1048 	  }
1049 	  else if (!strcasecmp(val, "Normal"))
1050 	  {
1051 	    h->cupsInteger[1] =  1;
1052 	    h->cupsInteger[2] =  1;
1053 	  }
1054 	  else if (!strcasecmp(val, "Rotated"))
1055 	  {
1056 	    h->cupsInteger[1] = -1;
1057 	    h->cupsInteger[2] = -1;
1058 	  }
1059 	  else
1060 	  {
1061 	    h->cupsInteger[1] =  1;
1062 	    h->cupsInteger[2] =  1;
1063 	  }
1064 	}
1065 	else
1066 	{
1067 	  if (!strcasecmp(val, "Flipped"))
1068 	  {
1069 	    h->cupsInteger[1] = -1;
1070 	    h->cupsInteger[2] =  1;
1071 	  }
1072 	  else if (!strncasecmp(val, "Manual", 6))
1073 	  {
1074 	    h->cupsInteger[1] = -1;
1075 	    h->cupsInteger[2] = -1;
1076 	  }
1077 	  else if (!strcasecmp(val, "Normal"))
1078 	  {
1079 	    h->cupsInteger[1] =  1;
1080 	    h->cupsInteger[2] =  1;
1081 	  }
1082 	  else if (!strcasecmp(val, "Rotated"))
1083 	  {
1084 	    h->cupsInteger[1] =  1;
1085 	    h->cupsInteger[2] =  1;
1086 	  }
1087 	  else
1088 	  {
1089 	    h->cupsInteger[1] =  1;
1090 	    h->cupsInteger[2] =  1;
1091 	  }
1092 	}
1093       }
1094       else
1095       {
1096 	h->cupsInteger[1] = 1;
1097 	h->cupsInteger[2] = 1;
1098       }
1099     }
1100     else
1101     {
1102       h->cupsInteger[1] = 1;
1103       h->cupsInteger[2] = 1;
1104     }
1105 
1106     /* TODO - Support for ImageBoxLeft, ImageBoxTop, ImageBoxRight, and
1107        ImageBoxBottom (h->cupsInteger[3..6]), leave on 0 for now */
1108 
1109     if ((val = cupsGetOption("alternate-primary", num_options,
1110 			     options)) != NULL ||
1111 	(val = cupsGetOption("AlternatePrimary", num_options,
1112 			     options)) != NULL)
1113     {
1114       int alternateprimary = atoi(val);		/* SRGB value for black
1115 						   pixels */
1116       h->cupsInteger[7] = alternateprimary;
1117     }
1118 
1119     if ((val = cupsGetOption("print-quality", num_options, options)) != NULL ||
1120 	(val = cupsGetOption("PrintQuality", num_options, options)) != NULL ||
1121 	(val = cupsGetOption("Quality", num_options, options)) != NULL)
1122     {
1123       int quality = atoi(val);		/* print-quality value */
1124 
1125       if (!quality ||
1126 	  (quality >= IPP_QUALITY_DRAFT && quality <= IPP_QUALITY_HIGH))
1127 	h->cupsInteger[8] = quality;
1128       else
1129 	fprintf(stderr, "DEBUG: Unsupported print-quality %d.\n", quality);
1130     }
1131 
1132     /* Leave "reserved" fields (h->cupsInteger[9..13]) on 0 */
1133 
1134     if ((val = cupsGetOption("vendor-identifier", num_options,
1135 			     options)) != NULL ||
1136 	(val = cupsGetOption("VendorIdentifier", num_options,
1137 			     options)) != NULL)
1138     {
1139       int vendorid = atoi(val);		/* USB ID of manufacturer */
1140       h->cupsInteger[14] = vendorid;
1141     }
1142 
1143     if ((val = cupsGetOption("vendor-length", num_options,
1144 			     options)) != NULL ||
1145 	(val = cupsGetOption("VendorLength", num_options,
1146 			     options)) != NULL)
1147     {
1148       int vendorlength = atoi(val);		/* How many bytes of vendor
1149 						   data? */
1150       if (vendorlength <= 1088)
1151       {
1152 	h->cupsInteger[15] = vendorlength;
1153 	if ((val = cupsGetOption("vendor-data", num_options,
1154 				 options)) != NULL ||
1155 	    (val = cupsGetOption("VendorData", num_options,
1156 				 options)) != NULL)
1157 	  /* TODO - How to enter binary data here? */
1158 	  _strlcpy((char *)&(h->cupsReal[0]), val, 1088);
1159       }
1160     }
1161   }
1162 
1163   if (pwg_raster || set_defaults)
1164   {
1165     /* Set "reserved" fields to 0 */
1166     memset(h->cupsMarkerType, 0, 64);
1167   }
1168 
1169   if ((val = cupsGetOption("print-rendering-intent", num_options,
1170 			   options)) != NULL ||
1171       (val = cupsGetOption("PrintRenderingIntent", num_options,
1172 			   options)) != NULL ||
1173       (val = cupsGetOption("RenderingIntent", num_options,
1174 			   options)) != NULL)
1175   {
1176     if (!strcmp(val, "absolute"))
1177       _strlcpy(h->cupsRenderingIntent, "Absolute",
1178 	      sizeof(h->cupsRenderingIntent));
1179     else if (!strcmp(val, "automatic"))
1180       _strlcpy(h->cupsRenderingIntent, "Automatic",
1181 	      sizeof(h->cupsRenderingIntent));
1182     else if (!strcmp(val, "perceptual"))
1183       _strlcpy(h->cupsRenderingIntent, "Perceptual",
1184 	      sizeof(h->cupsRenderingIntent));
1185     else if (!strcmp(val, "relative"))
1186       _strlcpy(h->cupsRenderingIntent, "Relative",
1187 	      sizeof(h->cupsRenderingIntent));
1188     else if (!strcmp(val, "relative-bpc"))
1189       _strlcpy(h->cupsRenderingIntent, "RelativeBpc",
1190 	      sizeof(h->cupsRenderingIntent));
1191     else if (!strcmp(val, "saturation"))
1192       _strlcpy(h->cupsRenderingIntent, "Saturation",
1193 	      sizeof(h->cupsRenderingIntent));
1194     else
1195       fprintf(stderr, "DEBUG: Unsupported print-rendering-intent \"%s\".\n",
1196 	      val);
1197   }
1198   else if (set_defaults)
1199     h->cupsRenderingIntent[0] = '\0';
1200 
1201   if (media_source != NULL)
1202     free(media_source);
1203   if (media_type != NULL)
1204     free(media_type);
1205   if (page_size != NULL)
1206     free(page_size);
1207   if (num_non_ppd_options)
1208     cupsFreeOptions(num_non_ppd_options, non_ppd_options);
1209 #endif /* HAVE_CUPS_1_7 */
1210 
1211   return (0);
1212 }
1213 
1214 
1215 /*
1216  * End
1217  */
1218