]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/ppd-cache.c
The IPP backend incorrectly included the job-password attribute in Validate-Job
[thirdparty/cups.git] / cups / ppd-cache.c
CommitLineData
f14324a7
MS
1/*
2 * "$Id$"
3 *
7e86f2f6 4 * PPD cache implementation for CUPS.
f14324a7 5 *
79d7d84a 6 * Copyright 2010-2015 by Apple Inc.
f14324a7 7 *
7e86f2f6
MS
8 * These coded instructions, statements, and computer programs are the
9 * property of Apple Inc. and are protected by Federal copyright
10 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
11 * which should have been included with this file. If this file is
12 * file is missing or damaged, see the license at "http://www.cups.org/".
f14324a7 13 *
7e86f2f6 14 * This file is subject to the Apple OS-Developed Software exception.
f14324a7
MS
15 */
16
17/*
18 * Include necessary headers...
19 */
20
21#include "cups-private.h"
22#include <math.h>
23
24
25/*
26 * Macro to test for two almost-equal PWG measurements.
27 */
28
29#define _PWG_EQUIVALENT(x, y) (abs((x)-(y)) < 2)
30
31
32/*
33 * Local functions...
34 */
35
dcb445bc
MS
36static int pwg_compare_finishings(_pwg_finishings_t *a,
37 _pwg_finishings_t *b);
38static void pwg_free_finishings(_pwg_finishings_t *f);
5a08320a 39static void pwg_free_material(_pwg_material_t *m);
f14324a7 40static void pwg_ppdize_name(const char *ipp, char *name, size_t namesize);
d9fc71e4 41static void pwg_ppdize_resolution(ipp_attribute_t *attr, int element, int *xres, int *yres, char *name, size_t namesize);
c1420c87
MS
42static void pwg_unppdize_name(const char *ppd, char *name, size_t namesize,
43 const char *dashchars);
f14324a7
MS
44
45
f099325e
MS
46/*
47 * '_cupsConvertOptions()' - Convert printer options to standard IPP attributes.
48 *
49 * This functions converts PPD and CUPS-specific options to their standard IPP
50 * attributes and values and adds them to the specified IPP request.
51 */
52
53int /* O - New number of copies */
54_cupsConvertOptions(ipp_t *request, /* I - IPP request */
55 ppd_file_t *ppd, /* I - PPD file */
56 _ppd_cache_t *pc, /* I - PPD cache info */
57 ipp_attribute_t *media_col_sup,
58 /* I - media-col-supported values */
59 ipp_attribute_t *doc_handling_sup,
60 /* I - multiple-document-handling-supported values */
61 ipp_attribute_t *print_color_mode_sup,
62 /* I - Printer supports print-color-mode */
63 const char *user, /* I - User info */
64 const char *format, /* I - document-format value */
65 int copies, /* I - Number of copies */
66 int num_options, /* I - Number of options */
67 cups_option_t *options) /* I - Options */
68{
69 int i; /* Looping var */
70 const char *keyword; /* PWG keyword */
71 pwg_size_t *size; /* PWG media size */
72 ipp_t *media_col, /* media-col value */
73 *media_size; /* media-size value */
74 const char *media_source, /* media-source value */
75 *media_type, /* media-type value */
76 *collate_str, /* multiple-document-handling value */
77 *color_attr_name, /* Supported color attribute */
78 *mandatory; /* Mandatory attributes */
79 int num_finishings = 0, /* Number of finishing values */
80 finishings[10]; /* Finishing enum values */
81 ppd_choice_t *choice; /* Marked choice */
82
83
84 /*
85 * Send standard IPP attributes...
86 */
87
71a78e2f 88 if (pc->password && (keyword = cupsGetOption("job-password", num_options, options)) != NULL && ippGetOperation(request) != IPP_OP_VALIDATE_JOB)
f099325e
MS
89 {
90 ippAddOctetString(request, IPP_TAG_OPERATION, "job-password", keyword, (int)strlen(keyword));
91
92 if ((keyword = cupsGetOption("job-password-encryption", num_options, options)) == NULL)
93 keyword = "none";
94
95 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "job-password-encryption", NULL, keyword);
96 }
97
98 if (pc->account_id)
99 {
100 if ((keyword = cupsGetOption("job-account-id", num_options, options)) == NULL)
101 keyword = cupsGetOption("job-billing", num_options, options);
102
103 if (keyword)
104 ippAddString(request, IPP_TAG_JOB, IPP_TAG_NAME, "job-account-id", NULL, keyword);
105 }
106
107 if (pc->accounting_user_id)
108 {
109 if ((keyword = cupsGetOption("job-accounting-user-id", num_options, options)) == NULL)
110 keyword = user;
111
112 if (keyword)
113 ippAddString(request, IPP_TAG_JOB, IPP_TAG_NAME, "job-accounting-user-id", NULL, keyword);
114 }
115
116 for (mandatory = (const char *)cupsArrayFirst(pc->mandatory); mandatory; mandatory = (const char *)cupsArrayNext(pc->mandatory))
117 {
118 if (strcmp(mandatory, "copies") &&
119 strcmp(mandatory, "destination-uris") &&
120 strcmp(mandatory, "finishings") &&
121 strcmp(mandatory, "job-account-id") &&
122 strcmp(mandatory, "job-accounting-user-id") &&
123 strcmp(mandatory, "job-password") &&
124 strcmp(mandatory, "job-password-encryption") &&
125 strcmp(mandatory, "media") &&
126 strncmp(mandatory, "media-col", 9) &&
127 strcmp(mandatory, "multiple-document-handling") &&
128 strcmp(mandatory, "output-bin") &&
129 strcmp(mandatory, "print-color-mode") &&
130 strcmp(mandatory, "print-quality") &&
131 strcmp(mandatory, "sides") &&
132 (keyword = cupsGetOption(mandatory, num_options, options)) != NULL)
133 {
134 _ipp_option_t *opt = _ippFindOption(mandatory);
135 /* Option type */
136 ipp_tag_t value_tag = opt ? opt->value_tag : IPP_TAG_NAME;
137 /* Value type */
138
139 switch (value_tag)
140 {
141 case IPP_TAG_INTEGER :
142 case IPP_TAG_ENUM :
143 ippAddInteger(request, IPP_TAG_JOB, value_tag, mandatory, atoi(keyword));
144 break;
145 case IPP_TAG_BOOLEAN :
146 ippAddBoolean(request, IPP_TAG_JOB, mandatory, !_cups_strcasecmp(keyword, "true"));
147 break;
148 case IPP_TAG_RANGE :
149 {
150 int lower, upper; /* Range */
151
152 if (sscanf(keyword, "%d-%d", &lower, &upper) != 2)
153 lower = upper = atoi(keyword);
154
155 ippAddRange(request, IPP_TAG_JOB, mandatory, lower, upper);
156 }
157 break;
158 case IPP_TAG_STRING :
159 ippAddOctetString(request, IPP_TAG_JOB, mandatory, keyword, (int)strlen(keyword));
160 break;
161 default :
162 if (!strcmp(mandatory, "print-color-mode") && !strcmp(keyword, "monochrome"))
163 {
164 if (ippContainsString(print_color_mode_sup, "auto-monochrome"))
165 keyword = "auto-monochrome";
166 else if (ippContainsString(print_color_mode_sup, "process-monochrome") && !ippContainsString(print_color_mode_sup, "monochrome"))
167 keyword = "process-monochrome";
168 }
169
170 ippAddString(request, IPP_TAG_JOB, value_tag, mandatory, NULL, keyword);
171 break;
172 }
173 }
174 }
175
176 if ((keyword = cupsGetOption("PageSize", num_options, options)) == NULL)
177 keyword = cupsGetOption("media", num_options, options);
178
179 if ((size = _ppdCacheGetSize(pc, keyword)) != NULL)
180 {
181 /*
182 * Add a media-col value...
183 */
184
185 media_size = ippNew();
186 ippAddInteger(media_size, IPP_TAG_ZERO, IPP_TAG_INTEGER,
187 "x-dimension", size->width);
188 ippAddInteger(media_size, IPP_TAG_ZERO, IPP_TAG_INTEGER,
189 "y-dimension", size->length);
190
191 media_col = ippNew();
192 ippAddCollection(media_col, IPP_TAG_ZERO, "media-size", media_size);
193
194 media_source = _ppdCacheGetSource(pc, cupsGetOption("InputSlot",
195 num_options,
196 options));
197 media_type = _ppdCacheGetType(pc, cupsGetOption("MediaType",
198 num_options,
199 options));
200
201 for (i = 0; i < media_col_sup->num_values; i ++)
202 {
203 if (!strcmp(media_col_sup->values[i].string.text, "media-left-margin"))
204 ippAddInteger(media_col, IPP_TAG_ZERO, IPP_TAG_INTEGER, "media-left-margin", size->left);
205 else if (!strcmp(media_col_sup->values[i].string.text, "media-bottom-margin"))
206 ippAddInteger(media_col, IPP_TAG_ZERO, IPP_TAG_INTEGER, "media-bottom-margin", size->bottom);
207 else if (!strcmp(media_col_sup->values[i].string.text, "media-right-margin"))
208 ippAddInteger(media_col, IPP_TAG_ZERO, IPP_TAG_INTEGER, "media-right-margin", size->right);
209 else if (!strcmp(media_col_sup->values[i].string.text, "media-top-margin"))
210 ippAddInteger(media_col, IPP_TAG_ZERO, IPP_TAG_INTEGER, "media-top-margin", size->top);
211 else if (!strcmp(media_col_sup->values[i].string.text, "media-source") && media_source)
212 ippAddString(media_col, IPP_TAG_ZERO, IPP_TAG_KEYWORD, "media-source", NULL, media_source);
213 else if (!strcmp(media_col_sup->values[i].string.text, "media-type") && media_type)
214 ippAddString(media_col, IPP_TAG_ZERO, IPP_TAG_KEYWORD, "media-type", NULL, media_type);
215 }
216
217 ippAddCollection(request, IPP_TAG_JOB, "media-col", media_col);
218 }
219
220 if ((keyword = cupsGetOption("output-bin", num_options, options)) == NULL)
221 {
222 if ((choice = ppdFindMarkedChoice(ppd, "OutputBin")) != NULL)
223 keyword = _ppdCacheGetBin(pc, choice->choice);
224 }
225
226 if (keyword)
227 ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "output-bin", NULL, keyword);
228
229 color_attr_name = print_color_mode_sup ? "print-color-mode" : "output-mode";
230
231 if ((keyword = cupsGetOption("print-color-mode", num_options, options)) == NULL)
232 {
233 if ((choice = ppdFindMarkedChoice(ppd, "ColorModel")) != NULL)
234 {
235 if (!_cups_strcasecmp(choice->choice, "Gray"))
236 keyword = "monochrome";
237 else
238 keyword = "color";
239 }
240 }
241
242 if (keyword && !strcmp(keyword, "monochrome"))
243 {
244 if (ippContainsString(print_color_mode_sup, "auto-monochrome"))
245 keyword = "auto-monochrome";
246 else if (ippContainsString(print_color_mode_sup, "process-monochrome") && !ippContainsString(print_color_mode_sup, "monochrome"))
247 keyword = "process-monochrome";
248 }
249
250 if (keyword)
251 ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, color_attr_name, NULL, keyword);
252
253 if ((keyword = cupsGetOption("print-quality", num_options, options)) != NULL)
254 ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_ENUM, "print-quality", atoi(keyword));
255 else if ((choice = ppdFindMarkedChoice(ppd, "cupsPrintQuality")) != NULL)
256 {
257 if (!_cups_strcasecmp(choice->choice, "draft"))
258 ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_ENUM, "print-quality", IPP_QUALITY_DRAFT);
259 else if (!_cups_strcasecmp(choice->choice, "normal"))
260 ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_ENUM, "print-quality", IPP_QUALITY_NORMAL);
261 else if (!_cups_strcasecmp(choice->choice, "high"))
262 ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_ENUM, "print-quality", IPP_QUALITY_HIGH);
263 }
264
265 if ((keyword = cupsGetOption("sides", num_options, options)) != NULL)
266 ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "sides", NULL, keyword);
267 else if (pc->sides_option && (choice = ppdFindMarkedChoice(ppd, pc->sides_option)) != NULL)
268 {
269 if (!_cups_strcasecmp(choice->choice, pc->sides_1sided))
270 ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "sides", NULL, "one-sided");
271 else if (!_cups_strcasecmp(choice->choice, pc->sides_2sided_long))
272 ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "sides", NULL, "two-sided-long-edge");
273 if (!_cups_strcasecmp(choice->choice, pc->sides_2sided_short))
274 ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "sides", NULL, "two-sided-short-edge");
275 }
276
277 /*
278 * Copies...
279 */
280
281 if ((keyword = cupsGetOption("multiple-document-handling", num_options, options)) != NULL)
282 {
283 if (strstr(keyword, "uncollated"))
284 keyword = "false";
285 else
286 keyword = "true";
287 }
288 else if ((keyword = cupsGetOption("collate", num_options, options)) == NULL)
289 keyword = "true";
290
291 if (format)
292 {
293 if (!_cups_strcasecmp(format, "image/gif") ||
294 !_cups_strcasecmp(format, "image/jp2") ||
295 !_cups_strcasecmp(format, "image/jpeg") ||
296 !_cups_strcasecmp(format, "image/png") ||
297 !_cups_strcasecmp(format, "image/tiff") ||
298 !_cups_strncasecmp(format, "image/x-", 8))
299 {
300 /*
301 * Collation makes no sense for single page image formats...
302 */
303
304 keyword = "false";
305 }
306 else if (!_cups_strncasecmp(format, "image/", 6) ||
307 !_cups_strcasecmp(format, "application/vnd.cups-raster"))
308 {
309 /*
310 * Multi-page image formats will have copies applied by the upstream
311 * filters...
312 */
313
314 copies = 1;
315 }
316 }
317
318 if (doc_handling_sup)
319 {
320 if (!_cups_strcasecmp(keyword, "true"))
321 collate_str = "separate-documents-collated-copies";
322 else
323 collate_str = "separate-documents-uncollated-copies";
324
325 for (i = 0; i < doc_handling_sup->num_values; i ++)
326 {
327 if (!strcmp(doc_handling_sup->values[i].string.text, collate_str))
328 {
329 ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "multiple-document-handling", NULL, collate_str);
330 break;
331 }
332 }
333
334 if (i >= doc_handling_sup->num_values)
335 copies = 1;
336 }
337
338 /*
339 * Map finishing options...
340 */
341
342 num_finishings = _ppdCacheGetFinishingValues(pc, num_options, options, (int)(sizeof(finishings) / sizeof(finishings[0])), finishings);
343 if (num_finishings > 0)
344 {
345 ippAddIntegers(request, IPP_TAG_JOB, IPP_TAG_ENUM, "finishings", num_finishings, finishings);
346
347 if (copies > 1 && (keyword = cupsGetOption("job-impressions", num_options, options)) != NULL)
348 {
349 /*
350 * Send job-pages-per-set attribute to apply finishings correctly...
351 */
352
353 ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-pages-per-set", atoi(keyword) / copies);
354 }
355 }
356
357 return (copies);
358}
359
360
f14324a7
MS
361/*
362 * '_ppdCacheCreateWithFile()' - Create PPD cache and mapping data from a
363 * written file.
364 *
365 * Use the @link _ppdCacheWriteFile@ function to write PWG mapping data to a
366 * file.
367 */
368
369_ppd_cache_t * /* O - PPD cache and mapping data */
370_ppdCacheCreateWithFile(
371 const char *filename, /* I - File to read */
372 ipp_t **attrs) /* IO - IPP attributes, if any */
373{
374 cups_file_t *fp; /* File */
375 _ppd_cache_t *pc; /* PWG mapping data */
6961465f
MS
376 pwg_size_t *size; /* Current size */
377 pwg_map_t *map; /* Current map */
dcb445bc 378 _pwg_finishings_t *finishings; /* Current finishings option */
f14324a7
MS
379 int linenum, /* Current line number */
380 num_bins, /* Number of bins in file */
381 num_sizes, /* Number of sizes in file */
382 num_sources, /* Number of sources in file */
383 num_types; /* Number of types in file */
384 char line[2048], /* Current line */
385 *value, /* Pointer to value in line */
386 *valueptr, /* Pointer into value */
387 pwg_keyword[128], /* PWG keyword */
388 ppd_keyword[PPD_MAX_NAME];
389 /* PPD keyword */
390 _pwg_print_color_mode_t print_color_mode;
391 /* Print color mode for preset */
392 _pwg_print_quality_t print_quality; /* Print quality for preset */
393
394
395 DEBUG_printf(("_ppdCacheCreateWithFile(filename=\"%s\")", filename));
396
397 /*
398 * Range check input...
399 */
400
401 if (attrs)
402 *attrs = NULL;
403
404 if (!filename)
405 {
cb7f98ee 406 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
f14324a7
MS
407 return (NULL);
408 }
409
410 /*
411 * Open the file...
412 */
413
414 if ((fp = cupsFileOpen(filename, "r")) == NULL)
415 {
cb7f98ee 416 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
f14324a7
MS
417 return (NULL);
418 }
419
420 /*
421 * Read the first line and make sure it has "#CUPS-PPD-CACHE-version" in it...
422 */
423
424 if (!cupsFileGets(fp, line, sizeof(line)))
425 {
cb7f98ee 426 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
f14324a7
MS
427 DEBUG_puts("_ppdCacheCreateWithFile: Unable to read first line.");
428 cupsFileClose(fp);
429 return (NULL);
430 }
431
22c9029b 432 if (strncmp(line, "#CUPS-PPD-CACHE-", 16))
f14324a7 433 {
cb7f98ee 434 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
435 DEBUG_printf(("_ppdCacheCreateWithFile: Wrong first line \"%s\".", line));
436 cupsFileClose(fp);
437 return (NULL);
438 }
439
22c9029b
MS
440 if (atoi(line + 16) != _PPD_CACHE_VERSION)
441 {
cb7f98ee 442 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Out of date PPD cache file."), 1);
22c9029b
MS
443 DEBUG_printf(("_ppdCacheCreateWithFile: Cache file has version %s, "
444 "expected %d.", line + 16, _PPD_CACHE_VERSION));
445 cupsFileClose(fp);
446 return (NULL);
447 }
448
f14324a7
MS
449 /*
450 * Allocate the mapping data structure...
451 */
452
453 if ((pc = calloc(1, sizeof(_ppd_cache_t))) == NULL)
454 {
cb7f98ee 455 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
f14324a7
MS
456 DEBUG_puts("_ppdCacheCreateWithFile: Unable to allocate _ppd_cache_t.");
457 goto create_error;
458 }
459
3e7fe0ca
MS
460 pc->max_copies = 9999;
461
f14324a7
MS
462 /*
463 * Read the file...
464 */
465
466 linenum = 0;
467 num_bins = 0;
468 num_sizes = 0;
469 num_sources = 0;
470 num_types = 0;
471
472 while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
473 {
474 DEBUG_printf(("_ppdCacheCreateWithFile: line=\"%s\", value=\"%s\", "
475 "linenum=%d", line, value, linenum));
476
477 if (!value)
478 {
479 DEBUG_printf(("_ppdCacheCreateWithFile: Missing value on line %d.",
480 linenum));
cb7f98ee 481 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
482 goto create_error;
483 }
5a08320a
MS
484 else if (!_cups_strcasecmp(line, "3D"))
485 {
486 pc->cups_3d = _cupsStrAlloc(value);
487 }
488 else if (!_cups_strcasecmp(line, "LayerOrder"))
489 {
490 pc->cups_layer_order = _cupsStrAlloc(value);
491 }
492 else if (!_cups_strcasecmp(line, "Accuracy"))
493 {
494 sscanf(value, "%d%d%d", pc->cups_accuracy + 0, pc->cups_accuracy + 1, pc->cups_accuracy + 2);
495 }
496 else if (!_cups_strcasecmp(line, "Volume"))
497 {
498 sscanf(value, "%d%d%d", pc->cups_volume + 0, pc->cups_volume + 1, pc->cups_volume + 2);
499 }
500 else if (!_cups_strcasecmp(line, "Material"))
501 {
502 /*
503 * Material key "name" name=value ... name=value
504 */
505
506 if ((valueptr = strchr(value, ' ')) != NULL)
507 {
508 _pwg_material_t *material = (_pwg_material_t *)calloc(1, sizeof(_pwg_material_t));
509
510 *valueptr++ = '\0';
511
512 material->key = _cupsStrAlloc(value);
513
514 if (*valueptr == '\"')
515 {
516 value = valueptr + 1;
517 if ((valueptr = strchr(value, '\"')) != NULL)
518 {
519 *valueptr++ = '\0';
520 material->name = _cupsStrAlloc(value);
521 material->num_props = cupsParseOptions(valueptr, 0, &material->props);
522 }
523 }
524
525 if (!pc->materials)
526 pc->materials = cupsArrayNew3(NULL, NULL, NULL, 0, NULL, (cups_afree_func_t)pwg_free_material);
527
528 cupsArrayAdd(pc->materials, material);
529 }
530 }
88f9aafc 531 else if (!_cups_strcasecmp(line, "Filter"))
f14324a7
MS
532 {
533 if (!pc->filters)
534 pc->filters = cupsArrayNew3(NULL, NULL, NULL, 0,
535 (cups_acopy_func_t)_cupsStrAlloc,
536 (cups_afree_func_t)_cupsStrFree);
537
538 cupsArrayAdd(pc->filters, value);
539 }
88f9aafc 540 else if (!_cups_strcasecmp(line, "PreFilter"))
f14324a7
MS
541 {
542 if (!pc->prefilters)
543 pc->prefilters = cupsArrayNew3(NULL, NULL, NULL, 0,
544 (cups_acopy_func_t)_cupsStrAlloc,
545 (cups_afree_func_t)_cupsStrFree);
546
547 cupsArrayAdd(pc->prefilters, value);
548 }
88f9aafc 549 else if (!_cups_strcasecmp(line, "Product"))
f14324a7
MS
550 {
551 pc->product = _cupsStrAlloc(value);
552 }
88f9aafc 553 else if (!_cups_strcasecmp(line, "SingleFile"))
82f97232 554 {
88f9aafc 555 pc->single_file = !_cups_strcasecmp(value, "true");
82f97232 556 }
88f9aafc 557 else if (!_cups_strcasecmp(line, "IPP"))
f14324a7
MS
558 {
559 off_t pos = cupsFileTell(fp), /* Position in file */
560 length = strtol(value, NULL, 10);
561 /* Length of IPP attributes */
562
563 if (attrs && *attrs)
564 {
565 DEBUG_puts("_ppdCacheCreateWithFile: IPP listed multiple times.");
cb7f98ee 566 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
567 goto create_error;
568 }
569 else if (length <= 0)
570 {
571 DEBUG_puts("_ppdCacheCreateWithFile: Bad IPP length.");
cb7f98ee 572 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
573 goto create_error;
574 }
575
576 if (attrs)
577 {
578 /*
579 * Read IPP attributes into the provided variable...
580 */
581
582 *attrs = ippNew();
583
584 if (ippReadIO(fp, (ipp_iocb_t)cupsFileRead, 1, NULL,
cb7f98ee 585 *attrs) != IPP_STATE_DATA)
f14324a7
MS
586 {
587 DEBUG_puts("_ppdCacheCreateWithFile: Bad IPP data.");
cb7f98ee 588 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
589 goto create_error;
590 }
591 }
592 else
593 {
594 /*
595 * Skip the IPP data entirely...
596 */
597
598 cupsFileSeek(fp, pos + length);
599 }
600
601 if (cupsFileTell(fp) != (pos + length))
602 {
603 DEBUG_puts("_ppdCacheCreateWithFile: Bad IPP data.");
cb7f98ee 604 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
605 goto create_error;
606 }
607 }
88f9aafc 608 else if (!_cups_strcasecmp(line, "NumBins"))
f14324a7
MS
609 {
610 if (num_bins > 0)
611 {
612 DEBUG_puts("_ppdCacheCreateWithFile: NumBins listed multiple times.");
cb7f98ee 613 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
614 goto create_error;
615 }
616
617 if ((num_bins = atoi(value)) <= 0 || num_bins > 65536)
618 {
619 DEBUG_printf(("_ppdCacheCreateWithFile: Bad NumBins value %d on line "
620 "%d.", num_sizes, linenum));
cb7f98ee 621 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
622 goto create_error;
623 }
624
7e86f2f6 625 if ((pc->bins = calloc((size_t)num_bins, sizeof(pwg_map_t))) == NULL)
f14324a7
MS
626 {
627 DEBUG_printf(("_ppdCacheCreateWithFile: Unable to allocate %d bins.",
628 num_sizes));
cb7f98ee 629 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
f14324a7
MS
630 goto create_error;
631 }
632 }
88f9aafc 633 else if (!_cups_strcasecmp(line, "Bin"))
f14324a7
MS
634 {
635 if (sscanf(value, "%127s%40s", pwg_keyword, ppd_keyword) != 2)
636 {
637 DEBUG_printf(("_ppdCacheCreateWithFile: Bad Bin on line %d.", linenum));
cb7f98ee 638 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
639 goto create_error;
640 }
641
642 if (pc->num_bins >= num_bins)
643 {
644 DEBUG_printf(("_ppdCacheCreateWithFile: Too many Bin's on line %d.",
645 linenum));
cb7f98ee 646 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
647 goto create_error;
648 }
649
650 map = pc->bins + pc->num_bins;
651 map->pwg = _cupsStrAlloc(pwg_keyword);
652 map->ppd = _cupsStrAlloc(ppd_keyword);
653
654 pc->num_bins ++;
655 }
88f9aafc 656 else if (!_cups_strcasecmp(line, "NumSizes"))
f14324a7
MS
657 {
658 if (num_sizes > 0)
659 {
660 DEBUG_puts("_ppdCacheCreateWithFile: NumSizes listed multiple times.");
cb7f98ee 661 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
662 goto create_error;
663 }
664
5a9febac 665 if ((num_sizes = atoi(value)) < 0 || num_sizes > 65536)
f14324a7
MS
666 {
667 DEBUG_printf(("_ppdCacheCreateWithFile: Bad NumSizes value %d on line "
668 "%d.", num_sizes, linenum));
cb7f98ee 669 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
670 goto create_error;
671 }
672
5a9febac 673 if (num_sizes > 0)
f14324a7 674 {
7e86f2f6 675 if ((pc->sizes = calloc((size_t)num_sizes, sizeof(pwg_size_t))) == NULL)
5a9febac
MS
676 {
677 DEBUG_printf(("_ppdCacheCreateWithFile: Unable to allocate %d sizes.",
678 num_sizes));
cb7f98ee 679 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
5a9febac
MS
680 goto create_error;
681 }
f14324a7
MS
682 }
683 }
88f9aafc 684 else if (!_cups_strcasecmp(line, "Size"))
f14324a7
MS
685 {
686 if (pc->num_sizes >= num_sizes)
687 {
688 DEBUG_printf(("_ppdCacheCreateWithFile: Too many Size's on line %d.",
689 linenum));
cb7f98ee 690 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
691 goto create_error;
692 }
693
694 size = pc->sizes + pc->num_sizes;
695
696 if (sscanf(value, "%127s%40s%d%d%d%d%d%d", pwg_keyword, ppd_keyword,
697 &(size->width), &(size->length), &(size->left),
698 &(size->bottom), &(size->right), &(size->top)) != 8)
699 {
700 DEBUG_printf(("_ppdCacheCreateWithFile: Bad Size on line %d.",
701 linenum));
cb7f98ee 702 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
703 goto create_error;
704 }
705
706 size->map.pwg = _cupsStrAlloc(pwg_keyword);
707 size->map.ppd = _cupsStrAlloc(ppd_keyword);
708
709 pc->num_sizes ++;
710 }
88f9aafc 711 else if (!_cups_strcasecmp(line, "CustomSize"))
f14324a7
MS
712 {
713 if (pc->custom_max_width > 0)
714 {
715 DEBUG_printf(("_ppdCacheCreateWithFile: Too many CustomSize's on line "
716 "%d.", linenum));
cb7f98ee 717 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
718 goto create_error;
719 }
720
721 if (sscanf(value, "%d%d%d%d%d%d%d%d", &(pc->custom_max_width),
722 &(pc->custom_max_length), &(pc->custom_min_width),
723 &(pc->custom_min_length), &(pc->custom_size.left),
724 &(pc->custom_size.bottom), &(pc->custom_size.right),
725 &(pc->custom_size.top)) != 8)
726 {
727 DEBUG_printf(("_ppdCacheCreateWithFile: Bad CustomSize on line %d.",
728 linenum));
cb7f98ee 729 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
730 goto create_error;
731 }
732
6961465f
MS
733 pwgFormatSizeName(pwg_keyword, sizeof(pwg_keyword), "custom", "max",
734 pc->custom_max_width, pc->custom_max_length, NULL);
f14324a7
MS
735 pc->custom_max_keyword = _cupsStrAlloc(pwg_keyword);
736
6961465f
MS
737 pwgFormatSizeName(pwg_keyword, sizeof(pwg_keyword), "custom", "min",
738 pc->custom_min_width, pc->custom_min_length, NULL);
f14324a7
MS
739 pc->custom_min_keyword = _cupsStrAlloc(pwg_keyword);
740 }
88f9aafc 741 else if (!_cups_strcasecmp(line, "SourceOption"))
f14324a7
MS
742 {
743 pc->source_option = _cupsStrAlloc(value);
744 }
88f9aafc 745 else if (!_cups_strcasecmp(line, "NumSources"))
f14324a7
MS
746 {
747 if (num_sources > 0)
748 {
749 DEBUG_puts("_ppdCacheCreateWithFile: NumSources listed multiple "
750 "times.");
cb7f98ee 751 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
752 goto create_error;
753 }
754
755 if ((num_sources = atoi(value)) <= 0 || num_sources > 65536)
756 {
757 DEBUG_printf(("_ppdCacheCreateWithFile: Bad NumSources value %d on "
758 "line %d.", num_sources, linenum));
cb7f98ee 759 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
760 goto create_error;
761 }
762
7e86f2f6 763 if ((pc->sources = calloc((size_t)num_sources, sizeof(pwg_map_t))) == NULL)
f14324a7
MS
764 {
765 DEBUG_printf(("_ppdCacheCreateWithFile: Unable to allocate %d sources.",
766 num_sources));
cb7f98ee 767 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
f14324a7
MS
768 goto create_error;
769 }
770 }
88f9aafc 771 else if (!_cups_strcasecmp(line, "Source"))
f14324a7
MS
772 {
773 if (sscanf(value, "%127s%40s", pwg_keyword, ppd_keyword) != 2)
774 {
775 DEBUG_printf(("_ppdCacheCreateWithFile: Bad Source on line %d.",
776 linenum));
cb7f98ee 777 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
778 goto create_error;
779 }
780
781 if (pc->num_sources >= num_sources)
782 {
783 DEBUG_printf(("_ppdCacheCreateWithFile: Too many Source's on line %d.",
784 linenum));
cb7f98ee 785 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
786 goto create_error;
787 }
788
789 map = pc->sources + pc->num_sources;
790 map->pwg = _cupsStrAlloc(pwg_keyword);
791 map->ppd = _cupsStrAlloc(ppd_keyword);
792
793 pc->num_sources ++;
794 }
88f9aafc 795 else if (!_cups_strcasecmp(line, "NumTypes"))
f14324a7
MS
796 {
797 if (num_types > 0)
798 {
799 DEBUG_puts("_ppdCacheCreateWithFile: NumTypes listed multiple times.");
cb7f98ee 800 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
801 goto create_error;
802 }
803
804 if ((num_types = atoi(value)) <= 0 || num_types > 65536)
805 {
806 DEBUG_printf(("_ppdCacheCreateWithFile: Bad NumTypes value %d on "
807 "line %d.", num_types, linenum));
cb7f98ee 808 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
809 goto create_error;
810 }
811
7e86f2f6 812 if ((pc->types = calloc((size_t)num_types, sizeof(pwg_map_t))) == NULL)
f14324a7
MS
813 {
814 DEBUG_printf(("_ppdCacheCreateWithFile: Unable to allocate %d types.",
815 num_types));
cb7f98ee 816 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
f14324a7
MS
817 goto create_error;
818 }
819 }
88f9aafc 820 else if (!_cups_strcasecmp(line, "Type"))
f14324a7
MS
821 {
822 if (sscanf(value, "%127s%40s", pwg_keyword, ppd_keyword) != 2)
823 {
824 DEBUG_printf(("_ppdCacheCreateWithFile: Bad Type on line %d.",
825 linenum));
cb7f98ee 826 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
827 goto create_error;
828 }
829
830 if (pc->num_types >= num_types)
831 {
832 DEBUG_printf(("_ppdCacheCreateWithFile: Too many Type's on line %d.",
833 linenum));
cb7f98ee 834 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
835 goto create_error;
836 }
837
838 map = pc->types + pc->num_types;
839 map->pwg = _cupsStrAlloc(pwg_keyword);
840 map->ppd = _cupsStrAlloc(ppd_keyword);
841
842 pc->num_types ++;
843 }
88f9aafc 844 else if (!_cups_strcasecmp(line, "Preset"))
f14324a7
MS
845 {
846 /*
847 * Preset output-mode print-quality name=value ...
848 */
849
850 print_color_mode = (_pwg_print_color_mode_t)strtol(value, &valueptr, 10);
851 print_quality = (_pwg_print_quality_t)strtol(valueptr, &valueptr, 10);
852
853 if (print_color_mode < _PWG_PRINT_COLOR_MODE_MONOCHROME ||
854 print_color_mode >= _PWG_PRINT_COLOR_MODE_MAX ||
855 print_quality < _PWG_PRINT_QUALITY_DRAFT ||
856 print_quality >= _PWG_PRINT_QUALITY_MAX ||
857 valueptr == value || !*valueptr)
858 {
859 DEBUG_printf(("_ppdCacheCreateWithFile: Bad Preset on line %d.",
860 linenum));
cb7f98ee 861 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
862 goto create_error;
863 }
864
865 pc->num_presets[print_color_mode][print_quality] =
866 cupsParseOptions(valueptr, 0,
867 pc->presets[print_color_mode] + print_quality);
868 }
88f9aafc 869 else if (!_cups_strcasecmp(line, "SidesOption"))
f14324a7 870 pc->sides_option = _cupsStrAlloc(value);
88f9aafc 871 else if (!_cups_strcasecmp(line, "Sides1Sided"))
f14324a7 872 pc->sides_1sided = _cupsStrAlloc(value);
88f9aafc 873 else if (!_cups_strcasecmp(line, "Sides2SidedLong"))
f14324a7 874 pc->sides_2sided_long = _cupsStrAlloc(value);
88f9aafc 875 else if (!_cups_strcasecmp(line, "Sides2SidedShort"))
f14324a7 876 pc->sides_2sided_short = _cupsStrAlloc(value);
dcb445bc
MS
877 else if (!_cups_strcasecmp(line, "Finishings"))
878 {
879 if (!pc->finishings)
880 pc->finishings =
881 cupsArrayNew3((cups_array_func_t)pwg_compare_finishings,
882 NULL, NULL, 0, NULL,
883 (cups_afree_func_t)pwg_free_finishings);
884
885 if ((finishings = calloc(1, sizeof(_pwg_finishings_t))) == NULL)
886 goto create_error;
887
7e86f2f6 888 finishings->value = (ipp_finishings_t)strtol(value, &valueptr, 10);
dcb445bc
MS
889 finishings->num_options = cupsParseOptions(valueptr, 0,
890 &(finishings->options));
891
892 cupsArrayAdd(pc->finishings, finishings);
893 }
3e7fe0ca
MS
894 else if (!_cups_strcasecmp(line, "MaxCopies"))
895 pc->max_copies = atoi(value);
a469f8a5
MS
896 else if (!_cups_strcasecmp(line, "ChargeInfoURI"))
897 pc->charge_info_uri = _cupsStrAlloc(value);
5a9febac
MS
898 else if (!_cups_strcasecmp(line, "JobAccountId"))
899 pc->account_id = !_cups_strcasecmp(value, "true");
900 else if (!_cups_strcasecmp(line, "JobAccountingUserId"))
901 pc->accounting_user_id = !_cups_strcasecmp(value, "true");
902 else if (!_cups_strcasecmp(line, "JobPassword"))
903 pc->password = _cupsStrAlloc(value);
904 else if (!_cups_strcasecmp(line, "Mandatory"))
905 {
906 if (pc->mandatory)
907 _cupsArrayAddStrings(pc->mandatory, value, ' ');
908 else
909 pc->mandatory = _cupsArrayNewStrings(value, ' ');
910 }
c1420c87
MS
911 else if (!_cups_strcasecmp(line, "SupportFile"))
912 {
913 if (!pc->support_files)
914 pc->support_files = cupsArrayNew3(NULL, NULL, NULL, 0,
915 (cups_acopy_func_t)_cupsStrAlloc,
916 (cups_afree_func_t)_cupsStrFree);
917
918 cupsArrayAdd(pc->support_files, value);
919 }
f14324a7
MS
920 else
921 {
922 DEBUG_printf(("_ppdCacheCreateWithFile: Unknown %s on line %d.", line,
923 linenum));
f14324a7
MS
924 }
925 }
926
927 if (pc->num_sizes < num_sizes)
928 {
929 DEBUG_printf(("_ppdCacheCreateWithFile: Not enough sizes (%d < %d).",
930 pc->num_sizes, num_sizes));
cb7f98ee 931 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
932 goto create_error;
933 }
934
935 if (pc->num_sources < num_sources)
936 {
937 DEBUG_printf(("_ppdCacheCreateWithFile: Not enough sources (%d < %d).",
938 pc->num_sources, num_sources));
cb7f98ee 939 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
940 goto create_error;
941 }
942
943 if (pc->num_types < num_types)
944 {
945 DEBUG_printf(("_ppdCacheCreateWithFile: Not enough types (%d < %d).",
946 pc->num_types, num_types));
cb7f98ee 947 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
948 goto create_error;
949 }
950
951 cupsFileClose(fp);
952
953 return (pc);
954
955 /*
956 * If we get here the file was bad - free any data and return...
957 */
958
959 create_error:
960
961 cupsFileClose(fp);
962 _ppdCacheDestroy(pc);
963
964 if (attrs)
22c9029b 965 {
f14324a7 966 ippDelete(*attrs);
22c9029b
MS
967 *attrs = NULL;
968 }
f14324a7
MS
969
970 return (NULL);
971}
972
973
974/*
975 * '_ppdCacheCreateWithPPD()' - Create PWG mapping data from a PPD file.
976 */
977
978_ppd_cache_t * /* O - PPD cache and mapping data */
979_ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */
980{
981 int i, j, k; /* Looping vars */
982 _ppd_cache_t *pc; /* PWG mapping data */
983 ppd_option_t *input_slot, /* InputSlot option */
984 *media_type, /* MediaType option */
985 *output_bin, /* OutputBin option */
986 *color_model, /* ColorModel option */
987 *duplex; /* Duplex option */
988 ppd_choice_t *choice; /* Current InputSlot/MediaType */
6961465f 989 pwg_map_t *map; /* Current source/type map */
f14324a7
MS
990 ppd_attr_t *ppd_attr; /* Current PPD preset attribute */
991 int num_options; /* Number of preset options and props */
992 cups_option_t *options; /* Preset options and properties */
993 ppd_size_t *ppd_size; /* Current PPD size */
6961465f 994 pwg_size_t *pwg_size; /* Current PWG size */
f14324a7
MS
995 char pwg_keyword[3 + PPD_MAX_NAME + 1 + 12 + 1 + 12 + 3],
996 /* PWG keyword string */
997 ppd_name[PPD_MAX_NAME];
998 /* Normalized PPD name */
999 const char *pwg_name; /* Standard PWG media name */
6961465f 1000 pwg_media_t *pwg_media; /* PWG media data */
f14324a7
MS
1001 _pwg_print_color_mode_t pwg_print_color_mode;
1002 /* print-color-mode index */
1003 _pwg_print_quality_t pwg_print_quality;
1004 /* print-quality index */
1005 int similar; /* Are the old and new size similar? */
6961465f 1006 pwg_size_t *old_size; /* Current old size */
f14324a7
MS
1007 int old_imageable, /* Old imageable length in 2540ths */
1008 old_borderless, /* Old borderless state */
1009 old_known_pwg; /* Old PWG name is well-known */
1010 int new_width, /* New width in 2540ths */
1011 new_length, /* New length in 2540ths */
1012 new_left, /* New left margin in 2540ths */
1013 new_bottom, /* New bottom margin in 2540ths */
1014 new_right, /* New right margin in 2540ths */
1015 new_top, /* New top margin in 2540ths */
1016 new_imageable, /* New imageable length in 2540ths */
1017 new_borderless, /* New borderless state */
1018 new_known_pwg; /* New PWG name is well-known */
6961465f 1019 pwg_size_t *new_size; /* New size to add, if any */
f14324a7 1020 const char *filter; /* Current filter */
dcb445bc 1021 _pwg_finishings_t *finishings; /* Current finishings value */
f14324a7
MS
1022
1023
1024 DEBUG_printf(("_ppdCacheCreateWithPPD(ppd=%p)", ppd));
1025
1026 /*
1027 * Range check input...
1028 */
1029
1030 if (!ppd)
1031 return (NULL);
1032
1033 /*
1034 * Allocate memory...
1035 */
1036
1037 if ((pc = calloc(1, sizeof(_ppd_cache_t))) == NULL)
1038 {
1039 DEBUG_puts("_ppdCacheCreateWithPPD: Unable to allocate _ppd_cache_t.");
1040 goto create_error;
1041 }
1042
1043 /*
1044 * Copy and convert size data...
1045 */
1046
5a9febac 1047 if (ppd->num_sizes > 0)
f14324a7 1048 {
7e86f2f6 1049 if ((pc->sizes = calloc((size_t)ppd->num_sizes, sizeof(pwg_size_t))) == NULL)
f14324a7 1050 {
5a9febac 1051 DEBUG_printf(("_ppdCacheCreateWithPPD: Unable to allocate %d "
6961465f 1052 "pwg_size_t's.", ppd->num_sizes));
5a9febac 1053 goto create_error;
f14324a7
MS
1054 }
1055
5a9febac
MS
1056 for (i = ppd->num_sizes, pwg_size = pc->sizes, ppd_size = ppd->sizes;
1057 i > 0;
1058 i --, ppd_size ++)
f14324a7
MS
1059 {
1060 /*
5a9febac 1061 * Don't copy over custom size...
f14324a7
MS
1062 */
1063
5a9febac
MS
1064 if (!_cups_strcasecmp(ppd_size->name, "Custom"))
1065 continue;
1066
f14324a7 1067 /*
5a9febac 1068 * Convert the PPD size name to the corresponding PWG keyword name.
f14324a7
MS
1069 */
1070
6961465f 1071 if ((pwg_media = pwgMediaForPPD(ppd_size->name)) != NULL)
5a9febac
MS
1072 {
1073 /*
1074 * Standard name, do we have conflicts?
1075 */
f14324a7 1076
5a9febac
MS
1077 for (j = 0; j < pc->num_sizes; j ++)
1078 if (!strcmp(pc->sizes[j].map.pwg, pwg_media->pwg))
1079 {
1080 pwg_media = NULL;
1081 break;
1082 }
1083 }
f14324a7 1084
5a9febac
MS
1085 if (pwg_media)
1086 {
1087 /*
1088 * Standard name and no conflicts, use it!
1089 */
f14324a7 1090
5a9febac
MS
1091 pwg_name = pwg_media->pwg;
1092 new_known_pwg = 1;
1093 }
1094 else
f14324a7
MS
1095 {
1096 /*
5a9febac
MS
1097 * Not a standard name; convert it to a PWG vendor name of the form:
1098 *
1099 * pp_lowerppd_WIDTHxHEIGHTuu
f14324a7
MS
1100 */
1101
5a9febac
MS
1102 pwg_name = pwg_keyword;
1103 new_known_pwg = 0;
1104
c1420c87 1105 pwg_unppdize_name(ppd_size->name, ppd_name, sizeof(ppd_name), "_.");
6961465f
MS
1106 pwgFormatSizeName(pwg_keyword, sizeof(pwg_keyword), NULL, ppd_name,
1107 PWG_FROM_POINTS(ppd_size->width),
1108 PWG_FROM_POINTS(ppd_size->length), NULL);
f14324a7 1109 }
f14324a7 1110
f14324a7 1111 /*
5a9febac
MS
1112 * If we have a similar paper with non-zero margins then we only want to
1113 * keep it if it has a larger imageable area length. The NULL check is for
1114 * dimensions that are <= 0...
f14324a7
MS
1115 */
1116
c3ebc4c6
MS
1117 if ((pwg_media = _pwgMediaNearSize(PWG_FROM_POINTS(ppd_size->width),
1118 PWG_FROM_POINTS(ppd_size->length),
1119 0)) == NULL)
5a9febac 1120 continue;
f14324a7 1121
5a9febac
MS
1122 new_width = pwg_media->width;
1123 new_length = pwg_media->length;
6961465f
MS
1124 new_left = PWG_FROM_POINTS(ppd_size->left);
1125 new_bottom = PWG_FROM_POINTS(ppd_size->bottom);
1126 new_right = PWG_FROM_POINTS(ppd_size->width - ppd_size->right);
1127 new_top = PWG_FROM_POINTS(ppd_size->length - ppd_size->top);
5a9febac
MS
1128 new_imageable = new_length - new_top - new_bottom;
1129 new_borderless = new_bottom == 0 && new_top == 0 &&
1130 new_left == 0 && new_right == 0;
1131
1132 for (k = pc->num_sizes, similar = 0, old_size = pc->sizes, new_size = NULL;
1133 k > 0 && !similar;
1134 k --, old_size ++)
1135 {
1136 old_imageable = old_size->length - old_size->top - old_size->bottom;
1137 old_borderless = old_size->left == 0 && old_size->bottom == 0 &&
1138 old_size->right == 0 && old_size->top == 0;
1139 old_known_pwg = strncmp(old_size->map.pwg, "oe_", 3) &&
1140 strncmp(old_size->map.pwg, "om_", 3);
1141
1142 similar = old_borderless == new_borderless &&
1143 _PWG_EQUIVALENT(old_size->width, new_width) &&
1144 _PWG_EQUIVALENT(old_size->length, new_length);
1145
1146 if (similar &&
1147 (new_known_pwg || (!old_known_pwg && new_imageable > old_imageable)))
1148 {
1149 /*
1150 * The new paper has a larger imageable area so it could replace
1151 * the older paper. Regardless of the imageable area, we always
1152 * prefer the size with a well-known PWG name.
1153 */
1154
1155 new_size = old_size;
1156 _cupsStrFree(old_size->map.ppd);
1157 _cupsStrFree(old_size->map.pwg);
1158 }
1159 }
1160
1161 if (!similar)
1162 {
1163 /*
1164 * The paper was unique enough to deserve its own entry so add it to the
1165 * end.
1166 */
1167
1168 new_size = pwg_size ++;
1169 pc->num_sizes ++;
1170 }
1171
1172 if (new_size)
1173 {
1174 /*
1175 * Save this size...
1176 */
f14324a7 1177
5a9febac
MS
1178 new_size->map.ppd = _cupsStrAlloc(ppd_size->name);
1179 new_size->map.pwg = _cupsStrAlloc(pwg_name);
1180 new_size->width = new_width;
1181 new_size->length = new_length;
1182 new_size->left = new_left;
1183 new_size->bottom = new_bottom;
1184 new_size->right = new_right;
1185 new_size->top = new_top;
1186 }
f14324a7
MS
1187 }
1188 }
1189
1190 if (ppd->variable_sizes)
1191 {
1192 /*
1193 * Generate custom size data...
1194 */
1195
6961465f
MS
1196 pwgFormatSizeName(pwg_keyword, sizeof(pwg_keyword), "custom", "max",
1197 PWG_FROM_POINTS(ppd->custom_max[0]),
1198 PWG_FROM_POINTS(ppd->custom_max[1]), NULL);
f14324a7 1199 pc->custom_max_keyword = _cupsStrAlloc(pwg_keyword);
6961465f
MS
1200 pc->custom_max_width = PWG_FROM_POINTS(ppd->custom_max[0]);
1201 pc->custom_max_length = PWG_FROM_POINTS(ppd->custom_max[1]);
f14324a7 1202
6961465f
MS
1203 pwgFormatSizeName(pwg_keyword, sizeof(pwg_keyword), "custom", "min",
1204 PWG_FROM_POINTS(ppd->custom_min[0]),
1205 PWG_FROM_POINTS(ppd->custom_min[1]), NULL);
f14324a7 1206 pc->custom_min_keyword = _cupsStrAlloc(pwg_keyword);
6961465f
MS
1207 pc->custom_min_width = PWG_FROM_POINTS(ppd->custom_min[0]);
1208 pc->custom_min_length = PWG_FROM_POINTS(ppd->custom_min[1]);
f14324a7 1209
6961465f
MS
1210 pc->custom_size.left = PWG_FROM_POINTS(ppd->custom_margins[0]);
1211 pc->custom_size.bottom = PWG_FROM_POINTS(ppd->custom_margins[1]);
1212 pc->custom_size.right = PWG_FROM_POINTS(ppd->custom_margins[2]);
1213 pc->custom_size.top = PWG_FROM_POINTS(ppd->custom_margins[3]);
f14324a7
MS
1214 }
1215
1216 /*
1217 * Copy and convert InputSlot data...
1218 */
1219
1220 if ((input_slot = ppdFindOption(ppd, "InputSlot")) == NULL)
1221 input_slot = ppdFindOption(ppd, "HPPaperSource");
1222
1223 if (input_slot)
1224 {
1225 pc->source_option = _cupsStrAlloc(input_slot->keyword);
1226
7e86f2f6 1227 if ((pc->sources = calloc((size_t)input_slot->num_choices, sizeof(pwg_map_t))) == NULL)
f14324a7
MS
1228 {
1229 DEBUG_printf(("_ppdCacheCreateWithPPD: Unable to allocate %d "
6961465f 1230 "pwg_map_t's for InputSlot.", input_slot->num_choices));
f14324a7
MS
1231 goto create_error;
1232 }
1233
1234 pc->num_sources = input_slot->num_choices;
1235
1236 for (i = input_slot->num_choices, choice = input_slot->choices,
1237 map = pc->sources;
1238 i > 0;
1239 i --, choice ++, map ++)
1240 {
88f9aafc
MS
1241 if (!_cups_strncasecmp(choice->choice, "Auto", 4) ||
1242 !_cups_strcasecmp(choice->choice, "Default"))
f14324a7 1243 pwg_name = "auto";
88f9aafc 1244 else if (!_cups_strcasecmp(choice->choice, "Cassette"))
f14324a7 1245 pwg_name = "main";
88f9aafc 1246 else if (!_cups_strcasecmp(choice->choice, "PhotoTray"))
f14324a7 1247 pwg_name = "photo";
88f9aafc 1248 else if (!_cups_strcasecmp(choice->choice, "CDTray"))
f14324a7 1249 pwg_name = "disc";
88f9aafc
MS
1250 else if (!_cups_strncasecmp(choice->choice, "Multipurpose", 12) ||
1251 !_cups_strcasecmp(choice->choice, "MP") ||
1252 !_cups_strcasecmp(choice->choice, "MPTray"))
12f89d24 1253 pwg_name = "by-pass-tray";
88f9aafc 1254 else if (!_cups_strcasecmp(choice->choice, "LargeCapacity"))
f14324a7 1255 pwg_name = "large-capacity";
88f9aafc 1256 else if (!_cups_strncasecmp(choice->choice, "Lower", 5))
f14324a7 1257 pwg_name = "bottom";
88f9aafc 1258 else if (!_cups_strncasecmp(choice->choice, "Middle", 6))
f14324a7 1259 pwg_name = "middle";
88f9aafc 1260 else if (!_cups_strncasecmp(choice->choice, "Upper", 5))
f14324a7 1261 pwg_name = "top";
88f9aafc 1262 else if (!_cups_strncasecmp(choice->choice, "Side", 4))
f14324a7 1263 pwg_name = "side";
a4845881 1264 else if (!_cups_strcasecmp(choice->choice, "Roll"))
f14324a7 1265 pwg_name = "main-roll";
f14324a7
MS
1266 else
1267 {
1268 /*
1269 * Convert PPD name to lowercase...
1270 */
1271
1272 pwg_name = pwg_keyword;
c1420c87
MS
1273 pwg_unppdize_name(choice->choice, pwg_keyword, sizeof(pwg_keyword),
1274 "_");
f14324a7
MS
1275 }
1276
1277 map->pwg = _cupsStrAlloc(pwg_name);
1278 map->ppd = _cupsStrAlloc(choice->choice);
1279 }
1280 }
1281
1282 /*
1283 * Copy and convert MediaType data...
1284 */
1285
1286 if ((media_type = ppdFindOption(ppd, "MediaType")) != NULL)
1287 {
7e86f2f6 1288 if ((pc->types = calloc((size_t)media_type->num_choices, sizeof(pwg_map_t))) == NULL)
f14324a7
MS
1289 {
1290 DEBUG_printf(("_ppdCacheCreateWithPPD: Unable to allocate %d "
6961465f 1291 "pwg_map_t's for MediaType.", media_type->num_choices));
f14324a7
MS
1292 goto create_error;
1293 }
1294
1295 pc->num_types = media_type->num_choices;
1296
1297 for (i = media_type->num_choices, choice = media_type->choices,
1298 map = pc->types;
1299 i > 0;
1300 i --, choice ++, map ++)
1301 {
88f9aafc
MS
1302 if (!_cups_strncasecmp(choice->choice, "Auto", 4) ||
1303 !_cups_strcasecmp(choice->choice, "Any") ||
1304 !_cups_strcasecmp(choice->choice, "Default"))
f14324a7 1305 pwg_name = "auto";
88f9aafc 1306 else if (!_cups_strncasecmp(choice->choice, "Card", 4))
f14324a7 1307 pwg_name = "cardstock";
88f9aafc 1308 else if (!_cups_strncasecmp(choice->choice, "Env", 3))
f14324a7 1309 pwg_name = "envelope";
88f9aafc 1310 else if (!_cups_strncasecmp(choice->choice, "Gloss", 5))
f14324a7 1311 pwg_name = "photographic-glossy";
88f9aafc 1312 else if (!_cups_strcasecmp(choice->choice, "HighGloss"))
f14324a7 1313 pwg_name = "photographic-high-gloss";
88f9aafc 1314 else if (!_cups_strcasecmp(choice->choice, "Matte"))
f14324a7 1315 pwg_name = "photographic-matte";
88f9aafc 1316 else if (!_cups_strncasecmp(choice->choice, "Plain", 5))
f14324a7 1317 pwg_name = "stationery";
88f9aafc 1318 else if (!_cups_strncasecmp(choice->choice, "Coated", 6))
f14324a7 1319 pwg_name = "stationery-coated";
88f9aafc 1320 else if (!_cups_strcasecmp(choice->choice, "Inkjet"))
f14324a7 1321 pwg_name = "stationery-inkjet";
88f9aafc 1322 else if (!_cups_strcasecmp(choice->choice, "Letterhead"))
f14324a7 1323 pwg_name = "stationery-letterhead";
88f9aafc 1324 else if (!_cups_strncasecmp(choice->choice, "Preprint", 8))
f14324a7 1325 pwg_name = "stationery-preprinted";
a4845881
MS
1326 else if (!_cups_strcasecmp(choice->choice, "Recycled"))
1327 pwg_name = "stationery-recycled";
88f9aafc 1328 else if (!_cups_strncasecmp(choice->choice, "Transparen", 10))
f14324a7
MS
1329 pwg_name = "transparency";
1330 else
1331 {
1332 /*
1333 * Convert PPD name to lowercase...
1334 */
1335
1336 pwg_name = pwg_keyword;
c1420c87
MS
1337 pwg_unppdize_name(choice->choice, pwg_keyword, sizeof(pwg_keyword),
1338 "_");
f14324a7
MS
1339 }
1340
1341 map->pwg = _cupsStrAlloc(pwg_name);
1342 map->ppd = _cupsStrAlloc(choice->choice);
1343 }
1344 }
1345
f14324a7
MS
1346 /*
1347 * Copy and convert OutputBin data...
1348 */
1349
1350 if ((output_bin = ppdFindOption(ppd, "OutputBin")) != NULL)
1351 {
7e86f2f6 1352 if ((pc->bins = calloc((size_t)output_bin->num_choices, sizeof(pwg_map_t))) == NULL)
f14324a7
MS
1353 {
1354 DEBUG_printf(("_ppdCacheCreateWithPPD: Unable to allocate %d "
6961465f 1355 "pwg_map_t's for OutputBin.", output_bin->num_choices));
f14324a7
MS
1356 goto create_error;
1357 }
1358
1359 pc->num_bins = output_bin->num_choices;
1360
1361 for (i = output_bin->num_choices, choice = output_bin->choices,
1362 map = pc->bins;
1363 i > 0;
1364 i --, choice ++, map ++)
1365 {
c1420c87 1366 pwg_unppdize_name(choice->choice, pwg_keyword, sizeof(pwg_keyword), "_");
f14324a7
MS
1367
1368 map->pwg = _cupsStrAlloc(pwg_keyword);
1369 map->ppd = _cupsStrAlloc(choice->choice);
1370 }
1371 }
1372
1373 if ((ppd_attr = ppdFindAttr(ppd, "APPrinterPreset", NULL)) != NULL)
1374 {
1375 /*
1376 * Copy and convert APPrinterPreset (output-mode + print-quality) data...
1377 */
1378
1379 const char *quality, /* com.apple.print.preset.quality value */
1380 *output_mode, /* com.apple.print.preset.output-mode value */
1381 *color_model_val, /* ColorModel choice */
1382 *graphicsType, /* com.apple.print.preset.graphicsType value */
1383 *media_front_coating; /* com.apple.print.preset.media-front-coating value */
1384
1385 do
1386 {
1387 num_options = _ppdParseOptions(ppd_attr->value, 0, &options,
1388 _PPD_PARSE_ALL);
1389
1390 if ((quality = cupsGetOption("com.apple.print.preset.quality",
1391 num_options, options)) != NULL)
1392 {
1393 /*
1394 * Get the print-quality for this preset...
1395 */
1396
1397 if (!strcmp(quality, "low"))
1398 pwg_print_quality = _PWG_PRINT_QUALITY_DRAFT;
1399 else if (!strcmp(quality, "high"))
1400 pwg_print_quality = _PWG_PRINT_QUALITY_HIGH;
1401 else
1402 pwg_print_quality = _PWG_PRINT_QUALITY_NORMAL;
1403
1404 /*
1405 * Ignore graphicsType "Photo" presets that are not high quality.
1406 */
1407
1408 graphicsType = cupsGetOption("com.apple.print.preset.graphicsType",
1409 num_options, options);
1410
1411 if (pwg_print_quality != _PWG_PRINT_QUALITY_HIGH && graphicsType &&
1412 !strcmp(graphicsType, "Photo"))
1413 continue;
1414
1415 /*
1416 * Ignore presets for normal and draft quality where the coating
1417 * isn't "none" or "autodetect".
1418 */
1419
1420 media_front_coating = cupsGetOption(
1421 "com.apple.print.preset.media-front-coating",
1422 num_options, options);
1423
1424 if (pwg_print_quality != _PWG_PRINT_QUALITY_HIGH &&
1425 media_front_coating &&
1426 strcmp(media_front_coating, "none") &&
1427 strcmp(media_front_coating, "autodetect"))
1428 continue;
1429
1430 /*
1431 * Get the output mode for this preset...
1432 */
1433
1434 output_mode = cupsGetOption("com.apple.print.preset.output-mode",
1435 num_options, options);
1436 color_model_val = cupsGetOption("ColorModel", num_options, options);
1437
1438 if (output_mode)
1439 {
1440 if (!strcmp(output_mode, "monochrome"))
1441 pwg_print_color_mode = _PWG_PRINT_COLOR_MODE_MONOCHROME;
1442 else
1443 pwg_print_color_mode = _PWG_PRINT_COLOR_MODE_COLOR;
1444 }
1445 else if (color_model_val)
1446 {
88f9aafc 1447 if (!_cups_strcasecmp(color_model_val, "Gray"))
f14324a7
MS
1448 pwg_print_color_mode = _PWG_PRINT_COLOR_MODE_MONOCHROME;
1449 else
1450 pwg_print_color_mode = _PWG_PRINT_COLOR_MODE_COLOR;
1451 }
1452 else
1453 pwg_print_color_mode = _PWG_PRINT_COLOR_MODE_COLOR;
1454
1455 /*
1456 * Save the options for this combination as needed...
1457 */
1458
1459 if (!pc->num_presets[pwg_print_color_mode][pwg_print_quality])
1460 pc->num_presets[pwg_print_color_mode][pwg_print_quality] =
1461 _ppdParseOptions(ppd_attr->value, 0,
1462 pc->presets[pwg_print_color_mode] +
1463 pwg_print_quality, _PPD_PARSE_OPTIONS);
1464 }
1465
1466 cupsFreeOptions(num_options, options);
1467 }
1468 while ((ppd_attr = ppdFindNextAttr(ppd, "APPrinterPreset", NULL)) != NULL);
1469 }
1470
1471 if (!pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][_PWG_PRINT_QUALITY_DRAFT] &&
1472 !pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][_PWG_PRINT_QUALITY_NORMAL] &&
1473 !pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][_PWG_PRINT_QUALITY_HIGH])
1474 {
1475 /*
1476 * Try adding some common color options to create grayscale presets. These
1477 * are listed in order of popularity...
1478 */
1479
1480 const char *color_option = NULL, /* Color control option */
1481 *gray_choice = NULL; /* Choice to select grayscale */
1482
1483 if ((color_model = ppdFindOption(ppd, "ColorModel")) != NULL &&
1484 ppdFindChoice(color_model, "Gray"))
1485 {
1486 color_option = "ColorModel";
1487 gray_choice = "Gray";
1488 }
1489 else if ((color_model = ppdFindOption(ppd, "HPColorMode")) != NULL &&
1490 ppdFindChoice(color_model, "grayscale"))
1491 {
1492 color_option = "HPColorMode";
1493 gray_choice = "grayscale";
1494 }
1495 else if ((color_model = ppdFindOption(ppd, "BRMonoColor")) != NULL &&
1496 ppdFindChoice(color_model, "Mono"))
1497 {
1498 color_option = "BRMonoColor";
1499 gray_choice = "Mono";
1500 }
1501 else if ((color_model = ppdFindOption(ppd, "CNIJSGrayScale")) != NULL &&
1502 ppdFindChoice(color_model, "1"))
1503 {
1504 color_option = "CNIJSGrayScale";
1505 gray_choice = "1";
1506 }
1507 else if ((color_model = ppdFindOption(ppd, "HPColorAsGray")) != NULL &&
1508 ppdFindChoice(color_model, "True"))
1509 {
1510 color_option = "HPColorAsGray";
1511 gray_choice = "True";
1512 }
1513
1514 if (color_option && gray_choice)
1515 {
1516 /*
1517 * Copy and convert ColorModel (output-mode) data...
1518 */
1519
1520 cups_option_t *coption, /* Color option */
1521 *moption; /* Monochrome option */
1522
1523 for (pwg_print_quality = _PWG_PRINT_QUALITY_DRAFT;
1524 pwg_print_quality < _PWG_PRINT_QUALITY_MAX;
1525 pwg_print_quality ++)
1526 {
1527 if (pc->num_presets[_PWG_PRINT_COLOR_MODE_COLOR][pwg_print_quality])
1528 {
1529 /*
1530 * Copy the color options...
1531 */
1532
1533 num_options = pc->num_presets[_PWG_PRINT_COLOR_MODE_COLOR]
1534 [pwg_print_quality];
7e86f2f6 1535 options = calloc(sizeof(cups_option_t), (size_t)num_options);
f14324a7
MS
1536
1537 if (options)
1538 {
1539 for (i = num_options, moption = options,
1540 coption = pc->presets[_PWG_PRINT_COLOR_MODE_COLOR]
1541 [pwg_print_quality];
1542 i > 0;
1543 i --, moption ++, coption ++)
1544 {
1545 moption->name = _cupsStrRetain(coption->name);
1546 moption->value = _cupsStrRetain(coption->value);
1547 }
1548
1549 pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][pwg_print_quality] =
1550 num_options;
1551 pc->presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][pwg_print_quality] =
1552 options;
1553 }
1554 }
1555 else if (pwg_print_quality != _PWG_PRINT_QUALITY_NORMAL)
1556 continue;
1557
1558 /*
1559 * Add the grayscale option to the preset...
1560 */
1561
1562 pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][pwg_print_quality] =
1563 cupsAddOption(color_option, gray_choice,
1564 pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME]
1565 [pwg_print_quality],
1566 pc->presets[_PWG_PRINT_COLOR_MODE_MONOCHROME] +
1567 pwg_print_quality);
1568 }
1569 }
1570 }
1571
1572 /*
1573 * Copy and convert Duplex (sides) data...
1574 */
1575
1576 if ((duplex = ppdFindOption(ppd, "Duplex")) == NULL)
1577 if ((duplex = ppdFindOption(ppd, "JCLDuplex")) == NULL)
1578 if ((duplex = ppdFindOption(ppd, "EFDuplex")) == NULL)
1579 if ((duplex = ppdFindOption(ppd, "EFDuplexing")) == NULL)
1580 duplex = ppdFindOption(ppd, "KD03Duplex");
1581
1582 if (duplex)
1583 {
1584 pc->sides_option = _cupsStrAlloc(duplex->keyword);
1585
1586 for (i = duplex->num_choices, choice = duplex->choices;
1587 i > 0;
1588 i --, choice ++)
1589 {
88f9aafc
MS
1590 if ((!_cups_strcasecmp(choice->choice, "None") ||
1591 !_cups_strcasecmp(choice->choice, "False")) && !pc->sides_1sided)
f14324a7 1592 pc->sides_1sided = _cupsStrAlloc(choice->choice);
88f9aafc
MS
1593 else if ((!_cups_strcasecmp(choice->choice, "DuplexNoTumble") ||
1594 !_cups_strcasecmp(choice->choice, "LongEdge") ||
1595 !_cups_strcasecmp(choice->choice, "Top")) && !pc->sides_2sided_long)
f14324a7 1596 pc->sides_2sided_long = _cupsStrAlloc(choice->choice);
88f9aafc
MS
1597 else if ((!_cups_strcasecmp(choice->choice, "DuplexTumble") ||
1598 !_cups_strcasecmp(choice->choice, "ShortEdge") ||
1599 !_cups_strcasecmp(choice->choice, "Bottom")) &&
f14324a7
MS
1600 !pc->sides_2sided_short)
1601 pc->sides_2sided_short = _cupsStrAlloc(choice->choice);
1602 }
1603 }
1604
1605 /*
1606 * Copy filters and pre-filters...
1607 */
1608
1609 pc->filters = cupsArrayNew3(NULL, NULL, NULL, 0,
1610 (cups_acopy_func_t)_cupsStrAlloc,
1611 (cups_afree_func_t)_cupsStrFree);
1612
1613 cupsArrayAdd(pc->filters,
1614 "application/vnd.cups-raw application/octet-stream 0 -");
1615
1616 if ((ppd_attr = ppdFindAttr(ppd, "cupsFilter2", NULL)) != NULL)
1617 {
1618 do
1619 {
1620 cupsArrayAdd(pc->filters, ppd_attr->value);
1621 }
1622 while ((ppd_attr = ppdFindNextAttr(ppd, "cupsFilter2", NULL)) != NULL);
1623 }
1624 else if (ppd->num_filters > 0)
1625 {
1626 for (i = 0; i < ppd->num_filters; i ++)
1627 cupsArrayAdd(pc->filters, ppd->filters[i]);
1628 }
1629 else
1630 cupsArrayAdd(pc->filters, "application/vnd.cups-postscript 0 -");
1631
1632 /*
1633 * See if we have a command filter...
1634 */
1635
1636 for (filter = (const char *)cupsArrayFirst(pc->filters);
1637 filter;
1638 filter = (const char *)cupsArrayNext(pc->filters))
88f9aafc 1639 if (!_cups_strncasecmp(filter, "application/vnd.cups-command", 28) &&
f14324a7
MS
1640 _cups_isspace(filter[28]))
1641 break;
1642
1643 if (!filter &&
1644 ((ppd_attr = ppdFindAttr(ppd, "cupsCommands", NULL)) == NULL ||
88f9aafc 1645 _cups_strcasecmp(ppd_attr->value, "none")))
f14324a7
MS
1646 {
1647 /*
1648 * No command filter and no cupsCommands keyword telling us not to use one.
1649 * See if this is a PostScript printer, and if so add a PostScript command
1650 * filter...
1651 */
1652
1653 for (filter = (const char *)cupsArrayFirst(pc->filters);
1654 filter;
1655 filter = (const char *)cupsArrayNext(pc->filters))
88f9aafc 1656 if (!_cups_strncasecmp(filter, "application/vnd.cups-postscript", 31) &&
f14324a7
MS
1657 _cups_isspace(filter[31]))
1658 break;
1659
1660 if (filter)
1661 cupsArrayAdd(pc->filters,
a2326b5b
MS
1662 "application/vnd.cups-command application/postscript 100 "
1663 "commandtops");
f14324a7
MS
1664 }
1665
1666 if ((ppd_attr = ppdFindAttr(ppd, "cupsPreFilter", NULL)) != NULL)
1667 {
1668 pc->prefilters = cupsArrayNew3(NULL, NULL, NULL, 0,
1669 (cups_acopy_func_t)_cupsStrAlloc,
1670 (cups_afree_func_t)_cupsStrFree);
1671
1672 do
1673 {
1674 cupsArrayAdd(pc->prefilters, ppd_attr->value);
1675 }
1676 while ((ppd_attr = ppdFindNextAttr(ppd, "cupsPreFilter", NULL)) != NULL);
1677 }
1678
82f97232 1679 if ((ppd_attr = ppdFindAttr(ppd, "cupsSingleFile", NULL)) != NULL)
88f9aafc 1680 pc->single_file = !_cups_strcasecmp(ppd_attr->value, "true");
82f97232 1681
f14324a7
MS
1682 /*
1683 * Copy the product string, if any...
1684 */
1685
1686 if (ppd->product)
1687 pc->product = _cupsStrAlloc(ppd->product);
1688
dcb445bc
MS
1689 /*
1690 * Copy finishings mapping data...
1691 */
1692
1693 if ((ppd_attr = ppdFindAttr(ppd, "cupsIPPFinishings", NULL)) != NULL)
1694 {
1695 pc->finishings = cupsArrayNew3((cups_array_func_t)pwg_compare_finishings,
1696 NULL, NULL, 0, NULL,
1697 (cups_afree_func_t)pwg_free_finishings);
1698
1699 do
1700 {
1701 if ((finishings = calloc(1, sizeof(_pwg_finishings_t))) == NULL)
1702 goto create_error;
1703
7e86f2f6 1704 finishings->value = (ipp_finishings_t)atoi(ppd_attr->spec);
dcb445bc
MS
1705 finishings->num_options = _ppdParseOptions(ppd_attr->value, 0,
1706 &(finishings->options),
1707 _PPD_PARSE_OPTIONS);
1708
1709 cupsArrayAdd(pc->finishings, finishings);
1710 }
1711 while ((ppd_attr = ppdFindNextAttr(ppd, "cupsIPPFinishings",
1712 NULL)) != NULL);
1713 }
1714
3e7fe0ca
MS
1715 /*
1716 * Max copies...
1717 */
1718
1719 if ((ppd_attr = ppdFindAttr(ppd, "cupsMaxCopies", NULL)) != NULL)
1720 pc->max_copies = atoi(ppd_attr->value);
1721 else if (ppd->manual_copies)
1722 pc->max_copies = 1;
1723 else
1724 pc->max_copies = 9999;
1725
5a9febac 1726 /*
a469f8a5
MS
1727 * cupsChargeInfoURI, cupsJobAccountId, cupsJobAccountingUserId,
1728 * cupsJobPassword, and cupsMandatory.
5a9febac
MS
1729 */
1730
a469f8a5
MS
1731 if ((ppd_attr = ppdFindAttr(ppd, "cupsChargeInfoURI", NULL)) != NULL)
1732 pc->charge_info_uri = _cupsStrAlloc(ppd_attr->value);
1733
5a9febac
MS
1734 if ((ppd_attr = ppdFindAttr(ppd, "cupsJobAccountId", NULL)) != NULL)
1735 pc->account_id = !_cups_strcasecmp(ppd_attr->value, "true");
1736
1737 if ((ppd_attr = ppdFindAttr(ppd, "cupsJobAccountingUserId", NULL)) != NULL)
1738 pc->accounting_user_id = !_cups_strcasecmp(ppd_attr->value, "true");
1739
1740 if ((ppd_attr = ppdFindAttr(ppd, "cupsJobPassword", NULL)) != NULL)
1741 pc->password = _cupsStrAlloc(ppd_attr->value);
1742
1743 if ((ppd_attr = ppdFindAttr(ppd, "cupsMandatory", NULL)) != NULL)
1744 pc->mandatory = _cupsArrayNewStrings(ppd_attr->value, ' ');
1745
c1420c87
MS
1746 /*
1747 * Support files...
1748 */
1749
1750 pc->support_files = cupsArrayNew3(NULL, NULL, NULL, 0,
1751 (cups_acopy_func_t)_cupsStrAlloc,
1752 (cups_afree_func_t)_cupsStrFree);
1753
1754 for (ppd_attr = ppdFindAttr(ppd, "cupsICCProfile", NULL);
1755 ppd_attr;
1756 ppd_attr = ppdFindNextAttr(ppd, "cupsICCProfile", NULL))
1757 cupsArrayAdd(pc->support_files, ppd_attr->value);
1758
1759 if ((ppd_attr = ppdFindAttr(ppd, "APPrinterIconPath", NULL)) != NULL)
1760 cupsArrayAdd(pc->support_files, ppd_attr->value);
1761
5a08320a
MS
1762 /*
1763 * 3D stuff...
1764 */
1765
1766 if ((ppd_attr = ppdFindAttr(ppd, "cups3D", NULL)) != NULL)
1767 pc->cups_3d = _cupsStrAlloc(ppd_attr->value);
1768
1769 if ((ppd_attr = ppdFindAttr(ppd, "cupsLayerOrder", NULL)) != NULL)
1770 pc->cups_layer_order = _cupsStrAlloc(ppd_attr->value);
1771
1772 if ((ppd_attr = ppdFindAttr(ppd, "cupsAccuracy", NULL)) != NULL)
1773 sscanf(ppd_attr->value, "%d%d%d", pc->cups_accuracy + 0, pc->cups_accuracy + 1, pc->cups_accuracy + 2);
1774
1775 if ((ppd_attr = ppdFindAttr(ppd, "cupsVolume", NULL)) != NULL)
1776 sscanf(ppd_attr->value, "%d%d%d", pc->cups_volume + 0, pc->cups_volume + 1, pc->cups_volume + 2);
1777
1778 for (ppd_attr = ppdFindAttr(ppd, "cupsMaterial", NULL);
1779 ppd_attr;
1780 ppd_attr = ppdFindNextAttr(ppd, "cupsMaterial", NULL))
1781 {
1782 /*
1783 * *cupsMaterial key/name: "name=value ... name=value"
1784 */
1785
1786 _pwg_material_t *material = (_pwg_material_t *)calloc(1, sizeof(_pwg_material_t));
1787
1788 material->key = _cupsStrAlloc(ppd_attr->name);
1789 material->name = _cupsStrAlloc(ppd_attr->text);
1790 material->num_props = cupsParseOptions(ppd_attr->value, 0, &material->props);
1791
1792 if (!pc->materials)
1793 pc->materials = cupsArrayNew3(NULL, NULL, NULL, 0, NULL, (cups_afree_func_t)pwg_free_material);
1794
1795 cupsArrayAdd(pc->materials, material);
1796 }
1797
f14324a7
MS
1798 /*
1799 * Return the cache data...
1800 */
1801
1802 return (pc);
1803
1804 /*
1805 * If we get here we need to destroy the PWG mapping data and return NULL...
1806 */
1807
1808 create_error:
1809
cb7f98ee 1810 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Out of memory."), 1);
f14324a7
MS
1811 _ppdCacheDestroy(pc);
1812
1813 return (NULL);
1814}
1815
1816
1817/*
1818 * '_ppdCacheDestroy()' - Free all memory used for PWG mapping data.
1819 */
1820
1821void
1822_ppdCacheDestroy(_ppd_cache_t *pc) /* I - PPD cache and mapping data */
1823{
1824 int i; /* Looping var */
6961465f
MS
1825 pwg_map_t *map; /* Current map */
1826 pwg_size_t *size; /* Current size */
f14324a7
MS
1827
1828
1829 /*
1830 * Range check input...
1831 */
1832
1833 if (!pc)
1834 return;
1835
1836 /*
1837 * Free memory as needed...
1838 */
1839
1840 if (pc->bins)
1841 {
1842 for (i = pc->num_bins, map = pc->bins; i > 0; i --, map ++)
1843 {
1844 _cupsStrFree(map->pwg);
1845 _cupsStrFree(map->ppd);
1846 }
1847
1848 free(pc->bins);
1849 }
1850
1851 if (pc->sizes)
1852 {
1853 for (i = pc->num_sizes, size = pc->sizes; i > 0; i --, size ++)
1854 {
1855 _cupsStrFree(size->map.pwg);
1856 _cupsStrFree(size->map.ppd);
1857 }
1858
1859 free(pc->sizes);
1860 }
1861
1862 if (pc->source_option)
1863 _cupsStrFree(pc->source_option);
1864
1865 if (pc->sources)
1866 {
1867 for (i = pc->num_sources, map = pc->sources; i > 0; i --, map ++)
1868 {
1869 _cupsStrFree(map->pwg);
1870 _cupsStrFree(map->ppd);
1871 }
1872
1873 free(pc->sources);
1874 }
1875
1876 if (pc->types)
1877 {
1878 for (i = pc->num_types, map = pc->types; i > 0; i --, map ++)
1879 {
1880 _cupsStrFree(map->pwg);
1881 _cupsStrFree(map->ppd);
1882 }
1883
1884 free(pc->types);
1885 }
1886
1887 if (pc->custom_max_keyword)
1888 _cupsStrFree(pc->custom_max_keyword);
1889
1890 if (pc->custom_min_keyword)
1891 _cupsStrFree(pc->custom_min_keyword);
1892
1893 _cupsStrFree(pc->product);
1894 cupsArrayDelete(pc->filters);
1895 cupsArrayDelete(pc->prefilters);
dcb445bc 1896 cupsArrayDelete(pc->finishings);
f14324a7 1897
a469f8a5 1898 _cupsStrFree(pc->charge_info_uri);
5a9febac
MS
1899 _cupsStrFree(pc->password);
1900
1901 cupsArrayDelete(pc->mandatory);
1902
c1420c87
MS
1903 cupsArrayDelete(pc->support_files);
1904
5a08320a
MS
1905 _cupsStrFree(pc->cups_3d);
1906 _cupsStrFree(pc->cups_layer_order);
1907
1908 cupsArrayDelete(pc->materials);
1909
f14324a7
MS
1910 free(pc);
1911}
1912
1913
1914/*
1915 * '_ppdCacheGetBin()' - Get the PWG output-bin keyword associated with a PPD
1916 * OutputBin.
1917 */
1918
1919const char * /* O - output-bin or NULL */
1920_ppdCacheGetBin(
1921 _ppd_cache_t *pc, /* I - PPD cache and mapping data */
1922 const char *output_bin) /* I - PPD OutputBin string */
1923{
1924 int i; /* Looping var */
1925
1926
1927 /*
1928 * Range check input...
1929 */
1930
1931 if (!pc || !output_bin)
1932 return (NULL);
1933
1934 /*
1935 * Look up the OutputBin string...
1936 */
1937
1938
1939 for (i = 0; i < pc->num_bins; i ++)
88f9aafc 1940 if (!_cups_strcasecmp(output_bin, pc->bins[i].ppd))
f14324a7
MS
1941 return (pc->bins[i].pwg);
1942
1943 return (NULL);
1944}
1945
1946
dcb445bc
MS
1947/*
1948 * '_ppdCacheGetFinishingOptions()' - Get PPD finishing options for the given
1949 * IPP finishings value(s).
1950 */
1951
1952int /* O - New number of options */
1953_ppdCacheGetFinishingOptions(
cb7f98ee
MS
1954 _ppd_cache_t *pc, /* I - PPD cache and mapping data */
1955 ipp_t *job, /* I - Job attributes or NULL */
1956 ipp_finishings_t value, /* I - IPP finishings value of IPP_FINISHINGS_NONE */
1957 int num_options, /* I - Number of options */
1958 cups_option_t **options) /* IO - Options */
dcb445bc
MS
1959{
1960 int i; /* Looping var */
1961 _pwg_finishings_t *f, /* PWG finishings options */
1962 key; /* Search key */
1963 ipp_attribute_t *attr; /* Finishings attribute */
1964 cups_option_t *option; /* Current finishings option */
1965
1966
1967 /*
1968 * Range check input...
1969 */
1970
1971 if (!pc || cupsArrayCount(pc->finishings) == 0 || !options ||
1972 (!job && value == IPP_FINISHINGS_NONE))
1973 return (num_options);
1974
1975 /*
1976 * Apply finishing options...
1977 */
1978
1979 if (job && (attr = ippFindAttribute(job, "finishings", IPP_TAG_ENUM)) != NULL)
1980 {
1981 int num_values = ippGetCount(attr); /* Number of values */
1982
1983 for (i = 0; i < num_values; i ++)
1984 {
7e86f2f6 1985 key.value = (ipp_finishings_t)ippGetInteger(attr, i);
dcb445bc
MS
1986
1987 if ((f = cupsArrayFind(pc->finishings, &key)) != NULL)
1988 {
1989 int j; /* Another looping var */
1990
1991 for (j = f->num_options, option = f->options; j > 0; j --, option ++)
1992 num_options = cupsAddOption(option->name, option->value,
1993 num_options, options);
1994 }
1995 }
1996 }
1997 else if (value != IPP_FINISHINGS_NONE)
1998 {
1999 key.value = value;
2000
2001 if ((f = cupsArrayFind(pc->finishings, &key)) != NULL)
2002 {
2003 int j; /* Another looping var */
2004
2005 for (j = f->num_options, option = f->options; j > 0; j --, option ++)
2006 num_options = cupsAddOption(option->name, option->value,
2007 num_options, options);
2008 }
2009 }
2010
2011 return (num_options);
2012}
2013
2014
2015/*
2016 * '_ppdCacheGetFinishingValues()' - Get IPP finishings value(s) from the given
2017 * PPD options.
2018 */
2019
2020int /* O - Number of finishings values */
2021_ppdCacheGetFinishingValues(
2022 _ppd_cache_t *pc, /* I - PPD cache and mapping data */
2023 int num_options, /* I - Number of options */
2024 cups_option_t *options, /* I - Options */
2025 int max_values, /* I - Maximum number of finishings values */
2026 int *values) /* O - Finishings values */
2027{
2028 int i, /* Looping var */
2029 num_values = 0; /* Number of values */
2030 _pwg_finishings_t *f; /* Current finishings option */
2031 cups_option_t *option; /* Current option */
2032 const char *val; /* Value for option */
2033
2034
2035 /*
2036 * Range check input...
2037 */
2038
b2b9911d
MS
2039 DEBUG_printf(("_ppdCacheGetFinishingValues(pc=%p, num_options=%d, options=%p, max_values=%d, values=%p)", pc, num_options, options, max_values, values));
2040
dcb445bc 2041 if (!pc || !pc->finishings || num_options < 1 || max_values < 1 || !values)
b2b9911d
MS
2042 {
2043 DEBUG_puts("_ppdCacheGetFinishingValues: Bad arguments, returning 0.");
dcb445bc 2044 return (0);
b2b9911d 2045 }
dcb445bc
MS
2046
2047 /*
2048 * Go through the finishings options and see what is set...
2049 */
2050
2051 for (f = (_pwg_finishings_t *)cupsArrayFirst(pc->finishings);
2052 f;
2053 f = (_pwg_finishings_t *)cupsArrayNext(pc->finishings))
2054 {
b2b9911d
MS
2055 DEBUG_printf(("_ppdCacheGetFinishingValues: Checking %d (%s)", f->value, ippEnumString("finishings", f->value)));
2056
dcb445bc 2057 for (i = f->num_options, option = f->options; i > 0; i --, option ++)
b2b9911d
MS
2058 {
2059 DEBUG_printf(("_ppdCacheGetFinishingValues: %s=%s?", option->name, option->value));
2060
dcb445bc
MS
2061 if ((val = cupsGetOption(option->name, num_options, options)) == NULL ||
2062 _cups_strcasecmp(option->value, val))
b2b9911d
MS
2063 {
2064 DEBUG_puts("_ppdCacheGetFinishingValues: NO");
dcb445bc 2065 break;
b2b9911d
MS
2066 }
2067 }
dcb445bc
MS
2068
2069 if (i == 0)
2070 {
b2b9911d
MS
2071 DEBUG_printf(("_ppdCacheGetFinishingValues: Adding %d.", f->value));
2072
dcb445bc
MS
2073 values[num_values ++] = f->value;
2074
2075 if (num_values >= max_values)
2076 break;
2077 }
2078 }
2079
b2b9911d
MS
2080 DEBUG_printf(("_ppdCacheGetFinishingValues: Returning %d.", num_values));
2081
dcb445bc
MS
2082 return (num_values);
2083}
2084
2085
f14324a7
MS
2086/*
2087 * '_ppdCacheGetInputSlot()' - Get the PPD InputSlot associated with the job
2088 * attributes or a keyword string.
2089 */
2090
2091const char * /* O - PPD InputSlot or NULL */
2092_ppdCacheGetInputSlot(
2093 _ppd_cache_t *pc, /* I - PPD cache and mapping data */
2094 ipp_t *job, /* I - Job attributes or NULL */
2095 const char *keyword) /* I - Keyword string or NULL */
2096{
2097 /*
2098 * Range check input...
2099 */
2100
2101 if (!pc || pc->num_sources == 0 || (!job && !keyword))
2102 return (NULL);
2103
2104 if (job && !keyword)
2105 {
2106 /*
2107 * Lookup the media-col attribute and any media-source found there...
2108 */
2109
2110 ipp_attribute_t *media_col, /* media-col attribute */
2111 *media_source; /* media-source attribute */
6961465f 2112 pwg_size_t size; /* Dimensional size */
f14324a7
MS
2113 int margins_set; /* Were the margins set? */
2114
2115 media_col = ippFindAttribute(job, "media-col", IPP_TAG_BEGIN_COLLECTION);
2116 if (media_col &&
dcb445bc 2117 (media_source = ippFindAttribute(ippGetCollection(media_col, 0),
f14324a7
MS
2118 "media-source",
2119 IPP_TAG_KEYWORD)) != NULL)
2120 {
2121 /*
2122 * Use the media-source value from media-col...
2123 */
2124
dcb445bc 2125 keyword = ippGetString(media_source, 0, NULL);
f14324a7 2126 }
6961465f 2127 else if (pwgInitSize(&size, job, &margins_set))
f14324a7
MS
2128 {
2129 /*
2130 * For media <= 5x7, look for a photo tray...
2131 */
2132
2133 if (size.width <= (5 * 2540) && size.length <= (7 * 2540))
2134 keyword = "photo";
2135 }
2136 }
2137
2138 if (keyword)
2139 {
2140 int i; /* Looping var */
2141
2142 for (i = 0; i < pc->num_sources; i ++)
88f9aafc 2143 if (!_cups_strcasecmp(keyword, pc->sources[i].pwg))
f14324a7
MS
2144 return (pc->sources[i].ppd);
2145 }
2146
2147 return (NULL);
2148}
2149
2150
2151/*
2152 * '_ppdCacheGetMediaType()' - Get the PPD MediaType associated with the job
2153 * attributes or a keyword string.
2154 */
2155
2156const char * /* O - PPD MediaType or NULL */
2157_ppdCacheGetMediaType(
2158 _ppd_cache_t *pc, /* I - PPD cache and mapping data */
2159 ipp_t *job, /* I - Job attributes or NULL */
2160 const char *keyword) /* I - Keyword string or NULL */
2161{
2162 /*
2163 * Range check input...
2164 */
2165
2166 if (!pc || pc->num_types == 0 || (!job && !keyword))
2167 return (NULL);
2168
2169 if (job && !keyword)
2170 {
2171 /*
2172 * Lookup the media-col attribute and any media-source found there...
2173 */
2174
2175 ipp_attribute_t *media_col, /* media-col attribute */
2176 *media_type; /* media-type attribute */
2177
2178 media_col = ippFindAttribute(job, "media-col", IPP_TAG_BEGIN_COLLECTION);
2179 if (media_col)
2180 {
2181 if ((media_type = ippFindAttribute(media_col->values[0].collection,
2182 "media-type",
2183 IPP_TAG_KEYWORD)) == NULL)
2184 media_type = ippFindAttribute(media_col->values[0].collection,
2185 "media-type", IPP_TAG_NAME);
2186
2187 if (media_type)
2188 keyword = media_type->values[0].string.text;
2189 }
2190 }
2191
2192 if (keyword)
2193 {
2194 int i; /* Looping var */
2195
2196 for (i = 0; i < pc->num_types; i ++)
88f9aafc 2197 if (!_cups_strcasecmp(keyword, pc->types[i].pwg))
f14324a7
MS
2198 return (pc->types[i].ppd);
2199 }
2200
2201 return (NULL);
2202}
2203
2204
2205/*
2206 * '_ppdCacheGetOutputBin()' - Get the PPD OutputBin associated with the keyword
2207 * string.
2208 */
2209
2210const char * /* O - PPD OutputBin or NULL */
2211_ppdCacheGetOutputBin(
2212 _ppd_cache_t *pc, /* I - PPD cache and mapping data */
2213 const char *output_bin) /* I - Keyword string */
2214{
2215 int i; /* Looping var */
2216
2217
2218 /*
2219 * Range check input...
2220 */
2221
2222 if (!pc || !output_bin)
2223 return (NULL);
2224
2225 /*
2226 * Look up the OutputBin string...
2227 */
2228
2229
2230 for (i = 0; i < pc->num_bins; i ++)
88f9aafc 2231 if (!_cups_strcasecmp(output_bin, pc->bins[i].pwg))
f14324a7
MS
2232 return (pc->bins[i].ppd);
2233
2234 return (NULL);
2235}
2236
2237
2238/*
2239 * '_ppdCacheGetPageSize()' - Get the PPD PageSize associated with the job
2240 * attributes or a keyword string.
2241 */
2242
2243const char * /* O - PPD PageSize or NULL */
2244_ppdCacheGetPageSize(
2245 _ppd_cache_t *pc, /* I - PPD cache and mapping data */
2246 ipp_t *job, /* I - Job attributes or NULL */
2247 const char *keyword, /* I - Keyword string or NULL */
2248 int *exact) /* O - 1 if exact match, 0 otherwise */
2249{
2250 int i; /* Looping var */
6961465f 2251 pwg_size_t *size, /* Current size */
f14324a7
MS
2252 *closest, /* Closest size */
2253 jobsize; /* Size data from job */
2254 int margins_set, /* Were the margins set? */
2255 dwidth, /* Difference in width */
2256 dlength, /* Difference in length */
2257 dleft, /* Difference in left margins */
2258 dright, /* Difference in right margins */
2259 dbottom, /* Difference in bottom margins */
2260 dtop, /* Difference in top margins */
2261 dmin, /* Minimum difference */
2262 dclosest; /* Closest difference */
2263 const char *ppd_name; /* PPD media name */
2264
2265
2266 DEBUG_printf(("_ppdCacheGetPageSize(pc=%p, job=%p, keyword=\"%s\", exact=%p)",
2267 pc, job, keyword, exact));
2268
2269 /*
2270 * Range check input...
2271 */
2272
2273 if (!pc || (!job && !keyword))
2274 return (NULL);
2275
2276 if (exact)
2277 *exact = 0;
2278
2279 ppd_name = keyword;
2280
2281 if (job)
2282 {
2283 /*
2284 * Try getting the PPD media name from the job attributes...
2285 */
2286
2287 ipp_attribute_t *attr; /* Job attribute */
2288
2289 if ((attr = ippFindAttribute(job, "PageSize", IPP_TAG_ZERO)) == NULL)
2290 if ((attr = ippFindAttribute(job, "PageRegion", IPP_TAG_ZERO)) == NULL)
2291 attr = ippFindAttribute(job, "media", IPP_TAG_ZERO);
2292
2293#ifdef DEBUG
2294 if (attr)
2295 DEBUG_printf(("1_ppdCacheGetPageSize: Found attribute %s (%s)",
2296 attr->name, ippTagString(attr->value_tag)));
2297 else
2298 DEBUG_puts("1_ppdCacheGetPageSize: Did not find media attribute.");
2299#endif /* DEBUG */
2300
2301 if (attr && (attr->value_tag == IPP_TAG_NAME ||
2302 attr->value_tag == IPP_TAG_KEYWORD))
2303 ppd_name = attr->values[0].string.text;
2304 }
2305
2306 DEBUG_printf(("1_ppdCacheGetPageSize: ppd_name=\"%s\"", ppd_name));
2307
2308 if (ppd_name)
2309 {
2310 /*
2311 * Try looking up the named PPD size first...
2312 */
2313
2314 for (i = pc->num_sizes, size = pc->sizes; i > 0; i --, size ++)
2315 {
2316 DEBUG_printf(("2_ppdCacheGetPageSize: size[%d]=[\"%s\" \"%s\"]",
2317 (int)(size - pc->sizes), size->map.pwg, size->map.ppd));
2318
88f9aafc
MS
2319 if (!_cups_strcasecmp(ppd_name, size->map.ppd) ||
2320 !_cups_strcasecmp(ppd_name, size->map.pwg))
f14324a7
MS
2321 {
2322 if (exact)
2323 *exact = 1;
2324
2325 DEBUG_printf(("1_ppdCacheGetPageSize: Returning \"%s\"", ppd_name));
2326
2327 return (size->map.ppd);
2328 }
2329 }
2330 }
2331
2332 if (job && !keyword)
2333 {
2334 /*
2335 * Get the size using media-col or media, with the preference being
2336 * media-col.
2337 */
2338
6961465f 2339 if (!pwgInitSize(&jobsize, job, &margins_set))
f14324a7
MS
2340 return (NULL);
2341 }
2342 else
2343 {
2344 /*
2345 * Get the size using a media keyword...
2346 */
2347
6961465f 2348 pwg_media_t *media; /* Media definition */
f14324a7
MS
2349
2350
6961465f
MS
2351 if ((media = pwgMediaForPWG(keyword)) == NULL)
2352 if ((media = pwgMediaForLegacy(keyword)) == NULL)
2353 if ((media = pwgMediaForPPD(keyword)) == NULL)
f14324a7
MS
2354 return (NULL);
2355
2356 jobsize.width = media->width;
2357 jobsize.length = media->length;
2358 margins_set = 0;
2359 }
2360
2361 /*
2362 * Now that we have the dimensions and possibly the margins, look at the
2363 * available sizes and find the match...
2364 */
2365
2366 closest = NULL;
2367 dclosest = 999999999;
2368
88f9aafc
MS
2369 if (!ppd_name || _cups_strncasecmp(ppd_name, "Custom.", 7) ||
2370 _cups_strncasecmp(ppd_name, "custom_", 7))
f14324a7
MS
2371 {
2372 for (i = pc->num_sizes, size = pc->sizes; i > 0; i --, size ++)
2373 {
2374 /*
2375 * Adobe uses a size matching algorithm with an epsilon of 5 points, which
2376 * is just about 176/2540ths...
2377 */
2378
2379 dwidth = size->width - jobsize.width;
2380 dlength = size->length - jobsize.length;
2381
2382 if (dwidth <= -176 || dwidth >= 176 || dlength <= -176 || dlength >= 176)
2383 continue;
2384
2385 if (margins_set)
2386 {
2387 /*
2388 * Use a tighter epsilon of 1 point (35/2540ths) for margins...
2389 */
2390
2391 dleft = size->left - jobsize.left;
2392 dright = size->right - jobsize.right;
2393 dtop = size->top - jobsize.top;
2394 dbottom = size->bottom - jobsize.bottom;
2395
2396 if (dleft <= -35 || dleft >= 35 || dright <= -35 || dright >= 35 ||
2397 dtop <= -35 || dtop >= 35 || dbottom <= -35 || dbottom >= 35)
2398 {
2399 dleft = dleft < 0 ? -dleft : dleft;
2400 dright = dright < 0 ? -dright : dright;
2401 dbottom = dbottom < 0 ? -dbottom : dbottom;
2402 dtop = dtop < 0 ? -dtop : dtop;
2403 dmin = dleft + dright + dbottom + dtop;
2404
2405 if (dmin < dclosest)
2406 {
2407 dclosest = dmin;
2408 closest = size;
2409 }
2410
2411 continue;
2412 }
2413 }
2414
2415 if (exact)
2416 *exact = 1;
2417
2418 DEBUG_printf(("1_ppdCacheGetPageSize: Returning \"%s\"", size->map.ppd));
2419
2420 return (size->map.ppd);
2421 }
2422 }
2423
2424 if (closest)
2425 {
2426 DEBUG_printf(("1_ppdCacheGetPageSize: Returning \"%s\" (closest)",
2427 closest->map.ppd));
2428
2429 return (closest->map.ppd);
2430 }
2431
2432 /*
2433 * If we get here we need to check for custom page size support...
2434 */
2435
2436 if (jobsize.width >= pc->custom_min_width &&
2437 jobsize.width <= pc->custom_max_width &&
2438 jobsize.length >= pc->custom_min_length &&
2439 jobsize.length <= pc->custom_max_length)
2440 {
2441 /*
2442 * In range, format as Custom.WWWWxLLLL (points).
2443 */
2444
2445 snprintf(pc->custom_ppd_size, sizeof(pc->custom_ppd_size), "Custom.%dx%d",
6961465f 2446 (int)PWG_TO_POINTS(jobsize.width), (int)PWG_TO_POINTS(jobsize.length));
f14324a7
MS
2447
2448 if (margins_set && exact)
2449 {
2450 dleft = pc->custom_size.left - jobsize.left;
2451 dright = pc->custom_size.right - jobsize.right;
2452 dtop = pc->custom_size.top - jobsize.top;
2453 dbottom = pc->custom_size.bottom - jobsize.bottom;
2454
2455 if (dleft > -35 && dleft < 35 && dright > -35 && dright < 35 &&
2456 dtop > -35 && dtop < 35 && dbottom > -35 && dbottom < 35)
2457 *exact = 1;
2458 }
2459 else if (exact)
2460 *exact = 1;
2461
2462 DEBUG_printf(("1_ppdCacheGetPageSize: Returning \"%s\" (custom)",
2463 pc->custom_ppd_size));
2464
2465 return (pc->custom_ppd_size);
2466 }
2467
2468 /*
2469 * No custom page size support or the size is out of range - return NULL.
2470 */
2471
2472 DEBUG_puts("1_ppdCacheGetPageSize: Returning NULL");
2473
2474 return (NULL);
2475}
2476
2477
2478/*
2479 * '_ppdCacheGetSize()' - Get the PWG size associated with a PPD PageSize.
2480 */
2481
6961465f 2482pwg_size_t * /* O - PWG size or NULL */
f14324a7
MS
2483_ppdCacheGetSize(
2484 _ppd_cache_t *pc, /* I - PPD cache and mapping data */
2485 const char *page_size) /* I - PPD PageSize */
2486{
dcb445bc 2487 int i; /* Looping var */
6961465f
MS
2488 pwg_media_t *media; /* Media */
2489 pwg_size_t *size; /* Current size */
f14324a7
MS
2490
2491
2492 /*
2493 * Range check input...
2494 */
2495
2496 if (!pc || !page_size)
2497 return (NULL);
2498
88f9aafc 2499 if (!_cups_strncasecmp(page_size, "Custom.", 7))
f14324a7
MS
2500 {
2501 /*
2502 * Custom size; size name can be one of the following:
2503 *
2504 * Custom.WIDTHxLENGTHin - Size in inches
2505 * Custom.WIDTHxLENGTHft - Size in feet
2506 * Custom.WIDTHxLENGTHcm - Size in centimeters
2507 * Custom.WIDTHxLENGTHmm - Size in millimeters
2508 * Custom.WIDTHxLENGTHm - Size in meters
2509 * Custom.WIDTHxLENGTH[pt] - Size in points
2510 */
2511
2512 double w, l; /* Width and length of page */
2513 char *ptr; /* Pointer into PageSize */
2514 struct lconv *loc; /* Locale data */
2515
2516 loc = localeconv();
2517 w = (float)_cupsStrScand(page_size + 7, &ptr, loc);
2518 if (!ptr || *ptr != 'x')
2519 return (NULL);
2520
2521 l = (float)_cupsStrScand(ptr + 1, &ptr, loc);
2522 if (!ptr)
2523 return (NULL);
2524
88f9aafc 2525 if (!_cups_strcasecmp(ptr, "in"))
f14324a7
MS
2526 {
2527 w *= 2540.0;
2528 l *= 2540.0;
2529 }
88f9aafc 2530 else if (!_cups_strcasecmp(ptr, "ft"))
f14324a7
MS
2531 {
2532 w *= 12.0 * 2540.0;
2533 l *= 12.0 * 2540.0;
2534 }
88f9aafc 2535 else if (!_cups_strcasecmp(ptr, "mm"))
f14324a7
MS
2536 {
2537 w *= 100.0;
2538 l *= 100.0;
2539 }
88f9aafc 2540 else if (!_cups_strcasecmp(ptr, "cm"))
f14324a7
MS
2541 {
2542 w *= 1000.0;
2543 l *= 1000.0;
2544 }
88f9aafc 2545 else if (!_cups_strcasecmp(ptr, "m"))
f14324a7
MS
2546 {
2547 w *= 100000.0;
2548 l *= 100000.0;
2549 }
2550 else
2551 {
2552 w *= 2540.0 / 72.0;
2553 l *= 2540.0 / 72.0;
2554 }
2555
2556 pc->custom_size.width = (int)w;
2557 pc->custom_size.length = (int)l;
2558
2559 return (&(pc->custom_size));
2560 }
2561
2562 /*
2563 * Not a custom size - look it up...
2564 */
2565
2566 for (i = pc->num_sizes, size = pc->sizes; i > 0; i --, size ++)
dcb445bc
MS
2567 if (!_cups_strcasecmp(page_size, size->map.ppd) ||
2568 !_cups_strcasecmp(page_size, size->map.pwg))
f14324a7
MS
2569 return (size);
2570
dcb445bc
MS
2571 /*
2572 * Look up standard sizes...
2573 */
2574
6961465f
MS
2575 if ((media = pwgMediaForPPD(page_size)) == NULL)
2576 if ((media = pwgMediaForLegacy(page_size)) == NULL)
2577 media = pwgMediaForPWG(page_size);
dcb445bc
MS
2578
2579 if (media)
2580 {
2581 pc->custom_size.width = media->width;
2582 pc->custom_size.length = media->length;
2583
2584 return (&(pc->custom_size));
2585 }
2586
f14324a7
MS
2587 return (NULL);
2588}
2589
2590
2591/*
2592 * '_ppdCacheGetSource()' - Get the PWG media-source associated with a PPD
2593 * InputSlot.
2594 */
2595
2596const char * /* O - PWG media-source keyword */
2597_ppdCacheGetSource(
2598 _ppd_cache_t *pc, /* I - PPD cache and mapping data */
2599 const char *input_slot) /* I - PPD InputSlot */
2600{
2601 int i; /* Looping var */
6961465f 2602 pwg_map_t *source; /* Current source */
f14324a7
MS
2603
2604
2605 /*
2606 * Range check input...
2607 */
2608
2609 if (!pc || !input_slot)
2610 return (NULL);
2611
2612 for (i = pc->num_sources, source = pc->sources; i > 0; i --, source ++)
88f9aafc 2613 if (!_cups_strcasecmp(input_slot, source->ppd))
f14324a7
MS
2614 return (source->pwg);
2615
2616 return (NULL);
2617}
2618
2619
2620/*
2621 * '_ppdCacheGetType()' - Get the PWG media-type associated with a PPD
2622 * MediaType.
2623 */
2624
2625const char * /* O - PWG media-type keyword */
2626_ppdCacheGetType(
2627 _ppd_cache_t *pc, /* I - PPD cache and mapping data */
2628 const char *media_type) /* I - PPD MediaType */
2629{
2630 int i; /* Looping var */
6961465f 2631 pwg_map_t *type; /* Current type */
f14324a7
MS
2632
2633
2634 /*
2635 * Range check input...
2636 */
2637
2638 if (!pc || !media_type)
2639 return (NULL);
2640
2641 for (i = pc->num_types, type = pc->types; i > 0; i --, type ++)
88f9aafc 2642 if (!_cups_strcasecmp(media_type, type->ppd))
f14324a7
MS
2643 return (type->pwg);
2644
2645 return (NULL);
2646}
2647
2648
2649/*
2650 * '_ppdCacheWriteFile()' - Write PWG mapping data to a file.
2651 */
2652
2653int /* O - 1 on success, 0 on failure */
2654_ppdCacheWriteFile(
2655 _ppd_cache_t *pc, /* I - PPD cache and mapping data */
2656 const char *filename, /* I - File to write */
2657 ipp_t *attrs) /* I - Attributes to write, if any */
2658{
dcb445bc
MS
2659 int i, j, k; /* Looping vars */
2660 cups_file_t *fp; /* Output file */
6961465f
MS
2661 pwg_size_t *size; /* Current size */
2662 pwg_map_t *map; /* Current map */
dcb445bc
MS
2663 _pwg_finishings_t *f; /* Current finishing option */
2664 cups_option_t *option; /* Current option */
2665 const char *value; /* Filter/pre-filter value */
2666 char newfile[1024]; /* New filename */
5a08320a 2667 _pwg_material_t *m; /* Material */
f14324a7
MS
2668
2669
2670 /*
2671 * Range check input...
2672 */
2673
2674 if (!pc || !filename)
2675 {
cb7f98ee 2676 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
f14324a7
MS
2677 return (0);
2678 }
2679
2680 /*
2681 * Open the file and write with compression...
2682 */
2683
321d8d57
MS
2684 snprintf(newfile, sizeof(newfile), "%s.N", filename);
2685 if ((fp = cupsFileOpen(newfile, "w9")) == NULL)
f14324a7 2686 {
cb7f98ee 2687 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
f14324a7
MS
2688 return (0);
2689 }
2690
2691 /*
2692 * Standard header...
2693 */
2694
2695 cupsFilePrintf(fp, "#CUPS-PPD-CACHE-%d\n", _PPD_CACHE_VERSION);
2696
2697 /*
2698 * Output bins...
2699 */
2700
2701 if (pc->num_bins > 0)
2702 {
2703 cupsFilePrintf(fp, "NumBins %d\n", pc->num_bins);
2704 for (i = pc->num_bins, map = pc->bins; i > 0; i --, map ++)
2705 cupsFilePrintf(fp, "Bin %s %s\n", map->pwg, map->ppd);
2706 }
2707
2708 /*
2709 * Media sizes...
2710 */
2711
2712 cupsFilePrintf(fp, "NumSizes %d\n", pc->num_sizes);
2713 for (i = pc->num_sizes, size = pc->sizes; i > 0; i --, size ++)
2714 cupsFilePrintf(fp, "Size %s %s %d %d %d %d %d %d\n", size->map.pwg,
2715 size->map.ppd, size->width, size->length, size->left,
2716 size->bottom, size->right, size->top);
2717 if (pc->custom_max_width > 0)
2718 cupsFilePrintf(fp, "CustomSize %d %d %d %d %d %d %d %d\n",
2719 pc->custom_max_width, pc->custom_max_length,
2720 pc->custom_min_width, pc->custom_min_length,
2721 pc->custom_size.left, pc->custom_size.bottom,
2722 pc->custom_size.right, pc->custom_size.top);
2723
2724 /*
2725 * Media sources...
2726 */
2727
2728 if (pc->source_option)
2729 cupsFilePrintf(fp, "SourceOption %s\n", pc->source_option);
2730
2731 if (pc->num_sources > 0)
2732 {
2733 cupsFilePrintf(fp, "NumSources %d\n", pc->num_sources);
2734 for (i = pc->num_sources, map = pc->sources; i > 0; i --, map ++)
2735 cupsFilePrintf(fp, "Source %s %s\n", map->pwg, map->ppd);
2736 }
2737
2738 /*
2739 * Media types...
2740 */
2741
2742 if (pc->num_types > 0)
2743 {
2744 cupsFilePrintf(fp, "NumTypes %d\n", pc->num_types);
2745 for (i = pc->num_types, map = pc->types; i > 0; i --, map ++)
2746 cupsFilePrintf(fp, "Type %s %s\n", map->pwg, map->ppd);
2747 }
2748
2749 /*
2750 * Presets...
2751 */
2752
2753 for (i = _PWG_PRINT_COLOR_MODE_MONOCHROME; i < _PWG_PRINT_COLOR_MODE_MAX; i ++)
2754 for (j = _PWG_PRINT_QUALITY_DRAFT; j < _PWG_PRINT_QUALITY_MAX; j ++)
2755 if (pc->num_presets[i][j])
2756 {
2757 cupsFilePrintf(fp, "Preset %d %d", i, j);
2758 for (k = pc->num_presets[i][j], option = pc->presets[i][j];
2759 k > 0;
2760 k --, option ++)
2761 cupsFilePrintf(fp, " %s=%s", option->name, option->value);
2762 cupsFilePutChar(fp, '\n');
2763 }
2764
2765 /*
2766 * Duplex/sides...
2767 */
2768
2769 if (pc->sides_option)
2770 cupsFilePrintf(fp, "SidesOption %s\n", pc->sides_option);
2771
2772 if (pc->sides_1sided)
2773 cupsFilePrintf(fp, "Sides1Sided %s\n", pc->sides_1sided);
2774
2775 if (pc->sides_2sided_long)
2776 cupsFilePrintf(fp, "Sides2SidedLong %s\n", pc->sides_2sided_long);
2777
2778 if (pc->sides_2sided_short)
2779 cupsFilePrintf(fp, "Sides2SidedShort %s\n", pc->sides_2sided_short);
2780
2781 /*
2782 * Product, cupsFilter, cupsFilter2, and cupsPreFilter...
2783 */
2784
2785 if (pc->product)
2786 cupsFilePutConf(fp, "Product", pc->product);
2787
2788 for (value = (const char *)cupsArrayFirst(pc->filters);
2789 value;
2790 value = (const char *)cupsArrayNext(pc->filters))
2791 cupsFilePutConf(fp, "Filter", value);
2792
2793 for (value = (const char *)cupsArrayFirst(pc->prefilters);
2794 value;
2795 value = (const char *)cupsArrayNext(pc->prefilters))
2796 cupsFilePutConf(fp, "PreFilter", value);
2797
82f97232
MS
2798 cupsFilePrintf(fp, "SingleFile %s\n", pc->single_file ? "true" : "false");
2799
dcb445bc
MS
2800 /*
2801 * Finishing options...
2802 */
2803
2804 for (f = (_pwg_finishings_t *)cupsArrayFirst(pc->finishings);
2805 f;
2806 f = (_pwg_finishings_t *)cupsArrayNext(pc->finishings))
2807 {
2808 cupsFilePrintf(fp, "Finishings %d", f->value);
2809 for (i = f->num_options, option = f->options; i > 0; i --, option ++)
2810 cupsFilePrintf(fp, " %s=%s", option->name, option->value);
2811 cupsFilePutChar(fp, '\n');
2812 }
2813
3e7fe0ca
MS
2814 /*
2815 * Max copies...
2816 */
2817
2818 cupsFilePrintf(fp, "MaxCopies %d\n", pc->max_copies);
2819
5a9febac
MS
2820 /*
2821 * Accounting/quota/PIN/managed printing values...
2822 */
2823
a469f8a5
MS
2824 if (pc->charge_info_uri)
2825 cupsFilePutConf(fp, "ChargeInfoURI", pc->charge_info_uri);
2826
5a9febac
MS
2827 cupsFilePrintf(fp, "AccountId %s\n", pc->account_id ? "true" : "false");
2828 cupsFilePrintf(fp, "AccountingUserId %s\n",
2829 pc->accounting_user_id ? "true" : "false");
2830
2831 if (pc->password)
2832 cupsFilePutConf(fp, "Password", pc->password);
2833
2834 for (value = (char *)cupsArrayFirst(pc->mandatory);
2835 value;
2836 value = (char *)cupsArrayNext(pc->mandatory))
2837 cupsFilePutConf(fp, "Mandatory", value);
2838
c1420c87
MS
2839 /*
2840 * Support files...
2841 */
2842
2843 for (value = (char *)cupsArrayFirst(pc->support_files);
2844 value;
2845 value = (char *)cupsArrayNext(pc->support_files))
2846 cupsFilePutConf(fp, "SupportFile", value);
2847
5a08320a
MS
2848 /*
2849 * 3D stuff...
2850 */
2851
2852 if (pc->cups_3d)
2853 cupsFilePutConf(fp, "3D", pc->cups_3d);
2854
2855 if (pc->cups_layer_order)
2856 cupsFilePutConf(fp, "LayerOrder", pc->cups_layer_order);
2857
2858 if (pc->cups_accuracy[0] || pc->cups_accuracy[0] || pc->cups_accuracy[2])
2859 cupsFilePrintf(fp, "Accuracy %d %d %d\n", pc->cups_accuracy[0], pc->cups_accuracy[1], pc->cups_accuracy[2]);
2860
2861 if (pc->cups_volume[0] || pc->cups_volume[0] || pc->cups_volume[2])
2862 cupsFilePrintf(fp, "Volume %d %d %d\n", pc->cups_volume[0], pc->cups_volume[1], pc->cups_volume[2]);
2863
2864 for (m = (_pwg_material_t *)cupsArrayFirst(pc->materials);
2865 m;
2866 m = (_pwg_material_t *)cupsArrayNext(pc->materials))
2867 {
2868 cupsFilePrintf(fp, "Material %s \"%s\"", m->key, m->name);
2869 for (i = 0; i < m->num_props; i ++)
2870 cupsFilePrintf(fp, " %s=%s", m->props[i].name, m->props[i].value);
2871 cupsFilePuts(fp, "\n");
2872 }
2873
f14324a7
MS
2874 /*
2875 * IPP attributes, if any...
2876 */
2877
2878 if (attrs)
2879 {
2880 cupsFilePrintf(fp, "IPP " CUPS_LLFMT "\n", CUPS_LLCAST ippLength(attrs));
2881
cb7f98ee 2882 attrs->state = IPP_STATE_IDLE;
f14324a7
MS
2883 ippWriteIO(fp, (ipp_iocb_t)cupsFileWrite, 1, NULL, attrs);
2884 }
2885
2886 /*
2887 * Close and return...
2888 */
2889
321d8d57
MS
2890 if (cupsFileClose(fp))
2891 {
2892 unlink(newfile);
2893 return (0);
2894 }
2895
2896 unlink(filename);
2897 return (!rename(newfile, filename));
f14324a7
MS
2898}
2899
2900
d9fc71e4
MS
2901/*
2902 * '_ppdCreateFromIPP()' - Create a PPD file describing the capabilities
2903 * of an IPP printer.
2904 */
2905
2906char * /* O - PPD filename or NULL on error */
2907_ppdCreateFromIPP(char *buffer, /* I - Filename buffer */
2908 size_t bufsize, /* I - Size of filename buffer */
2909 ipp_t *response) /* I - Get-Printer-Attributes response */
2910{
2911 cups_file_t *fp; /* PPD file */
2912 ipp_attribute_t *attr, /* xxx-supported */
2913 *defattr, /* xxx-default */
2914 *x_dim, *y_dim; /* Media dimensions */
2915 ipp_t *media_size; /* Media size collection */
2916 char make[256], /* Make and model */
2917 *model, /* Model name */
2918 ppdname[PPD_MAX_NAME];
2919 /* PPD keyword */
2920 int i, j, /* Looping vars */
2921 count, /* Number of values */
2922 bottom, /* Largest bottom margin */
2923 left, /* Largest left margin */
2924 right, /* Largest right margin */
2925 top; /* Largest top margin */
2926 pwg_media_t *pwg; /* PWG media size */
2927 int xres, yres; /* Resolution values */
560634d3
MS
2928 struct lconv *loc = localeconv();
2929 /* Locale data */
d9fc71e4
MS
2930
2931
2932 /*
2933 * Range check input...
2934 */
2935
fffed089
MS
2936 if (buffer)
2937 *buffer = '\0';
2938
d9fc71e4
MS
2939 if (!buffer || bufsize < 1 || !response)
2940 return (NULL);
2941
2942 /*
2943 * Open a temporary file for the PPD...
2944 */
2945
2946 if ((fp = cupsTempFile2(buffer, (int)bufsize)) == NULL)
2947 return (NULL);
2948
2949 /*
2950 * Standard stuff for PPD file...
2951 */
2952
2953 cupsFilePuts(fp, "*PPD-Adobe: \"4.3\"\n");
2954 cupsFilePuts(fp, "*FormatVersion: \"4.3\"\n");
2955 cupsFilePrintf(fp, "*FileVersion: \"%d.%d\"\n", CUPS_VERSION_MAJOR, CUPS_VERSION_MINOR);
2956 cupsFilePuts(fp, "*LanguageVersion: English\n");
2957 cupsFilePuts(fp, "*LanguageEncoding: ISOLatin1\n");
2958 cupsFilePuts(fp, "*PSVersion: \"(3010.000) 0\"\n");
2959 cupsFilePuts(fp, "*LanguageLevel: \"3\"\n");
2960 cupsFilePuts(fp, "*FileSystem: False\n");
2961 cupsFilePuts(fp, "*PCFileName: \"ippeve.ppd\"\n");
2962
2963 if ((attr = ippFindAttribute(response, "printer-make-and-model", IPP_TAG_TEXT)) != NULL)
2964 strlcpy(make, ippGetString(attr, 0, NULL), sizeof(make));
2965 else
2966 strlcpy(make, "Unknown Printer", sizeof(make));
2967
2968 if (!_cups_strncasecmp(make, "Hewlett Packard ", 16) ||
2969 !_cups_strncasecmp(make, "Hewlett-Packard ", 16))
2970 {
2971 model = make + 16;
2972 strlcpy(make, "HP", sizeof(make));
2973 }
2974 else if ((model = strchr(make, ' ')) != NULL)
2975 *model++ = '\0';
2976 else
2977 model = make;
2978
2979 cupsFilePrintf(fp, "*Manufacturer: \"%s\"\n", make);
2980 cupsFilePrintf(fp, "*ModelName: \"%s\"\n", model);
2981 cupsFilePrintf(fp, "*Product: \"(%s)\"\n", model);
2982 cupsFilePrintf(fp, "*NickName: \"%s\"\n", model);
2983 cupsFilePrintf(fp, "*ShortNickName: \"%s\"\n", model);
2984
fb2d5470
MS
2985 if ((attr = ippFindAttribute(response, "color-supported", IPP_TAG_BOOLEAN)) != NULL && ippGetBoolean(attr, 0))
2986 cupsFilePuts(fp, "*ColorDevice: True\n");
2987 else
2988 cupsFilePuts(fp, "*ColorDevice: False\n");
2989
d9fc71e4
MS
2990 cupsFilePrintf(fp, "*cupsVersion: %d.%d\n", CUPS_VERSION_MAJOR, CUPS_VERSION_MINOR);
2991 cupsFilePuts(fp, "*cupsSNMPSupplies: False\n");
2992 cupsFilePuts(fp, "*cupsLanguages: \"en\"\n");
2993
2994 /*
2995 * Filters...
2996 */
2997
2998 if ((attr = ippFindAttribute(response, "document-format-supported", IPP_TAG_MIMETYPE)) != NULL)
2999 {
3000 for (i = 0, count = ippGetCount(attr); i < count; i ++)
3001 {
3002 const char *format = ippGetString(attr, i, NULL);
3003 /* PDL */
3004
3005 if (!_cups_strcasecmp(format, "application/pdf"))
3006 cupsFilePuts(fp, "*cupsFilter2: \"application/vnd.cups-pdf application/pdf 10 -\"\n");
fb2d5470
MS
3007 else if (!_cups_strcasecmp(format, "application/postscript"))
3008 cupsFilePuts(fp, "*cupsFilter2: \"application/vnd.cups-postscript application/postscript 10 -\"\n");
3009 else if (_cups_strcasecmp(format, "application/octet-stream") && _cups_strcasecmp(format, "application/vnd.hp-pcl") && _cups_strcasecmp(format, "text/plain"))
d9fc71e4
MS
3010 cupsFilePrintf(fp, "*cupsFilter2: \"%s %s 10 -\"\n", format, format);
3011 }
3012 }
3013
3014 /*
3015 * PageSize/PageRegion/ImageableArea/PaperDimension
3016 */
3017
3018 if ((attr = ippFindAttribute(response, "media-bottom-margin-supported", IPP_TAG_INTEGER)) != NULL)
3019 {
3020 for (i = 1, bottom = ippGetInteger(attr, 0), count = ippGetCount(attr); i < count; i ++)
3021 if (ippGetInteger(attr, i) > bottom)
3022 bottom = ippGetInteger(attr, i);
3023 }
3024 else
3025 bottom = 1270;
3026
3027 if ((attr = ippFindAttribute(response, "media-left-margin-supported", IPP_TAG_INTEGER)) != NULL)
3028 {
3029 for (i = 1, left = ippGetInteger(attr, 0), count = ippGetCount(attr); i < count; i ++)
3030 if (ippGetInteger(attr, i) > left)
3031 left = ippGetInteger(attr, i);
3032 }
3033 else
3034 left = 635;
3035
3036 if ((attr = ippFindAttribute(response, "media-right-margin-supported", IPP_TAG_INTEGER)) != NULL)
3037 {
3038 for (i = 1, right = ippGetInteger(attr, 0), count = ippGetCount(attr); i < count; i ++)
3039 if (ippGetInteger(attr, i) > right)
3040 right = ippGetInteger(attr, i);
3041 }
3042 else
3043 right = 635;
3044
3045 if ((attr = ippFindAttribute(response, "media-top-margin-supported", IPP_TAG_INTEGER)) != NULL)
3046 {
3047 for (i = 1, top = ippGetInteger(attr, 0), count = ippGetCount(attr); i < count; i ++)
3048 if (ippGetInteger(attr, i) > top)
3049 top = ippGetInteger(attr, i);
3050 }
3051 else
3052 top = 1270;
3053
3054 if ((defattr = ippFindAttribute(response, "media-col-default", IPP_TAG_BEGIN_COLLECTION)) != NULL)
3055 {
3056 if ((attr = ippFindAttribute(ippGetCollection(defattr, 0), "media-size", IPP_TAG_BEGIN_COLLECTION)) != NULL)
3057 {
3058 media_size = ippGetCollection(attr, 0);
3059 x_dim = ippFindAttribute(media_size, "x-dimension", IPP_TAG_INTEGER);
3060 y_dim = ippFindAttribute(media_size, "y-dimension", IPP_TAG_INTEGER);
3061
3062 if (x_dim && y_dim)
3063 {
3064 pwg = pwgMediaForSize(ippGetInteger(x_dim, 0), ippGetInteger(y_dim, 0));
3065 strlcpy(ppdname, pwg->ppd, sizeof(ppdname));
3066 }
3067 else
3068 strlcpy(ppdname, "Unknown", sizeof(ppdname));
3069 }
3070 else
3071 strlcpy(ppdname, "Unknown", sizeof(ppdname));
3072 }
3073
3074 if ((attr = ippFindAttribute(response, "media-size-supported", IPP_TAG_BEGIN_COLLECTION)) != NULL)
3075 {
3076 cupsFilePrintf(fp, "*OpenUI *PageSize: PickOne\n"
3077 "*OrderDependency: 10 AnySetup *PageSize\n"
3078 "*DefaultPageSize: %s\n", ppdname);
3079 for (i = 0, count = ippGetCount(attr); i < count; i ++)
3080 {
3081 media_size = ippGetCollection(attr, i);
3082 x_dim = ippFindAttribute(media_size, "x-dimension", IPP_TAG_INTEGER);
3083 y_dim = ippFindAttribute(media_size, "y-dimension", IPP_TAG_INTEGER);
3084
3085 if (x_dim && y_dim)
3086 {
560634d3
MS
3087 char twidth[256], /* Width string */
3088 tlength[256]; /* Length string */
3089
d9fc71e4
MS
3090 pwg = pwgMediaForSize(ippGetInteger(x_dim, 0), ippGetInteger(y_dim, 0));
3091
560634d3
MS
3092 _cupsStrFormatd(twidth, twidth + sizeof(twidth), pwg->width * 72.0 / 2540.0, loc);
3093 _cupsStrFormatd(tlength, tlength + sizeof(tlength), pwg->length * 72.0 / 2540.0, loc);
3094
3095 cupsFilePrintf(fp, "*PageSize %s: \"<</PageSize[%s %s]>>setpagedevice\"\n", pwg->ppd, twidth, tlength);
d9fc71e4
MS
3096 }
3097 }
3098 cupsFilePuts(fp, "*CloseUI: *PageSize\n");
3099
3100 cupsFilePrintf(fp, "*OpenUI *PageRegion: PickOne\n"
3101 "*OrderDependency: 10 AnySetup *PageRegion\n"
3102 "*DefaultPageRegion: %s\n", ppdname);
3103 for (i = 0, count = ippGetCount(attr); i < count; i ++)
3104 {
3105 media_size = ippGetCollection(attr, i);
3106 x_dim = ippFindAttribute(media_size, "x-dimension", IPP_TAG_INTEGER);
3107 y_dim = ippFindAttribute(media_size, "y-dimension", IPP_TAG_INTEGER);
3108
3109 if (x_dim && y_dim)
3110 {
560634d3
MS
3111 char twidth[256], /* Width string */
3112 tlength[256]; /* Length string */
3113
d9fc71e4
MS
3114 pwg = pwgMediaForSize(ippGetInteger(x_dim, 0), ippGetInteger(y_dim, 0));
3115
560634d3
MS
3116 _cupsStrFormatd(twidth, twidth + sizeof(twidth), pwg->width * 72.0 / 2540.0, loc);
3117 _cupsStrFormatd(tlength, tlength + sizeof(tlength), pwg->length * 72.0 / 2540.0, loc);
3118
d1db56d4 3119 cupsFilePrintf(fp, "*PageRegion %s: \"<</PageSize[%s %s]>>setpagedevice\"\n", pwg->ppd, twidth, tlength);
d9fc71e4
MS
3120 }
3121 }
3122 cupsFilePuts(fp, "*CloseUI: *PageRegion\n");
3123
3124 cupsFilePrintf(fp, "*DefaultImageableArea: %s\n"
3125 "*DefaultPaperDimension: %s\n", ppdname, ppdname);
3126 for (i = 0, count = ippGetCount(attr); i < count; i ++)
3127 {
3128 media_size = ippGetCollection(attr, i);
3129 x_dim = ippFindAttribute(media_size, "x-dimension", IPP_TAG_INTEGER);
3130 y_dim = ippFindAttribute(media_size, "y-dimension", IPP_TAG_INTEGER);
3131
3132 if (x_dim && y_dim)
3133 {
560634d3
MS
3134 char tleft[256], /* Left string */
3135 tbottom[256], /* Bottom string */
3136 tright[256], /* Right string */
3137 ttop[256], /* Top string */
3138 twidth[256], /* Width string */
3139 tlength[256]; /* Length string */
3140
d9fc71e4
MS
3141 pwg = pwgMediaForSize(ippGetInteger(x_dim, 0), ippGetInteger(y_dim, 0));
3142
560634d3
MS
3143 _cupsStrFormatd(tleft, tleft + sizeof(tleft), left * 72.0 / 2540.0, loc);
3144 _cupsStrFormatd(tbottom, tbottom + sizeof(tbottom), bottom * 72.0 / 2540.0, loc);
3145 _cupsStrFormatd(tright, tright + sizeof(tright), (pwg->width - right) * 72.0 / 2540.0, loc);
3146 _cupsStrFormatd(ttop, ttop + sizeof(ttop), (pwg->length - top) * 72.0 / 2540.0, loc);
3147 _cupsStrFormatd(twidth, twidth + sizeof(twidth), pwg->width * 72.0 / 2540.0, loc);
3148 _cupsStrFormatd(tlength, tlength + sizeof(tlength), pwg->length * 72.0 / 2540.0, loc);
3149
3150 cupsFilePrintf(fp, "*ImageableArea %s: \"%s %s %s %s\"\n", pwg->ppd, tleft, tbottom, tright, ttop);
3151 cupsFilePrintf(fp, "*PaperDimension %s: \"%s %s\"\n", pwg->ppd, twidth, tlength);
d9fc71e4
MS
3152 }
3153 }
3154 }
3155
3156 /*
3157 * InputSlot...
3158 */
3159
3160 if ((attr = ippFindAttribute(ippGetCollection(defattr, 0), "media-source", IPP_TAG_KEYWORD)) != NULL)
3161 pwg_ppdize_name(ippGetString(attr, 0, NULL), ppdname, sizeof(ppdname));
3162 else
3163 strlcpy(ppdname, "Unknown", sizeof(ppdname));
3164
3165 if ((attr = ippFindAttribute(response, "media-source-supported", IPP_TAG_KEYWORD)) != NULL && (count = ippGetCount(attr)) > 1)
3166 {
3167 static const char * const sources[][2] =
3168 {
3169 { "Auto", "Automatic" },
3170 { "Main", "Main" },
3171 { "Alternate", "Alternate" },
3172 { "LargeCapacity", "Large Capacity" },
3173 { "Manual", "Manual" },
3174 { "Envelope", "Envelope" },
3175 { "Disc", "Disc" },
3176 { "Photo", "Photo" },
3177 { "Hagaki", "Hagaki" },
3178 { "MainRoll", "Main Roll" },
3179 { "AlternateRoll", "Alternate Roll" },
3180 { "Top", "Top" },
3181 { "Middle", "Middle" },
3182 { "Bottom", "Bottom" },
3183 { "Side", "Side" },
3184 { "Left", "Left" },
3185 { "Right", "Right" },
3186 { "Center", "Center" },
3187 { "Rear", "Rear" },
3188 { "ByPassTray", "Multipurpose" },
3189 { "Tray1", "Tray 1" },
3190 { "Tray2", "Tray 2" },
3191 { "Tray3", "Tray 3" },
3192 { "Tray4", "Tray 4" },
3193 { "Tray5", "Tray 5" },
3194 { "Tray6", "Tray 6" },
3195 { "Tray7", "Tray 7" },
3196 { "Tray8", "Tray 8" },
3197 { "Tray9", "Tray 9" },
3198 { "Tray10", "Tray 10" },
3199 { "Tray11", "Tray 11" },
3200 { "Tray12", "Tray 12" },
3201 { "Tray13", "Tray 13" },
3202 { "Tray14", "Tray 14" },
3203 { "Tray15", "Tray 15" },
3204 { "Tray16", "Tray 16" },
3205 { "Tray17", "Tray 17" },
3206 { "Tray18", "Tray 18" },
3207 { "Tray19", "Tray 19" },
3208 { "Tray20", "Tray 20" },
3209 { "Roll1", "Roll 1" },
3210 { "Roll2", "Roll 2" },
3211 { "Roll3", "Roll 3" },
3212 { "Roll4", "Roll 4" },
3213 { "Roll5", "Roll 5" },
3214 { "Roll6", "Roll 6" },
3215 { "Roll7", "Roll 7" },
3216 { "Roll8", "Roll 8" },
3217 { "Roll9", "Roll 9" },
3218 { "Roll10", "Roll 10" }
3219 };
3220
3221 cupsFilePrintf(fp, "*OpenUI *InputSlot: PickOne\n"
3222 "*OrderDependency: 10 AnySetup *InputSlot\n"
3223 "*DefaultInputSlot: %s\n", ppdname);
3224 for (i = 0, count = ippGetCount(attr); i < count; i ++)
3225 {
3226 pwg_ppdize_name(ippGetString(attr, i, NULL), ppdname, sizeof(ppdname));
3227
3228 for (j = 0; j < (int)(sizeof(sources) / sizeof(sources[0])); j ++)
3229 if (!strcmp(sources[j][0], ppdname))
3230 {
3231 cupsFilePrintf(fp, "*InputSlot %s/%s: \"<</MediaPosition %d>>setpagedevice\"\n", ppdname, sources[j][1], j);
3232 break;
3233 }
3234 }
3235 cupsFilePuts(fp, "*CloseUI: *InputSlot\n");
3236 }
3237
3238 /*
3239 * MediaType...
3240 */
3241
3242 if ((attr = ippFindAttribute(ippGetCollection(defattr, 0), "media-type", IPP_TAG_KEYWORD)) != NULL)
3243 pwg_ppdize_name(ippGetString(attr, 0, NULL), ppdname, sizeof(ppdname));
3244 else
3245 strlcpy(ppdname, "Unknown", sizeof(ppdname));
3246
3247 if ((attr = ippFindAttribute(response, "media-type-supported", IPP_TAG_KEYWORD)) != NULL && (count = ippGetCount(attr)) > 1)
3248 {
3249 static const char * const types[][2] =
3250 { /* Media type strings (far from complete) */
3251 { "Auto", "Automatic" },
3252 { "Cardstock", "Cardstock" },
3253 { "Disc", "CD/DVD/Bluray" },
3254 { "Envelope", "Envelope" },
3255 { "Labels", "Label" },
3256 { "Other", "Other" },
3257 { "Photographic", "Photo" },
3258 { "PhotographicGlossy", "Glossy Photo" },
3259 { "PhotographicHighGloss", "High-Gloss Photo" },
3260 { "PhotographicMatte", "Matte Photo" },
3261 { "PhotographicSatin", "Satin Photo" },
3262 { "PhotographicSemiGloss", "Semi-Gloss Photo" },
3263 { "Stationery", "Plain Paper" },
3264 { "StationeryLetterhead", "Letterhead" },
3265 { "Transparency", "Transparency" }
3266 };
3267
3268 cupsFilePrintf(fp, "*OpenUI *MediaType: PickOne\n"
3269 "*OrderDependency: 10 AnySetup *MediaType\n"
3270 "*DefaultMediaType: %s\n", ppdname);
3271 for (i = 0, count = ippGetCount(attr); i < count; i ++)
3272 {
3273 pwg_ppdize_name(ippGetString(attr, i, NULL), ppdname, sizeof(ppdname));
3274
3275 for (j = 0; j < (int)(sizeof(types) / sizeof(types[0])); j ++)
3276 if (!strcmp(types[j][0], ppdname))
3277 {
3278 cupsFilePrintf(fp, "*MediaType %s/%s: \"<</MediaType(%s)>>setpagedevice\"\n", ppdname, types[j][1], ppdname);
3279 break;
3280 }
3281
3282 if (j >= (int)(sizeof(types) / sizeof(types[0])))
3283 cupsFilePrintf(fp, "*MediaType %s: \"<</MediaType(%s)>>setpagedevice\"\n", ppdname, ppdname);
3284
3285 }
3286 cupsFilePuts(fp, "*CloseUI: *MediaType\n");
3287 }
3288
3289 /*
3290 * ColorModel...
3291 */
3292
3293 if ((attr = ippFindAttribute(response, "pwg-raster-document-type-supported", IPP_TAG_KEYWORD)) == NULL)
3294 attr = ippFindAttribute(response, "print-color-mode-supported", IPP_TAG_KEYWORD);
3295
3296 if (attr)
3297 {
3298 const char *default_color = NULL; /* Default */
3299
d9fc71e4
MS
3300 for (i = 0, count = ippGetCount(attr); i < count; i ++)
3301 {
3302 const char *keyword = ippGetString(attr, i, NULL);
3303 /* Keyword for color/bit depth */
3304
fb2d5470 3305 if (!strcmp(keyword, "black_1") || !strcmp(keyword, "bi-level") || !strcmp(keyword, "process-bi-level"))
d9fc71e4 3306 {
5e7464ec
MS
3307 if (!default_color)
3308 cupsFilePuts(fp, "*OpenUI *ColorModel/Color Mode: PickOne\n"
3309 "*OrderDependency: 10 AnySetup *ColorModel\n");
3310
d9fc71e4
MS
3311 cupsFilePuts(fp, "*ColorModel FastGray/Fast Grayscale: \"<</cupsColorSpace 3/cupsBitsPerColor 1/cupsColorOrder 0/cupsCompression 0>>setpagedevice\"\n");
3312
3313 if (!default_color)
3314 default_color = "FastGray";
3315 }
3316 else if (!strcmp(keyword, "sgray_8") || !strcmp(keyword, "monochrome") || !strcmp(keyword, "process-monochrome"))
3317 {
5e7464ec
MS
3318 if (!default_color)
3319 cupsFilePuts(fp, "*OpenUI *ColorModel/Color Mode: PickOne\n"
3320 "*OrderDependency: 10 AnySetup *ColorModel\n");
3321
d9fc71e4
MS
3322 cupsFilePuts(fp, "*ColorModel Gray/Grayscale: \"<</cupsColorSpace 18/cupsBitsPerColor 8/cupsColorOrder 0/cupsCompression 0>>setpagedevice\"\n");
3323
3324 if (!default_color || !strcmp(default_color, "FastGray"))
3325 default_color = "Gray";
3326 }
3327 else if (!strcmp(keyword, "srgb_8") || !strcmp(keyword, "color"))
3328 {
5e7464ec
MS
3329 if (!default_color)
3330 cupsFilePuts(fp, "*OpenUI *ColorModel/Color Mode: PickOne\n"
3331 "*OrderDependency: 10 AnySetup *ColorModel\n");
3332
d9fc71e4
MS
3333 cupsFilePuts(fp, "*ColorModel RGB/Color: \"<</cupsColorSpace 19/cupsBitsPerColor 8/cupsColorOrder 0/cupsCompression 0>>setpagedevice\"\n");
3334
3335 default_color = "RGB";
3336 }
3337 }
3338
3339 if (default_color)
5e7464ec 3340 {
d9fc71e4 3341 cupsFilePrintf(fp, "*DefaultColorModel: %s\n", default_color);
5e7464ec
MS
3342 cupsFilePuts(fp, "*CloseUI: *ColorModel\n");
3343 }
d9fc71e4
MS
3344 }
3345
3346 /*
3347 * Duplex...
3348 */
3349
3350 if ((attr = ippFindAttribute(response, "sides-supported", IPP_TAG_KEYWORD)) != NULL && ippContainsString(attr, "two-sided-long-edge"))
3351 {
3352 cupsFilePuts(fp, "*OpenUI *Duplex/2-Sided Printing: PickOne\n"
3353 "*OrderDependency: 10 AnySetup *Duplex\n"
3354 "*DefaultDuplex: None\n"
3355 "*Duplex None/Off (1-Sided): \"<</Duplex false>>setpagedevice\"\n"
3356 "*Duplex DuplexNoTumble/Long-Edge (Portrait): \"<</Duplex true/Tumble false>>setpagedevice\"\n"
3357 "*Duplex DuplexTumble/Short-Edge (Landscape): \"<</Duplex true/Tumble true>>setpagedevice\"\n"
3358 "*CloseUI: *Duplex\n");
3359
3360 if ((attr = ippFindAttribute(response, "pwg-raster-document-sheet-back", IPP_TAG_KEYWORD)) != NULL)
3361 {
3362 const char *keyword = ippGetString(attr, 0, NULL);
3363 /* Keyword value */
3364
3365 if (!strcmp(keyword, "flipped"))
3366 cupsFilePuts(fp, "*cupsBackSide: Flipped\n");
3367 else if (!strcmp(keyword, "manual-tumble"))
3368 cupsFilePuts(fp, "*cupsBackSide: ManualTumble\n");
3369 else if (!strcmp(keyword, "normal"))
3370 cupsFilePuts(fp, "*cupsBackSide: Normal\n");
3371 else
3372 cupsFilePuts(fp, "*cupsBackSide: Rotated\n");
3373 }
fb2d5470
MS
3374 else if ((attr = ippFindAttribute(response, "urf-supported", IPP_TAG_KEYWORD)) != NULL)
3375 {
3376 for (i = 0, count = ippGetCount(attr); i < count; i ++)
3377 {
3378 const char *dm = ippGetString(attr, i, NULL);
3379 /* DM value */
3380
3381 if (!_cups_strcasecmp(dm, "DM1"))
3382 {
3383 cupsFilePuts(fp, "*cupsBackSide: Normal\n");
3384 break;
3385 }
3386 else if (!_cups_strcasecmp(dm, "DM2"))
3387 {
3388 cupsFilePuts(fp, "*cupsBackSide: Flipped\n");
3389 break;
3390 }
3391 else if (!_cups_strcasecmp(dm, "DM3"))
3392 {
3393 cupsFilePuts(fp, "*cupsBackSide: Rotated\n");
3394 break;
3395 }
3396 else if (!_cups_strcasecmp(dm, "DM4"))
3397 {
3398 cupsFilePuts(fp, "*cupsBackSide: ManualTumble\n");
3399 break;
3400 }
3401 }
3402 }
d9fc71e4
MS
3403 }
3404
3405 /*
3406 * cupsPrintQuality and DefaultResolution...
3407 */
3408
3409 if ((attr = ippFindAttribute(response, "pwg-raster-document-resolution-supported", IPP_TAG_RESOLUTION)) != NULL)
3410 {
3411 count = ippGetCount(attr);
3412
3413 pwg_ppdize_resolution(attr, count / 2, &xres, &yres, ppdname, sizeof(ppdname));
3414 cupsFilePrintf(fp, "*DefaultResolution: %s\n", ppdname);
3415
3416 cupsFilePuts(fp, "*OpenUI *cupsPrintQuality/Print Quality: PickOne\n"
3417 "*OrderDependency: 10 AnySetup *cupsPrintQuality\n"
3418 "*DefaultcupsPrintQuality: Normal\n");
3419 if (count > 2)
3420 {
3421 pwg_ppdize_resolution(attr, 0, &xres, &yres, NULL, 0);
3422 cupsFilePrintf(fp, "*cupsPrintQuality Draft: \"<</HWResolution[%d %d]>>setpagedevice\"\n", xres, yres);
3423 }
3424 pwg_ppdize_resolution(attr, count / 2, &xres, &yres, NULL, 0);
3425 cupsFilePrintf(fp, "*cupsPrintQuality Normal: \"<</HWResolution[%d %d]>>setpagedevice\"\n", xres, yres);
3426 if (count > 1)
3427 {
3428 pwg_ppdize_resolution(attr, count - 1, &xres, &yres, NULL, 0);
3429 cupsFilePrintf(fp, "*cupsPrintQuality High: \"<</HWResolution[%d %d]>>setpagedevice\"\n", xres, yres);
3430 }
3431
3432 cupsFilePuts(fp, "*CloseUI: *cupsPrintQuality\n");
3433 }
fb2d5470
MS
3434 else if ((attr = ippFindAttribute(response, "urf-supported", IPP_TAG_KEYWORD)) != NULL)
3435 {
3436 int lowdpi = 0, hidpi = 0; /* Lower and higher resolution */
3437
3438 for (i = 0, count = ippGetCount(attr); i < count; i ++)
3439 {
3440 const char *rs = ippGetString(attr, i, NULL);
3441 /* RS value */
3442
3443 if (_cups_strncasecmp(rs, "RS", 2))
3444 continue;
3445
3446 lowdpi = atoi(rs + 2);
3447 if ((rs = strrchr(rs, '-')) != NULL)
3448 hidpi = atoi(rs + 1);
3449 else
3450 hidpi = lowdpi;
3451 break;
3452 }
3453
3454 if (lowdpi == 0)
3455 {
3456 /*
3457 * Invalid "urf-supported" value...
3458 */
3459
3460 cupsFilePuts(fp, "*DefaultResolution: 300dpi\n");
3461 }
3462 else
3463 {
3464 /*
3465 * Generate print qualities based on low and high DPIs...
3466 */
3467
3468 cupsFilePrintf(fp, "*DefaultResolution: %ddpi\n", lowdpi);
3469
3470 cupsFilePuts(fp, "*OpenUI *cupsPrintQuality/Print Quality: PickOne\n"
3471 "*OrderDependency: 10 AnySetup *cupsPrintQuality\n"
3472 "*DefaultcupsPrintQuality: Normal\n");
3473 if ((lowdpi & 1) == 0)
3474 cupsFilePrintf(fp, "*cupsPrintQuality Draft: \"<</HWResolution[%d %d]>>setpagedevice\"\n", lowdpi, lowdpi / 2);
3475 cupsFilePrintf(fp, "*cupsPrintQuality Normal: \"<</HWResolution[%d %d]>>setpagedevice\"\n", lowdpi, lowdpi);
3476 if (hidpi > lowdpi)
3477 cupsFilePrintf(fp, "*cupsPrintQuality High: \"<</HWResolution[%d %d]>>setpagedevice\"\n", hidpi, hidpi);
3478 cupsFilePuts(fp, "*CloseUI: *cupsPrintQuality\n");
3479 }
3480 }
d9fc71e4
MS
3481 else if ((attr = ippFindAttribute(response, "printer-resolution-default", IPP_TAG_RESOLUTION)) != NULL)
3482 {
3483 pwg_ppdize_resolution(attr, 0, &xres, &yres, ppdname, sizeof(ppdname));
3484 cupsFilePrintf(fp, "*DefaultResolution: %s\n", ppdname);
3485 }
3486 else
3487 cupsFilePuts(fp, "*DefaultResolution: 300dpi\n");
3488
3489 /*
3490 * Close up and return...
3491 */
3492
3493 cupsFileClose(fp);
3494
3495 return (buffer);
3496}
3497
3498
f14324a7
MS
3499/*
3500 * '_pwgInputSlotForSource()' - Get the InputSlot name for the given PWG
3501 * media-source.
3502 */
3503
3504const char * /* O - InputSlot name */
3505_pwgInputSlotForSource(
3506 const char *media_source, /* I - PWG media-source */
3507 char *name, /* I - Name buffer */
3508 size_t namesize) /* I - Size of name buffer */
3509{
3510 /*
3511 * Range check input...
3512 */
3513
3514 if (!media_source || !name || namesize < PPD_MAX_NAME)
3515 return (NULL);
3516
88f9aafc 3517 if (_cups_strcasecmp(media_source, "main"))
f14324a7 3518 strlcpy(name, "Cassette", namesize);
88f9aafc 3519 else if (_cups_strcasecmp(media_source, "alternate"))
f14324a7 3520 strlcpy(name, "Multipurpose", namesize);
88f9aafc 3521 else if (_cups_strcasecmp(media_source, "large-capacity"))
f14324a7 3522 strlcpy(name, "LargeCapacity", namesize);
88f9aafc 3523 else if (_cups_strcasecmp(media_source, "bottom"))
f14324a7 3524 strlcpy(name, "Lower", namesize);
88f9aafc 3525 else if (_cups_strcasecmp(media_source, "middle"))
f14324a7 3526 strlcpy(name, "Middle", namesize);
88f9aafc 3527 else if (_cups_strcasecmp(media_source, "top"))
f14324a7 3528 strlcpy(name, "Upper", namesize);
88f9aafc 3529 else if (_cups_strcasecmp(media_source, "rear"))
f14324a7 3530 strlcpy(name, "Rear", namesize);
88f9aafc 3531 else if (_cups_strcasecmp(media_source, "side"))
f14324a7 3532 strlcpy(name, "Side", namesize);
88f9aafc 3533 else if (_cups_strcasecmp(media_source, "envelope"))
f14324a7 3534 strlcpy(name, "Envelope", namesize);
88f9aafc 3535 else if (_cups_strcasecmp(media_source, "main-roll"))
f14324a7 3536 strlcpy(name, "Roll", namesize);
88f9aafc 3537 else if (_cups_strcasecmp(media_source, "alternate-roll"))
f14324a7
MS
3538 strlcpy(name, "Roll2", namesize);
3539 else
3540 pwg_ppdize_name(media_source, name, namesize);
3541
3542 return (name);
3543}
3544
3545
3546/*
3547 * '_pwgMediaTypeForType()' - Get the MediaType name for the given PWG
3548 * media-type.
3549 */
3550
3551const char * /* O - MediaType name */
3552_pwgMediaTypeForType(
3553 const char *media_type, /* I - PWG media-type */
3554 char *name, /* I - Name buffer */
3555 size_t namesize) /* I - Size of name buffer */
3556{
3557 /*
3558 * Range check input...
3559 */
3560
3561 if (!media_type || !name || namesize < PPD_MAX_NAME)
3562 return (NULL);
3563
88f9aafc 3564 if (_cups_strcasecmp(media_type, "auto"))
f14324a7 3565 strlcpy(name, "Auto", namesize);
88f9aafc 3566 else if (_cups_strcasecmp(media_type, "cardstock"))
f14324a7 3567 strlcpy(name, "Cardstock", namesize);
88f9aafc 3568 else if (_cups_strcasecmp(media_type, "envelope"))
f14324a7 3569 strlcpy(name, "Envelope", namesize);
88f9aafc 3570 else if (_cups_strcasecmp(media_type, "photographic-glossy"))
f14324a7 3571 strlcpy(name, "Glossy", namesize);
88f9aafc 3572 else if (_cups_strcasecmp(media_type, "photographic-high-gloss"))
f14324a7 3573 strlcpy(name, "HighGloss", namesize);
88f9aafc 3574 else if (_cups_strcasecmp(media_type, "photographic-matte"))
f14324a7 3575 strlcpy(name, "Matte", namesize);
88f9aafc 3576 else if (_cups_strcasecmp(media_type, "stationery"))
f14324a7 3577 strlcpy(name, "Plain", namesize);
88f9aafc 3578 else if (_cups_strcasecmp(media_type, "stationery-coated"))
f14324a7 3579 strlcpy(name, "Coated", namesize);
88f9aafc 3580 else if (_cups_strcasecmp(media_type, "stationery-inkjet"))
f14324a7 3581 strlcpy(name, "Inkjet", namesize);
88f9aafc 3582 else if (_cups_strcasecmp(media_type, "stationery-letterhead"))
f14324a7 3583 strlcpy(name, "Letterhead", namesize);
88f9aafc 3584 else if (_cups_strcasecmp(media_type, "stationery-preprinted"))
f14324a7 3585 strlcpy(name, "Preprinted", namesize);
88f9aafc 3586 else if (_cups_strcasecmp(media_type, "transparency"))
f14324a7
MS
3587 strlcpy(name, "Transparency", namesize);
3588 else
3589 pwg_ppdize_name(media_type, name, namesize);
3590
3591 return (name);
3592}
3593
3594
3595/*
3596 * '_pwgPageSizeForMedia()' - Get the PageSize name for the given media.
3597 */
3598
3599const char * /* O - PageSize name */
3600_pwgPageSizeForMedia(
6961465f 3601 pwg_media_t *media, /* I - Media */
f14324a7
MS
3602 char *name, /* I - PageSize name buffer */
3603 size_t namesize) /* I - Size of name buffer */
3604{
3605 const char *sizeptr, /* Pointer to size in PWG name */
3606 *dimptr; /* Pointer to dimensions in PWG name */
3607
3608
3609 /*
3610 * Range check input...
3611 */
3612
3613 if (!media || !name || namesize < PPD_MAX_NAME)
3614 return (NULL);
3615
3616 /*
3617 * Copy or generate a PageSize name...
3618 */
3619
3620 if (media->ppd)
3621 {
3622 /*
3623 * Use a standard Adobe name...
3624 */
3625
3626 strlcpy(name, media->ppd, namesize);
3627 }
3628 else if (!media->pwg || !strncmp(media->pwg, "custom_", 7) ||
3629 (sizeptr = strchr(media->pwg, '_')) == NULL ||
3630 (dimptr = strchr(sizeptr + 1, '_')) == NULL ||
3631 (size_t)(dimptr - sizeptr) > namesize)
3632 {
3633 /*
3634 * Use a name of the form "wNNNhNNN"...
3635 */
3636
6961465f
MS
3637 snprintf(name, namesize, "w%dh%d", (int)PWG_TO_POINTS(media->width),
3638 (int)PWG_TO_POINTS(media->length));
f14324a7
MS
3639 }
3640 else
3641 {
3642 /*
3643 * Copy the size name from class_sizename_dimensions...
3644 */
3645
07623986 3646 memcpy(name, sizeptr + 1, (size_t)(dimptr - sizeptr - 1));
f14324a7
MS
3647 name[dimptr - sizeptr - 1] = '\0';
3648 }
3649
3650 return (name);
3651}
3652
3653
dcb445bc
MS
3654/*
3655 * 'pwg_compare_finishings()' - Compare two finishings values.
3656 */
3657
3658static int /* O- Result of comparison */
3659pwg_compare_finishings(
3660 _pwg_finishings_t *a, /* I - First finishings value */
3661 _pwg_finishings_t *b) /* I - Second finishings value */
3662{
7d5824d6 3663 return ((int)b->value - (int)a->value);
dcb445bc
MS
3664}
3665
3666
3667/*
3668 * 'pwg_free_finishings()' - Free a finishings value.
3669 */
3670
3671static void
3672pwg_free_finishings(
3673 _pwg_finishings_t *f) /* I - Finishings value */
3674{
3675 cupsFreeOptions(f->num_options, f->options);
3676 free(f);
3677}
3678
3679
5a08320a
MS
3680/*
3681 * 'pwg_free_material()' - Free a material value.
3682 */
3683
3684static void
3685pwg_free_material(_pwg_material_t *m) /* I - Material value */
3686{
3687 _cupsStrFree(m->key);
3688 _cupsStrFree(m->name);
3689
3690 cupsFreeOptions(m->num_props, m->props);
3691
3692 free(m);
3693}
3694
3695
f14324a7
MS
3696/*
3697 * 'pwg_ppdize_name()' - Convert an IPP keyword to a PPD keyword.
3698 */
3699
3700static void
3701pwg_ppdize_name(const char *ipp, /* I - IPP keyword */
3702 char *name, /* I - Name buffer */
3703 size_t namesize) /* I - Size of name buffer */
3704{
3705 char *ptr, /* Pointer into name buffer */
3706 *end; /* End of name buffer */
3707
3708
7e86f2f6 3709 *name = (char)toupper(*ipp++);
f14324a7
MS
3710
3711 for (ptr = name + 1, end = name + namesize - 1; *ipp && ptr < end;)
3712 {
3713 if (*ipp == '-' && _cups_isalpha(ipp[1]))
3714 {
3715 ipp ++;
7e86f2f6 3716 *ptr++ = (char)toupper(*ipp++ & 255);
f14324a7
MS
3717 }
3718 else
3719 *ptr++ = *ipp++;
3720 }
3721
3722 *ptr = '\0';
3723}
3724
3725
d9fc71e4
MS
3726/*
3727 * 'pwg_ppdize_resolution()' - Convert PWG resolution values to PPD values.
3728 */
3729
3730static void
3731pwg_ppdize_resolution(
3732 ipp_attribute_t *attr, /* I - Attribute to convert */
3733 int element, /* I - Element to convert */
3734 int *xres, /* O - X resolution in DPI */
3735 int *yres, /* O - Y resolution in DPI */
3736 char *name, /* I - Name buffer */
3737 size_t namesize) /* I - Size of name buffer */
3738{
3739 ipp_res_t units; /* Units for resolution */
3740
3741
3742 *xres = ippGetResolution(attr, element, yres, &units);
3743
3744 if (units == IPP_RES_PER_CM)
3745 {
3746 *xres = (int)(*xres * 2.54);
3747 *yres = (int)(*yres * 2.54);
3748 }
3749
3750 if (name && namesize > 4)
3751 {
3752 if (*xres == *yres)
3753 snprintf(name, namesize, "%ddpi", *xres);
3754 else
3755 snprintf(name, namesize, "%dx%ddpi", *xres, *yres);
3756 }
3757}
3758
3759
f14324a7
MS
3760/*
3761 * 'pwg_unppdize_name()' - Convert a PPD keyword to a lowercase IPP keyword.
3762 */
3763
3764static void
3765pwg_unppdize_name(const char *ppd, /* I - PPD keyword */
3766 char *name, /* I - Name buffer */
c1420c87
MS
3767 size_t namesize, /* I - Size of name buffer */
3768 const char *dashchars)/* I - Characters to be replaced by dashes */
f14324a7
MS
3769{
3770 char *ptr, /* Pointer into name buffer */
3771 *end; /* End of name buffer */
3772
3773
79d7d84a
MS
3774 if (_cups_islower(*ppd))
3775 {
3776 /*
3777 * Already lowercase name, use as-is?
3778 */
3779
3780 const char *ppdptr; /* Pointer into PPD keyword */
3781
3782 for (ppdptr = ppd + 1; *ppdptr; ppdptr ++)
3783 if (_cups_isupper(*ppdptr) || strchr(dashchars, *ppdptr))
3784 break;
3785
3786 if (!*ppdptr)
3787 {
3788 strlcpy(name, ppd, namesize);
3789 return;
3790 }
3791 }
3792
f14324a7
MS
3793 for (ptr = name, end = name + namesize - 1; *ppd && ptr < end; ppd ++)
3794 {
3795 if (_cups_isalnum(*ppd) || *ppd == '-')
7e86f2f6 3796 *ptr++ = (char)tolower(*ppd & 255);
c1420c87 3797 else if (strchr(dashchars, *ppd))
f14324a7 3798 *ptr++ = '-';
c1420c87
MS
3799 else
3800 *ptr++ = *ppd;
f14324a7
MS
3801
3802 if (!_cups_isupper(*ppd) && _cups_isalnum(*ppd) &&
3803 _cups_isupper(ppd[1]) && ptr < end)
3804 *ptr++ = '-';
d489df6a
MS
3805 else if (!isdigit(*ppd & 255) && isdigit(ppd[1] & 255))
3806 *ptr++ = '-';
f14324a7
MS
3807 }
3808
3809 *ptr = '\0';
3810}
3811
3812
3813/*
3814 * End of "$Id$".
3815 */