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