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