]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/ppd-cache.c
Fix Linux compiler warning.
[thirdparty/cups.git] / cups / ppd-cache.c
CommitLineData
f14324a7 1/*
7e86f2f6 2 * PPD cache implementation for CUPS.
f14324a7 3 *
149eecf6 4 * Copyright 2010-2017 by Apple Inc.
f14324a7 5 *
e3101897 6 * Licensed under Apache License v2.0. See the file "LICENSE" for more information.
f14324a7
MS
7 */
8
9/*
10 * Include necessary headers...
11 */
12
13#include "cups-private.h"
f787e1e3 14#include "ppd-private.h"
f14324a7
MS
15#include <math.h>
16
17
18/*
19 * Macro to test for two almost-equal PWG measurements.
20 */
21
22#define _PWG_EQUIVALENT(x, y) (abs((x)-(y)) < 2)
23
24
25/*
26 * Local functions...
27 */
28
89550f3f 29static int cups_get_url(http_t **http, const char *url, char *name, size_t namesize);
1fbd0cab 30static void pwg_add_finishing(cups_array_t *finishings, ipp_finishings_t template, const char *name, const char *value);
982be458
MS
31static int pwg_compare_finishings(_pwg_finishings_t *a, _pwg_finishings_t *b);
32static int pwg_compare_sizes(cups_size_t *a, cups_size_t *b);
33static cups_size_t *pwg_copy_size(cups_size_t *size);
dcb445bc 34static void pwg_free_finishings(_pwg_finishings_t *f);
f14324a7 35static void pwg_ppdize_name(const char *ipp, char *name, size_t namesize);
d9fc71e4 36static void pwg_ppdize_resolution(ipp_attribute_t *attr, int element, int *xres, int *yres, char *name, size_t namesize);
c1420c87
MS
37static void pwg_unppdize_name(const char *ppd, char *name, size_t namesize,
38 const char *dashchars);
f14324a7
MS
39
40
f099325e
MS
41/*
42 * '_cupsConvertOptions()' - Convert printer options to standard IPP attributes.
43 *
44 * This functions converts PPD and CUPS-specific options to their standard IPP
45 * attributes and values and adds them to the specified IPP request.
46 */
47
a740a849
MS
48int /* O - New number of copies */
49_cupsConvertOptions(
50 ipp_t *request, /* I - IPP request */
51 ppd_file_t *ppd, /* I - PPD file */
52 _ppd_cache_t *pc, /* I - PPD cache info */
53 ipp_attribute_t *media_col_sup, /* I - media-col-supported values */
54 ipp_attribute_t *doc_handling_sup, /* I - multiple-document-handling-supported values */
55 ipp_attribute_t *print_color_mode_sup,
56 /* I - Printer supports print-color-mode */
57 const char *user, /* I - User info */
58 const char *format, /* I - document-format value */
59 int copies, /* I - Number of copies */
60 int num_options, /* I - Number of options */
61 cups_option_t *options) /* I - Options */
f099325e
MS
62{
63 int i; /* Looping var */
5ae9fbb3
MS
64 const char *keyword, /* PWG keyword */
65 *password; /* Password string */
f099325e
MS
66 pwg_size_t *size; /* PWG media size */
67 ipp_t *media_col, /* media-col value */
68 *media_size; /* media-size value */
69 const char *media_source, /* media-source value */
70 *media_type, /* media-type value */
71 *collate_str, /* multiple-document-handling value */
72 *color_attr_name, /* Supported color attribute */
4f63d6cd
MS
73 *mandatory, /* Mandatory attributes */
74 *finishing_template; /* Finishing template */
f099325e
MS
75 int num_finishings = 0, /* Number of finishing values */
76 finishings[10]; /* Finishing enum values */
77 ppd_choice_t *choice; /* Marked choice */
49f495c3
MS
78 int finishings_copies = copies;
79 /* Number of copies for finishings */
f099325e
MS
80
81
82 /*
83 * Send standard IPP attributes...
84 */
85
5ae9fbb3 86 if (pc->password && (password = cupsGetOption("job-password", num_options, options)) != NULL && ippGetOperation(request) != IPP_OP_VALIDATE_JOB)
f099325e 87 {
5ae9fbb3 88 ipp_attribute_t *attr = NULL; /* job-password attribute */
f099325e
MS
89
90 if ((keyword = cupsGetOption("job-password-encryption", num_options, options)) == NULL)
91 keyword = "none";
92
5ae9fbb3
MS
93 if (!strcmp(keyword, "none"))
94 {
95 /*
96 * Add plain-text job-password...
97 */
98
99 attr = ippAddOctetString(request, IPP_TAG_OPERATION, "job-password", password, (int)strlen(password));
100 }
101 else
102 {
103 /*
104 * Add hashed job-password...
105 */
106
107 unsigned char hash[64]; /* Hash of password */
108 ssize_t hashlen; /* Length of hash */
109
110 if ((hashlen = cupsHashData(keyword, password, strlen(password), hash, sizeof(hash))) > 0)
111 attr = ippAddOctetString(request, IPP_TAG_OPERATION, "job-password", hash, (int)hashlen);
112 }
113
114 if (attr)
115 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "job-password-encryption", NULL, keyword);
f099325e
MS
116 }
117
118 if (pc->account_id)
119 {
120 if ((keyword = cupsGetOption("job-account-id", num_options, options)) == NULL)
121 keyword = cupsGetOption("job-billing", num_options, options);
122
123 if (keyword)
124 ippAddString(request, IPP_TAG_JOB, IPP_TAG_NAME, "job-account-id", NULL, keyword);
125 }
126
127 if (pc->accounting_user_id)
128 {
129 if ((keyword = cupsGetOption("job-accounting-user-id", num_options, options)) == NULL)
130 keyword = user;
131
132 if (keyword)
133 ippAddString(request, IPP_TAG_JOB, IPP_TAG_NAME, "job-accounting-user-id", NULL, keyword);
134 }
135
136 for (mandatory = (const char *)cupsArrayFirst(pc->mandatory); mandatory; mandatory = (const char *)cupsArrayNext(pc->mandatory))
137 {
138 if (strcmp(mandatory, "copies") &&
139 strcmp(mandatory, "destination-uris") &&
140 strcmp(mandatory, "finishings") &&
4f63d6cd
MS
141 strcmp(mandatory, "finishings-col") &&
142 strcmp(mandatory, "finishing-template") &&
f099325e
MS
143 strcmp(mandatory, "job-account-id") &&
144 strcmp(mandatory, "job-accounting-user-id") &&
145 strcmp(mandatory, "job-password") &&
146 strcmp(mandatory, "job-password-encryption") &&
147 strcmp(mandatory, "media") &&
148 strncmp(mandatory, "media-col", 9) &&
149 strcmp(mandatory, "multiple-document-handling") &&
150 strcmp(mandatory, "output-bin") &&
151 strcmp(mandatory, "print-color-mode") &&
152 strcmp(mandatory, "print-quality") &&
153 strcmp(mandatory, "sides") &&
154 (keyword = cupsGetOption(mandatory, num_options, options)) != NULL)
155 {
156 _ipp_option_t *opt = _ippFindOption(mandatory);
157 /* Option type */
158 ipp_tag_t value_tag = opt ? opt->value_tag : IPP_TAG_NAME;
159 /* Value type */
160
161 switch (value_tag)
162 {
163 case IPP_TAG_INTEGER :
164 case IPP_TAG_ENUM :
165 ippAddInteger(request, IPP_TAG_JOB, value_tag, mandatory, atoi(keyword));
166 break;
167 case IPP_TAG_BOOLEAN :
168 ippAddBoolean(request, IPP_TAG_JOB, mandatory, !_cups_strcasecmp(keyword, "true"));
169 break;
170 case IPP_TAG_RANGE :
171 {
172 int lower, upper; /* Range */
173
174 if (sscanf(keyword, "%d-%d", &lower, &upper) != 2)
175 lower = upper = atoi(keyword);
176
177 ippAddRange(request, IPP_TAG_JOB, mandatory, lower, upper);
178 }
179 break;
180 case IPP_TAG_STRING :
181 ippAddOctetString(request, IPP_TAG_JOB, mandatory, keyword, (int)strlen(keyword));
182 break;
183 default :
184 if (!strcmp(mandatory, "print-color-mode") && !strcmp(keyword, "monochrome"))
185 {
186 if (ippContainsString(print_color_mode_sup, "auto-monochrome"))
187 keyword = "auto-monochrome";
188 else if (ippContainsString(print_color_mode_sup, "process-monochrome") && !ippContainsString(print_color_mode_sup, "monochrome"))
189 keyword = "process-monochrome";
190 }
191
192 ippAddString(request, IPP_TAG_JOB, value_tag, mandatory, NULL, keyword);
193 break;
194 }
195 }
196 }
197
198 if ((keyword = cupsGetOption("PageSize", num_options, options)) == NULL)
199 keyword = cupsGetOption("media", num_options, options);
200
40c80860
MS
201 media_source = _ppdCacheGetSource(pc, cupsGetOption("InputSlot", num_options, options));
202 media_type = _ppdCacheGetType(pc, cupsGetOption("MediaType", num_options, options));
203 size = _ppdCacheGetSize(pc, keyword);
204
205 if (size || media_source || media_type)
f099325e
MS
206 {
207 /*
208 * Add a media-col value...
209 */
210
f099325e 211 media_col = ippNew();
f099325e 212
40c80860
MS
213 if (size)
214 {
215 media_size = ippNew();
216 ippAddInteger(media_size, IPP_TAG_ZERO, IPP_TAG_INTEGER,
217 "x-dimension", size->width);
218 ippAddInteger(media_size, IPP_TAG_ZERO, IPP_TAG_INTEGER,
219 "y-dimension", size->length);
220
221 ippAddCollection(media_col, IPP_TAG_ZERO, "media-size", media_size);
222 }
f099325e
MS
223
224 for (i = 0; i < media_col_sup->num_values; i ++)
225 {
40c80860 226 if (size && !strcmp(media_col_sup->values[i].string.text, "media-left-margin"))
f099325e 227 ippAddInteger(media_col, IPP_TAG_ZERO, IPP_TAG_INTEGER, "media-left-margin", size->left);
40c80860 228 else if (size && !strcmp(media_col_sup->values[i].string.text, "media-bottom-margin"))
f099325e 229 ippAddInteger(media_col, IPP_TAG_ZERO, IPP_TAG_INTEGER, "media-bottom-margin", size->bottom);
40c80860 230 else if (size && !strcmp(media_col_sup->values[i].string.text, "media-right-margin"))
f099325e 231 ippAddInteger(media_col, IPP_TAG_ZERO, IPP_TAG_INTEGER, "media-right-margin", size->right);
40c80860 232 else if (size && !strcmp(media_col_sup->values[i].string.text, "media-top-margin"))
f099325e 233 ippAddInteger(media_col, IPP_TAG_ZERO, IPP_TAG_INTEGER, "media-top-margin", size->top);
40c80860 234 else if (media_source && !strcmp(media_col_sup->values[i].string.text, "media-source"))
f099325e 235 ippAddString(media_col, IPP_TAG_ZERO, IPP_TAG_KEYWORD, "media-source", NULL, media_source);
40c80860 236 else if (media_type && !strcmp(media_col_sup->values[i].string.text, "media-type"))
f099325e
MS
237 ippAddString(media_col, IPP_TAG_ZERO, IPP_TAG_KEYWORD, "media-type", NULL, media_type);
238 }
239
240 ippAddCollection(request, IPP_TAG_JOB, "media-col", media_col);
241 }
242
243 if ((keyword = cupsGetOption("output-bin", num_options, options)) == NULL)
244 {
245 if ((choice = ppdFindMarkedChoice(ppd, "OutputBin")) != NULL)
246 keyword = _ppdCacheGetBin(pc, choice->choice);
247 }
248
249 if (keyword)
250 ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "output-bin", NULL, keyword);
251
252 color_attr_name = print_color_mode_sup ? "print-color-mode" : "output-mode";
253
254 if ((keyword = cupsGetOption("print-color-mode", num_options, options)) == NULL)
255 {
256 if ((choice = ppdFindMarkedChoice(ppd, "ColorModel")) != NULL)
257 {
258 if (!_cups_strcasecmp(choice->choice, "Gray"))
259 keyword = "monochrome";
260 else
261 keyword = "color";
262 }
263 }
264
265 if (keyword && !strcmp(keyword, "monochrome"))
266 {
267 if (ippContainsString(print_color_mode_sup, "auto-monochrome"))
268 keyword = "auto-monochrome";
269 else if (ippContainsString(print_color_mode_sup, "process-monochrome") && !ippContainsString(print_color_mode_sup, "monochrome"))
270 keyword = "process-monochrome";
271 }
272
273 if (keyword)
274 ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, color_attr_name, NULL, keyword);
275
276 if ((keyword = cupsGetOption("print-quality", num_options, options)) != NULL)
277 ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_ENUM, "print-quality", atoi(keyword));
278 else if ((choice = ppdFindMarkedChoice(ppd, "cupsPrintQuality")) != NULL)
279 {
280 if (!_cups_strcasecmp(choice->choice, "draft"))
281 ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_ENUM, "print-quality", IPP_QUALITY_DRAFT);
282 else if (!_cups_strcasecmp(choice->choice, "normal"))
283 ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_ENUM, "print-quality", IPP_QUALITY_NORMAL);
284 else if (!_cups_strcasecmp(choice->choice, "high"))
285 ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_ENUM, "print-quality", IPP_QUALITY_HIGH);
286 }
287
288 if ((keyword = cupsGetOption("sides", num_options, options)) != NULL)
289 ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "sides", NULL, keyword);
290 else if (pc->sides_option && (choice = ppdFindMarkedChoice(ppd, pc->sides_option)) != NULL)
291 {
292 if (!_cups_strcasecmp(choice->choice, pc->sides_1sided))
293 ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "sides", NULL, "one-sided");
294 else if (!_cups_strcasecmp(choice->choice, pc->sides_2sided_long))
295 ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "sides", NULL, "two-sided-long-edge");
296 if (!_cups_strcasecmp(choice->choice, pc->sides_2sided_short))
297 ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "sides", NULL, "two-sided-short-edge");
298 }
299
300 /*
301 * Copies...
302 */
303
304 if ((keyword = cupsGetOption("multiple-document-handling", num_options, options)) != NULL)
305 {
306 if (strstr(keyword, "uncollated"))
307 keyword = "false";
308 else
309 keyword = "true";
310 }
311 else if ((keyword = cupsGetOption("collate", num_options, options)) == NULL)
312 keyword = "true";
313
314 if (format)
315 {
316 if (!_cups_strcasecmp(format, "image/gif") ||
317 !_cups_strcasecmp(format, "image/jp2") ||
318 !_cups_strcasecmp(format, "image/jpeg") ||
319 !_cups_strcasecmp(format, "image/png") ||
320 !_cups_strcasecmp(format, "image/tiff") ||
321 !_cups_strncasecmp(format, "image/x-", 8))
322 {
323 /*
324 * Collation makes no sense for single page image formats...
325 */
326
327 keyword = "false";
328 }
329 else if (!_cups_strncasecmp(format, "image/", 6) ||
330 !_cups_strcasecmp(format, "application/vnd.cups-raster"))
331 {
332 /*
333 * Multi-page image formats will have copies applied by the upstream
334 * filters...
335 */
336
337 copies = 1;
338 }
339 }
340
341 if (doc_handling_sup)
342 {
343 if (!_cups_strcasecmp(keyword, "true"))
344 collate_str = "separate-documents-collated-copies";
345 else
346 collate_str = "separate-documents-uncollated-copies";
347
348 for (i = 0; i < doc_handling_sup->num_values; i ++)
349 {
350 if (!strcmp(doc_handling_sup->values[i].string.text, collate_str))
351 {
352 ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "multiple-document-handling", NULL, collate_str);
353 break;
354 }
355 }
356
357 if (i >= doc_handling_sup->num_values)
358 copies = 1;
359 }
360
361 /*
362 * Map finishing options...
363 */
364
4f63d6cd
MS
365 if ((finishing_template = cupsGetOption("cupsFinishingTemplate", num_options, options)) == NULL)
366 finishing_template = cupsGetOption("finishing-template", num_options, options);
367
368 if (finishing_template)
f099325e 369 {
4f63d6cd
MS
370 ipp_t *fin_col = ippNew(); /* finishings-col value */
371
372 ippAddString(fin_col, IPP_TAG_JOB, IPP_TAG_KEYWORD, "finishing-template", NULL, finishing_template);
373 ippAddCollection(request, IPP_TAG_JOB, "finishings-col", fin_col);
374 ippDelete(fin_col);
f099325e 375
49f495c3 376 if (copies != finishings_copies && (keyword = cupsGetOption("job-impressions", num_options, options)) != NULL)
f099325e
MS
377 {
378 /*
379 * Send job-pages-per-set attribute to apply finishings correctly...
380 */
381
49f495c3 382 ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-pages-per-set", atoi(keyword) / finishings_copies);
f099325e
MS
383 }
384 }
4f63d6cd
MS
385 else
386 {
387 num_finishings = _ppdCacheGetFinishingValues(pc, num_options, options, (int)(sizeof(finishings) / sizeof(finishings[0])), finishings);
388 if (num_finishings > 0)
389 {
390 ippAddIntegers(request, IPP_TAG_JOB, IPP_TAG_ENUM, "finishings", num_finishings, finishings);
391
392 if (copies != finishings_copies && (keyword = cupsGetOption("job-impressions", num_options, options)) != NULL)
393 {
394 /*
395 * Send job-pages-per-set attribute to apply finishings correctly...
396 */
397
398 ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-pages-per-set", atoi(keyword) / finishings_copies);
399 }
400 }
401 }
f099325e
MS
402
403 return (copies);
404}
405
406
f14324a7
MS
407/*
408 * '_ppdCacheCreateWithFile()' - Create PPD cache and mapping data from a
409 * written file.
410 *
411 * Use the @link _ppdCacheWriteFile@ function to write PWG mapping data to a
412 * file.
413 */
414
415_ppd_cache_t * /* O - PPD cache and mapping data */
416_ppdCacheCreateWithFile(
417 const char *filename, /* I - File to read */
418 ipp_t **attrs) /* IO - IPP attributes, if any */
419{
420 cups_file_t *fp; /* File */
421 _ppd_cache_t *pc; /* PWG mapping data */
6961465f
MS
422 pwg_size_t *size; /* Current size */
423 pwg_map_t *map; /* Current map */
dcb445bc 424 _pwg_finishings_t *finishings; /* Current finishings option */
f14324a7
MS
425 int linenum, /* Current line number */
426 num_bins, /* Number of bins in file */
427 num_sizes, /* Number of sizes in file */
428 num_sources, /* Number of sources in file */
429 num_types; /* Number of types in file */
430 char line[2048], /* Current line */
431 *value, /* Pointer to value in line */
432 *valueptr, /* Pointer into value */
433 pwg_keyword[128], /* PWG keyword */
434 ppd_keyword[PPD_MAX_NAME];
435 /* PPD keyword */
436 _pwg_print_color_mode_t print_color_mode;
437 /* Print color mode for preset */
438 _pwg_print_quality_t print_quality; /* Print quality for preset */
439
440
441 DEBUG_printf(("_ppdCacheCreateWithFile(filename=\"%s\")", filename));
442
443 /*
444 * Range check input...
445 */
446
447 if (attrs)
448 *attrs = NULL;
449
450 if (!filename)
451 {
cb7f98ee 452 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
f14324a7
MS
453 return (NULL);
454 }
455
456 /*
457 * Open the file...
458 */
459
460 if ((fp = cupsFileOpen(filename, "r")) == NULL)
461 {
cb7f98ee 462 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
f14324a7
MS
463 return (NULL);
464 }
465
466 /*
467 * Read the first line and make sure it has "#CUPS-PPD-CACHE-version" in it...
468 */
469
470 if (!cupsFileGets(fp, line, sizeof(line)))
471 {
cb7f98ee 472 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
f14324a7
MS
473 DEBUG_puts("_ppdCacheCreateWithFile: Unable to read first line.");
474 cupsFileClose(fp);
475 return (NULL);
476 }
477
22c9029b 478 if (strncmp(line, "#CUPS-PPD-CACHE-", 16))
f14324a7 479 {
cb7f98ee 480 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
481 DEBUG_printf(("_ppdCacheCreateWithFile: Wrong first line \"%s\".", line));
482 cupsFileClose(fp);
483 return (NULL);
484 }
485
22c9029b
MS
486 if (atoi(line + 16) != _PPD_CACHE_VERSION)
487 {
cb7f98ee 488 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Out of date PPD cache file."), 1);
22c9029b
MS
489 DEBUG_printf(("_ppdCacheCreateWithFile: Cache file has version %s, "
490 "expected %d.", line + 16, _PPD_CACHE_VERSION));
491 cupsFileClose(fp);
492 return (NULL);
493 }
494
f14324a7
MS
495 /*
496 * Allocate the mapping data structure...
497 */
498
499 if ((pc = calloc(1, sizeof(_ppd_cache_t))) == NULL)
500 {
cb7f98ee 501 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
f14324a7
MS
502 DEBUG_puts("_ppdCacheCreateWithFile: Unable to allocate _ppd_cache_t.");
503 goto create_error;
504 }
505
3e7fe0ca
MS
506 pc->max_copies = 9999;
507
f14324a7
MS
508 /*
509 * Read the file...
510 */
511
512 linenum = 0;
513 num_bins = 0;
514 num_sizes = 0;
515 num_sources = 0;
516 num_types = 0;
517
518 while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
519 {
520 DEBUG_printf(("_ppdCacheCreateWithFile: line=\"%s\", value=\"%s\", "
521 "linenum=%d", line, value, linenum));
522
523 if (!value)
524 {
525 DEBUG_printf(("_ppdCacheCreateWithFile: Missing value on line %d.",
526 linenum));
cb7f98ee 527 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
528 goto create_error;
529 }
88f9aafc 530 else if (!_cups_strcasecmp(line, "Filter"))
f14324a7
MS
531 {
532 if (!pc->filters)
533 pc->filters = cupsArrayNew3(NULL, NULL, NULL, 0,
534 (cups_acopy_func_t)_cupsStrAlloc,
535 (cups_afree_func_t)_cupsStrFree);
536
537 cupsArrayAdd(pc->filters, value);
538 }
88f9aafc 539 else if (!_cups_strcasecmp(line, "PreFilter"))
f14324a7
MS
540 {
541 if (!pc->prefilters)
542 pc->prefilters = cupsArrayNew3(NULL, NULL, NULL, 0,
543 (cups_acopy_func_t)_cupsStrAlloc,
544 (cups_afree_func_t)_cupsStrFree);
545
546 cupsArrayAdd(pc->prefilters, value);
547 }
88f9aafc 548 else if (!_cups_strcasecmp(line, "Product"))
f14324a7
MS
549 {
550 pc->product = _cupsStrAlloc(value);
551 }
88f9aafc 552 else if (!_cups_strcasecmp(line, "SingleFile"))
82f97232 553 {
88f9aafc 554 pc->single_file = !_cups_strcasecmp(value, "true");
82f97232 555 }
88f9aafc 556 else if (!_cups_strcasecmp(line, "IPP"))
f14324a7
MS
557 {
558 off_t pos = cupsFileTell(fp), /* Position in file */
559 length = strtol(value, NULL, 10);
560 /* Length of IPP attributes */
561
562 if (attrs && *attrs)
563 {
564 DEBUG_puts("_ppdCacheCreateWithFile: IPP listed multiple times.");
cb7f98ee 565 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
566 goto create_error;
567 }
568 else if (length <= 0)
569 {
570 DEBUG_puts("_ppdCacheCreateWithFile: Bad IPP length.");
cb7f98ee 571 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
572 goto create_error;
573 }
574
575 if (attrs)
576 {
577 /*
578 * Read IPP attributes into the provided variable...
579 */
580
581 *attrs = ippNew();
582
583 if (ippReadIO(fp, (ipp_iocb_t)cupsFileRead, 1, NULL,
cb7f98ee 584 *attrs) != IPP_STATE_DATA)
f14324a7
MS
585 {
586 DEBUG_puts("_ppdCacheCreateWithFile: Bad IPP data.");
cb7f98ee 587 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
588 goto create_error;
589 }
590 }
591 else
592 {
593 /*
594 * Skip the IPP data entirely...
595 */
596
597 cupsFileSeek(fp, pos + length);
598 }
599
600 if (cupsFileTell(fp) != (pos + length))
601 {
602 DEBUG_puts("_ppdCacheCreateWithFile: Bad IPP data.");
cb7f98ee 603 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
604 goto create_error;
605 }
606 }
88f9aafc 607 else if (!_cups_strcasecmp(line, "NumBins"))
f14324a7
MS
608 {
609 if (num_bins > 0)
610 {
611 DEBUG_puts("_ppdCacheCreateWithFile: NumBins listed multiple times.");
cb7f98ee 612 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
613 goto create_error;
614 }
615
616 if ((num_bins = atoi(value)) <= 0 || num_bins > 65536)
617 {
618 DEBUG_printf(("_ppdCacheCreateWithFile: Bad NumBins value %d on line "
619 "%d.", num_sizes, linenum));
cb7f98ee 620 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
621 goto create_error;
622 }
623
7e86f2f6 624 if ((pc->bins = calloc((size_t)num_bins, sizeof(pwg_map_t))) == NULL)
f14324a7
MS
625 {
626 DEBUG_printf(("_ppdCacheCreateWithFile: Unable to allocate %d bins.",
627 num_sizes));
cb7f98ee 628 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
f14324a7
MS
629 goto create_error;
630 }
631 }
88f9aafc 632 else if (!_cups_strcasecmp(line, "Bin"))
f14324a7
MS
633 {
634 if (sscanf(value, "%127s%40s", pwg_keyword, ppd_keyword) != 2)
635 {
636 DEBUG_printf(("_ppdCacheCreateWithFile: Bad Bin on line %d.", linenum));
cb7f98ee 637 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
638 goto create_error;
639 }
640
641 if (pc->num_bins >= num_bins)
642 {
643 DEBUG_printf(("_ppdCacheCreateWithFile: Too many Bin's on line %d.",
644 linenum));
cb7f98ee 645 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
646 goto create_error;
647 }
648
649 map = pc->bins + pc->num_bins;
650 map->pwg = _cupsStrAlloc(pwg_keyword);
651 map->ppd = _cupsStrAlloc(ppd_keyword);
652
653 pc->num_bins ++;
654 }
88f9aafc 655 else if (!_cups_strcasecmp(line, "NumSizes"))
f14324a7
MS
656 {
657 if (num_sizes > 0)
658 {
659 DEBUG_puts("_ppdCacheCreateWithFile: NumSizes listed multiple times.");
cb7f98ee 660 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
661 goto create_error;
662 }
663
5a9febac 664 if ((num_sizes = atoi(value)) < 0 || num_sizes > 65536)
f14324a7
MS
665 {
666 DEBUG_printf(("_ppdCacheCreateWithFile: Bad NumSizes value %d on line "
667 "%d.", num_sizes, linenum));
cb7f98ee 668 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
669 goto create_error;
670 }
671
5a9febac 672 if (num_sizes > 0)
f14324a7 673 {
7e86f2f6 674 if ((pc->sizes = calloc((size_t)num_sizes, sizeof(pwg_size_t))) == NULL)
5a9febac
MS
675 {
676 DEBUG_printf(("_ppdCacheCreateWithFile: Unable to allocate %d sizes.",
677 num_sizes));
cb7f98ee 678 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
5a9febac
MS
679 goto create_error;
680 }
f14324a7
MS
681 }
682 }
88f9aafc 683 else if (!_cups_strcasecmp(line, "Size"))
f14324a7
MS
684 {
685 if (pc->num_sizes >= num_sizes)
686 {
687 DEBUG_printf(("_ppdCacheCreateWithFile: Too many Size's on line %d.",
688 linenum));
cb7f98ee 689 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
690 goto create_error;
691 }
692
693 size = pc->sizes + pc->num_sizes;
694
695 if (sscanf(value, "%127s%40s%d%d%d%d%d%d", pwg_keyword, ppd_keyword,
696 &(size->width), &(size->length), &(size->left),
697 &(size->bottom), &(size->right), &(size->top)) != 8)
698 {
699 DEBUG_printf(("_ppdCacheCreateWithFile: Bad Size on line %d.",
700 linenum));
cb7f98ee 701 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
702 goto create_error;
703 }
704
705 size->map.pwg = _cupsStrAlloc(pwg_keyword);
706 size->map.ppd = _cupsStrAlloc(ppd_keyword);
707
708 pc->num_sizes ++;
709 }
88f9aafc 710 else if (!_cups_strcasecmp(line, "CustomSize"))
f14324a7
MS
711 {
712 if (pc->custom_max_width > 0)
713 {
714 DEBUG_printf(("_ppdCacheCreateWithFile: Too many CustomSize's on line "
715 "%d.", linenum));
cb7f98ee 716 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
717 goto create_error;
718 }
719
720 if (sscanf(value, "%d%d%d%d%d%d%d%d", &(pc->custom_max_width),
721 &(pc->custom_max_length), &(pc->custom_min_width),
722 &(pc->custom_min_length), &(pc->custom_size.left),
723 &(pc->custom_size.bottom), &(pc->custom_size.right),
724 &(pc->custom_size.top)) != 8)
725 {
726 DEBUG_printf(("_ppdCacheCreateWithFile: Bad CustomSize on line %d.",
727 linenum));
cb7f98ee 728 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
729 goto create_error;
730 }
731
6961465f
MS
732 pwgFormatSizeName(pwg_keyword, sizeof(pwg_keyword), "custom", "max",
733 pc->custom_max_width, pc->custom_max_length, NULL);
f14324a7
MS
734 pc->custom_max_keyword = _cupsStrAlloc(pwg_keyword);
735
6961465f
MS
736 pwgFormatSizeName(pwg_keyword, sizeof(pwg_keyword), "custom", "min",
737 pc->custom_min_width, pc->custom_min_length, NULL);
f14324a7
MS
738 pc->custom_min_keyword = _cupsStrAlloc(pwg_keyword);
739 }
88f9aafc 740 else if (!_cups_strcasecmp(line, "SourceOption"))
f14324a7
MS
741 {
742 pc->source_option = _cupsStrAlloc(value);
743 }
88f9aafc 744 else if (!_cups_strcasecmp(line, "NumSources"))
f14324a7
MS
745 {
746 if (num_sources > 0)
747 {
748 DEBUG_puts("_ppdCacheCreateWithFile: NumSources listed multiple "
749 "times.");
cb7f98ee 750 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
751 goto create_error;
752 }
753
754 if ((num_sources = atoi(value)) <= 0 || num_sources > 65536)
755 {
756 DEBUG_printf(("_ppdCacheCreateWithFile: Bad NumSources value %d on "
757 "line %d.", num_sources, linenum));
cb7f98ee 758 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
759 goto create_error;
760 }
761
7e86f2f6 762 if ((pc->sources = calloc((size_t)num_sources, sizeof(pwg_map_t))) == NULL)
f14324a7
MS
763 {
764 DEBUG_printf(("_ppdCacheCreateWithFile: Unable to allocate %d sources.",
765 num_sources));
cb7f98ee 766 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
f14324a7
MS
767 goto create_error;
768 }
769 }
88f9aafc 770 else if (!_cups_strcasecmp(line, "Source"))
f14324a7
MS
771 {
772 if (sscanf(value, "%127s%40s", pwg_keyword, ppd_keyword) != 2)
773 {
774 DEBUG_printf(("_ppdCacheCreateWithFile: Bad Source on line %d.",
775 linenum));
cb7f98ee 776 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
777 goto create_error;
778 }
779
780 if (pc->num_sources >= num_sources)
781 {
782 DEBUG_printf(("_ppdCacheCreateWithFile: Too many Source's on line %d.",
783 linenum));
cb7f98ee 784 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
785 goto create_error;
786 }
787
788 map = pc->sources + pc->num_sources;
789 map->pwg = _cupsStrAlloc(pwg_keyword);
790 map->ppd = _cupsStrAlloc(ppd_keyword);
791
792 pc->num_sources ++;
793 }
88f9aafc 794 else if (!_cups_strcasecmp(line, "NumTypes"))
f14324a7
MS
795 {
796 if (num_types > 0)
797 {
798 DEBUG_puts("_ppdCacheCreateWithFile: NumTypes listed multiple times.");
cb7f98ee 799 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
800 goto create_error;
801 }
802
803 if ((num_types = atoi(value)) <= 0 || num_types > 65536)
804 {
805 DEBUG_printf(("_ppdCacheCreateWithFile: Bad NumTypes value %d on "
806 "line %d.", num_types, linenum));
cb7f98ee 807 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
808 goto create_error;
809 }
810
7e86f2f6 811 if ((pc->types = calloc((size_t)num_types, sizeof(pwg_map_t))) == NULL)
f14324a7
MS
812 {
813 DEBUG_printf(("_ppdCacheCreateWithFile: Unable to allocate %d types.",
814 num_types));
cb7f98ee 815 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
f14324a7
MS
816 goto create_error;
817 }
818 }
88f9aafc 819 else if (!_cups_strcasecmp(line, "Type"))
f14324a7
MS
820 {
821 if (sscanf(value, "%127s%40s", pwg_keyword, ppd_keyword) != 2)
822 {
823 DEBUG_printf(("_ppdCacheCreateWithFile: Bad Type on line %d.",
824 linenum));
cb7f98ee 825 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
826 goto create_error;
827 }
828
829 if (pc->num_types >= num_types)
830 {
831 DEBUG_printf(("_ppdCacheCreateWithFile: Too many Type's on line %d.",
832 linenum));
cb7f98ee 833 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
834 goto create_error;
835 }
836
837 map = pc->types + pc->num_types;
838 map->pwg = _cupsStrAlloc(pwg_keyword);
839 map->ppd = _cupsStrAlloc(ppd_keyword);
840
841 pc->num_types ++;
842 }
88f9aafc 843 else if (!_cups_strcasecmp(line, "Preset"))
f14324a7
MS
844 {
845 /*
846 * Preset output-mode print-quality name=value ...
847 */
848
849 print_color_mode = (_pwg_print_color_mode_t)strtol(value, &valueptr, 10);
850 print_quality = (_pwg_print_quality_t)strtol(valueptr, &valueptr, 10);
851
852 if (print_color_mode < _PWG_PRINT_COLOR_MODE_MONOCHROME ||
853 print_color_mode >= _PWG_PRINT_COLOR_MODE_MAX ||
854 print_quality < _PWG_PRINT_QUALITY_DRAFT ||
855 print_quality >= _PWG_PRINT_QUALITY_MAX ||
856 valueptr == value || !*valueptr)
857 {
858 DEBUG_printf(("_ppdCacheCreateWithFile: Bad Preset on line %d.",
859 linenum));
cb7f98ee 860 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
861 goto create_error;
862 }
863
864 pc->num_presets[print_color_mode][print_quality] =
865 cupsParseOptions(valueptr, 0,
866 pc->presets[print_color_mode] + print_quality);
867 }
88f9aafc 868 else if (!_cups_strcasecmp(line, "SidesOption"))
f14324a7 869 pc->sides_option = _cupsStrAlloc(value);
88f9aafc 870 else if (!_cups_strcasecmp(line, "Sides1Sided"))
f14324a7 871 pc->sides_1sided = _cupsStrAlloc(value);
88f9aafc 872 else if (!_cups_strcasecmp(line, "Sides2SidedLong"))
f14324a7 873 pc->sides_2sided_long = _cupsStrAlloc(value);
88f9aafc 874 else if (!_cups_strcasecmp(line, "Sides2SidedShort"))
f14324a7 875 pc->sides_2sided_short = _cupsStrAlloc(value);
dcb445bc
MS
876 else if (!_cups_strcasecmp(line, "Finishings"))
877 {
878 if (!pc->finishings)
879 pc->finishings =
880 cupsArrayNew3((cups_array_func_t)pwg_compare_finishings,
881 NULL, NULL, 0, NULL,
882 (cups_afree_func_t)pwg_free_finishings);
883
884 if ((finishings = calloc(1, sizeof(_pwg_finishings_t))) == NULL)
885 goto create_error;
886
7e86f2f6 887 finishings->value = (ipp_finishings_t)strtol(value, &valueptr, 10);
dcb445bc
MS
888 finishings->num_options = cupsParseOptions(valueptr, 0,
889 &(finishings->options));
890
891 cupsArrayAdd(pc->finishings, finishings);
892 }
4f63d6cd
MS
893 else if (!_cups_strcasecmp(line, "FinishingTemplate"))
894 {
895 if (!pc->templates)
896 pc->templates = cupsArrayNew3((cups_array_func_t)strcmp, NULL, NULL, 0, (cups_acopy_func_t)_cupsStrAlloc, (cups_afree_func_t)_cupsStrFree);
897
898 cupsArrayAdd(pc->templates, value);
899 }
3e7fe0ca
MS
900 else if (!_cups_strcasecmp(line, "MaxCopies"))
901 pc->max_copies = atoi(value);
a469f8a5
MS
902 else if (!_cups_strcasecmp(line, "ChargeInfoURI"))
903 pc->charge_info_uri = _cupsStrAlloc(value);
5a9febac
MS
904 else if (!_cups_strcasecmp(line, "JobAccountId"))
905 pc->account_id = !_cups_strcasecmp(value, "true");
906 else if (!_cups_strcasecmp(line, "JobAccountingUserId"))
907 pc->accounting_user_id = !_cups_strcasecmp(value, "true");
908 else if (!_cups_strcasecmp(line, "JobPassword"))
909 pc->password = _cupsStrAlloc(value);
910 else if (!_cups_strcasecmp(line, "Mandatory"))
911 {
912 if (pc->mandatory)
913 _cupsArrayAddStrings(pc->mandatory, value, ' ');
914 else
915 pc->mandatory = _cupsArrayNewStrings(value, ' ');
916 }
89550f3f
MS
917 else if (!_cups_strcasecmp(line, "StringsURI"))
918 pc->strings_uri = _cupsStrAlloc(value);
c1420c87
MS
919 else if (!_cups_strcasecmp(line, "SupportFile"))
920 {
921 if (!pc->support_files)
922 pc->support_files = cupsArrayNew3(NULL, NULL, NULL, 0,
923 (cups_acopy_func_t)_cupsStrAlloc,
924 (cups_afree_func_t)_cupsStrFree);
925
926 cupsArrayAdd(pc->support_files, value);
927 }
f14324a7
MS
928 else
929 {
930 DEBUG_printf(("_ppdCacheCreateWithFile: Unknown %s on line %d.", line,
931 linenum));
f14324a7
MS
932 }
933 }
934
935 if (pc->num_sizes < num_sizes)
936 {
937 DEBUG_printf(("_ppdCacheCreateWithFile: Not enough sizes (%d < %d).",
938 pc->num_sizes, num_sizes));
cb7f98ee 939 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
940 goto create_error;
941 }
942
943 if (pc->num_sources < num_sources)
944 {
945 DEBUG_printf(("_ppdCacheCreateWithFile: Not enough sources (%d < %d).",
946 pc->num_sources, num_sources));
cb7f98ee 947 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
948 goto create_error;
949 }
950
951 if (pc->num_types < num_types)
952 {
953 DEBUG_printf(("_ppdCacheCreateWithFile: Not enough types (%d < %d).",
954 pc->num_types, num_types));
cb7f98ee 955 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
f14324a7
MS
956 goto create_error;
957 }
958
959 cupsFileClose(fp);
960
961 return (pc);
962
963 /*
964 * If we get here the file was bad - free any data and return...
965 */
966
967 create_error:
968
969 cupsFileClose(fp);
970 _ppdCacheDestroy(pc);
971
972 if (attrs)
22c9029b 973 {
f14324a7 974 ippDelete(*attrs);
22c9029b
MS
975 *attrs = NULL;
976 }
f14324a7
MS
977
978 return (NULL);
979}
980
981
982/*
983 * '_ppdCacheCreateWithPPD()' - Create PWG mapping data from a PPD file.
984 */
985
986_ppd_cache_t * /* O - PPD cache and mapping data */
987_ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */
988{
989 int i, j, k; /* Looping vars */
990 _ppd_cache_t *pc; /* PWG mapping data */
991 ppd_option_t *input_slot, /* InputSlot option */
992 *media_type, /* MediaType option */
993 *output_bin, /* OutputBin option */
994 *color_model, /* ColorModel option */
4f63d6cd
MS
995 *duplex, /* Duplex option */
996 *ppd_option; /* Other PPD option */
f14324a7 997 ppd_choice_t *choice; /* Current InputSlot/MediaType */
6961465f 998 pwg_map_t *map; /* Current source/type map */
f14324a7
MS
999 ppd_attr_t *ppd_attr; /* Current PPD preset attribute */
1000 int num_options; /* Number of preset options and props */
1001 cups_option_t *options; /* Preset options and properties */
1002 ppd_size_t *ppd_size; /* Current PPD size */
6961465f 1003 pwg_size_t *pwg_size; /* Current PWG size */
f14324a7
MS
1004 char pwg_keyword[3 + PPD_MAX_NAME + 1 + 12 + 1 + 12 + 3],
1005 /* PWG keyword string */
1006 ppd_name[PPD_MAX_NAME];
1007 /* Normalized PPD name */
1008 const char *pwg_name; /* Standard PWG media name */
6961465f 1009 pwg_media_t *pwg_media; /* PWG media data */
f14324a7
MS
1010 _pwg_print_color_mode_t pwg_print_color_mode;
1011 /* print-color-mode index */
1012 _pwg_print_quality_t pwg_print_quality;
1013 /* print-quality index */
1014 int similar; /* Are the old and new size similar? */
6961465f 1015 pwg_size_t *old_size; /* Current old size */
f14324a7
MS
1016 int old_imageable, /* Old imageable length in 2540ths */
1017 old_borderless, /* Old borderless state */
1018 old_known_pwg; /* Old PWG name is well-known */
1019 int new_width, /* New width in 2540ths */
1020 new_length, /* New length in 2540ths */
1021 new_left, /* New left margin in 2540ths */
1022 new_bottom, /* New bottom margin in 2540ths */
1023 new_right, /* New right margin in 2540ths */
1024 new_top, /* New top margin in 2540ths */
1025 new_imageable, /* New imageable length in 2540ths */
1026 new_borderless, /* New borderless state */
1027 new_known_pwg; /* New PWG name is well-known */
6961465f 1028 pwg_size_t *new_size; /* New size to add, if any */
f14324a7 1029 const char *filter; /* Current filter */
dcb445bc 1030 _pwg_finishings_t *finishings; /* Current finishings value */
f14324a7
MS
1031
1032
1033 DEBUG_printf(("_ppdCacheCreateWithPPD(ppd=%p)", ppd));
1034
1035 /*
1036 * Range check input...
1037 */
1038
1039 if (!ppd)
1040 return (NULL);
1041
1042 /*
1043 * Allocate memory...
1044 */
1045
1046 if ((pc = calloc(1, sizeof(_ppd_cache_t))) == NULL)
1047 {
1048 DEBUG_puts("_ppdCacheCreateWithPPD: Unable to allocate _ppd_cache_t.");
1049 goto create_error;
1050 }
1051
1052 /*
1053 * Copy and convert size data...
1054 */
1055
5a9febac 1056 if (ppd->num_sizes > 0)
f14324a7 1057 {
7e86f2f6 1058 if ((pc->sizes = calloc((size_t)ppd->num_sizes, sizeof(pwg_size_t))) == NULL)
f14324a7 1059 {
5a9febac 1060 DEBUG_printf(("_ppdCacheCreateWithPPD: Unable to allocate %d "
6961465f 1061 "pwg_size_t's.", ppd->num_sizes));
5a9febac 1062 goto create_error;
f14324a7
MS
1063 }
1064
5a9febac
MS
1065 for (i = ppd->num_sizes, pwg_size = pc->sizes, ppd_size = ppd->sizes;
1066 i > 0;
1067 i --, ppd_size ++)
f14324a7
MS
1068 {
1069 /*
5a9febac 1070 * Don't copy over custom size...
f14324a7
MS
1071 */
1072
5a9febac
MS
1073 if (!_cups_strcasecmp(ppd_size->name, "Custom"))
1074 continue;
1075
f14324a7 1076 /*
5a9febac 1077 * Convert the PPD size name to the corresponding PWG keyword name.
f14324a7
MS
1078 */
1079
6961465f 1080 if ((pwg_media = pwgMediaForPPD(ppd_size->name)) != NULL)
5a9febac
MS
1081 {
1082 /*
1083 * Standard name, do we have conflicts?
1084 */
f14324a7 1085
5a9febac
MS
1086 for (j = 0; j < pc->num_sizes; j ++)
1087 if (!strcmp(pc->sizes[j].map.pwg, pwg_media->pwg))
1088 {
1089 pwg_media = NULL;
1090 break;
1091 }
1092 }
f14324a7 1093
5a9febac
MS
1094 if (pwg_media)
1095 {
1096 /*
1097 * Standard name and no conflicts, use it!
1098 */
f14324a7 1099
5a9febac
MS
1100 pwg_name = pwg_media->pwg;
1101 new_known_pwg = 1;
1102 }
1103 else
f14324a7
MS
1104 {
1105 /*
5a9febac
MS
1106 * Not a standard name; convert it to a PWG vendor name of the form:
1107 *
1108 * pp_lowerppd_WIDTHxHEIGHTuu
f14324a7
MS
1109 */
1110
5a9febac
MS
1111 pwg_name = pwg_keyword;
1112 new_known_pwg = 0;
1113
c1420c87 1114 pwg_unppdize_name(ppd_size->name, ppd_name, sizeof(ppd_name), "_.");
6961465f
MS
1115 pwgFormatSizeName(pwg_keyword, sizeof(pwg_keyword), NULL, ppd_name,
1116 PWG_FROM_POINTS(ppd_size->width),
1117 PWG_FROM_POINTS(ppd_size->length), NULL);
f14324a7 1118 }
f14324a7 1119
f14324a7 1120 /*
5a9febac
MS
1121 * If we have a similar paper with non-zero margins then we only want to
1122 * keep it if it has a larger imageable area length. The NULL check is for
1123 * dimensions that are <= 0...
f14324a7
MS
1124 */
1125
c3ebc4c6
MS
1126 if ((pwg_media = _pwgMediaNearSize(PWG_FROM_POINTS(ppd_size->width),
1127 PWG_FROM_POINTS(ppd_size->length),
1128 0)) == NULL)
5a9febac 1129 continue;
f14324a7 1130
5a9febac
MS
1131 new_width = pwg_media->width;
1132 new_length = pwg_media->length;
6961465f
MS
1133 new_left = PWG_FROM_POINTS(ppd_size->left);
1134 new_bottom = PWG_FROM_POINTS(ppd_size->bottom);
1135 new_right = PWG_FROM_POINTS(ppd_size->width - ppd_size->right);
1136 new_top = PWG_FROM_POINTS(ppd_size->length - ppd_size->top);
5a9febac
MS
1137 new_imageable = new_length - new_top - new_bottom;
1138 new_borderless = new_bottom == 0 && new_top == 0 &&
1139 new_left == 0 && new_right == 0;
1140
1141 for (k = pc->num_sizes, similar = 0, old_size = pc->sizes, new_size = NULL;
1142 k > 0 && !similar;
1143 k --, old_size ++)
1144 {
1145 old_imageable = old_size->length - old_size->top - old_size->bottom;
1146 old_borderless = old_size->left == 0 && old_size->bottom == 0 &&
1147 old_size->right == 0 && old_size->top == 0;
1148 old_known_pwg = strncmp(old_size->map.pwg, "oe_", 3) &&
1149 strncmp(old_size->map.pwg, "om_", 3);
1150
1151 similar = old_borderless == new_borderless &&
1152 _PWG_EQUIVALENT(old_size->width, new_width) &&
1153 _PWG_EQUIVALENT(old_size->length, new_length);
1154
1155 if (similar &&
1156 (new_known_pwg || (!old_known_pwg && new_imageable > old_imageable)))
1157 {
1158 /*
1159 * The new paper has a larger imageable area so it could replace
1160 * the older paper. Regardless of the imageable area, we always
1161 * prefer the size with a well-known PWG name.
1162 */
1163
1164 new_size = old_size;
1165 _cupsStrFree(old_size->map.ppd);
1166 _cupsStrFree(old_size->map.pwg);
1167 }
1168 }
1169
1170 if (!similar)
1171 {
1172 /*
1173 * The paper was unique enough to deserve its own entry so add it to the
1174 * end.
1175 */
1176
1177 new_size = pwg_size ++;
1178 pc->num_sizes ++;
1179 }
1180
1181 if (new_size)
1182 {
1183 /*
1184 * Save this size...
1185 */
f14324a7 1186
5a9febac
MS
1187 new_size->map.ppd = _cupsStrAlloc(ppd_size->name);
1188 new_size->map.pwg = _cupsStrAlloc(pwg_name);
1189 new_size->width = new_width;
1190 new_size->length = new_length;
1191 new_size->left = new_left;
1192 new_size->bottom = new_bottom;
1193 new_size->right = new_right;
1194 new_size->top = new_top;
1195 }
f14324a7
MS
1196 }
1197 }
1198
1199 if (ppd->variable_sizes)
1200 {
1201 /*
1202 * Generate custom size data...
1203 */
1204
6961465f
MS
1205 pwgFormatSizeName(pwg_keyword, sizeof(pwg_keyword), "custom", "max",
1206 PWG_FROM_POINTS(ppd->custom_max[0]),
1207 PWG_FROM_POINTS(ppd->custom_max[1]), NULL);
f14324a7 1208 pc->custom_max_keyword = _cupsStrAlloc(pwg_keyword);
6961465f
MS
1209 pc->custom_max_width = PWG_FROM_POINTS(ppd->custom_max[0]);
1210 pc->custom_max_length = PWG_FROM_POINTS(ppd->custom_max[1]);
f14324a7 1211
6961465f
MS
1212 pwgFormatSizeName(pwg_keyword, sizeof(pwg_keyword), "custom", "min",
1213 PWG_FROM_POINTS(ppd->custom_min[0]),
1214 PWG_FROM_POINTS(ppd->custom_min[1]), NULL);
f14324a7 1215 pc->custom_min_keyword = _cupsStrAlloc(pwg_keyword);
6961465f
MS
1216 pc->custom_min_width = PWG_FROM_POINTS(ppd->custom_min[0]);
1217 pc->custom_min_length = PWG_FROM_POINTS(ppd->custom_min[1]);
f14324a7 1218
6961465f
MS
1219 pc->custom_size.left = PWG_FROM_POINTS(ppd->custom_margins[0]);
1220 pc->custom_size.bottom = PWG_FROM_POINTS(ppd->custom_margins[1]);
1221 pc->custom_size.right = PWG_FROM_POINTS(ppd->custom_margins[2]);
1222 pc->custom_size.top = PWG_FROM_POINTS(ppd->custom_margins[3]);
f14324a7
MS
1223 }
1224
1225 /*
1226 * Copy and convert InputSlot data...
1227 */
1228
1229 if ((input_slot = ppdFindOption(ppd, "InputSlot")) == NULL)
1230 input_slot = ppdFindOption(ppd, "HPPaperSource");
1231
1232 if (input_slot)
1233 {
1234 pc->source_option = _cupsStrAlloc(input_slot->keyword);
1235
7e86f2f6 1236 if ((pc->sources = calloc((size_t)input_slot->num_choices, sizeof(pwg_map_t))) == NULL)
f14324a7
MS
1237 {
1238 DEBUG_printf(("_ppdCacheCreateWithPPD: Unable to allocate %d "
6961465f 1239 "pwg_map_t's for InputSlot.", input_slot->num_choices));
f14324a7
MS
1240 goto create_error;
1241 }
1242
1243 pc->num_sources = input_slot->num_choices;
1244
1245 for (i = input_slot->num_choices, choice = input_slot->choices,
1246 map = pc->sources;
1247 i > 0;
1248 i --, choice ++, map ++)
1249 {
88f9aafc
MS
1250 if (!_cups_strncasecmp(choice->choice, "Auto", 4) ||
1251 !_cups_strcasecmp(choice->choice, "Default"))
f14324a7 1252 pwg_name = "auto";
88f9aafc 1253 else if (!_cups_strcasecmp(choice->choice, "Cassette"))
f14324a7 1254 pwg_name = "main";
88f9aafc 1255 else if (!_cups_strcasecmp(choice->choice, "PhotoTray"))
f14324a7 1256 pwg_name = "photo";
88f9aafc 1257 else if (!_cups_strcasecmp(choice->choice, "CDTray"))
f14324a7 1258 pwg_name = "disc";
88f9aafc
MS
1259 else if (!_cups_strncasecmp(choice->choice, "Multipurpose", 12) ||
1260 !_cups_strcasecmp(choice->choice, "MP") ||
1261 !_cups_strcasecmp(choice->choice, "MPTray"))
12f89d24 1262 pwg_name = "by-pass-tray";
88f9aafc 1263 else if (!_cups_strcasecmp(choice->choice, "LargeCapacity"))
f14324a7 1264 pwg_name = "large-capacity";
88f9aafc 1265 else if (!_cups_strncasecmp(choice->choice, "Lower", 5))
f14324a7 1266 pwg_name = "bottom";
88f9aafc 1267 else if (!_cups_strncasecmp(choice->choice, "Middle", 6))
f14324a7 1268 pwg_name = "middle";
88f9aafc 1269 else if (!_cups_strncasecmp(choice->choice, "Upper", 5))
f14324a7 1270 pwg_name = "top";
88f9aafc 1271 else if (!_cups_strncasecmp(choice->choice, "Side", 4))
f14324a7 1272 pwg_name = "side";
a4845881 1273 else if (!_cups_strcasecmp(choice->choice, "Roll"))
f14324a7 1274 pwg_name = "main-roll";
f14324a7
MS
1275 else
1276 {
1277 /*
1278 * Convert PPD name to lowercase...
1279 */
1280
1281 pwg_name = pwg_keyword;
c1420c87
MS
1282 pwg_unppdize_name(choice->choice, pwg_keyword, sizeof(pwg_keyword),
1283 "_");
f14324a7
MS
1284 }
1285
1286 map->pwg = _cupsStrAlloc(pwg_name);
1287 map->ppd = _cupsStrAlloc(choice->choice);
1288 }
1289 }
1290
1291 /*
1292 * Copy and convert MediaType data...
1293 */
1294
1295 if ((media_type = ppdFindOption(ppd, "MediaType")) != NULL)
1296 {
7e86f2f6 1297 if ((pc->types = calloc((size_t)media_type->num_choices, sizeof(pwg_map_t))) == NULL)
f14324a7
MS
1298 {
1299 DEBUG_printf(("_ppdCacheCreateWithPPD: Unable to allocate %d "
6961465f 1300 "pwg_map_t's for MediaType.", media_type->num_choices));
f14324a7
MS
1301 goto create_error;
1302 }
1303
1304 pc->num_types = media_type->num_choices;
1305
1306 for (i = media_type->num_choices, choice = media_type->choices,
1307 map = pc->types;
1308 i > 0;
1309 i --, choice ++, map ++)
1310 {
88f9aafc
MS
1311 if (!_cups_strncasecmp(choice->choice, "Auto", 4) ||
1312 !_cups_strcasecmp(choice->choice, "Any") ||
1313 !_cups_strcasecmp(choice->choice, "Default"))
f14324a7 1314 pwg_name = "auto";
88f9aafc 1315 else if (!_cups_strncasecmp(choice->choice, "Card", 4))
f14324a7 1316 pwg_name = "cardstock";
88f9aafc 1317 else if (!_cups_strncasecmp(choice->choice, "Env", 3))
f14324a7 1318 pwg_name = "envelope";
88f9aafc 1319 else if (!_cups_strncasecmp(choice->choice, "Gloss", 5))
f14324a7 1320 pwg_name = "photographic-glossy";
88f9aafc 1321 else if (!_cups_strcasecmp(choice->choice, "HighGloss"))
f14324a7 1322 pwg_name = "photographic-high-gloss";
88f9aafc 1323 else if (!_cups_strcasecmp(choice->choice, "Matte"))
f14324a7 1324 pwg_name = "photographic-matte";
88f9aafc 1325 else if (!_cups_strncasecmp(choice->choice, "Plain", 5))
f14324a7 1326 pwg_name = "stationery";
88f9aafc 1327 else if (!_cups_strncasecmp(choice->choice, "Coated", 6))
f14324a7 1328 pwg_name = "stationery-coated";
88f9aafc 1329 else if (!_cups_strcasecmp(choice->choice, "Inkjet"))
f14324a7 1330 pwg_name = "stationery-inkjet";
88f9aafc 1331 else if (!_cups_strcasecmp(choice->choice, "Letterhead"))
f14324a7 1332 pwg_name = "stationery-letterhead";
88f9aafc 1333 else if (!_cups_strncasecmp(choice->choice, "Preprint", 8))
f14324a7 1334 pwg_name = "stationery-preprinted";
a4845881
MS
1335 else if (!_cups_strcasecmp(choice->choice, "Recycled"))
1336 pwg_name = "stationery-recycled";
88f9aafc 1337 else if (!_cups_strncasecmp(choice->choice, "Transparen", 10))
f14324a7
MS
1338 pwg_name = "transparency";
1339 else
1340 {
1341 /*
1342 * Convert PPD name to lowercase...
1343 */
1344
1345 pwg_name = pwg_keyword;
c1420c87
MS
1346 pwg_unppdize_name(choice->choice, pwg_keyword, sizeof(pwg_keyword),
1347 "_");
f14324a7
MS
1348 }
1349
1350 map->pwg = _cupsStrAlloc(pwg_name);
1351 map->ppd = _cupsStrAlloc(choice->choice);
1352 }
1353 }
1354
f14324a7
MS
1355 /*
1356 * Copy and convert OutputBin data...
1357 */
1358
1359 if ((output_bin = ppdFindOption(ppd, "OutputBin")) != NULL)
1360 {
7e86f2f6 1361 if ((pc->bins = calloc((size_t)output_bin->num_choices, sizeof(pwg_map_t))) == NULL)
f14324a7
MS
1362 {
1363 DEBUG_printf(("_ppdCacheCreateWithPPD: Unable to allocate %d "
6961465f 1364 "pwg_map_t's for OutputBin.", output_bin->num_choices));
f14324a7
MS
1365 goto create_error;
1366 }
1367
1368 pc->num_bins = output_bin->num_choices;
1369
1370 for (i = output_bin->num_choices, choice = output_bin->choices,
1371 map = pc->bins;
1372 i > 0;
1373 i --, choice ++, map ++)
1374 {
c1420c87 1375 pwg_unppdize_name(choice->choice, pwg_keyword, sizeof(pwg_keyword), "_");
f14324a7
MS
1376
1377 map->pwg = _cupsStrAlloc(pwg_keyword);
1378 map->ppd = _cupsStrAlloc(choice->choice);
1379 }
1380 }
1381
1382 if ((ppd_attr = ppdFindAttr(ppd, "APPrinterPreset", NULL)) != NULL)
1383 {
1384 /*
1385 * Copy and convert APPrinterPreset (output-mode + print-quality) data...
1386 */
1387
1388 const char *quality, /* com.apple.print.preset.quality value */
1389 *output_mode, /* com.apple.print.preset.output-mode value */
1390 *color_model_val, /* ColorModel choice */
1391 *graphicsType, /* com.apple.print.preset.graphicsType value */
1392 *media_front_coating; /* com.apple.print.preset.media-front-coating value */
1393
1394 do
1395 {
1396 num_options = _ppdParseOptions(ppd_attr->value, 0, &options,
1397 _PPD_PARSE_ALL);
1398
1399 if ((quality = cupsGetOption("com.apple.print.preset.quality",
1400 num_options, options)) != NULL)
1401 {
1402 /*
1403 * Get the print-quality for this preset...
1404 */
1405
1406 if (!strcmp(quality, "low"))
1407 pwg_print_quality = _PWG_PRINT_QUALITY_DRAFT;
1408 else if (!strcmp(quality, "high"))
1409 pwg_print_quality = _PWG_PRINT_QUALITY_HIGH;
1410 else
1411 pwg_print_quality = _PWG_PRINT_QUALITY_NORMAL;
1412
1413 /*
1414 * Ignore graphicsType "Photo" presets that are not high quality.
1415 */
1416
1417 graphicsType = cupsGetOption("com.apple.print.preset.graphicsType",
1418 num_options, options);
1419
1420 if (pwg_print_quality != _PWG_PRINT_QUALITY_HIGH && graphicsType &&
1421 !strcmp(graphicsType, "Photo"))
1422 continue;
1423
1424 /*
1425 * Ignore presets for normal and draft quality where the coating
1426 * isn't "none" or "autodetect".
1427 */
1428
1429 media_front_coating = cupsGetOption(
1430 "com.apple.print.preset.media-front-coating",
1431 num_options, options);
1432
1433 if (pwg_print_quality != _PWG_PRINT_QUALITY_HIGH &&
1434 media_front_coating &&
1435 strcmp(media_front_coating, "none") &&
1436 strcmp(media_front_coating, "autodetect"))
1437 continue;
1438
1439 /*
1440 * Get the output mode for this preset...
1441 */
1442
1443 output_mode = cupsGetOption("com.apple.print.preset.output-mode",
1444 num_options, options);
1445 color_model_val = cupsGetOption("ColorModel", num_options, options);
1446
1447 if (output_mode)
1448 {
1449 if (!strcmp(output_mode, "monochrome"))
1450 pwg_print_color_mode = _PWG_PRINT_COLOR_MODE_MONOCHROME;
1451 else
1452 pwg_print_color_mode = _PWG_PRINT_COLOR_MODE_COLOR;
1453 }
1454 else if (color_model_val)
1455 {
88f9aafc 1456 if (!_cups_strcasecmp(color_model_val, "Gray"))
f14324a7
MS
1457 pwg_print_color_mode = _PWG_PRINT_COLOR_MODE_MONOCHROME;
1458 else
1459 pwg_print_color_mode = _PWG_PRINT_COLOR_MODE_COLOR;
1460 }
1461 else
1462 pwg_print_color_mode = _PWG_PRINT_COLOR_MODE_COLOR;
1463
1464 /*
1465 * Save the options for this combination as needed...
1466 */
1467
1468 if (!pc->num_presets[pwg_print_color_mode][pwg_print_quality])
1469 pc->num_presets[pwg_print_color_mode][pwg_print_quality] =
1470 _ppdParseOptions(ppd_attr->value, 0,
1471 pc->presets[pwg_print_color_mode] +
1472 pwg_print_quality, _PPD_PARSE_OPTIONS);
1473 }
1474
1475 cupsFreeOptions(num_options, options);
1476 }
1477 while ((ppd_attr = ppdFindNextAttr(ppd, "APPrinterPreset", NULL)) != NULL);
1478 }
1479
1480 if (!pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][_PWG_PRINT_QUALITY_DRAFT] &&
1481 !pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][_PWG_PRINT_QUALITY_NORMAL] &&
1482 !pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][_PWG_PRINT_QUALITY_HIGH])
1483 {
1484 /*
1485 * Try adding some common color options to create grayscale presets. These
1486 * are listed in order of popularity...
1487 */
1488
1489 const char *color_option = NULL, /* Color control option */
1490 *gray_choice = NULL; /* Choice to select grayscale */
1491
1492 if ((color_model = ppdFindOption(ppd, "ColorModel")) != NULL &&
1493 ppdFindChoice(color_model, "Gray"))
1494 {
1495 color_option = "ColorModel";
1496 gray_choice = "Gray";
1497 }
1498 else if ((color_model = ppdFindOption(ppd, "HPColorMode")) != NULL &&
1499 ppdFindChoice(color_model, "grayscale"))
1500 {
1501 color_option = "HPColorMode";
1502 gray_choice = "grayscale";
1503 }
1504 else if ((color_model = ppdFindOption(ppd, "BRMonoColor")) != NULL &&
1505 ppdFindChoice(color_model, "Mono"))
1506 {
1507 color_option = "BRMonoColor";
1508 gray_choice = "Mono";
1509 }
1510 else if ((color_model = ppdFindOption(ppd, "CNIJSGrayScale")) != NULL &&
1511 ppdFindChoice(color_model, "1"))
1512 {
1513 color_option = "CNIJSGrayScale";
1514 gray_choice = "1";
1515 }
1516 else if ((color_model = ppdFindOption(ppd, "HPColorAsGray")) != NULL &&
1517 ppdFindChoice(color_model, "True"))
1518 {
1519 color_option = "HPColorAsGray";
1520 gray_choice = "True";
1521 }
1522
1523 if (color_option && gray_choice)
1524 {
1525 /*
1526 * Copy and convert ColorModel (output-mode) data...
1527 */
1528
1529 cups_option_t *coption, /* Color option */
1530 *moption; /* Monochrome option */
1531
1532 for (pwg_print_quality = _PWG_PRINT_QUALITY_DRAFT;
1533 pwg_print_quality < _PWG_PRINT_QUALITY_MAX;
1534 pwg_print_quality ++)
1535 {
1536 if (pc->num_presets[_PWG_PRINT_COLOR_MODE_COLOR][pwg_print_quality])
1537 {
1538 /*
1539 * Copy the color options...
1540 */
1541
1542 num_options = pc->num_presets[_PWG_PRINT_COLOR_MODE_COLOR]
1543 [pwg_print_quality];
7e86f2f6 1544 options = calloc(sizeof(cups_option_t), (size_t)num_options);
f14324a7
MS
1545
1546 if (options)
1547 {
1548 for (i = num_options, moption = options,
1549 coption = pc->presets[_PWG_PRINT_COLOR_MODE_COLOR]
1550 [pwg_print_quality];
1551 i > 0;
1552 i --, moption ++, coption ++)
1553 {
1554 moption->name = _cupsStrRetain(coption->name);
1555 moption->value = _cupsStrRetain(coption->value);
1556 }
1557
1558 pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][pwg_print_quality] =
1559 num_options;
1560 pc->presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][pwg_print_quality] =
1561 options;
1562 }
1563 }
1564 else if (pwg_print_quality != _PWG_PRINT_QUALITY_NORMAL)
1565 continue;
1566
1567 /*
1568 * Add the grayscale option to the preset...
1569 */
1570
1571 pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][pwg_print_quality] =
1572 cupsAddOption(color_option, gray_choice,
1573 pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME]
1574 [pwg_print_quality],
1575 pc->presets[_PWG_PRINT_COLOR_MODE_MONOCHROME] +
1576 pwg_print_quality);
1577 }
1578 }
1579 }
1580
1581 /*
1582 * Copy and convert Duplex (sides) data...
1583 */
1584
1585 if ((duplex = ppdFindOption(ppd, "Duplex")) == NULL)
1586 if ((duplex = ppdFindOption(ppd, "JCLDuplex")) == NULL)
1587 if ((duplex = ppdFindOption(ppd, "EFDuplex")) == NULL)
1588 if ((duplex = ppdFindOption(ppd, "EFDuplexing")) == NULL)
1589 duplex = ppdFindOption(ppd, "KD03Duplex");
1590
1591 if (duplex)
1592 {
1593 pc->sides_option = _cupsStrAlloc(duplex->keyword);
1594
1595 for (i = duplex->num_choices, choice = duplex->choices;
1596 i > 0;
1597 i --, choice ++)
1598 {
88f9aafc
MS
1599 if ((!_cups_strcasecmp(choice->choice, "None") ||
1600 !_cups_strcasecmp(choice->choice, "False")) && !pc->sides_1sided)
f14324a7 1601 pc->sides_1sided = _cupsStrAlloc(choice->choice);
88f9aafc
MS
1602 else if ((!_cups_strcasecmp(choice->choice, "DuplexNoTumble") ||
1603 !_cups_strcasecmp(choice->choice, "LongEdge") ||
1604 !_cups_strcasecmp(choice->choice, "Top")) && !pc->sides_2sided_long)
f14324a7 1605 pc->sides_2sided_long = _cupsStrAlloc(choice->choice);
88f9aafc
MS
1606 else if ((!_cups_strcasecmp(choice->choice, "DuplexTumble") ||
1607 !_cups_strcasecmp(choice->choice, "ShortEdge") ||
1608 !_cups_strcasecmp(choice->choice, "Bottom")) &&
f14324a7
MS
1609 !pc->sides_2sided_short)
1610 pc->sides_2sided_short = _cupsStrAlloc(choice->choice);
1611 }
1612 }
1613
1614 /*
1615 * Copy filters and pre-filters...
1616 */
1617
1618 pc->filters = cupsArrayNew3(NULL, NULL, NULL, 0,
1619 (cups_acopy_func_t)_cupsStrAlloc,
1620 (cups_afree_func_t)_cupsStrFree);
1621
1622 cupsArrayAdd(pc->filters,
1623 "application/vnd.cups-raw application/octet-stream 0 -");
1624
1625 if ((ppd_attr = ppdFindAttr(ppd, "cupsFilter2", NULL)) != NULL)
1626 {
1627 do
1628 {
1629 cupsArrayAdd(pc->filters, ppd_attr->value);
1630 }
1631 while ((ppd_attr = ppdFindNextAttr(ppd, "cupsFilter2", NULL)) != NULL);
1632 }
1633 else if (ppd->num_filters > 0)
1634 {
1635 for (i = 0; i < ppd->num_filters; i ++)
1636 cupsArrayAdd(pc->filters, ppd->filters[i]);
1637 }
1638 else
1639 cupsArrayAdd(pc->filters, "application/vnd.cups-postscript 0 -");
1640
1641 /*
1642 * See if we have a command filter...
1643 */
1644
1645 for (filter = (const char *)cupsArrayFirst(pc->filters);
1646 filter;
1647 filter = (const char *)cupsArrayNext(pc->filters))
88f9aafc 1648 if (!_cups_strncasecmp(filter, "application/vnd.cups-command", 28) &&
f14324a7
MS
1649 _cups_isspace(filter[28]))
1650 break;
1651
1652 if (!filter &&
1653 ((ppd_attr = ppdFindAttr(ppd, "cupsCommands", NULL)) == NULL ||
88f9aafc 1654 _cups_strcasecmp(ppd_attr->value, "none")))
f14324a7
MS
1655 {
1656 /*
1657 * No command filter and no cupsCommands keyword telling us not to use one.
1658 * See if this is a PostScript printer, and if so add a PostScript command
1659 * filter...
1660 */
1661
1662 for (filter = (const char *)cupsArrayFirst(pc->filters);
1663 filter;
1664 filter = (const char *)cupsArrayNext(pc->filters))
88f9aafc 1665 if (!_cups_strncasecmp(filter, "application/vnd.cups-postscript", 31) &&
f14324a7
MS
1666 _cups_isspace(filter[31]))
1667 break;
1668
1669 if (filter)
1670 cupsArrayAdd(pc->filters,
a2326b5b
MS
1671 "application/vnd.cups-command application/postscript 100 "
1672 "commandtops");
f14324a7
MS
1673 }
1674
1675 if ((ppd_attr = ppdFindAttr(ppd, "cupsPreFilter", NULL)) != NULL)
1676 {
1677 pc->prefilters = cupsArrayNew3(NULL, NULL, NULL, 0,
1678 (cups_acopy_func_t)_cupsStrAlloc,
1679 (cups_afree_func_t)_cupsStrFree);
1680
1681 do
1682 {
1683 cupsArrayAdd(pc->prefilters, ppd_attr->value);
1684 }
1685 while ((ppd_attr = ppdFindNextAttr(ppd, "cupsPreFilter", NULL)) != NULL);
1686 }
1687
82f97232 1688 if ((ppd_attr = ppdFindAttr(ppd, "cupsSingleFile", NULL)) != NULL)
88f9aafc 1689 pc->single_file = !_cups_strcasecmp(ppd_attr->value, "true");
82f97232 1690
f14324a7
MS
1691 /*
1692 * Copy the product string, if any...
1693 */
1694
1695 if (ppd->product)
1696 pc->product = _cupsStrAlloc(ppd->product);
1697
dcb445bc
MS
1698 /*
1699 * Copy finishings mapping data...
1700 */
1701
1702 if ((ppd_attr = ppdFindAttr(ppd, "cupsIPPFinishings", NULL)) != NULL)
1703 {
1fbd0cab
MS
1704 /*
1705 * Have proper vendor mapping of IPP finishings values to PPD options...
1706 */
1707
dcb445bc
MS
1708 pc->finishings = cupsArrayNew3((cups_array_func_t)pwg_compare_finishings,
1709 NULL, NULL, 0, NULL,
1710 (cups_afree_func_t)pwg_free_finishings);
1711
1712 do
1713 {
1714 if ((finishings = calloc(1, sizeof(_pwg_finishings_t))) == NULL)
1715 goto create_error;
1716
7e86f2f6 1717 finishings->value = (ipp_finishings_t)atoi(ppd_attr->spec);
dcb445bc
MS
1718 finishings->num_options = _ppdParseOptions(ppd_attr->value, 0,
1719 &(finishings->options),
1720 _PPD_PARSE_OPTIONS);
1721
1722 cupsArrayAdd(pc->finishings, finishings);
1723 }
1724 while ((ppd_attr = ppdFindNextAttr(ppd, "cupsIPPFinishings",
1725 NULL)) != NULL);
1726 }
1fbd0cab
MS
1727 else
1728 {
1729 /*
1730 * No IPP mapping data, try to map common/standard PPD keywords...
1731 */
1732
1fbd0cab
MS
1733 pc->finishings = cupsArrayNew3((cups_array_func_t)pwg_compare_finishings, NULL, NULL, 0, NULL, (cups_afree_func_t)pwg_free_finishings);
1734
1735 if ((ppd_option = ppdFindOption(ppd, "StapleLocation")) != NULL)
1736 {
1737 /*
1738 * Add staple finishings...
1739 */
1740
1741 if (ppdFindChoice(ppd_option, "SinglePortrait"))
1742 pwg_add_finishing(pc->finishings, IPP_FINISHINGS_STAPLE_TOP_LEFT, "StapleLocation", "SinglePortrait");
1743 if (ppdFindChoice(ppd_option, "UpperLeft")) /* Ricoh extension */
1744 pwg_add_finishing(pc->finishings, IPP_FINISHINGS_STAPLE_TOP_LEFT, "StapleLocation", "UpperLeft");
1745 if (ppdFindChoice(ppd_option, "UpperRight")) /* Ricoh extension */
1746 pwg_add_finishing(pc->finishings, IPP_FINISHINGS_STAPLE_TOP_RIGHT, "StapleLocation", "UpperRight");
1747 if (ppdFindChoice(ppd_option, "SingleLandscape"))
1748 pwg_add_finishing(pc->finishings, IPP_FINISHINGS_STAPLE_BOTTOM_LEFT, "StapleLocation", "SingleLandscape");
1749 if (ppdFindChoice(ppd_option, "DualLandscape"))
1750 pwg_add_finishing(pc->finishings, IPP_FINISHINGS_STAPLE_DUAL_LEFT, "StapleLocation", "DualLandscape");
1751 }
1752
1753 if ((ppd_option = ppdFindOption(ppd, "RIPunch")) != NULL)
1754 {
1755 /*
1756 * Add (Ricoh) punch finishings...
1757 */
1758
1759 if (ppdFindChoice(ppd_option, "Left2"))
1760 pwg_add_finishing(pc->finishings, IPP_FINISHINGS_PUNCH_DUAL_LEFT, "RIPunch", "Left2");
1761 if (ppdFindChoice(ppd_option, "Left3"))
1762 pwg_add_finishing(pc->finishings, IPP_FINISHINGS_PUNCH_TRIPLE_LEFT, "RIPunch", "Left3");
1763 if (ppdFindChoice(ppd_option, "Left4"))
1764 pwg_add_finishing(pc->finishings, IPP_FINISHINGS_PUNCH_QUAD_LEFT, "RIPunch", "Left4");
1765 if (ppdFindChoice(ppd_option, "Right2"))
1766 pwg_add_finishing(pc->finishings, IPP_FINISHINGS_PUNCH_DUAL_RIGHT, "RIPunch", "Right2");
1767 if (ppdFindChoice(ppd_option, "Right3"))
1768 pwg_add_finishing(pc->finishings, IPP_FINISHINGS_PUNCH_TRIPLE_RIGHT, "RIPunch", "Right3");
1769 if (ppdFindChoice(ppd_option, "Right4"))
1770 pwg_add_finishing(pc->finishings, IPP_FINISHINGS_PUNCH_QUAD_RIGHT, "RIPunch", "Right4");
1771 if (ppdFindChoice(ppd_option, "Upper2"))
1772 pwg_add_finishing(pc->finishings, IPP_FINISHINGS_PUNCH_DUAL_TOP, "RIPunch", "Upper2");
1773 if (ppdFindChoice(ppd_option, "Upper3"))
1774 pwg_add_finishing(pc->finishings, IPP_FINISHINGS_PUNCH_TRIPLE_TOP, "RIPunch", "Upper3");
1775 if (ppdFindChoice(ppd_option, "Upper4"))
1776 pwg_add_finishing(pc->finishings, IPP_FINISHINGS_PUNCH_QUAD_TOP, "RIPunch", "Upper4");
1777 }
1778
1779 if ((ppd_option = ppdFindOption(ppd, "BindEdge")) != NULL)
1780 {
1781 /*
1782 * Add bind finishings...
1783 */
1784
1785 if (ppdFindChoice(ppd_option, "Left"))
1786 pwg_add_finishing(pc->finishings, IPP_FINISHINGS_BIND_LEFT, "BindEdge", "Left");
1787 if (ppdFindChoice(ppd_option, "Right"))
1788 pwg_add_finishing(pc->finishings, IPP_FINISHINGS_BIND_RIGHT, "BindEdge", "Right");
1789 if (ppdFindChoice(ppd_option, "Top"))
1790 pwg_add_finishing(pc->finishings, IPP_FINISHINGS_BIND_TOP, "BindEdge", "Top");
1791 if (ppdFindChoice(ppd_option, "Bottom"))
1792 pwg_add_finishing(pc->finishings, IPP_FINISHINGS_BIND_BOTTOM, "BindEdge", "Bottom");
1793 }
1794
1795 if ((ppd_option = ppdFindOption(ppd, "FoldType")) != NULL)
1796 {
1797 /*
1798 * Add (Adobe) fold finishings...
1799 */
1800
1801 if (ppdFindChoice(ppd_option, "ZFold"))
1802 pwg_add_finishing(pc->finishings, IPP_FINISHINGS_FOLD_Z, "FoldType", "ZFold");
1803 if (ppdFindChoice(ppd_option, "Saddle"))
1804 pwg_add_finishing(pc->finishings, IPP_FINISHINGS_FOLD_HALF, "FoldType", "Saddle");
1805 if (ppdFindChoice(ppd_option, "DoubleGate"))
1806 pwg_add_finishing(pc->finishings, IPP_FINISHINGS_FOLD_DOUBLE_GATE, "FoldType", "DoubleGate");
1807 if (ppdFindChoice(ppd_option, "LeftGate"))
1808 pwg_add_finishing(pc->finishings, IPP_FINISHINGS_FOLD_LEFT_GATE, "FoldType", "LeftGate");
1809 if (ppdFindChoice(ppd_option, "RightGate"))
1810 pwg_add_finishing(pc->finishings, IPP_FINISHINGS_FOLD_RIGHT_GATE, "FoldType", "RightGate");
1811 if (ppdFindChoice(ppd_option, "Letter"))
1812 pwg_add_finishing(pc->finishings, IPP_FINISHINGS_FOLD_LETTER, "FoldType", "Letter");
1813 if (ppdFindChoice(ppd_option, "XFold"))
1814 pwg_add_finishing(pc->finishings, IPP_FINISHINGS_FOLD_POSTER, "FoldType", "XFold");
1815 }
1816
1817 if ((ppd_option = ppdFindOption(ppd, "RIFoldType")) != NULL)
1818 {
1819 /*
1820 * Add (Ricoh) fold finishings...
1821 */
1822
1823 if (ppdFindChoice(ppd_option, "OutsideTwoFold"))
1824 pwg_add_finishing(pc->finishings, IPP_FINISHINGS_FOLD_LETTER, "RIFoldType", "OutsideTwoFold");
1825 }
1826
1827 if (cupsArrayCount(pc->finishings) == 0)
1828 {
1829 cupsArrayDelete(pc->finishings);
1830 pc->finishings = NULL;
1831 }
1832 }
dcb445bc 1833
4f63d6cd
MS
1834 if ((ppd_option = ppdFindOption(ppd, "cupsFinishingTemplate")) != NULL)
1835 {
1836 pc->templates = cupsArrayNew3((cups_array_func_t)strcmp, NULL, NULL, 0, (cups_acopy_func_t)_cupsStrAlloc, (cups_afree_func_t)_cupsStrFree);
1837
1838 for (choice = ppd_option->choices, i = ppd_option->num_choices; i > 0; choice ++, i --)
1839 cupsArrayAdd(pc->templates, (void *)choice->choice);
1840 }
1841
3e7fe0ca
MS
1842 /*
1843 * Max copies...
1844 */
1845
1846 if ((ppd_attr = ppdFindAttr(ppd, "cupsMaxCopies", NULL)) != NULL)
1847 pc->max_copies = atoi(ppd_attr->value);
1848 else if (ppd->manual_copies)
1849 pc->max_copies = 1;
1850 else
1851 pc->max_copies = 9999;
1852
5a9febac 1853 /*
a469f8a5
MS
1854 * cupsChargeInfoURI, cupsJobAccountId, cupsJobAccountingUserId,
1855 * cupsJobPassword, and cupsMandatory.
5a9febac
MS
1856 */
1857
a469f8a5
MS
1858 if ((ppd_attr = ppdFindAttr(ppd, "cupsChargeInfoURI", NULL)) != NULL)
1859 pc->charge_info_uri = _cupsStrAlloc(ppd_attr->value);
1860
5a9febac
MS
1861 if ((ppd_attr = ppdFindAttr(ppd, "cupsJobAccountId", NULL)) != NULL)
1862 pc->account_id = !_cups_strcasecmp(ppd_attr->value, "true");
1863
1864 if ((ppd_attr = ppdFindAttr(ppd, "cupsJobAccountingUserId", NULL)) != NULL)
1865 pc->accounting_user_id = !_cups_strcasecmp(ppd_attr->value, "true");
1866
1867 if ((ppd_attr = ppdFindAttr(ppd, "cupsJobPassword", NULL)) != NULL)
1868 pc->password = _cupsStrAlloc(ppd_attr->value);
1869
1870 if ((ppd_attr = ppdFindAttr(ppd, "cupsMandatory", NULL)) != NULL)
1871 pc->mandatory = _cupsArrayNewStrings(ppd_attr->value, ' ');
1872
89550f3f
MS
1873 /*
1874 * Strings (remote) file...
1875 */
1876
1877 if ((ppd_attr = ppdFindAttr(ppd, "cupsStringsURI", NULL)) != NULL)
1878 pc->strings_uri = _cupsStrAlloc(ppd_attr->value);
1879
c1420c87
MS
1880 /*
1881 * Support files...
1882 */
1883
1884 pc->support_files = cupsArrayNew3(NULL, NULL, NULL, 0,
1885 (cups_acopy_func_t)_cupsStrAlloc,
1886 (cups_afree_func_t)_cupsStrFree);
1887
1888 for (ppd_attr = ppdFindAttr(ppd, "cupsICCProfile", NULL);
1889 ppd_attr;
1890 ppd_attr = ppdFindNextAttr(ppd, "cupsICCProfile", NULL))
1891 cupsArrayAdd(pc->support_files, ppd_attr->value);
1892
1893 if ((ppd_attr = ppdFindAttr(ppd, "APPrinterIconPath", NULL)) != NULL)
1894 cupsArrayAdd(pc->support_files, ppd_attr->value);
1895
f14324a7
MS
1896 /*
1897 * Return the cache data...
1898 */
1899
1900 return (pc);
1901
1902 /*
1903 * If we get here we need to destroy the PWG mapping data and return NULL...
1904 */
1905
1906 create_error:
1907
cb7f98ee 1908 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Out of memory."), 1);
f14324a7
MS
1909 _ppdCacheDestroy(pc);
1910
1911 return (NULL);
1912}
1913
1914
1915/*
1916 * '_ppdCacheDestroy()' - Free all memory used for PWG mapping data.
1917 */
1918
1919void
1920_ppdCacheDestroy(_ppd_cache_t *pc) /* I - PPD cache and mapping data */
1921{
1922 int i; /* Looping var */
6961465f
MS
1923 pwg_map_t *map; /* Current map */
1924 pwg_size_t *size; /* Current size */
f14324a7
MS
1925
1926
1927 /*
1928 * Range check input...
1929 */
1930
1931 if (!pc)
1932 return;
1933
1934 /*
1935 * Free memory as needed...
1936 */
1937
1938 if (pc->bins)
1939 {
1940 for (i = pc->num_bins, map = pc->bins; i > 0; i --, map ++)
1941 {
1942 _cupsStrFree(map->pwg);
1943 _cupsStrFree(map->ppd);
1944 }
1945
1946 free(pc->bins);
1947 }
1948
1949 if (pc->sizes)
1950 {
1951 for (i = pc->num_sizes, size = pc->sizes; i > 0; i --, size ++)
1952 {
1953 _cupsStrFree(size->map.pwg);
1954 _cupsStrFree(size->map.ppd);
1955 }
1956
1957 free(pc->sizes);
1958 }
1959
1960 if (pc->source_option)
1961 _cupsStrFree(pc->source_option);
1962
1963 if (pc->sources)
1964 {
1965 for (i = pc->num_sources, map = pc->sources; i > 0; i --, map ++)
1966 {
1967 _cupsStrFree(map->pwg);
1968 _cupsStrFree(map->ppd);
1969 }
1970
1971 free(pc->sources);
1972 }
1973
1974 if (pc->types)
1975 {
1976 for (i = pc->num_types, map = pc->types; i > 0; i --, map ++)
1977 {
1978 _cupsStrFree(map->pwg);
1979 _cupsStrFree(map->ppd);
1980 }
1981
1982 free(pc->types);
1983 }
1984
1985 if (pc->custom_max_keyword)
1986 _cupsStrFree(pc->custom_max_keyword);
1987
1988 if (pc->custom_min_keyword)
1989 _cupsStrFree(pc->custom_min_keyword);
1990
1991 _cupsStrFree(pc->product);
1992 cupsArrayDelete(pc->filters);
1993 cupsArrayDelete(pc->prefilters);
dcb445bc 1994 cupsArrayDelete(pc->finishings);
f14324a7 1995
a469f8a5 1996 _cupsStrFree(pc->charge_info_uri);
5a9febac
MS
1997 _cupsStrFree(pc->password);
1998
1999 cupsArrayDelete(pc->mandatory);
2000
c1420c87
MS
2001 cupsArrayDelete(pc->support_files);
2002
f14324a7
MS
2003 free(pc);
2004}
2005
2006
2007/*
2008 * '_ppdCacheGetBin()' - Get the PWG output-bin keyword associated with a PPD
2009 * OutputBin.
2010 */
2011
2012const char * /* O - output-bin or NULL */
2013_ppdCacheGetBin(
2014 _ppd_cache_t *pc, /* I - PPD cache and mapping data */
2015 const char *output_bin) /* I - PPD OutputBin string */
2016{
2017 int i; /* Looping var */
2018
2019
2020 /*
2021 * Range check input...
2022 */
2023
2024 if (!pc || !output_bin)
2025 return (NULL);
2026
2027 /*
2028 * Look up the OutputBin string...
2029 */
2030
2031
2032 for (i = 0; i < pc->num_bins; i ++)
88f9aafc 2033 if (!_cups_strcasecmp(output_bin, pc->bins[i].ppd))
f14324a7
MS
2034 return (pc->bins[i].pwg);
2035
2036 return (NULL);
2037}
2038
2039
dcb445bc
MS
2040/*
2041 * '_ppdCacheGetFinishingOptions()' - Get PPD finishing options for the given
2042 * IPP finishings value(s).
2043 */
2044
2045int /* O - New number of options */
2046_ppdCacheGetFinishingOptions(
cb7f98ee
MS
2047 _ppd_cache_t *pc, /* I - PPD cache and mapping data */
2048 ipp_t *job, /* I - Job attributes or NULL */
2049 ipp_finishings_t value, /* I - IPP finishings value of IPP_FINISHINGS_NONE */
2050 int num_options, /* I - Number of options */
2051 cups_option_t **options) /* IO - Options */
dcb445bc
MS
2052{
2053 int i; /* Looping var */
2054 _pwg_finishings_t *f, /* PWG finishings options */
2055 key; /* Search key */
2056 ipp_attribute_t *attr; /* Finishings attribute */
2057 cups_option_t *option; /* Current finishings option */
2058
2059
2060 /*
2061 * Range check input...
2062 */
2063
2064 if (!pc || cupsArrayCount(pc->finishings) == 0 || !options ||
2065 (!job && value == IPP_FINISHINGS_NONE))
2066 return (num_options);
2067
2068 /*
2069 * Apply finishing options...
2070 */
2071
2072 if (job && (attr = ippFindAttribute(job, "finishings", IPP_TAG_ENUM)) != NULL)
2073 {
2074 int num_values = ippGetCount(attr); /* Number of values */
2075
2076 for (i = 0; i < num_values; i ++)
2077 {
7e86f2f6 2078 key.value = (ipp_finishings_t)ippGetInteger(attr, i);
dcb445bc
MS
2079
2080 if ((f = cupsArrayFind(pc->finishings, &key)) != NULL)
2081 {
2082 int j; /* Another looping var */
2083
2084 for (j = f->num_options, option = f->options; j > 0; j --, option ++)
2085 num_options = cupsAddOption(option->name, option->value,
2086 num_options, options);
2087 }
2088 }
2089 }
2090 else if (value != IPP_FINISHINGS_NONE)
2091 {
2092 key.value = value;
2093
2094 if ((f = cupsArrayFind(pc->finishings, &key)) != NULL)
2095 {
2096 int j; /* Another looping var */
2097
2098 for (j = f->num_options, option = f->options; j > 0; j --, option ++)
2099 num_options = cupsAddOption(option->name, option->value,
2100 num_options, options);
2101 }
2102 }
2103
2104 return (num_options);
2105}
2106
2107
2108/*
2109 * '_ppdCacheGetFinishingValues()' - Get IPP finishings value(s) from the given
2110 * PPD options.
2111 */
2112
2113int /* O - Number of finishings values */
2114_ppdCacheGetFinishingValues(
2115 _ppd_cache_t *pc, /* I - PPD cache and mapping data */
2116 int num_options, /* I - Number of options */
2117 cups_option_t *options, /* I - Options */
2118 int max_values, /* I - Maximum number of finishings values */
2119 int *values) /* O - Finishings values */
2120{
2121 int i, /* Looping var */
2122 num_values = 0; /* Number of values */
2123 _pwg_finishings_t *f; /* Current finishings option */
2124 cups_option_t *option; /* Current option */
2125 const char *val; /* Value for option */
2126
2127
2128 /*
2129 * Range check input...
2130 */
2131
b2b9911d
MS
2132 DEBUG_printf(("_ppdCacheGetFinishingValues(pc=%p, num_options=%d, options=%p, max_values=%d, values=%p)", pc, num_options, options, max_values, values));
2133
e44bdfe7 2134 if (!pc || max_values < 1 || !values)
b2b9911d
MS
2135 {
2136 DEBUG_puts("_ppdCacheGetFinishingValues: Bad arguments, returning 0.");
dcb445bc 2137 return (0);
b2b9911d 2138 }
e44bdfe7
MS
2139 else if (!pc->finishings)
2140 {
2141 DEBUG_puts("_ppdCacheGetFinishingValues: No finishings support, returning 0.");
2142 return (0);
2143 }
dcb445bc
MS
2144
2145 /*
2146 * Go through the finishings options and see what is set...
2147 */
2148
2149 for (f = (_pwg_finishings_t *)cupsArrayFirst(pc->finishings);
2150 f;
2151 f = (_pwg_finishings_t *)cupsArrayNext(pc->finishings))
2152 {
b2b9911d
MS
2153 DEBUG_printf(("_ppdCacheGetFinishingValues: Checking %d (%s)", f->value, ippEnumString("finishings", f->value)));
2154
dcb445bc 2155 for (i = f->num_options, option = f->options; i > 0; i --, option ++)
b2b9911d
MS
2156 {
2157 DEBUG_printf(("_ppdCacheGetFinishingValues: %s=%s?", option->name, option->value));
2158
dcb445bc
MS
2159 if ((val = cupsGetOption(option->name, num_options, options)) == NULL ||
2160 _cups_strcasecmp(option->value, val))
b2b9911d
MS
2161 {
2162 DEBUG_puts("_ppdCacheGetFinishingValues: NO");
dcb445bc 2163 break;
b2b9911d
MS
2164 }
2165 }
dcb445bc
MS
2166
2167 if (i == 0)
2168 {
e44bdfe7 2169 DEBUG_printf(("_ppdCacheGetFinishingValues: Adding %d (%s)", f->value, ippEnumString("finishings", f->value)));
b2b9911d 2170
dcb445bc
MS
2171 values[num_values ++] = f->value;
2172
2173 if (num_values >= max_values)
2174 break;
2175 }
2176 }
2177
e44bdfe7
MS
2178 if (num_values == 0)
2179 {
2180 /*
2181 * Always have at least "finishings" = 'none'...
2182 */
2183
2184 DEBUG_puts("_ppdCacheGetFinishingValues: Adding 3 (none).");
2185 values[0] = IPP_FINISHINGS_NONE;
2186 num_values ++;
2187 }
2188
b2b9911d
MS
2189 DEBUG_printf(("_ppdCacheGetFinishingValues: Returning %d.", num_values));
2190
dcb445bc
MS
2191 return (num_values);
2192}
2193
2194
f14324a7
MS
2195/*
2196 * '_ppdCacheGetInputSlot()' - Get the PPD InputSlot associated with the job
2197 * attributes or a keyword string.
2198 */
2199
2200const char * /* O - PPD InputSlot or NULL */
2201_ppdCacheGetInputSlot(
2202 _ppd_cache_t *pc, /* I - PPD cache and mapping data */
2203 ipp_t *job, /* I - Job attributes or NULL */
2204 const char *keyword) /* I - Keyword string or NULL */
2205{
2206 /*
2207 * Range check input...
2208 */
2209
2210 if (!pc || pc->num_sources == 0 || (!job && !keyword))
2211 return (NULL);
2212
2213 if (job && !keyword)
2214 {
2215 /*
2216 * Lookup the media-col attribute and any media-source found there...
2217 */
2218
2219 ipp_attribute_t *media_col, /* media-col attribute */
2220 *media_source; /* media-source attribute */
6961465f 2221 pwg_size_t size; /* Dimensional size */
f14324a7
MS
2222 int margins_set; /* Were the margins set? */
2223
2224 media_col = ippFindAttribute(job, "media-col", IPP_TAG_BEGIN_COLLECTION);
2225 if (media_col &&
dcb445bc 2226 (media_source = ippFindAttribute(ippGetCollection(media_col, 0),
f14324a7
MS
2227 "media-source",
2228 IPP_TAG_KEYWORD)) != NULL)
2229 {
2230 /*
2231 * Use the media-source value from media-col...
2232 */
2233
dcb445bc 2234 keyword = ippGetString(media_source, 0, NULL);
f14324a7 2235 }
6961465f 2236 else if (pwgInitSize(&size, job, &margins_set))
f14324a7
MS
2237 {
2238 /*
2239 * For media <= 5x7, look for a photo tray...
2240 */
2241
2242 if (size.width <= (5 * 2540) && size.length <= (7 * 2540))
2243 keyword = "photo";
2244 }
2245 }
2246
2247 if (keyword)
2248 {
2249 int i; /* Looping var */
2250
2251 for (i = 0; i < pc->num_sources; i ++)
88f9aafc 2252 if (!_cups_strcasecmp(keyword, pc->sources[i].pwg))
f14324a7
MS
2253 return (pc->sources[i].ppd);
2254 }
2255
2256 return (NULL);
2257}
2258
2259
2260/*
2261 * '_ppdCacheGetMediaType()' - Get the PPD MediaType associated with the job
2262 * attributes or a keyword string.
2263 */
2264
2265const char * /* O - PPD MediaType or NULL */
2266_ppdCacheGetMediaType(
2267 _ppd_cache_t *pc, /* I - PPD cache and mapping data */
2268 ipp_t *job, /* I - Job attributes or NULL */
2269 const char *keyword) /* I - Keyword string or NULL */
2270{
2271 /*
2272 * Range check input...
2273 */
2274
2275 if (!pc || pc->num_types == 0 || (!job && !keyword))
2276 return (NULL);
2277
2278 if (job && !keyword)
2279 {
2280 /*
2281 * Lookup the media-col attribute and any media-source found there...
2282 */
2283
2284 ipp_attribute_t *media_col, /* media-col attribute */
2285 *media_type; /* media-type attribute */
2286
2287 media_col = ippFindAttribute(job, "media-col", IPP_TAG_BEGIN_COLLECTION);
2288 if (media_col)
2289 {
2290 if ((media_type = ippFindAttribute(media_col->values[0].collection,
2291 "media-type",
2292 IPP_TAG_KEYWORD)) == NULL)
2293 media_type = ippFindAttribute(media_col->values[0].collection,
2294 "media-type", IPP_TAG_NAME);
2295
2296 if (media_type)
2297 keyword = media_type->values[0].string.text;
2298 }
2299 }
2300
2301 if (keyword)
2302 {
2303 int i; /* Looping var */
2304
2305 for (i = 0; i < pc->num_types; i ++)
88f9aafc 2306 if (!_cups_strcasecmp(keyword, pc->types[i].pwg))
f14324a7
MS
2307 return (pc->types[i].ppd);
2308 }
2309
2310 return (NULL);
2311}
2312
2313
2314/*
2315 * '_ppdCacheGetOutputBin()' - Get the PPD OutputBin associated with the keyword
2316 * string.
2317 */
2318
2319const char * /* O - PPD OutputBin or NULL */
2320_ppdCacheGetOutputBin(
2321 _ppd_cache_t *pc, /* I - PPD cache and mapping data */
2322 const char *output_bin) /* I - Keyword string */
2323{
2324 int i; /* Looping var */
2325
2326
2327 /*
2328 * Range check input...
2329 */
2330
2331 if (!pc || !output_bin)
2332 return (NULL);
2333
2334 /*
2335 * Look up the OutputBin string...
2336 */
2337
2338
2339 for (i = 0; i < pc->num_bins; i ++)
88f9aafc 2340 if (!_cups_strcasecmp(output_bin, pc->bins[i].pwg))
f14324a7
MS
2341 return (pc->bins[i].ppd);
2342
2343 return (NULL);
2344}
2345
2346
2347/*
2348 * '_ppdCacheGetPageSize()' - Get the PPD PageSize associated with the job
2349 * attributes or a keyword string.
2350 */
2351
2352const char * /* O - PPD PageSize or NULL */
2353_ppdCacheGetPageSize(
2354 _ppd_cache_t *pc, /* I - PPD cache and mapping data */
2355 ipp_t *job, /* I - Job attributes or NULL */
2356 const char *keyword, /* I - Keyword string or NULL */
2357 int *exact) /* O - 1 if exact match, 0 otherwise */
2358{
2359 int i; /* Looping var */
6961465f 2360 pwg_size_t *size, /* Current size */
f14324a7
MS
2361 *closest, /* Closest size */
2362 jobsize; /* Size data from job */
2363 int margins_set, /* Were the margins set? */
2364 dwidth, /* Difference in width */
2365 dlength, /* Difference in length */
2366 dleft, /* Difference in left margins */
2367 dright, /* Difference in right margins */
2368 dbottom, /* Difference in bottom margins */
2369 dtop, /* Difference in top margins */
2370 dmin, /* Minimum difference */
2371 dclosest; /* Closest difference */
2372 const char *ppd_name; /* PPD media name */
2373
2374
2375 DEBUG_printf(("_ppdCacheGetPageSize(pc=%p, job=%p, keyword=\"%s\", exact=%p)",
2376 pc, job, keyword, exact));
2377
2378 /*
2379 * Range check input...
2380 */
2381
2382 if (!pc || (!job && !keyword))
2383 return (NULL);
2384
2385 if (exact)
2386 *exact = 0;
2387
2388 ppd_name = keyword;
2389
2390 if (job)
2391 {
2392 /*
2393 * Try getting the PPD media name from the job attributes...
2394 */
2395
2396 ipp_attribute_t *attr; /* Job attribute */
2397
2398 if ((attr = ippFindAttribute(job, "PageSize", IPP_TAG_ZERO)) == NULL)
2399 if ((attr = ippFindAttribute(job, "PageRegion", IPP_TAG_ZERO)) == NULL)
2400 attr = ippFindAttribute(job, "media", IPP_TAG_ZERO);
2401
2402#ifdef DEBUG
2403 if (attr)
2404 DEBUG_printf(("1_ppdCacheGetPageSize: Found attribute %s (%s)",
2405 attr->name, ippTagString(attr->value_tag)));
2406 else
2407 DEBUG_puts("1_ppdCacheGetPageSize: Did not find media attribute.");
2408#endif /* DEBUG */
2409
2410 if (attr && (attr->value_tag == IPP_TAG_NAME ||
2411 attr->value_tag == IPP_TAG_KEYWORD))
2412 ppd_name = attr->values[0].string.text;
2413 }
2414
2415 DEBUG_printf(("1_ppdCacheGetPageSize: ppd_name=\"%s\"", ppd_name));
2416
2417 if (ppd_name)
2418 {
2419 /*
2420 * Try looking up the named PPD size first...
2421 */
2422
2423 for (i = pc->num_sizes, size = pc->sizes; i > 0; i --, size ++)
2424 {
2425 DEBUG_printf(("2_ppdCacheGetPageSize: size[%d]=[\"%s\" \"%s\"]",
2426 (int)(size - pc->sizes), size->map.pwg, size->map.ppd));
2427
88f9aafc
MS
2428 if (!_cups_strcasecmp(ppd_name, size->map.ppd) ||
2429 !_cups_strcasecmp(ppd_name, size->map.pwg))
f14324a7
MS
2430 {
2431 if (exact)
2432 *exact = 1;
2433
2434 DEBUG_printf(("1_ppdCacheGetPageSize: Returning \"%s\"", ppd_name));
2435
2436 return (size->map.ppd);
2437 }
2438 }
2439 }
2440
2441 if (job && !keyword)
2442 {
2443 /*
2444 * Get the size using media-col or media, with the preference being
2445 * media-col.
2446 */
2447
6961465f 2448 if (!pwgInitSize(&jobsize, job, &margins_set))
f14324a7
MS
2449 return (NULL);
2450 }
2451 else
2452 {
2453 /*
2454 * Get the size using a media keyword...
2455 */
2456
6961465f 2457 pwg_media_t *media; /* Media definition */
f14324a7
MS
2458
2459
6961465f
MS
2460 if ((media = pwgMediaForPWG(keyword)) == NULL)
2461 if ((media = pwgMediaForLegacy(keyword)) == NULL)
2462 if ((media = pwgMediaForPPD(keyword)) == NULL)
f14324a7
MS
2463 return (NULL);
2464
2465 jobsize.width = media->width;
2466 jobsize.length = media->length;
2467 margins_set = 0;
2468 }
2469
2470 /*
2471 * Now that we have the dimensions and possibly the margins, look at the
2472 * available sizes and find the match...
2473 */
2474
2475 closest = NULL;
2476 dclosest = 999999999;
2477
88f9aafc
MS
2478 if (!ppd_name || _cups_strncasecmp(ppd_name, "Custom.", 7) ||
2479 _cups_strncasecmp(ppd_name, "custom_", 7))
f14324a7
MS
2480 {
2481 for (i = pc->num_sizes, size = pc->sizes; i > 0; i --, size ++)
2482 {
2483 /*
2484 * Adobe uses a size matching algorithm with an epsilon of 5 points, which
2485 * is just about 176/2540ths...
2486 */
2487
2488 dwidth = size->width - jobsize.width;
2489 dlength = size->length - jobsize.length;
2490
2491 if (dwidth <= -176 || dwidth >= 176 || dlength <= -176 || dlength >= 176)
2492 continue;
2493
2494 if (margins_set)
2495 {
2496 /*
2497 * Use a tighter epsilon of 1 point (35/2540ths) for margins...
2498 */
2499
2500 dleft = size->left - jobsize.left;
2501 dright = size->right - jobsize.right;
2502 dtop = size->top - jobsize.top;
2503 dbottom = size->bottom - jobsize.bottom;
2504
2505 if (dleft <= -35 || dleft >= 35 || dright <= -35 || dright >= 35 ||
2506 dtop <= -35 || dtop >= 35 || dbottom <= -35 || dbottom >= 35)
2507 {
2508 dleft = dleft < 0 ? -dleft : dleft;
2509 dright = dright < 0 ? -dright : dright;
2510 dbottom = dbottom < 0 ? -dbottom : dbottom;
2511 dtop = dtop < 0 ? -dtop : dtop;
2512 dmin = dleft + dright + dbottom + dtop;
2513
2514 if (dmin < dclosest)
2515 {
2516 dclosest = dmin;
2517 closest = size;
2518 }
2519
2520 continue;
2521 }
2522 }
2523
2524 if (exact)
2525 *exact = 1;
2526
2527 DEBUG_printf(("1_ppdCacheGetPageSize: Returning \"%s\"", size->map.ppd));
2528
2529 return (size->map.ppd);
2530 }
2531 }
2532
2533 if (closest)
2534 {
2535 DEBUG_printf(("1_ppdCacheGetPageSize: Returning \"%s\" (closest)",
2536 closest->map.ppd));
2537
2538 return (closest->map.ppd);
2539 }
2540
2541 /*
2542 * If we get here we need to check for custom page size support...
2543 */
2544
2545 if (jobsize.width >= pc->custom_min_width &&
2546 jobsize.width <= pc->custom_max_width &&
2547 jobsize.length >= pc->custom_min_length &&
2548 jobsize.length <= pc->custom_max_length)
2549 {
2550 /*
2551 * In range, format as Custom.WWWWxLLLL (points).
2552 */
2553
2554 snprintf(pc->custom_ppd_size, sizeof(pc->custom_ppd_size), "Custom.%dx%d",
6961465f 2555 (int)PWG_TO_POINTS(jobsize.width), (int)PWG_TO_POINTS(jobsize.length));
f14324a7
MS
2556
2557 if (margins_set && exact)
2558 {
2559 dleft = pc->custom_size.left - jobsize.left;
2560 dright = pc->custom_size.right - jobsize.right;
2561 dtop = pc->custom_size.top - jobsize.top;
2562 dbottom = pc->custom_size.bottom - jobsize.bottom;
2563
2564 if (dleft > -35 && dleft < 35 && dright > -35 && dright < 35 &&
2565 dtop > -35 && dtop < 35 && dbottom > -35 && dbottom < 35)
2566 *exact = 1;
2567 }
2568 else if (exact)
2569 *exact = 1;
2570
2571 DEBUG_printf(("1_ppdCacheGetPageSize: Returning \"%s\" (custom)",
2572 pc->custom_ppd_size));
2573
2574 return (pc->custom_ppd_size);
2575 }
2576
2577 /*
2578 * No custom page size support or the size is out of range - return NULL.
2579 */
2580
2581 DEBUG_puts("1_ppdCacheGetPageSize: Returning NULL");
2582
2583 return (NULL);
2584}
2585
2586
2587/*
2588 * '_ppdCacheGetSize()' - Get the PWG size associated with a PPD PageSize.
2589 */
2590
6961465f 2591pwg_size_t * /* O - PWG size or NULL */
f14324a7
MS
2592_ppdCacheGetSize(
2593 _ppd_cache_t *pc, /* I - PPD cache and mapping data */
2594 const char *page_size) /* I - PPD PageSize */
2595{
dcb445bc 2596 int i; /* Looping var */
6961465f
MS
2597 pwg_media_t *media; /* Media */
2598 pwg_size_t *size; /* Current size */
f14324a7
MS
2599
2600
2601 /*
2602 * Range check input...
2603 */
2604
2605 if (!pc || !page_size)
2606 return (NULL);
2607
88f9aafc 2608 if (!_cups_strncasecmp(page_size, "Custom.", 7))
f14324a7
MS
2609 {
2610 /*
2611 * Custom size; size name can be one of the following:
2612 *
2613 * Custom.WIDTHxLENGTHin - Size in inches
2614 * Custom.WIDTHxLENGTHft - Size in feet
2615 * Custom.WIDTHxLENGTHcm - Size in centimeters
2616 * Custom.WIDTHxLENGTHmm - Size in millimeters
2617 * Custom.WIDTHxLENGTHm - Size in meters
2618 * Custom.WIDTHxLENGTH[pt] - Size in points
2619 */
2620
2621 double w, l; /* Width and length of page */
2622 char *ptr; /* Pointer into PageSize */
2623 struct lconv *loc; /* Locale data */
2624
2625 loc = localeconv();
2626 w = (float)_cupsStrScand(page_size + 7, &ptr, loc);
2627 if (!ptr || *ptr != 'x')
2628 return (NULL);
2629
2630 l = (float)_cupsStrScand(ptr + 1, &ptr, loc);
2631 if (!ptr)
2632 return (NULL);
2633
88f9aafc 2634 if (!_cups_strcasecmp(ptr, "in"))
f14324a7
MS
2635 {
2636 w *= 2540.0;
2637 l *= 2540.0;
2638 }
88f9aafc 2639 else if (!_cups_strcasecmp(ptr, "ft"))
f14324a7
MS
2640 {
2641 w *= 12.0 * 2540.0;
2642 l *= 12.0 * 2540.0;
2643 }
88f9aafc 2644 else if (!_cups_strcasecmp(ptr, "mm"))
f14324a7
MS
2645 {
2646 w *= 100.0;
2647 l *= 100.0;
2648 }
88f9aafc 2649 else if (!_cups_strcasecmp(ptr, "cm"))
f14324a7
MS
2650 {
2651 w *= 1000.0;
2652 l *= 1000.0;
2653 }
88f9aafc 2654 else if (!_cups_strcasecmp(ptr, "m"))
f14324a7
MS
2655 {
2656 w *= 100000.0;
2657 l *= 100000.0;
2658 }
2659 else
2660 {
2661 w *= 2540.0 / 72.0;
2662 l *= 2540.0 / 72.0;
2663 }
2664
2665 pc->custom_size.width = (int)w;
2666 pc->custom_size.length = (int)l;
2667
2668 return (&(pc->custom_size));
2669 }
2670
2671 /*
2672 * Not a custom size - look it up...
2673 */
2674
2675 for (i = pc->num_sizes, size = pc->sizes; i > 0; i --, size ++)
dcb445bc
MS
2676 if (!_cups_strcasecmp(page_size, size->map.ppd) ||
2677 !_cups_strcasecmp(page_size, size->map.pwg))
f14324a7
MS
2678 return (size);
2679
dcb445bc
MS
2680 /*
2681 * Look up standard sizes...
2682 */
2683
6961465f
MS
2684 if ((media = pwgMediaForPPD(page_size)) == NULL)
2685 if ((media = pwgMediaForLegacy(page_size)) == NULL)
2686 media = pwgMediaForPWG(page_size);
dcb445bc
MS
2687
2688 if (media)
2689 {
2690 pc->custom_size.width = media->width;
2691 pc->custom_size.length = media->length;
2692
2693 return (&(pc->custom_size));
2694 }
2695
f14324a7
MS
2696 return (NULL);
2697}
2698
2699
2700/*
2701 * '_ppdCacheGetSource()' - Get the PWG media-source associated with a PPD
2702 * InputSlot.
2703 */
2704
2705const char * /* O - PWG media-source keyword */
2706_ppdCacheGetSource(
2707 _ppd_cache_t *pc, /* I - PPD cache and mapping data */
2708 const char *input_slot) /* I - PPD InputSlot */
2709{
2710 int i; /* Looping var */
6961465f 2711 pwg_map_t *source; /* Current source */
f14324a7
MS
2712
2713
2714 /*
2715 * Range check input...
2716 */
2717
2718 if (!pc || !input_slot)
2719 return (NULL);
2720
2721 for (i = pc->num_sources, source = pc->sources; i > 0; i --, source ++)
88f9aafc 2722 if (!_cups_strcasecmp(input_slot, source->ppd))
f14324a7
MS
2723 return (source->pwg);
2724
2725 return (NULL);
2726}
2727
2728
2729/*
2730 * '_ppdCacheGetType()' - Get the PWG media-type associated with a PPD
2731 * MediaType.
2732 */
2733
2734const char * /* O - PWG media-type keyword */
2735_ppdCacheGetType(
2736 _ppd_cache_t *pc, /* I - PPD cache and mapping data */
2737 const char *media_type) /* I - PPD MediaType */
2738{
2739 int i; /* Looping var */
6961465f 2740 pwg_map_t *type; /* Current type */
f14324a7
MS
2741
2742
2743 /*
2744 * Range check input...
2745 */
2746
2747 if (!pc || !media_type)
2748 return (NULL);
2749
2750 for (i = pc->num_types, type = pc->types; i > 0; i --, type ++)
88f9aafc 2751 if (!_cups_strcasecmp(media_type, type->ppd))
f14324a7
MS
2752 return (type->pwg);
2753
2754 return (NULL);
2755}
2756
2757
2758/*
2759 * '_ppdCacheWriteFile()' - Write PWG mapping data to a file.
2760 */
2761
2762int /* O - 1 on success, 0 on failure */
2763_ppdCacheWriteFile(
2764 _ppd_cache_t *pc, /* I - PPD cache and mapping data */
2765 const char *filename, /* I - File to write */
2766 ipp_t *attrs) /* I - Attributes to write, if any */
2767{
dcb445bc
MS
2768 int i, j, k; /* Looping vars */
2769 cups_file_t *fp; /* Output file */
6961465f
MS
2770 pwg_size_t *size; /* Current size */
2771 pwg_map_t *map; /* Current map */
dcb445bc
MS
2772 _pwg_finishings_t *f; /* Current finishing option */
2773 cups_option_t *option; /* Current option */
4f63d6cd 2774 const char *value; /* String value */
dcb445bc 2775 char newfile[1024]; /* New filename */
f14324a7
MS
2776
2777
2778 /*
2779 * Range check input...
2780 */
2781
2782 if (!pc || !filename)
2783 {
cb7f98ee 2784 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
f14324a7
MS
2785 return (0);
2786 }
2787
2788 /*
2789 * Open the file and write with compression...
2790 */
2791
321d8d57
MS
2792 snprintf(newfile, sizeof(newfile), "%s.N", filename);
2793 if ((fp = cupsFileOpen(newfile, "w9")) == NULL)
f14324a7 2794 {
cb7f98ee 2795 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
f14324a7
MS
2796 return (0);
2797 }
2798
2799 /*
2800 * Standard header...
2801 */
2802
2803 cupsFilePrintf(fp, "#CUPS-PPD-CACHE-%d\n", _PPD_CACHE_VERSION);
2804
2805 /*
2806 * Output bins...
2807 */
2808
2809 if (pc->num_bins > 0)
2810 {
2811 cupsFilePrintf(fp, "NumBins %d\n", pc->num_bins);
2812 for (i = pc->num_bins, map = pc->bins; i > 0; i --, map ++)
2813 cupsFilePrintf(fp, "Bin %s %s\n", map->pwg, map->ppd);
2814 }
2815
2816 /*
2817 * Media sizes...
2818 */
2819
2820 cupsFilePrintf(fp, "NumSizes %d\n", pc->num_sizes);
2821 for (i = pc->num_sizes, size = pc->sizes; i > 0; i --, size ++)
2822 cupsFilePrintf(fp, "Size %s %s %d %d %d %d %d %d\n", size->map.pwg,
2823 size->map.ppd, size->width, size->length, size->left,
2824 size->bottom, size->right, size->top);
2825 if (pc->custom_max_width > 0)
2826 cupsFilePrintf(fp, "CustomSize %d %d %d %d %d %d %d %d\n",
2827 pc->custom_max_width, pc->custom_max_length,
2828 pc->custom_min_width, pc->custom_min_length,
2829 pc->custom_size.left, pc->custom_size.bottom,
2830 pc->custom_size.right, pc->custom_size.top);
2831
2832 /*
2833 * Media sources...
2834 */
2835
2836 if (pc->source_option)
2837 cupsFilePrintf(fp, "SourceOption %s\n", pc->source_option);
2838
2839 if (pc->num_sources > 0)
2840 {
2841 cupsFilePrintf(fp, "NumSources %d\n", pc->num_sources);
2842 for (i = pc->num_sources, map = pc->sources; i > 0; i --, map ++)
2843 cupsFilePrintf(fp, "Source %s %s\n", map->pwg, map->ppd);
2844 }
2845
2846 /*
2847 * Media types...
2848 */
2849
2850 if (pc->num_types > 0)
2851 {
2852 cupsFilePrintf(fp, "NumTypes %d\n", pc->num_types);
2853 for (i = pc->num_types, map = pc->types; i > 0; i --, map ++)
2854 cupsFilePrintf(fp, "Type %s %s\n", map->pwg, map->ppd);
2855 }
2856
2857 /*
2858 * Presets...
2859 */
2860
2861 for (i = _PWG_PRINT_COLOR_MODE_MONOCHROME; i < _PWG_PRINT_COLOR_MODE_MAX; i ++)
2862 for (j = _PWG_PRINT_QUALITY_DRAFT; j < _PWG_PRINT_QUALITY_MAX; j ++)
2863 if (pc->num_presets[i][j])
2864 {
2865 cupsFilePrintf(fp, "Preset %d %d", i, j);
2866 for (k = pc->num_presets[i][j], option = pc->presets[i][j];
2867 k > 0;
2868 k --, option ++)
2869 cupsFilePrintf(fp, " %s=%s", option->name, option->value);
2870 cupsFilePutChar(fp, '\n');
2871 }
2872
2873 /*
2874 * Duplex/sides...
2875 */
2876
2877 if (pc->sides_option)
2878 cupsFilePrintf(fp, "SidesOption %s\n", pc->sides_option);
2879
2880 if (pc->sides_1sided)
2881 cupsFilePrintf(fp, "Sides1Sided %s\n", pc->sides_1sided);
2882
2883 if (pc->sides_2sided_long)
2884 cupsFilePrintf(fp, "Sides2SidedLong %s\n", pc->sides_2sided_long);
2885
2886 if (pc->sides_2sided_short)
2887 cupsFilePrintf(fp, "Sides2SidedShort %s\n", pc->sides_2sided_short);
2888
2889 /*
2890 * Product, cupsFilter, cupsFilter2, and cupsPreFilter...
2891 */
2892
2893 if (pc->product)
2894 cupsFilePutConf(fp, "Product", pc->product);
2895
2896 for (value = (const char *)cupsArrayFirst(pc->filters);
2897 value;
2898 value = (const char *)cupsArrayNext(pc->filters))
2899 cupsFilePutConf(fp, "Filter", value);
2900
2901 for (value = (const char *)cupsArrayFirst(pc->prefilters);
2902 value;
2903 value = (const char *)cupsArrayNext(pc->prefilters))
2904 cupsFilePutConf(fp, "PreFilter", value);
2905
82f97232
MS
2906 cupsFilePrintf(fp, "SingleFile %s\n", pc->single_file ? "true" : "false");
2907
dcb445bc
MS
2908 /*
2909 * Finishing options...
2910 */
2911
2912 for (f = (_pwg_finishings_t *)cupsArrayFirst(pc->finishings);
2913 f;
2914 f = (_pwg_finishings_t *)cupsArrayNext(pc->finishings))
2915 {
2916 cupsFilePrintf(fp, "Finishings %d", f->value);
2917 for (i = f->num_options, option = f->options; i > 0; i --, option ++)
2918 cupsFilePrintf(fp, " %s=%s", option->name, option->value);
2919 cupsFilePutChar(fp, '\n');
2920 }
2921
4f63d6cd
MS
2922 for (value = (const char *)cupsArrayFirst(pc->templates); value; value = (const char *)cupsArrayNext(pc->templates))
2923 cupsFilePutConf(fp, "FinishingTemplate", value);
2924
3e7fe0ca
MS
2925 /*
2926 * Max copies...
2927 */
2928
2929 cupsFilePrintf(fp, "MaxCopies %d\n", pc->max_copies);
2930
5a9febac
MS
2931 /*
2932 * Accounting/quota/PIN/managed printing values...
2933 */
2934
a469f8a5
MS
2935 if (pc->charge_info_uri)
2936 cupsFilePutConf(fp, "ChargeInfoURI", pc->charge_info_uri);
2937
5a9febac
MS
2938 cupsFilePrintf(fp, "AccountId %s\n", pc->account_id ? "true" : "false");
2939 cupsFilePrintf(fp, "AccountingUserId %s\n",
2940 pc->accounting_user_id ? "true" : "false");
2941
2942 if (pc->password)
2943 cupsFilePutConf(fp, "Password", pc->password);
2944
2945 for (value = (char *)cupsArrayFirst(pc->mandatory);
2946 value;
2947 value = (char *)cupsArrayNext(pc->mandatory))
2948 cupsFilePutConf(fp, "Mandatory", value);
2949
89550f3f
MS
2950 /*
2951 * (Remote) strings file...
2952 */
2953
2954 if (pc->strings_uri)
2955 cupsFilePutConf(fp, "StringsURI", pc->strings_uri);
2956
c1420c87
MS
2957 /*
2958 * Support files...
2959 */
2960
2961 for (value = (char *)cupsArrayFirst(pc->support_files);
2962 value;
2963 value = (char *)cupsArrayNext(pc->support_files))
2964 cupsFilePutConf(fp, "SupportFile", value);
2965
f14324a7
MS
2966 /*
2967 * IPP attributes, if any...
2968 */
2969
2970 if (attrs)
2971 {
2972 cupsFilePrintf(fp, "IPP " CUPS_LLFMT "\n", CUPS_LLCAST ippLength(attrs));
2973
cb7f98ee 2974 attrs->state = IPP_STATE_IDLE;
f14324a7
MS
2975 ippWriteIO(fp, (ipp_iocb_t)cupsFileWrite, 1, NULL, attrs);
2976 }
2977
2978 /*
2979 * Close and return...
2980 */
2981
321d8d57
MS
2982 if (cupsFileClose(fp))
2983 {
2984 unlink(newfile);
2985 return (0);
2986 }
2987
2988 unlink(filename);
2989 return (!rename(newfile, filename));
f14324a7
MS
2990}
2991
2992
d9fc71e4
MS
2993/*
2994 * '_ppdCreateFromIPP()' - Create a PPD file describing the capabilities
2995 * of an IPP printer.
2996 */
2997
d4259b45 2998char * /* O - PPD filename or @code NULL@ on error */
d9fc71e4
MS
2999_ppdCreateFromIPP(char *buffer, /* I - Filename buffer */
3000 size_t bufsize, /* I - Size of filename buffer */
3001 ipp_t *response) /* I - Get-Printer-Attributes response */
3002{
3003 cups_file_t *fp; /* PPD file */
982be458
MS
3004 cups_array_t *sizes; /* Media sizes supported by printer */
3005 cups_size_t *size; /* Current media size */
d9fc71e4
MS
3006 ipp_attribute_t *attr, /* xxx-supported */
3007 *defattr, /* xxx-default */
3b6c3c8e 3008 *quality, /* print-quality-supported */
d9fc71e4 3009 *x_dim, *y_dim; /* Media dimensions */
982be458
MS
3010 ipp_t *media_col, /* Media collection */
3011 *media_size; /* Media size collection */
d9fc71e4
MS
3012 char make[256], /* Make and model */
3013 *model, /* Model name */
3014 ppdname[PPD_MAX_NAME];
3015 /* PPD keyword */
3016 int i, j, /* Looping vars */
3017 count, /* Number of values */
3018 bottom, /* Largest bottom margin */
3019 left, /* Largest left margin */
3020 right, /* Largest right margin */
d4259b45 3021 top, /* Largest top margin */
982be458
MS
3022 max_length = 0, /* Maximum custom size */
3023 max_width = 0,
3024 min_length = INT_MAX,
3025 /* Minimum custom size */
3026 min_width = INT_MAX,
d4259b45
MS
3027 is_apple = 0, /* Does the printer support Apple raster? */
3028 is_pdf = 0, /* Does the printer support PDF? */
3029 is_pwg = 0; /* Does the printer support PWG Raster? */
d9fc71e4
MS
3030 pwg_media_t *pwg; /* PWG media size */
3031 int xres, yres; /* Resolution values */
fa76bc3d
MS
3032 int resolutions[1000];
3033 /* Array of resolution indices */
edf09ba9
MS
3034 char msgid[256]; /* Message identifier (attr.value) */
3035 const char *keyword, /* Keyword value */
3036 *msgstr; /* Localized string */
c0886523
MS
3037 cups_lang_t *lang = cupsLangDefault();
3038 /* Localization info */
89550f3f 3039 cups_array_t *strings = NULL;/* Printer strings file */
560634d3
MS
3040 struct lconv *loc = localeconv();
3041 /* Locale data */
27ee2c4d
MS
3042 cups_array_t *fin_options = NULL;
3043 /* Finishing options */
d9fc71e4
MS
3044
3045
3046 /*
3047 * Range check input...
3048 */
3049
fffed089
MS
3050 if (buffer)
3051 *buffer = '\0';
3052
a946858f
MS
3053 if (!buffer || bufsize < 1)
3054 {
3055 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
d9fc71e4 3056 return (NULL);
a946858f
MS
3057 }
3058
3059 if (!response)
3060 {
3061 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("No IPP attributes."), 1);
3062 return (NULL);
3063 }
d9fc71e4
MS
3064
3065 /*
3066 * Open a temporary file for the PPD...
3067 */
3068
3069 if ((fp = cupsTempFile2(buffer, (int)bufsize)) == NULL)
a946858f
MS
3070 {
3071 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
d9fc71e4 3072 return (NULL);
a946858f 3073 }
d9fc71e4
MS
3074
3075 /*
3076 * Standard stuff for PPD file...
3077 */
3078
3079 cupsFilePuts(fp, "*PPD-Adobe: \"4.3\"\n");
3080 cupsFilePuts(fp, "*FormatVersion: \"4.3\"\n");
3081 cupsFilePrintf(fp, "*FileVersion: \"%d.%d\"\n", CUPS_VERSION_MAJOR, CUPS_VERSION_MINOR);
3082 cupsFilePuts(fp, "*LanguageVersion: English\n");
3083 cupsFilePuts(fp, "*LanguageEncoding: ISOLatin1\n");
3084 cupsFilePuts(fp, "*PSVersion: \"(3010.000) 0\"\n");
3085 cupsFilePuts(fp, "*LanguageLevel: \"3\"\n");
3086 cupsFilePuts(fp, "*FileSystem: False\n");
3087 cupsFilePuts(fp, "*PCFileName: \"ippeve.ppd\"\n");
3088
3089 if ((attr = ippFindAttribute(response, "printer-make-and-model", IPP_TAG_TEXT)) != NULL)
3090 strlcpy(make, ippGetString(attr, 0, NULL), sizeof(make));
3091 else
3092 strlcpy(make, "Unknown Printer", sizeof(make));
3093
3094 if (!_cups_strncasecmp(make, "Hewlett Packard ", 16) ||
3095 !_cups_strncasecmp(make, "Hewlett-Packard ", 16))
3096 {
3097 model = make + 16;
3098 strlcpy(make, "HP", sizeof(make));
3099 }
3100 else if ((model = strchr(make, ' ')) != NULL)
3101 *model++ = '\0';
3102 else
3103 model = make;
3104
3105 cupsFilePrintf(fp, "*Manufacturer: \"%s\"\n", make);
3106 cupsFilePrintf(fp, "*ModelName: \"%s\"\n", model);
3107 cupsFilePrintf(fp, "*Product: \"(%s)\"\n", model);
3108 cupsFilePrintf(fp, "*NickName: \"%s\"\n", model);
3109 cupsFilePrintf(fp, "*ShortNickName: \"%s\"\n", model);
3110
fb2d5470
MS
3111 if ((attr = ippFindAttribute(response, "color-supported", IPP_TAG_BOOLEAN)) != NULL && ippGetBoolean(attr, 0))
3112 cupsFilePuts(fp, "*ColorDevice: True\n");
3113 else
3114 cupsFilePuts(fp, "*ColorDevice: False\n");
3115
d9fc71e4
MS
3116 cupsFilePrintf(fp, "*cupsVersion: %d.%d\n", CUPS_VERSION_MAJOR, CUPS_VERSION_MINOR);
3117 cupsFilePuts(fp, "*cupsSNMPSupplies: False\n");
89550f3f
MS
3118 cupsFilePrintf(fp, "*cupsLanguages: \"%s\"\n", lang->language);
3119
3120 if ((attr = ippFindAttribute(response, "printer-more-info", IPP_TAG_URI)) != NULL)
3121 cupsFilePrintf(fp, "*APSupplies: \"%s\"\n", ippGetString(attr, 0, NULL));
3122
3123 if ((attr = ippFindAttribute(response, "printer-charge-info-uri", IPP_TAG_URI)) != NULL)
3124 cupsFilePrintf(fp, "*cupsChargeInfoURI: \"%s\"\n", ippGetString(attr, 0, NULL));
3125
3126 if ((attr = ippFindAttribute(response, "printer-strings-uri", IPP_TAG_URI)) != NULL)
3127 {
3128 http_t *http = NULL; /* Connection to printer */
3129 char stringsfile[1024]; /* Temporary strings file */
3130
3131 if (cups_get_url(&http, ippGetString(attr, 0, NULL), stringsfile, sizeof(stringsfile)))
3132 {
3133 cupsFilePrintf(fp, "*cupsStringsURI: \"%s\"\n", ippGetString(attr, 0, NULL));
3134
3135 strings = _cupsMessageLoad(stringsfile, _CUPS_MESSAGE_STRINGS | _CUPS_MESSAGE_UNQUOTE);
3136
3137 unlink(stringsfile);
3138 }
3139
3140 if (http)
3141 httpClose(http);
3142 }
d9fc71e4
MS
3143
3144 /*
3145 * Filters...
3146 */
3147
3148 if ((attr = ippFindAttribute(response, "document-format-supported", IPP_TAG_MIMETYPE)) != NULL)
3149 {
d4259b45
MS
3150 is_apple = ippContainsString(attr, "image/urf");
3151 is_pdf = ippContainsString(attr, "application/pdf");
3152 is_pwg = ippContainsString(attr, "image/pwg-raster");
3153
d9fc71e4
MS
3154 for (i = 0, count = ippGetCount(attr); i < count; i ++)
3155 {
3156 const char *format = ippGetString(attr, i, NULL);
3157 /* PDL */
3158
d4259b45 3159 /*
07428f6a 3160 * Write cupsFilter2 lines for supported formats...
d4259b45
MS
3161 */
3162
d9fc71e4
MS
3163 if (!_cups_strcasecmp(format, "application/pdf"))
3164 cupsFilePuts(fp, "*cupsFilter2: \"application/vnd.cups-pdf application/pdf 10 -\"\n");
1add2337
MS
3165 else if (!_cups_strcasecmp(format, "image/jpeg") || !_cups_strcasecmp(format, "image/png"))
3166 cupsFilePrintf(fp, "*cupsFilter2: \"%s %s 0 -\"\n", format, format);
3167 else if (!_cups_strcasecmp(format, "image/pwg-raster") || !_cups_strcasecmp(format, "image/urf"))
3168 cupsFilePrintf(fp, "*cupsFilter2: \"%s %s 100 -\"\n", format, format);
d9fc71e4
MS
3169 }
3170 }
3171
d4259b45
MS
3172 if (!is_apple && !is_pdf && !is_pwg)
3173 goto bad_ppd;
3174
d9fc71e4
MS
3175 /*
3176 * PageSize/PageRegion/ImageableArea/PaperDimension
3177 */
3178
3179 if ((attr = ippFindAttribute(response, "media-bottom-margin-supported", IPP_TAG_INTEGER)) != NULL)
3180 {
3181 for (i = 1, bottom = ippGetInteger(attr, 0), count = ippGetCount(attr); i < count; i ++)
3182 if (ippGetInteger(attr, i) > bottom)
3183 bottom = ippGetInteger(attr, i);
3184 }
3185 else
3186 bottom = 1270;
3187
3188 if ((attr = ippFindAttribute(response, "media-left-margin-supported", IPP_TAG_INTEGER)) != NULL)
3189 {
3190 for (i = 1, left = ippGetInteger(attr, 0), count = ippGetCount(attr); i < count; i ++)
3191 if (ippGetInteger(attr, i) > left)
3192 left = ippGetInteger(attr, i);
3193 }
3194 else
3195 left = 635;
3196
3197 if ((attr = ippFindAttribute(response, "media-right-margin-supported", IPP_TAG_INTEGER)) != NULL)
3198 {
3199 for (i = 1, right = ippGetInteger(attr, 0), count = ippGetCount(attr); i < count; i ++)
3200 if (ippGetInteger(attr, i) > right)
3201 right = ippGetInteger(attr, i);
3202 }
3203 else
3204 right = 635;
3205
3206 if ((attr = ippFindAttribute(response, "media-top-margin-supported", IPP_TAG_INTEGER)) != NULL)
3207 {
3208 for (i = 1, top = ippGetInteger(attr, 0), count = ippGetCount(attr); i < count; i ++)
3209 if (ippGetInteger(attr, i) > top)
3210 top = ippGetInteger(attr, i);
3211 }
3212 else
3213 top = 1270;
3214
3215 if ((defattr = ippFindAttribute(response, "media-col-default", IPP_TAG_BEGIN_COLLECTION)) != NULL)
3216 {
3217 if ((attr = ippFindAttribute(ippGetCollection(defattr, 0), "media-size", IPP_TAG_BEGIN_COLLECTION)) != NULL)
3218 {
3219 media_size = ippGetCollection(attr, 0);
3220 x_dim = ippFindAttribute(media_size, "x-dimension", IPP_TAG_INTEGER);
3221 y_dim = ippFindAttribute(media_size, "y-dimension", IPP_TAG_INTEGER);
3222
2a8afc20 3223 if (x_dim && y_dim && (pwg = pwgMediaForSize(ippGetInteger(x_dim, 0), ippGetInteger(y_dim, 0))) != NULL)
d9fc71e4 3224 strlcpy(ppdname, pwg->ppd, sizeof(ppdname));
d9fc71e4
MS
3225 else
3226 strlcpy(ppdname, "Unknown", sizeof(ppdname));
3227 }
3228 else
3229 strlcpy(ppdname, "Unknown", sizeof(ppdname));
3230 }
670172ea
MS
3231 else if ((pwg = pwgMediaForPWG(ippGetString(ippFindAttribute(response, "media-default", IPP_TAG_ZERO), 0, NULL))) != NULL)
3232 strlcpy(ppdname, pwg->ppd, sizeof(ppdname));
3233 else
3234 strlcpy(ppdname, "Unknown", sizeof(ppdname));
d9fc71e4 3235
982be458 3236 sizes = cupsArrayNew3((cups_array_func_t)pwg_compare_sizes, NULL, NULL, 0, (cups_acopy_func_t)pwg_copy_size, (cups_afree_func_t)free);
7fad1ee9 3237
982be458
MS
3238 if ((attr = ippFindAttribute(response, "media-col-database", IPP_TAG_BEGIN_COLLECTION)) != NULL)
3239 {
d9fc71e4
MS
3240 for (i = 0, count = ippGetCount(attr); i < count; i ++)
3241 {
982be458
MS
3242 cups_size_t temp; /* Current size */
3243 ipp_attribute_t *margin; /* media-xxx-margin attribute */
d9fc71e4 3244
982be458
MS
3245 media_col = ippGetCollection(attr, i);
3246 media_size = ippGetCollection(ippFindAttribute(media_col, "media-size", IPP_TAG_BEGIN_COLLECTION), 0);
3247 x_dim = ippFindAttribute(media_size, "x-dimension", IPP_TAG_ZERO);
3248 y_dim = ippFindAttribute(media_size, "y-dimension", IPP_TAG_ZERO);
3249 pwg = pwgMediaForSize(ippGetInteger(x_dim, 0), ippGetInteger(y_dim, 0));
670172ea
MS
3250
3251 if (pwg)
d9fc71e4 3252 {
982be458
MS
3253 temp.width = pwg->width;
3254 temp.length = pwg->length;
560634d3 3255
982be458
MS
3256 if ((margin = ippFindAttribute(media_col, "media-bottom-margin", IPP_TAG_INTEGER)) != NULL)
3257 temp.bottom = ippGetInteger(margin, 0);
3258 else
3259 temp.bottom = bottom;
7fad1ee9 3260
982be458
MS
3261 if ((margin = ippFindAttribute(media_col, "media-left-margin", IPP_TAG_INTEGER)) != NULL)
3262 temp.left = ippGetInteger(margin, 0);
3263 else
3264 temp.left = left;
3265
3266 if ((margin = ippFindAttribute(media_col, "media-right-margin", IPP_TAG_INTEGER)) != NULL)
3267 temp.right = ippGetInteger(margin, 0);
3268 else
3269 temp.right = right;
7fad1ee9 3270
982be458
MS
3271 if ((margin = ippFindAttribute(media_col, "media-top-margin", IPP_TAG_INTEGER)) != NULL)
3272 temp.top = ippGetInteger(margin, 0);
3273 else
3274 temp.top = top;
560634d3 3275
982be458
MS
3276 if (temp.bottom == 0 && temp.left == 0 && temp.right == 0 && temp.top == 0)
3277 snprintf(temp.media, sizeof(temp.media), "%s.Borderless", pwg->ppd);
3278 else
3279 strlcpy(temp.media, pwg->ppd, sizeof(temp.media));
3280
3281 if (!cupsArrayFind(sizes, &temp))
3282 cupsArrayAdd(sizes, &temp);
d9fc71e4 3283 }
982be458
MS
3284 else if (ippGetValueTag(x_dim) == IPP_TAG_RANGE || ippGetValueTag(y_dim) == IPP_TAG_RANGE)
3285 {
3286 /*
3287 * Custom size - record the min/max values...
3288 */
d9fc71e4 3289
982be458 3290 int lower, upper; /* Range values */
7fad1ee9 3291
982be458
MS
3292 if (ippGetValueTag(x_dim) == IPP_TAG_RANGE)
3293 lower = ippGetRange(x_dim, 0, &upper);
3294 else
3295 lower = upper = ippGetInteger(x_dim, 0);
3296
3297 if (lower < min_width)
3298 min_width = lower;
3299 if (upper > max_width)
3300 max_width = upper;
3301
3302 if (ippGetValueTag(y_dim) == IPP_TAG_RANGE)
3303 lower = ippGetRange(y_dim, 0, &upper);
3304 else
3305 lower = upper = ippGetInteger(y_dim, 0);
3306
3307 if (lower < min_length)
3308 min_length = lower;
3309 if (upper > max_length)
3310 max_length = upper;
3311 }
3312 }
3313
3314 if ((max_width == 0 || max_length == 0) && (attr = ippFindAttribute(response, "media-size-supported", IPP_TAG_BEGIN_COLLECTION)) != NULL)
d9fc71e4 3315 {
982be458
MS
3316 /*
3317 * Some printers don't list custom size support in media-col-database...
3318 */
3319
3320 for (i = 0, count = ippGetCount(attr); i < count; i ++)
3be8e026 3321 {
982be458
MS
3322 media_size = ippGetCollection(attr, i);
3323 x_dim = ippFindAttribute(media_size, "x-dimension", IPP_TAG_ZERO);
3324 y_dim = ippFindAttribute(media_size, "y-dimension", IPP_TAG_ZERO);
3325
3326 if (ippGetValueTag(x_dim) == IPP_TAG_RANGE || ippGetValueTag(y_dim) == IPP_TAG_RANGE)
3327 {
3328 /*
3329 * Custom size - record the min/max values...
3330 */
d9fc71e4 3331
982be458
MS
3332 int lower, upper; /* Range values */
3333
3334 if (ippGetValueTag(x_dim) == IPP_TAG_RANGE)
3335 lower = ippGetRange(x_dim, 0, &upper);
3336 else
3337 lower = upper = ippGetInteger(x_dim, 0);
3338
3339 if (lower < min_width)
3340 min_width = lower;
3341 if (upper > max_width)
3342 max_width = upper;
3343
3344 if (ippGetValueTag(y_dim) == IPP_TAG_RANGE)
3345 lower = ippGetRange(y_dim, 0, &upper);
3346 else
3347 lower = upper = ippGetInteger(y_dim, 0);
3348
3349 if (lower < min_length)
3350 min_length = lower;
3351 if (upper > max_length)
3352 max_length = upper;
3353 }
3be8e026 3354 }
982be458
MS
3355 }
3356 }
3357 else if ((attr = ippFindAttribute(response, "media-size-supported", IPP_TAG_BEGIN_COLLECTION)) != NULL)
3358 {
3359 for (i = 0, count = ippGetCount(attr); i < count; i ++)
3360 {
3361 cups_size_t temp; /* Current size */
3362
3363 media_size = ippGetCollection(attr, i);
3364 x_dim = ippFindAttribute(media_size, "x-dimension", IPP_TAG_ZERO);
3365 y_dim = ippFindAttribute(media_size, "y-dimension", IPP_TAG_ZERO);
3366 pwg = pwgMediaForSize(ippGetInteger(x_dim, 0), ippGetInteger(y_dim, 0));
3be8e026
MS
3367
3368 if (pwg)
d9fc71e4 3369 {
982be458
MS
3370 temp.width = pwg->width;
3371 temp.length = pwg->length;
3372 temp.bottom = bottom;
3373 temp.left = left;
3374 temp.right = right;
3375 temp.top = top;
3376
3377 if (temp.bottom == 0 && temp.left == 0 && temp.right == 0 && temp.top == 0)
3378 snprintf(temp.media, sizeof(temp.media), "%s.Borderless", pwg->ppd);
3379 else
3380 strlcpy(temp.media, pwg->ppd, sizeof(temp.media));
560634d3 3381
982be458
MS
3382 if (!cupsArrayFind(sizes, &temp))
3383 cupsArrayAdd(sizes, &temp);
3384 }
3385 else if (ippGetValueTag(x_dim) == IPP_TAG_RANGE || ippGetValueTag(y_dim) == IPP_TAG_RANGE)
3386 {
3387 /*
3388 * Custom size - record the min/max values...
3389 */
7fad1ee9 3390
982be458 3391 int lower, upper; /* Range values */
7fad1ee9 3392
982be458
MS
3393 if (ippGetValueTag(x_dim) == IPP_TAG_RANGE)
3394 lower = ippGetRange(x_dim, 0, &upper);
3395 else
3396 lower = upper = ippGetInteger(x_dim, 0);
560634d3 3397
982be458
MS
3398 if (lower < min_width)
3399 min_width = lower;
3400 if (upper > max_width)
3401 max_width = upper;
d9fc71e4 3402
982be458
MS
3403 if (ippGetValueTag(y_dim) == IPP_TAG_RANGE)
3404 lower = ippGetRange(y_dim, 0, &upper);
3405 else
3406 lower = upper = ippGetInteger(y_dim, 0);
7fad1ee9 3407
982be458
MS
3408 if (lower < min_length)
3409 min_length = lower;
3410 if (upper > max_length)
3411 max_length = upper;
3412 }
3413 }
3414 }
3415 else if ((attr = ippFindAttribute(response, "media-supported", IPP_TAG_ZERO)) != NULL)
3416 {
d9fc71e4
MS
3417 for (i = 0, count = ippGetCount(attr); i < count; i ++)
3418 {
982be458
MS
3419 const char *pwg_size = ippGetString(attr, i, NULL);
3420 /* PWG size name */
3421 cups_size_t temp; /* Current size */
3422
3423 if ((pwg = pwgMediaForPWG(pwg_size)) != NULL)
3be8e026 3424 {
982be458
MS
3425 if (strstr(pwg_size, "_max_") || strstr(pwg_size, "_max."))
3426 {
3427 if (pwg->width > max_width)
3428 max_width = pwg->width;
3429 if (pwg->length > max_length)
3430 max_length = pwg->length;
3431 }
3432 else if (strstr(pwg_size, "_min_") || strstr(pwg_size, "_min."))
3433 {
3434 if (pwg->width < min_width)
3435 min_width = pwg->width;
3436 if (pwg->length < min_length)
3437 min_length = pwg->length;
3438 }
3439 else
3440 {
3441 temp.width = pwg->width;
3442 temp.length = pwg->length;
3443 temp.bottom = bottom;
3444 temp.left = left;
3445 temp.right = right;
3446 temp.top = top;
3447
3448 if (temp.bottom == 0 && temp.left == 0 && temp.right == 0 && temp.top == 0)
3449 snprintf(temp.media, sizeof(temp.media), "%s.Borderless", pwg->ppd);
3450 else
3451 strlcpy(temp.media, pwg->ppd, sizeof(temp.media));
d9fc71e4 3452
982be458
MS
3453 if (!cupsArrayFind(sizes, &temp))
3454 cupsArrayAdd(sizes, &temp);
3455 }
3be8e026 3456 }
982be458
MS
3457 }
3458 }
3be8e026 3459
982be458
MS
3460 if (cupsArrayCount(sizes) > 0)
3461 {
3462 /*
3463 * List all of the standard sizes...
3464 */
3465
3466 char tleft[256], /* Left string */
560634d3
MS
3467 tbottom[256], /* Bottom string */
3468 tright[256], /* Right string */
3469 ttop[256], /* Top string */
3470 twidth[256], /* Width string */
3471 tlength[256]; /* Length string */
3472
982be458
MS
3473 cupsFilePrintf(fp, "*OpenUI *PageSize: PickOne\n"
3474 "*OrderDependency: 10 AnySetup *PageSize\n"
3475 "*DefaultPageSize: %s\n", ppdname);
3476 for (size = (cups_size_t *)cupsArrayFirst(sizes); size; size = (cups_size_t *)cupsArrayNext(sizes))
3477 {
3478 _cupsStrFormatd(twidth, twidth + sizeof(twidth), size->width * 72.0 / 2540.0, loc);
3479 _cupsStrFormatd(tlength, tlength + sizeof(tlength), size->length * 72.0 / 2540.0, loc);
7fad1ee9 3480
982be458
MS
3481 cupsFilePrintf(fp, "*PageSize %s: \"<</PageSize[%s %s]>>setpagedevice\"\n", size->media, twidth, tlength);
3482 }
3483 cupsFilePuts(fp, "*CloseUI: *PageSize\n");
7fad1ee9 3484
982be458
MS
3485 cupsFilePrintf(fp, "*OpenUI *PageRegion: PickOne\n"
3486 "*OrderDependency: 10 AnySetup *PageRegion\n"
3487 "*DefaultPageRegion: %s\n", ppdname);
3488 for (size = (cups_size_t *)cupsArrayFirst(sizes); size; size = (cups_size_t *)cupsArrayNext(sizes))
3489 {
3490 _cupsStrFormatd(twidth, twidth + sizeof(twidth), size->width * 72.0 / 2540.0, loc);
3491 _cupsStrFormatd(tlength, tlength + sizeof(tlength), size->length * 72.0 / 2540.0, loc);
560634d3 3492
982be458
MS
3493 cupsFilePrintf(fp, "*PageRegion %s: \"<</PageSize[%s %s]>>setpagedevice\"\n", size->media, twidth, tlength);
3494 }
3495 cupsFilePuts(fp, "*CloseUI: *PageRegion\n");
3496
3497 cupsFilePrintf(fp, "*DefaultImageableArea: %s\n"
3498 "*DefaultPaperDimension: %s\n", ppdname, ppdname);
3499
3500 for (size = (cups_size_t *)cupsArrayFirst(sizes); size; size = (cups_size_t *)cupsArrayNext(sizes))
3501 {
3502 _cupsStrFormatd(tleft, tleft + sizeof(tleft), size->left * 72.0 / 2540.0, loc);
3503 _cupsStrFormatd(tbottom, tbottom + sizeof(tbottom), size->bottom * 72.0 / 2540.0, loc);
3504 _cupsStrFormatd(tright, tright + sizeof(tright), (size->width - size->right) * 72.0 / 2540.0, loc);
3505 _cupsStrFormatd(ttop, ttop + sizeof(ttop), (size->length - size->top) * 72.0 / 2540.0, loc);
3506 _cupsStrFormatd(twidth, twidth + sizeof(twidth), size->width * 72.0 / 2540.0, loc);
3507 _cupsStrFormatd(tlength, tlength + sizeof(tlength), size->length * 72.0 / 2540.0, loc);
3508
3509 cupsFilePrintf(fp, "*ImageableArea %s: \"%s %s %s %s\"\n", size->media, tleft, tbottom, tright, ttop);
3510 cupsFilePrintf(fp, "*PaperDimension %s: \"%s %s\"\n", size->media, twidth, tlength);
d9fc71e4 3511 }
7fad1ee9
MS
3512
3513 cupsArrayDelete(sizes);
982be458
MS
3514
3515 /*
3516 * Custom size support...
3517 */
3518
3519 if (max_width > 0 && min_width < INT_MAX && max_length > 0 && min_length < INT_MAX)
3520 {
3521 char tmax[256], tmin[256]; /* Min/max values */
3522
3523 _cupsStrFormatd(tleft, tleft + sizeof(tleft), left * 72.0 / 2540.0, loc);
3524 _cupsStrFormatd(tbottom, tbottom + sizeof(tbottom), bottom * 72.0 / 2540.0, loc);
3525 _cupsStrFormatd(tright, tright + sizeof(tright), right * 72.0 / 2540.0, loc);
3526 _cupsStrFormatd(ttop, ttop + sizeof(ttop), top * 72.0 / 2540.0, loc);
3527
3528 cupsFilePrintf(fp, "*HWMargins: \"%s %s %s %s\"\n", tleft, tbottom, tright, ttop);
3529
3530 _cupsStrFormatd(tmax, tmax + sizeof(tmax), max_width * 72.0 / 2540.0, loc);
3531 _cupsStrFormatd(tmin, tmin + sizeof(tmin), min_width * 72.0 / 2540.0, loc);
3532 cupsFilePrintf(fp, "*ParamCustomPageSize Width: 1 points %s %s\n", tmin, tmax);
3533
3534 _cupsStrFormatd(tmax, tmax + sizeof(tmax), max_length * 72.0 / 2540.0, loc);
3535 _cupsStrFormatd(tmin, tmin + sizeof(tmin), min_length * 72.0 / 2540.0, loc);
3536 cupsFilePrintf(fp, "*ParamCustomPageSize Height: 2 points %s %s\n", tmin, tmax);
3537
3538 cupsFilePuts(fp, "*ParamCustomPageSize WidthOffset: 3 points 0 0\n");
3539 cupsFilePuts(fp, "*ParamCustomPageSize HeightOffset: 4 points 0 0\n");
3540 cupsFilePuts(fp, "*ParamCustomPageSize Orientation: 5 int 0 3\n");
3541 cupsFilePuts(fp, "*CustomPageSize True: \"pop pop pop <</PageSize[5 -2 roll]/ImagingBBox null>>setpagedevice\"\n");
3542 }
d9fc71e4 3543 }
d4259b45 3544 else
982be458
MS
3545 {
3546 cupsArrayDelete(sizes);
d4259b45 3547 goto bad_ppd;
982be458 3548 }
d9fc71e4
MS
3549
3550 /*
3551 * InputSlot...
3552 */
3553
670172ea 3554 if ((attr = ippFindAttribute(ippGetCollection(defattr, 0), "media-source", IPP_TAG_ZERO)) != NULL)
d9fc71e4
MS
3555 pwg_ppdize_name(ippGetString(attr, 0, NULL), ppdname, sizeof(ppdname));
3556 else
3557 strlcpy(ppdname, "Unknown", sizeof(ppdname));
3558
670172ea 3559 if ((attr = ippFindAttribute(response, "media-source-supported", IPP_TAG_ZERO)) != NULL && (count = ippGetCount(attr)) > 1)
d9fc71e4 3560 {
edf09ba9
MS
3561 static const char * const sources[] =
3562 { /* Standard "media-source" strings */
3563 "auto",
3564 "main",
3565 "alternate",
3566 "large-capacity",
3567 "manual",
3568 "envelope",
3569 "disc",
3570 "photo",
3571 "hagaki",
3572 "main-roll",
3573 "alternate-roll",
3574 "top",
3575 "middle",
3576 "bottom",
3577 "side",
3578 "left",
3579 "right",
3580 "center",
3581 "rear",
3582 "by-pass-tray",
3583 "tray-1",
3584 "tray-2",
3585 "tray-3",
3586 "tray-4",
3587 "tray-5",
3588 "tray-6",
3589 "tray-7",
3590 "tray-8",
3591 "tray-9",
3592 "tray-10",
3593 "tray-11",
3594 "tray-12",
3595 "tray-13",
3596 "tray-14",
3597 "tray-15",
3598 "tray-16",
3599 "tray-17",
3600 "tray-18",
3601 "tray-19",
3602 "tray-20",
3603 "roll-1",
3604 "roll-2",
3605 "roll-3",
3606 "roll-4",
3607 "roll-5",
3608 "roll-6",
3609 "roll-7",
3610 "roll-8",
3611 "roll-9",
3612 "roll-10"
d9fc71e4
MS
3613 };
3614
3615 cupsFilePrintf(fp, "*OpenUI *InputSlot: PickOne\n"
3616 "*OrderDependency: 10 AnySetup *InputSlot\n"
3617 "*DefaultInputSlot: %s\n", ppdname);
3618 for (i = 0, count = ippGetCount(attr); i < count; i ++)
3619 {
edf09ba9
MS
3620 keyword = ippGetString(attr, i, NULL);
3621
3622 pwg_ppdize_name(keyword, ppdname, sizeof(ppdname));
d9fc71e4
MS
3623
3624 for (j = 0; j < (int)(sizeof(sources) / sizeof(sources[0])); j ++)
edf09ba9 3625 if (!strcmp(sources[j], keyword))
d9fc71e4 3626 {
edf09ba9
MS
3627 snprintf(msgid, sizeof(msgid), "media-source.%s", keyword);
3628 cupsFilePrintf(fp, "*InputSlot %s/%s: \"<</MediaPosition %d>>setpagedevice\"\n", ppdname, _cupsLangString(lang, msgid), j);
d9fc71e4
MS
3629 break;
3630 }
3631 }
3632 cupsFilePuts(fp, "*CloseUI: *InputSlot\n");
3633 }
3634
3635 /*
3636 * MediaType...
3637 */
3638
670172ea 3639 if ((attr = ippFindAttribute(ippGetCollection(defattr, 0), "media-type", IPP_TAG_ZERO)) != NULL)
d9fc71e4
MS
3640 pwg_ppdize_name(ippGetString(attr, 0, NULL), ppdname, sizeof(ppdname));
3641 else
3642 strlcpy(ppdname, "Unknown", sizeof(ppdname));
3643
670172ea 3644 if ((attr = ippFindAttribute(response, "media-type-supported", IPP_TAG_ZERO)) != NULL && (count = ippGetCount(attr)) > 1)
d9fc71e4 3645 {
d9fc71e4
MS
3646 cupsFilePrintf(fp, "*OpenUI *MediaType: PickOne\n"
3647 "*OrderDependency: 10 AnySetup *MediaType\n"
3648 "*DefaultMediaType: %s\n", ppdname);
3ae6282d 3649 for (i = 0; i < count; i ++)
d9fc71e4 3650 {
edf09ba9 3651 keyword = ippGetString(attr, i, NULL);
d9fc71e4 3652
3ae6282d 3653 pwg_ppdize_name(keyword, ppdname, sizeof(ppdname));
d9fc71e4 3654
edf09ba9
MS
3655 snprintf(msgid, sizeof(msgid), "media-type.%s", keyword);
3656 if ((msgstr = _cupsLangString(lang, msgid)) == msgid || !strcmp(msgid, msgstr))
3657 if ((msgstr = _cupsMessageLookup(strings, msgid)) == msgid)
3658 msgstr = keyword;
89550f3f 3659
edf09ba9 3660 cupsFilePrintf(fp, "*MediaType %s/%s: \"<</MediaType(%s)>>setpagedevice\"\n", ppdname, msgstr, ppdname);
d9fc71e4
MS
3661 }
3662 cupsFilePuts(fp, "*CloseUI: *MediaType\n");
3663 }
3664
3665 /*
3666 * ColorModel...
3667 */
3668
fa76bc3d
MS
3669 if ((attr = ippFindAttribute(response, "urf-supported", IPP_TAG_KEYWORD)) == NULL)
3670 if ((attr = ippFindAttribute(response, "pwg-raster-document-type-supported", IPP_TAG_KEYWORD)) == NULL)
670172ea
MS
3671 if ((attr = ippFindAttribute(response, "print-color-mode-supported", IPP_TAG_KEYWORD)) == NULL)
3672 attr = ippFindAttribute(response, "output-mode-supported", IPP_TAG_KEYWORD);
d9fc71e4
MS
3673
3674 if (attr)
3675 {
3676 const char *default_color = NULL; /* Default */
3677
d9fc71e4
MS
3678 for (i = 0, count = ippGetCount(attr); i < count; i ++)
3679 {
edf09ba9 3680 keyword = ippGetString(attr, i, NULL);
d9fc71e4 3681
d2817c9f 3682 if (!strcasecmp(keyword, "black_1") || !strcmp(keyword, "bi-level") || !strcmp(keyword, "process-bi-level"))
d9fc71e4 3683 {
5e7464ec 3684 if (!default_color)
c0886523
MS
3685 cupsFilePrintf(fp, "*OpenUI *ColorModel/%s: PickOne\n"
3686 "*OrderDependency: 10 AnySetup *ColorModel\n", _cupsLangString(lang, _("Color Mode")));
5e7464ec 3687
c0886523 3688 cupsFilePrintf(fp, "*ColorModel FastGray/%s: \"<</cupsColorSpace 3/cupsBitsPerColor 1/cupsColorOrder 0/cupsCompression 0>>setpagedevice\"\n", _cupsLangString(lang, _("Fast Grayscale")));
d9fc71e4
MS
3689
3690 if (!default_color)
3691 default_color = "FastGray";
3692 }
d2817c9f 3693 else if (!strcasecmp(keyword, "sgray_8") || !strcmp(keyword, "W8") || !strcmp(keyword, "monochrome") || !strcmp(keyword, "process-monochrome"))
d9fc71e4 3694 {
5e7464ec 3695 if (!default_color)
c0886523
MS
3696 cupsFilePrintf(fp, "*OpenUI *ColorModel/%s: PickOne\n"
3697 "*OrderDependency: 10 AnySetup *ColorModel\n", _cupsLangString(lang, _("Color Mode")));
5e7464ec 3698
c0886523 3699 cupsFilePrintf(fp, "*ColorModel Gray/%s: \"<</cupsColorSpace 18/cupsBitsPerColor 8/cupsColorOrder 0/cupsCompression 0>>setpagedevice\"\n", _cupsLangString(lang, _("Grayscale")));
d9fc71e4
MS
3700
3701 if (!default_color || !strcmp(default_color, "FastGray"))
3702 default_color = "Gray";
3703 }
d2817c9f 3704 else if (!strcasecmp(keyword, "srgb_8") || !strcmp(keyword, "SRGB24") || !strcmp(keyword, "color"))
d9fc71e4 3705 {
5e7464ec 3706 if (!default_color)
c0886523
MS
3707 cupsFilePrintf(fp, "*OpenUI *ColorModel/%s: PickOne\n"
3708 "*OrderDependency: 10 AnySetup *ColorModel\n", _cupsLangString(lang, _("Color Mode")));
5e7464ec 3709
c0886523 3710 cupsFilePrintf(fp, "*ColorModel RGB/%s: \"<</cupsColorSpace 19/cupsBitsPerColor 8/cupsColorOrder 0/cupsCompression 0>>setpagedevice\"\n", _cupsLangString(lang, _("Color")));
d9fc71e4
MS
3711
3712 default_color = "RGB";
3713 }
d2817c9f 3714 else if (!strcasecmp(keyword, "adobe-rgb_16") || !strcmp(keyword, "ADOBERGB48"))
2a8afc20
MS
3715 {
3716 if (!default_color)
3717 cupsFilePrintf(fp, "*OpenUI *ColorModel/%s: PickOne\n"
3718 "*OrderDependency: 10 AnySetup *ColorModel\n", _cupsLangString(lang, _("Color Mode")));
3719
3720 cupsFilePrintf(fp, "*ColorModel AdobeRGB/%s: \"<</cupsColorSpace 20/cupsBitsPerColor 16/cupsColorOrder 0/cupsCompression 0>>setpagedevice\"\n", _cupsLangString(lang, _("Deep Color")));
3721
d4259b45
MS
3722 if (!default_color)
3723 default_color = "AdobeRGB";
2a8afc20 3724 }
d9fc71e4
MS
3725 }
3726
3727 if (default_color)
5e7464ec 3728 {
d9fc71e4 3729 cupsFilePrintf(fp, "*DefaultColorModel: %s\n", default_color);
5e7464ec
MS
3730 cupsFilePuts(fp, "*CloseUI: *ColorModel\n");
3731 }
d9fc71e4
MS
3732 }
3733
3734 /*
3735 * Duplex...
3736 */
3737
3738 if ((attr = ippFindAttribute(response, "sides-supported", IPP_TAG_KEYWORD)) != NULL && ippContainsString(attr, "two-sided-long-edge"))
3739 {
c0886523
MS
3740 cupsFilePrintf(fp, "*OpenUI *Duplex/%s: PickOne\n"
3741 "*OrderDependency: 10 AnySetup *Duplex\n"
3742 "*DefaultDuplex: None\n"
3743 "*Duplex None/%s: \"<</Duplex false>>setpagedevice\"\n"
3744 "*Duplex DuplexNoTumble/%s: \"<</Duplex true/Tumble false>>setpagedevice\"\n"
3745 "*Duplex DuplexTumble/%s: \"<</Duplex true/Tumble true>>setpagedevice\"\n"
3746 "*CloseUI: *Duplex\n", _cupsLangString(lang, _("2-Sided Printing")), _cupsLangString(lang, _("Off (1-Sided)")), _cupsLangString(lang, _("Long-Edge (Portrait)")), _cupsLangString(lang, _("Short-Edge (Landscape)")));
d9fc71e4 3747
fa76bc3d
MS
3748 if ((attr = ippFindAttribute(response, "urf-supported", IPP_TAG_KEYWORD)) != NULL)
3749 {
3750 for (i = 0, count = ippGetCount(attr); i < count; i ++)
3751 {
3752 const char *dm = ippGetString(attr, i, NULL);
3753 /* DM value */
3754
3755 if (!_cups_strcasecmp(dm, "DM1"))
3756 {
3757 cupsFilePuts(fp, "*cupsBackSide: Normal\n");
3758 break;
3759 }
3760 else if (!_cups_strcasecmp(dm, "DM2"))
3761 {
3762 cupsFilePuts(fp, "*cupsBackSide: Flipped\n");
3763 break;
3764 }
3765 else if (!_cups_strcasecmp(dm, "DM3"))
3766 {
3767 cupsFilePuts(fp, "*cupsBackSide: Rotated\n");
3768 break;
3769 }
3770 else if (!_cups_strcasecmp(dm, "DM4"))
3771 {
3772 cupsFilePuts(fp, "*cupsBackSide: ManualTumble\n");
3773 break;
3774 }
3775 }
3776 }
3777 else if ((attr = ippFindAttribute(response, "pwg-raster-document-sheet-back", IPP_TAG_KEYWORD)) != NULL)
d9fc71e4 3778 {
edf09ba9 3779 keyword = ippGetString(attr, 0, NULL);
d9fc71e4
MS
3780
3781 if (!strcmp(keyword, "flipped"))
3782 cupsFilePuts(fp, "*cupsBackSide: Flipped\n");
3783 else if (!strcmp(keyword, "manual-tumble"))
3784 cupsFilePuts(fp, "*cupsBackSide: ManualTumble\n");
3785 else if (!strcmp(keyword, "normal"))
3786 cupsFilePuts(fp, "*cupsBackSide: Normal\n");
3787 else
3788 cupsFilePuts(fp, "*cupsBackSide: Rotated\n");
3789 }
3790 }
3791
1999164d
MS
3792 /*
3793 * Output bin...
3794 */
3795
3796 if ((attr = ippFindAttribute(response, "output-bin-default", IPP_TAG_ZERO)) != NULL)
3797 pwg_ppdize_name(ippGetString(attr, 0, NULL), ppdname, sizeof(ppdname));
3798 else
3799 strlcpy(ppdname, "Unknown", sizeof(ppdname));
3800
3942a9c8 3801 if ((attr = ippFindAttribute(response, "output-bin-supported", IPP_TAG_ZERO)) != NULL && (count = ippGetCount(attr)) > 1)
1999164d 3802 {
1999164d
MS
3803 cupsFilePrintf(fp, "*OpenUI *OutputBin: PickOne\n"
3804 "*OrderDependency: 10 AnySetup *OutputBin\n"
3805 "*DefaultOutputBin: %s\n", ppdname);
edf09ba9 3806 for (i = 0; i < count; i ++)
1999164d 3807 {
edf09ba9
MS
3808 keyword = ippGetString(attr, i, NULL);
3809
3810 pwg_ppdize_name(keyword, ppdname, sizeof(ppdname));
1999164d 3811
edf09ba9
MS
3812 snprintf(msgid, sizeof(msgid), "output-bin.%s", keyword);
3813 if ((msgstr = _cupsLangString(lang, msgid)) == msgid || !strcmp(msgid, msgstr))
3814 if ((msgstr = _cupsMessageLookup(strings, msgid)) == msgid)
3815 msgstr = keyword;
1999164d 3816
edf09ba9 3817 cupsFilePrintf(fp, "*OutputBin %s/%s: \"\"\n", ppdname, msgstr);
1999164d
MS
3818 }
3819 cupsFilePuts(fp, "*CloseUI: *OutputBin\n");
3820 }
3821
c0886523
MS
3822 /*
3823 * Finishing options...
3824 */
3825
a740a849 3826 if ((attr = ippFindAttribute(response, "finishings-supported", IPP_TAG_ENUM)) != NULL)
c0886523 3827 {
a740a849 3828 int value; /* Enum value */
30ea7759 3829 cups_array_t *names; /* Names we've added */
c0886523 3830
27ee2c4d
MS
3831 count = ippGetCount(attr);
3832 names = cupsArrayNew3((cups_array_func_t)strcmp, NULL, NULL, 0, (cups_acopy_func_t)strdup, (cups_afree_func_t)free);
3833 fin_options = cupsArrayNew((cups_array_func_t)strcmp, NULL);
c0886523 3834
a740a849
MS
3835 /*
3836 * Staple/Bind/Stitch
3837 */
c0886523
MS
3838
3839 for (i = 0; i < count; i ++)
3840 {
edf09ba9
MS
3841 value = ippGetInteger(attr, i);
3842 keyword = ippEnumString("finishings", value);
c0886523 3843
edf09ba9 3844 if (!strncmp(keyword, "staple-", 7) || !strncmp(keyword, "bind-", 5) || !strncmp(keyword, "edge-stitch-", 12) || !strcmp(keyword, "saddle-stitch"))
a740a849
MS
3845 break;
3846 }
30ea7759 3847
a740a849
MS
3848 if (i < count)
3849 {
27ee2c4d
MS
3850 cupsArrayAdd(fin_options, "*StapleLocation");
3851
a740a849
MS
3852 cupsFilePrintf(fp, "*OpenUI *StapleLocation/%s: PickOne\n", _cupsLangString(lang, _("Staple")));
3853 cupsFilePuts(fp, "*OrderDependency: 10 AnySetup *StapleLocation\n");
3854 cupsFilePuts(fp, "*DefaultStapleLocation: None\n");
3855 cupsFilePrintf(fp, "*StapleLocation None/%s: \"\"\n", _cupsLangString(lang, _("None")));
30ea7759 3856
a740a849 3857 for (; i < count; i ++)
c0886523 3858 {
edf09ba9
MS
3859 value = ippGetInteger(attr, i);
3860 keyword = ippEnumString("finishings", value);
c0886523 3861
edf09ba9 3862 if (strncmp(keyword, "staple-", 7) && strncmp(keyword, "bind-", 5) && strncmp(keyword, "edge-stitch-", 12) && strcmp(keyword, "saddle-stitch"))
a740a849 3863 continue;
c0886523 3864
edf09ba9 3865 if (cupsArrayFind(names, (char *)keyword))
a740a849
MS
3866 continue; /* Already did this finishing template */
3867
edf09ba9 3868 cupsArrayAdd(names, (char *)keyword);
a740a849 3869
edf09ba9
MS
3870 snprintf(msgid, sizeof(msgid), "finishings.%d", value);
3871 if ((msgstr = _cupsLangString(lang, msgid)) == msgid || !strcmp(msgid, msgstr))
3872 if ((msgstr = _cupsMessageLookup(strings, msgid)) == msgid)
3873 msgstr = keyword;
3874
3875 cupsFilePrintf(fp, "*StapleLocation %s/%s: \"\"\n", keyword, msgstr);
3876 cupsFilePrintf(fp, "*cupsIPPFinishings %d/%s: \"*StapleLocation %s\"\n", value, keyword, keyword);
c0886523 3877 }
a740a849
MS
3878
3879 cupsFilePuts(fp, "*CloseUI: *StapleLocation\n");
c0886523
MS
3880 }
3881
a740a849
MS
3882 /*
3883 * Fold
3884 */
30ea7759 3885
a740a849
MS
3886 for (i = 0; i < count; i ++)
3887 {
edf09ba9
MS
3888 value = ippGetInteger(attr, i);
3889 keyword = ippEnumString("finishings", value);
c0886523 3890
edf09ba9 3891 if (!strncmp(keyword, "fold-", 5))
a740a849
MS
3892 break;
3893 }
3894
3895 if (i < count)
3896 {
27ee2c4d
MS
3897 cupsArrayAdd(fin_options, "*FoldType");
3898
a740a849
MS
3899 cupsFilePrintf(fp, "*OpenUI *FoldType/%s: PickOne\n", _cupsLangString(lang, _("Fold")));
3900 cupsFilePuts(fp, "*OrderDependency: 10 AnySetup *FoldType\n");
3901 cupsFilePuts(fp, "*DefaultFoldType: None\n");
3902 cupsFilePrintf(fp, "*FoldType None/%s: \"\"\n", _cupsLangString(lang, _("None")));
3903
3904 for (; i < count; i ++)
3905 {
edf09ba9
MS
3906 value = ippGetInteger(attr, i);
3907 keyword = ippEnumString("finishings", value);
a740a849 3908
edf09ba9 3909 if (strncmp(keyword, "fold-", 5))
a740a849 3910 continue;
c0886523 3911
edf09ba9 3912 if (cupsArrayFind(names, (char *)keyword))
a740a849
MS
3913 continue; /* Already did this finishing template */
3914
edf09ba9 3915 cupsArrayAdd(names, (char *)keyword);
a740a849 3916
edf09ba9
MS
3917 snprintf(msgid, sizeof(msgid), "finishings.%d", value);
3918 if ((msgstr = _cupsLangString(lang, msgid)) == msgid || !strcmp(msgid, msgstr))
3919 if ((msgstr = _cupsMessageLookup(strings, msgid)) == msgid)
3920 msgstr = keyword;
3921
3922 cupsFilePrintf(fp, "*FoldType %s/%s: \"\"\n", keyword, msgstr);
3923 cupsFilePrintf(fp, "*cupsIPPFinishings %d/%s: \"*FoldType %s\"\n", value, keyword, keyword);
a740a849
MS
3924 }
3925
3926 cupsFilePuts(fp, "*CloseUI: *FoldType\n");
3927 }
3928
3929 /*
3930 * Punch
3931 */
c0886523
MS
3932
3933 for (i = 0; i < count; i ++)
3934 {
edf09ba9
MS
3935 value = ippGetInteger(attr, i);
3936 keyword = ippEnumString("finishings", value);
a740a849 3937
edf09ba9 3938 if (!strncmp(keyword, "punch-", 6))
a740a849
MS
3939 break;
3940 }
3941
3942 if (i < count)
3943 {
27ee2c4d
MS
3944 cupsArrayAdd(fin_options, "*PunchMedia");
3945
a740a849
MS
3946 cupsFilePrintf(fp, "*OpenUI *PunchMedia/%s: PickOne\n", _cupsLangString(lang, _("Punch")));
3947 cupsFilePuts(fp, "*OrderDependency: 10 AnySetup *PunchMedia\n");
3948 cupsFilePuts(fp, "*DefaultPunchMedia: None\n");
3949 cupsFilePrintf(fp, "*PunchMedia None/%s: \"\"\n", _cupsLangString(lang, _("None")));
c0886523 3950
a740a849 3951 for (i = 0; i < count; i ++)
c0886523 3952 {
edf09ba9
MS
3953 value = ippGetInteger(attr, i);
3954 keyword = ippEnumString("finishings", value);
a740a849 3955
edf09ba9 3956 if (strncmp(keyword, "punch-", 6))
a740a849
MS
3957 continue;
3958
edf09ba9 3959 if (cupsArrayFind(names, (char *)keyword))
a740a849
MS
3960 continue; /* Already did this finishing template */
3961
edf09ba9 3962 cupsArrayAdd(names, (char *)keyword);
a740a849 3963
edf09ba9
MS
3964 snprintf(msgid, sizeof(msgid), "finishings.%d", value);
3965 if ((msgstr = _cupsLangString(lang, msgid)) == msgid || !strcmp(msgid, msgstr))
3966 if ((msgstr = _cupsMessageLookup(strings, msgid)) == msgid)
3967 msgstr = keyword;
3968
3969 cupsFilePrintf(fp, "*PunchMedia %s/%s: \"\"\n", keyword, msgstr);
3970 cupsFilePrintf(fp, "*cupsIPPFinishings %d/%s: \"*PunchMedia %s\"\n", value, keyword, keyword);
c0886523 3971 }
a740a849
MS
3972
3973 cupsFilePuts(fp, "*CloseUI: *PunchMedia\n");
3974 }
3975
3976 /*
3977 * Booklet
3978 */
3979
3980 if (ippContainsInteger(attr, IPP_FINISHINGS_BOOKLET_MAKER))
3981 {
27ee2c4d
MS
3982 cupsArrayAdd(fin_options, "*Booklet");
3983
a740a849
MS
3984 cupsFilePrintf(fp, "*OpenUI *Booklet/%s: Boolean\n", _cupsLangString(lang, _("Booklet")));
3985 cupsFilePuts(fp, "*OrderDependency: 10 AnySetup *Booklet\n");
3986 cupsFilePuts(fp, "*DefaultBooklet: False\n");
3987 cupsFilePuts(fp, "*Booklet False: \"\"\n");
3988 cupsFilePuts(fp, "*Booklet True: \"\"\n");
3989 cupsFilePrintf(fp, "*cupsIPPFinishings %d/booklet-maker: \"*Booklet True\"\n", IPP_FINISHINGS_BOOKLET_MAKER);
3990 cupsFilePuts(fp, "*CloseUI: *Booklet\n");
c0886523
MS
3991 }
3992
a740a849 3993 cupsArrayDelete(names);
c0886523
MS
3994 }
3995
27ee2c4d
MS
3996 if ((attr = ippFindAttribute(response, "finishings-col-database", IPP_TAG_BEGIN_COLLECTION)) != NULL)
3997 {
3998 ipp_t *finishing_col; /* Current finishing collection */
edf09ba9 3999 ipp_attribute_t *finishing_attr; /* Current finishing member attribute */
27ee2c4d
MS
4000 cups_array_t *templates; /* Finishing templates */
4001
4002 cupsFilePrintf(fp, "*OpenUI *cupsFinishingTemplate/%s: PickOne\n", _cupsLangString(lang, _("Finishing Preset")));
4003 cupsFilePuts(fp, "*OrderDependency: 10 AnySetup *cupsFinishingTemplate\n");
4f63d6cd
MS
4004 cupsFilePuts(fp, "*DefaultcupsFinishingTemplate: none\n");
4005 cupsFilePrintf(fp, "*cupsFinishingTemplate none/%s: \"\"\n", _cupsLangString(lang, _("None")));
27ee2c4d
MS
4006
4007 templates = cupsArrayNew((cups_array_func_t)strcmp, NULL);
4008 count = ippGetCount(attr);
4009
4010 for (i = 0; i < count; i ++)
4011 {
4012 finishing_col = ippGetCollection(attr, i);
edf09ba9 4013 keyword = ippGetString(ippFindAttribute(finishing_col, "finishing_template", IPP_TAG_ZERO), 0, NULL);
27ee2c4d 4014
edf09ba9 4015 if (!keyword || cupsArrayFind(templates, (void *)keyword))
27ee2c4d
MS
4016 continue;
4017
edf09ba9 4018 if (strncmp(keyword, "fold-", 5) && (strstr(keyword, "-bottom") || strstr(keyword, "-left") || strstr(keyword, "-right") || strstr(keyword, "-top")))
27ee2c4d
MS
4019 continue;
4020
edf09ba9 4021 cupsArrayAdd(templates, (void *)keyword);
27ee2c4d 4022
edf09ba9
MS
4023 snprintf(msgid, sizeof(msgid), "finishing-template.%s", keyword);
4024 if ((msgstr = _cupsLangString(lang, msgid)) == msgid || !strcmp(msgid, msgstr))
4025 if ((msgstr = _cupsMessageLookup(strings, msgid)) == msgid)
4026 msgstr = keyword;
27ee2c4d 4027
edf09ba9
MS
4028 cupsFilePrintf(fp, "*cupsFinishingTemplate %s/%s: \"\n", keyword, msgstr);
4029 for (finishing_attr = ippFirstAttribute(finishing_col); finishing_attr; finishing_attr = ippNextAttribute(finishing_col))
27ee2c4d 4030 {
edf09ba9
MS
4031 if (ippGetValueTag(finishing_attr) == IPP_TAG_BEGIN_COLLECTION)
4032 {
4033 const char *name = ippGetName(finishing_attr);
4034 /* Member attribute name */
27ee2c4d 4035
edf09ba9
MS
4036 if (strcmp(name, "media-size"))
4037 cupsFilePrintf(fp, "%s\n", name);
4038 }
27ee2c4d 4039 }
edf09ba9
MS
4040 cupsFilePuts(fp, "\"\n");
4041 cupsFilePuts(fp, "*End\n");
27ee2c4d
MS
4042 }
4043
4044 cupsFilePuts(fp, "*CloseUI: *cupsFinishingTemplate\n");
4045
4046 if (cupsArrayCount(fin_options))
4047 {
4048 const char *fin_option; /* Current finishing option */
4049
4050 cupsFilePuts(fp, "*cupsUIConstraint finisings: \"*cupsFinishingTemplate");
4051 for (fin_option = (const char *)cupsArrayFirst(fin_options); fin_option; fin_option = (const char *)cupsArrayNext(fin_options))
4052 cupsFilePrintf(fp, " %s", fin_option);
4053 cupsFilePuts(fp, "\"\n");
4054
4055 cupsFilePuts(fp, "*cupsUIResolver finisings: \"*cupsFinishingTemplate None");
4056 for (fin_option = (const char *)cupsArrayFirst(fin_options); fin_option; fin_option = (const char *)cupsArrayNext(fin_options))
4057 cupsFilePrintf(fp, " %s None", fin_option);
4058 cupsFilePuts(fp, "\"\n");
4059 }
4060
4061 cupsArrayDelete(templates);
4062 }
4063
4064 cupsArrayDelete(fin_options);
4065
d9fc71e4
MS
4066 /*
4067 * cupsPrintQuality and DefaultResolution...
4068 */
4069
3b6c3c8e
MS
4070 quality = ippFindAttribute(response, "print-quality-supported", IPP_TAG_ENUM);
4071
fa76bc3d 4072 if ((attr = ippFindAttribute(response, "urf-supported", IPP_TAG_KEYWORD)) != NULL)
d9fc71e4 4073 {
fa76bc3d 4074 int lowdpi = 0, hidpi = 0; /* Lower and higher resolution */
fb2d5470
MS
4075
4076 for (i = 0, count = ippGetCount(attr); i < count; i ++)
4077 {
4078 const char *rs = ippGetString(attr, i, NULL);
fa76bc3d 4079 /* RS value */
fb2d5470
MS
4080
4081 if (_cups_strncasecmp(rs, "RS", 2))
4082 continue;
4083
4084 lowdpi = atoi(rs + 2);
4085 if ((rs = strrchr(rs, '-')) != NULL)
4086 hidpi = atoi(rs + 1);
4087 else
4088 hidpi = lowdpi;
4089 break;
4090 }
4091
4092 if (lowdpi == 0)
4093 {
4094 /*
4095 * Invalid "urf-supported" value...
4096 */
4097
d4259b45 4098 goto bad_ppd;
fb2d5470
MS
4099 }
4100 else
4101 {
4102 /*
4103 * Generate print qualities based on low and high DPIs...
4104 */
4105
4106 cupsFilePrintf(fp, "*DefaultResolution: %ddpi\n", lowdpi);
4107
c0886523 4108 cupsFilePrintf(fp, "*OpenUI *cupsPrintQuality/%s: PickOne\n"
fa76bc3d
MS
4109 "*OrderDependency: 10 AnySetup *cupsPrintQuality\n"
4110 "*DefaultcupsPrintQuality: Normal\n", _cupsLangString(lang, _("Print Quality")));
fb2d5470 4111 if ((lowdpi & 1) == 0)
fa76bc3d 4112 cupsFilePrintf(fp, "*cupsPrintQuality Draft/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n", _cupsLangString(lang, _("Draft")), lowdpi, lowdpi / 2);
3b6c3c8e 4113 else if (ippContainsInteger(quality, IPP_QUALITY_DRAFT))
fa76bc3d 4114 cupsFilePrintf(fp, "*cupsPrintQuality Draft/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n", _cupsLangString(lang, _("Draft")), lowdpi, lowdpi);
c0886523 4115 cupsFilePrintf(fp, "*cupsPrintQuality Normal/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n", _cupsLangString(lang, _("Normal")), lowdpi, lowdpi);
3b6c3c8e 4116 if (hidpi > lowdpi || ippContainsInteger(quality, IPP_QUALITY_HIGH))
fa76bc3d 4117 cupsFilePrintf(fp, "*cupsPrintQuality High/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n", _cupsLangString(lang, _("High")), hidpi, hidpi);
fb2d5470
MS
4118 cupsFilePuts(fp, "*CloseUI: *cupsPrintQuality\n");
4119 }
4120 }
fa76bc3d
MS
4121 else if ((attr = ippFindAttribute(response, "pwg-raster-document-resolution-supported", IPP_TAG_RESOLUTION)) != NULL)
4122 {
4123 /*
4124 * Make a sorted list of resolutions.
4125 */
4126
4127 count = ippGetCount(attr);
4128 if (count > (int)(sizeof(resolutions) / sizeof(resolutions[0])))
4129 count = (int)(sizeof(resolutions) / sizeof(resolutions[0]));
4130
25140c63
MS
4131 resolutions[0] = 0; /* Not in loop to silence Clang static analyzer... */
4132 for (i = 1; i < count; i ++)
fa76bc3d
MS
4133 resolutions[i] = i;
4134
4135 for (i = 0; i < (count - 1); i ++)
4136 {
91d748b9 4137 for (j = i + 1; j < count; j ++)
fa76bc3d
MS
4138 {
4139 int ix, iy, /* First X and Y resolution */
4140 jx, jy, /* Second X and Y resolution */
4141 temp; /* Swap variable */
4142 ipp_res_t units; /* Resolution units */
4143
4144 ix = ippGetResolution(attr, resolutions[i], &iy, &units);
4145 jx = ippGetResolution(attr, resolutions[j], &jy, &units);
4146
4147 if (ix > jx || (ix == jx && iy > jy))
4148 {
4149 /*
4150 * Swap these two resolutions...
4151 */
4152
4153 temp = resolutions[i];
4154 resolutions[i] = resolutions[j];
4155 resolutions[j] = temp;
4156 }
4157 }
4158 }
4159
4160 /*
4161 * Generate print quality options...
4162 */
4163
4164 pwg_ppdize_resolution(attr, resolutions[count / 2], &xres, &yres, ppdname, sizeof(ppdname));
4165 cupsFilePrintf(fp, "*DefaultResolution: %s\n", ppdname);
4166
4167 cupsFilePrintf(fp, "*OpenUI *cupsPrintQuality/%s: PickOne\n"
4168 "*OrderDependency: 10 AnySetup *cupsPrintQuality\n"
4169 "*DefaultcupsPrintQuality: Normal\n", _cupsLangString(lang, _("Print Quality")));
4170 if (count > 2 || ippContainsInteger(quality, IPP_QUALITY_DRAFT))
4171 {
4172 pwg_ppdize_resolution(attr, resolutions[0], &xres, &yres, NULL, 0);
4173 cupsFilePrintf(fp, "*cupsPrintQuality Draft/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n", _cupsLangString(lang, _("Draft")), xres, yres);
4174 }
4175 pwg_ppdize_resolution(attr, resolutions[count / 2], &xres, &yres, NULL, 0);
4176 cupsFilePrintf(fp, "*cupsPrintQuality Normal/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n", _cupsLangString(lang, _("Normal")), xres, yres);
4177 if (count > 1 || ippContainsInteger(quality, IPP_QUALITY_HIGH))
4178 {
4179 pwg_ppdize_resolution(attr, resolutions[count - 1], &xres, &yres, NULL, 0);
4180 cupsFilePrintf(fp, "*cupsPrintQuality High/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n", _cupsLangString(lang, _("High")), xres, yres);
4181 }
4182
4183 cupsFilePuts(fp, "*CloseUI: *cupsPrintQuality\n");
4184 }
d4259b45
MS
4185 else if (is_apple || is_pwg)
4186 goto bad_ppd;
3b6c3c8e 4187 else
d9fc71e4 4188 {
3b6c3c8e
MS
4189 if ((attr = ippFindAttribute(response, "printer-resolution-default", IPP_TAG_RESOLUTION)) != NULL)
4190 {
4191 pwg_ppdize_resolution(attr, 0, &xres, &yres, ppdname, sizeof(ppdname));
4192 }
4193 else
4194 {
4195 xres = yres = 300;
4196 strlcpy(ppdname, "300dpi", sizeof(ppdname));
4197 }
4198
d9fc71e4 4199 cupsFilePrintf(fp, "*DefaultResolution: %s\n", ppdname);
3b6c3c8e
MS
4200
4201 cupsFilePrintf(fp, "*OpenUI *cupsPrintQuality/%s: PickOne\n"
4202 "*OrderDependency: 10 AnySetup *cupsPrintQuality\n"
4203 "*DefaultcupsPrintQuality: Normal\n", _cupsLangString(lang, _("Print Quality")));
4204 if (ippContainsInteger(quality, IPP_QUALITY_DRAFT))
4205 cupsFilePrintf(fp, "*cupsPrintQuality Draft/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n", _cupsLangString(lang, _("Draft")), xres, yres);
4206 cupsFilePrintf(fp, "*cupsPrintQuality Normal/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n", _cupsLangString(lang, _("Normal")), xres, yres);
4207 if (ippContainsInteger(quality, IPP_QUALITY_HIGH))
4208 cupsFilePrintf(fp, "*cupsPrintQuality High/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n", _cupsLangString(lang, _("High")), xres, yres);
4209 cupsFilePuts(fp, "*CloseUI: *cupsPrintQuality\n");
d9fc71e4 4210 }
d9fc71e4
MS
4211
4212 /*
4213 * Close up and return...
4214 */
4215
4216 cupsFileClose(fp);
4217
4218 return (buffer);
d4259b45
MS
4219
4220 /*
4221 * If we get here then there was a problem creating the PPD...
4222 */
4223
4224 bad_ppd:
4225
4226 cupsFileClose(fp);
4227 unlink(buffer);
4228 *buffer = '\0';
4229
a946858f
MS
4230 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Printer does not support required IPP attributes or document formats."), 1);
4231
d4259b45 4232 return (NULL);
d9fc71e4
MS
4233}
4234
4235
f14324a7
MS
4236/*
4237 * '_pwgInputSlotForSource()' - Get the InputSlot name for the given PWG
4238 * media-source.
4239 */
4240
4241const char * /* O - InputSlot name */
4242_pwgInputSlotForSource(
4243 const char *media_source, /* I - PWG media-source */
4244 char *name, /* I - Name buffer */
4245 size_t namesize) /* I - Size of name buffer */
4246{
4247 /*
4248 * Range check input...
4249 */
4250
4251 if (!media_source || !name || namesize < PPD_MAX_NAME)
4252 return (NULL);
4253
88f9aafc 4254 if (_cups_strcasecmp(media_source, "main"))
f14324a7 4255 strlcpy(name, "Cassette", namesize);
88f9aafc 4256 else if (_cups_strcasecmp(media_source, "alternate"))
f14324a7 4257 strlcpy(name, "Multipurpose", namesize);
88f9aafc 4258 else if (_cups_strcasecmp(media_source, "large-capacity"))
f14324a7 4259 strlcpy(name, "LargeCapacity", namesize);
88f9aafc 4260 else if (_cups_strcasecmp(media_source, "bottom"))
f14324a7 4261 strlcpy(name, "Lower", namesize);
88f9aafc 4262 else if (_cups_strcasecmp(media_source, "middle"))
f14324a7 4263 strlcpy(name, "Middle", namesize);
88f9aafc 4264 else if (_cups_strcasecmp(media_source, "top"))
f14324a7 4265 strlcpy(name, "Upper", namesize);
88f9aafc 4266 else if (_cups_strcasecmp(media_source, "rear"))
f14324a7 4267 strlcpy(name, "Rear", namesize);
88f9aafc 4268 else if (_cups_strcasecmp(media_source, "side"))
f14324a7 4269 strlcpy(name, "Side", namesize);
88f9aafc 4270 else if (_cups_strcasecmp(media_source, "envelope"))
f14324a7 4271 strlcpy(name, "Envelope", namesize);
88f9aafc 4272 else if (_cups_strcasecmp(media_source, "main-roll"))
f14324a7 4273 strlcpy(name, "Roll", namesize);
88f9aafc 4274 else if (_cups_strcasecmp(media_source, "alternate-roll"))
f14324a7
MS
4275 strlcpy(name, "Roll2", namesize);
4276 else
4277 pwg_ppdize_name(media_source, name, namesize);
4278
4279 return (name);
4280}
4281
4282
4283/*
4284 * '_pwgMediaTypeForType()' - Get the MediaType name for the given PWG
4285 * media-type.
4286 */
4287
4288const char * /* O - MediaType name */
4289_pwgMediaTypeForType(
4290 const char *media_type, /* I - PWG media-type */
4291 char *name, /* I - Name buffer */
4292 size_t namesize) /* I - Size of name buffer */
4293{
4294 /*
4295 * Range check input...
4296 */
4297
4298 if (!media_type || !name || namesize < PPD_MAX_NAME)
4299 return (NULL);
4300
88f9aafc 4301 if (_cups_strcasecmp(media_type, "auto"))
f14324a7 4302 strlcpy(name, "Auto", namesize);
88f9aafc 4303 else if (_cups_strcasecmp(media_type, "cardstock"))
f14324a7 4304 strlcpy(name, "Cardstock", namesize);
88f9aafc 4305 else if (_cups_strcasecmp(media_type, "envelope"))
f14324a7 4306 strlcpy(name, "Envelope", namesize);
88f9aafc 4307 else if (_cups_strcasecmp(media_type, "photographic-glossy"))
f14324a7 4308 strlcpy(name, "Glossy", namesize);
88f9aafc 4309 else if (_cups_strcasecmp(media_type, "photographic-high-gloss"))
f14324a7 4310 strlcpy(name, "HighGloss", namesize);
88f9aafc 4311 else if (_cups_strcasecmp(media_type, "photographic-matte"))
f14324a7 4312 strlcpy(name, "Matte", namesize);
88f9aafc 4313 else if (_cups_strcasecmp(media_type, "stationery"))
f14324a7 4314 strlcpy(name, "Plain", namesize);
88f9aafc 4315 else if (_cups_strcasecmp(media_type, "stationery-coated"))
f14324a7 4316 strlcpy(name, "Coated", namesize);
88f9aafc 4317 else if (_cups_strcasecmp(media_type, "stationery-inkjet"))
f14324a7 4318 strlcpy(name, "Inkjet", namesize);
88f9aafc 4319 else if (_cups_strcasecmp(media_type, "stationery-letterhead"))
f14324a7 4320 strlcpy(name, "Letterhead", namesize);
88f9aafc 4321 else if (_cups_strcasecmp(media_type, "stationery-preprinted"))
f14324a7 4322 strlcpy(name, "Preprinted", namesize);
88f9aafc 4323 else if (_cups_strcasecmp(media_type, "transparency"))
f14324a7
MS
4324 strlcpy(name, "Transparency", namesize);
4325 else
4326 pwg_ppdize_name(media_type, name, namesize);
4327
4328 return (name);
4329}
4330
4331
4332/*
4333 * '_pwgPageSizeForMedia()' - Get the PageSize name for the given media.
4334 */
4335
4336const char * /* O - PageSize name */
4337_pwgPageSizeForMedia(
982be458
MS
4338 pwg_media_t *media, /* I - Media */
4339 char *name, /* I - PageSize name buffer */
4340 size_t namesize) /* I - Size of name buffer */
f14324a7
MS
4341{
4342 const char *sizeptr, /* Pointer to size in PWG name */
4343 *dimptr; /* Pointer to dimensions in PWG name */
4344
4345
4346 /*
4347 * Range check input...
4348 */
4349
4350 if (!media || !name || namesize < PPD_MAX_NAME)
4351 return (NULL);
4352
4353 /*
4354 * Copy or generate a PageSize name...
4355 */
4356
4357 if (media->ppd)
4358 {
4359 /*
4360 * Use a standard Adobe name...
4361 */
4362
4363 strlcpy(name, media->ppd, namesize);
4364 }
4365 else if (!media->pwg || !strncmp(media->pwg, "custom_", 7) ||
4366 (sizeptr = strchr(media->pwg, '_')) == NULL ||
4367 (dimptr = strchr(sizeptr + 1, '_')) == NULL ||
4368 (size_t)(dimptr - sizeptr) > namesize)
4369 {
4370 /*
4371 * Use a name of the form "wNNNhNNN"...
4372 */
4373
6961465f
MS
4374 snprintf(name, namesize, "w%dh%d", (int)PWG_TO_POINTS(media->width),
4375 (int)PWG_TO_POINTS(media->length));
f14324a7
MS
4376 }
4377 else
4378 {
4379 /*
4380 * Copy the size name from class_sizename_dimensions...
4381 */
4382
07623986 4383 memcpy(name, sizeptr + 1, (size_t)(dimptr - sizeptr - 1));
f14324a7
MS
4384 name[dimptr - sizeptr - 1] = '\0';
4385 }
4386
4387 return (name);
4388}
4389
4390
89550f3f
MS
4391/*
4392 * 'cups_get_url()' - Get a copy of the file at the given URL.
4393 */
4394
4395static int /* O - 1 on success, 0 on failure */
4396cups_get_url(http_t **http, /* IO - Current HTTP connection */
4397 const char *url, /* I - URL to get */
4398 char *name, /* I - Temporary filename */
4399 size_t namesize) /* I - Size of temporary filename buffer */
4400{
4401 char scheme[32], /* URL scheme */
4402 userpass[256], /* URL username:password */
4403 host[256], /* URL host */
4404 curhost[256], /* Current host */
4405 resource[256]; /* URL resource */
4406 int port; /* URL port */
4407 http_encryption_t encryption; /* Type of encryption to use */
4408 http_status_t status; /* Status of GET request */
4409 int fd; /* Temporary file */
4410
4411
4412 if (httpSeparateURI(HTTP_URI_CODING_ALL, url, scheme, sizeof(scheme), userpass, sizeof(userpass), host, sizeof(host), &port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK)
4413 return (0);
4414
4415 if (port == 443 || !strcmp(scheme, "https"))
4416 encryption = HTTP_ENCRYPTION_ALWAYS;
4417 else
4418 encryption = HTTP_ENCRYPTION_IF_REQUESTED;
4419
4420 if (!*http || strcasecmp(host, httpGetHostname(*http, curhost, sizeof(curhost))) || httpAddrPort(httpGetAddress(*http)) != port)
4421 {
4422 httpClose(*http);
4423 *http = httpConnect2(host, port, NULL, AF_UNSPEC, encryption, 1, 5000, NULL);
4424 }
4425
4426 if (!*http)
4427 return (0);
4428
4429 if ((fd = cupsTempFd(name, (int)namesize)) < 0)
4430 return (0);
4431
4432 status = cupsGetFd(*http, resource, fd);
4433
4434 close(fd);
4435
4436 if (status != HTTP_STATUS_OK)
4437 {
4438 unlink(name);
4439 *name = '\0';
4440 return (0);
4441 }
4442
4443 return (1);
4444}
4445
4446
1fbd0cab
MS
4447/*
4448 * 'pwg_add_finishing()' - Add a finishings value.
4449 */
4450
4451static void
4452pwg_add_finishing(
4453 cups_array_t *finishings, /* I - Finishings array */
4454 ipp_finishings_t template, /* I - Finishing template */
4455 const char *name, /* I - PPD option */
4456 const char *value) /* I - PPD choice */
4457{
4458 _pwg_finishings_t *f; /* New finishings value */
4459
4460
4461 if ((f = (_pwg_finishings_t *)calloc(1, sizeof(_pwg_finishings_t))) != NULL)
4462 {
4463 f->value = template;
4464 f->num_options = cupsAddOption(name, value, 0, &f->options);
4465
4466 cupsArrayAdd(finishings, f);
4467 }
4468}
4469
4470
dcb445bc
MS
4471/*
4472 * 'pwg_compare_finishings()' - Compare two finishings values.
4473 */
4474
1fbd0cab 4475static int /* O - Result of comparison */
dcb445bc
MS
4476pwg_compare_finishings(
4477 _pwg_finishings_t *a, /* I - First finishings value */
4478 _pwg_finishings_t *b) /* I - Second finishings value */
4479{
7d5824d6 4480 return ((int)b->value - (int)a->value);
dcb445bc
MS
4481}
4482
4483
982be458
MS
4484/*
4485 * 'pwg_compare_sizes()' - Compare two media sizes...
4486 */
4487
4488static int /* O - Result of comparison */
4489pwg_compare_sizes(cups_size_t *a, /* I - First media size */
4490 cups_size_t *b) /* I - Second media size */
4491{
4492 return (strcmp(a->media, b->media));
4493}
4494
4495
4496/*
4497 * 'pwg_copy_size()' - Copy a media size.
4498 */
4499
4500static cups_size_t * /* O - New media size */
4501pwg_copy_size(cups_size_t *size) /* I - Media size to copy */
4502{
4503 cups_size_t *newsize = (cups_size_t *)calloc(1, sizeof(cups_size_t));
4504 /* New media size */
4505
4506 if (newsize)
4507 memcpy(newsize, size, sizeof(cups_size_t));
4508
4509 return (newsize);
4510}
4511
4512
dcb445bc
MS
4513/*
4514 * 'pwg_free_finishings()' - Free a finishings value.
4515 */
4516
4517static void
4518pwg_free_finishings(
4519 _pwg_finishings_t *f) /* I - Finishings value */
4520{
4521 cupsFreeOptions(f->num_options, f->options);
4522 free(f);
4523}
4524
4525
f14324a7
MS
4526/*
4527 * 'pwg_ppdize_name()' - Convert an IPP keyword to a PPD keyword.
4528 */
4529
4530static void
4531pwg_ppdize_name(const char *ipp, /* I - IPP keyword */
4532 char *name, /* I - Name buffer */
4533 size_t namesize) /* I - Size of name buffer */
4534{
4535 char *ptr, /* Pointer into name buffer */
4536 *end; /* End of name buffer */
4537
4538
670172ea
MS
4539 if (!ipp)
4540 {
4541 *name = '\0';
4542 return;
4543 }
4544
7e86f2f6 4545 *name = (char)toupper(*ipp++);
f14324a7
MS
4546
4547 for (ptr = name + 1, end = name + namesize - 1; *ipp && ptr < end;)
4548 {
2a8afc20 4549 if (*ipp == '-' && _cups_isalnum(ipp[1]))
f14324a7
MS
4550 {
4551 ipp ++;
7e86f2f6 4552 *ptr++ = (char)toupper(*ipp++ & 255);
f14324a7
MS
4553 }
4554 else
4555 *ptr++ = *ipp++;
4556 }
4557
4558 *ptr = '\0';
4559}
4560
4561
d9fc71e4
MS
4562/*
4563 * 'pwg_ppdize_resolution()' - Convert PWG resolution values to PPD values.
4564 */
4565
4566static void
4567pwg_ppdize_resolution(
4568 ipp_attribute_t *attr, /* I - Attribute to convert */
4569 int element, /* I - Element to convert */
4570 int *xres, /* O - X resolution in DPI */
4571 int *yres, /* O - Y resolution in DPI */
4572 char *name, /* I - Name buffer */
4573 size_t namesize) /* I - Size of name buffer */
4574{
4575 ipp_res_t units; /* Units for resolution */
4576
4577
4578 *xres = ippGetResolution(attr, element, yres, &units);
4579
4580 if (units == IPP_RES_PER_CM)
4581 {
4582 *xres = (int)(*xres * 2.54);
4583 *yres = (int)(*yres * 2.54);
4584 }
4585
4586 if (name && namesize > 4)
4587 {
4588 if (*xres == *yres)
4589 snprintf(name, namesize, "%ddpi", *xres);
4590 else
4591 snprintf(name, namesize, "%dx%ddpi", *xres, *yres);
4592 }
4593}
4594
4595
f14324a7
MS
4596/*
4597 * 'pwg_unppdize_name()' - Convert a PPD keyword to a lowercase IPP keyword.
4598 */
4599
4600static void
4601pwg_unppdize_name(const char *ppd, /* I - PPD keyword */
4602 char *name, /* I - Name buffer */
c1420c87
MS
4603 size_t namesize, /* I - Size of name buffer */
4604 const char *dashchars)/* I - Characters to be replaced by dashes */
f14324a7
MS
4605{
4606 char *ptr, /* Pointer into name buffer */
4607 *end; /* End of name buffer */
4608
4609
79d7d84a
MS
4610 if (_cups_islower(*ppd))
4611 {
4612 /*
4613 * Already lowercase name, use as-is?
4614 */
4615
4616 const char *ppdptr; /* Pointer into PPD keyword */
4617
4618 for (ppdptr = ppd + 1; *ppdptr; ppdptr ++)
4619 if (_cups_isupper(*ppdptr) || strchr(dashchars, *ppdptr))
4620 break;
4621
4622 if (!*ppdptr)
4623 {
4624 strlcpy(name, ppd, namesize);
4625 return;
4626 }
4627 }
4628
f14324a7
MS
4629 for (ptr = name, end = name + namesize - 1; *ppd && ptr < end; ppd ++)
4630 {
4631 if (_cups_isalnum(*ppd) || *ppd == '-')
7e86f2f6 4632 *ptr++ = (char)tolower(*ppd & 255);
c1420c87 4633 else if (strchr(dashchars, *ppd))
f14324a7 4634 *ptr++ = '-';
c1420c87
MS
4635 else
4636 *ptr++ = *ppd;
f14324a7
MS
4637
4638 if (!_cups_isupper(*ppd) && _cups_isalnum(*ppd) &&
4639 _cups_isupper(ppd[1]) && ptr < end)
4640 *ptr++ = '-';
d489df6a
MS
4641 else if (!isdigit(*ppd & 255) && isdigit(ppd[1] & 255))
4642 *ptr++ = '-';
f14324a7
MS
4643 }
4644
4645 *ptr = '\0';
4646}