X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=cups%2Fppd-cache.c;h=5965e382bb80b2108b7c9ebbf56451daa4af53fb;hb=HEAD;hp=a919d21e8a9292c5c1daa4dbe8a4e93e91687b8f;hpb=1999164de01976ea595a6b4dd69e6d97924c24b2;p=thirdparty%2Fcups.git diff --git a/cups/ppd-cache.c b/cups/ppd-cache.c index a919d21e8..091f39f3c 100644 --- a/cups/ppd-cache.c +++ b/cups/ppd-cache.c @@ -1,15 +1,10 @@ /* * PPD cache implementation for CUPS. * - * Copyright 2010-2016 by Apple Inc. + * Copyright © 2010-2019 by Apple Inc. * - * These coded instructions, statements, and computer programs are the - * property of Apple Inc. and are protected by Federal copyright - * law. Distribution and use rights are outlined in the file "LICENSE.txt" - * which should have been included with this file. If this file is - * file is missing or damaged, see the license at "http://www.cups.org/". - * - * This file is subject to the Apple OS-Developed Software exception. + * Licensed under Apache License v2.0. See the file "LICENSE" for more + * information. */ /* @@ -18,6 +13,7 @@ #include "cups-private.h" #include "ppd-private.h" +#include "debug-internal.h" #include @@ -32,10 +28,13 @@ * Local functions... */ -static int pwg_compare_finishings(_pwg_finishings_t *a, - _pwg_finishings_t *b); +static int cups_get_url(http_t **http, const char *url, char *name, size_t namesize); +static void pwg_add_finishing(cups_array_t *finishings, ipp_finishings_t template, const char *name, const char *value); +static void pwg_add_message(cups_array_t *a, const char *msg, const char *str); +static int pwg_compare_finishings(_pwg_finishings_t *a, _pwg_finishings_t *b); +static int pwg_compare_sizes(cups_size_t *a, cups_size_t *b); +static cups_size_t *pwg_copy_size(cups_size_t *size); static void pwg_free_finishings(_pwg_finishings_t *f); -static void pwg_free_material(_pwg_material_t *m); static void pwg_ppdize_name(const char *ipp, char *name, size_t namesize); static void pwg_ppdize_resolution(ipp_attribute_t *attr, int element, int *xres, int *yres, char *name, size_t namesize); static void pwg_unppdize_name(const char *ppd, char *name, size_t namesize, @@ -49,21 +48,20 @@ static void pwg_unppdize_name(const char *ppd, char *name, size_t namesize, * attributes and values and adds them to the specified IPP request. */ -int /* O - New number of copies */ -_cupsConvertOptions(ipp_t *request, /* I - IPP request */ - ppd_file_t *ppd, /* I - PPD file */ - _ppd_cache_t *pc, /* I - PPD cache info */ - ipp_attribute_t *media_col_sup, - /* I - media-col-supported values */ - ipp_attribute_t *doc_handling_sup, - /* I - multiple-document-handling-supported values */ - ipp_attribute_t *print_color_mode_sup, - /* I - Printer supports print-color-mode */ - const char *user, /* I - User info */ - const char *format, /* I - document-format value */ - int copies, /* I - Number of copies */ - int num_options, /* I - Number of options */ - cups_option_t *options) /* I - Options */ +int /* O - New number of copies */ +_cupsConvertOptions( + ipp_t *request, /* I - IPP request */ + ppd_file_t *ppd, /* I - PPD file */ + _ppd_cache_t *pc, /* I - PPD cache info */ + ipp_attribute_t *media_col_sup, /* I - media-col-supported values */ + ipp_attribute_t *doc_handling_sup, /* I - multiple-document-handling-supported values */ + ipp_attribute_t *print_color_mode_sup, + /* I - Printer supports print-color-mode */ + const char *user, /* I - User info */ + const char *format, /* I - document-format value */ + int copies, /* I - Number of copies */ + int num_options, /* I - Number of options */ + cups_option_t *options) /* I - Options */ { int i; /* Looping var */ const char *keyword, /* PWG keyword */ @@ -75,10 +73,16 @@ _cupsConvertOptions(ipp_t *request, /* I - IPP request */ *media_type, /* media-type value */ *collate_str, /* multiple-document-handling value */ *color_attr_name, /* Supported color attribute */ - *mandatory; /* Mandatory attributes */ + *mandatory, /* Mandatory attributes */ + *finishing_template; /* Finishing template */ int num_finishings = 0, /* Number of finishing values */ finishings[10]; /* Finishing enum values */ ppd_choice_t *choice; /* Marked choice */ + int finishings_copies = copies, + /* Number of copies for finishings */ + job_pages = 0, /* job-pages value */ + number_up = 1; /* number-up value */ + const char *value; /* Option value */ /* @@ -140,6 +144,8 @@ _cupsConvertOptions(ipp_t *request, /* I - IPP request */ if (strcmp(mandatory, "copies") && strcmp(mandatory, "destination-uris") && strcmp(mandatory, "finishings") && + strcmp(mandatory, "finishings-col") && + strcmp(mandatory, "finishing-template") && strcmp(mandatory, "job-account-id") && strcmp(mandatory, "job-accounting-user-id") && strcmp(mandatory, "job-password") && @@ -198,41 +204,42 @@ _cupsConvertOptions(ipp_t *request, /* I - IPP request */ if ((keyword = cupsGetOption("PageSize", num_options, options)) == NULL) keyword = cupsGetOption("media", num_options, options); - if ((size = _ppdCacheGetSize(pc, keyword)) != NULL) + media_source = _ppdCacheGetSource(pc, cupsGetOption("InputSlot", num_options, options)); + media_type = _ppdCacheGetType(pc, cupsGetOption("MediaType", num_options, options)); + size = _ppdCacheGetSize(pc, keyword); + + if (size || media_source || media_type) { /* * Add a media-col value... */ - media_size = ippNew(); - ippAddInteger(media_size, IPP_TAG_ZERO, IPP_TAG_INTEGER, - "x-dimension", size->width); - ippAddInteger(media_size, IPP_TAG_ZERO, IPP_TAG_INTEGER, - "y-dimension", size->length); - media_col = ippNew(); - ippAddCollection(media_col, IPP_TAG_ZERO, "media-size", media_size); - media_source = _ppdCacheGetSource(pc, cupsGetOption("InputSlot", - num_options, - options)); - media_type = _ppdCacheGetType(pc, cupsGetOption("MediaType", - num_options, - options)); + if (size) + { + media_size = ippNew(); + ippAddInteger(media_size, IPP_TAG_ZERO, IPP_TAG_INTEGER, + "x-dimension", size->width); + ippAddInteger(media_size, IPP_TAG_ZERO, IPP_TAG_INTEGER, + "y-dimension", size->length); + + ippAddCollection(media_col, IPP_TAG_ZERO, "media-size", media_size); + } for (i = 0; i < media_col_sup->num_values; i ++) { - if (!strcmp(media_col_sup->values[i].string.text, "media-left-margin")) + if (size && !strcmp(media_col_sup->values[i].string.text, "media-left-margin")) ippAddInteger(media_col, IPP_TAG_ZERO, IPP_TAG_INTEGER, "media-left-margin", size->left); - else if (!strcmp(media_col_sup->values[i].string.text, "media-bottom-margin")) + else if (size && !strcmp(media_col_sup->values[i].string.text, "media-bottom-margin")) ippAddInteger(media_col, IPP_TAG_ZERO, IPP_TAG_INTEGER, "media-bottom-margin", size->bottom); - else if (!strcmp(media_col_sup->values[i].string.text, "media-right-margin")) + else if (size && !strcmp(media_col_sup->values[i].string.text, "media-right-margin")) ippAddInteger(media_col, IPP_TAG_ZERO, IPP_TAG_INTEGER, "media-right-margin", size->right); - else if (!strcmp(media_col_sup->values[i].string.text, "media-top-margin")) + else if (size && !strcmp(media_col_sup->values[i].string.text, "media-top-margin")) ippAddInteger(media_col, IPP_TAG_ZERO, IPP_TAG_INTEGER, "media-top-margin", size->top); - else if (!strcmp(media_col_sup->values[i].string.text, "media-source") && media_source) + else if (media_source && !strcmp(media_col_sup->values[i].string.text, "media-source")) ippAddString(media_col, IPP_TAG_ZERO, IPP_TAG_KEYWORD, "media-source", NULL, media_source); - else if (!strcmp(media_col_sup->values[i].string.text, "media-type") && media_type) + else if (media_type && !strcmp(media_col_sup->values[i].string.text, "media-type")) ippAddString(media_col, IPP_TAG_ZERO, IPP_TAG_KEYWORD, "media-type", NULL, media_type); } @@ -288,11 +295,11 @@ _cupsConvertOptions(ipp_t *request, /* I - IPP request */ ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "sides", NULL, keyword); else if (pc->sides_option && (choice = ppdFindMarkedChoice(ppd, pc->sides_option)) != NULL) { - if (!_cups_strcasecmp(choice->choice, pc->sides_1sided)) + if (pc->sides_1sided && !_cups_strcasecmp(choice->choice, pc->sides_1sided)) ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "sides", NULL, "one-sided"); - else if (!_cups_strcasecmp(choice->choice, pc->sides_2sided_long)) + else if (pc->sides_2sided_long && !_cups_strcasecmp(choice->choice, pc->sides_2sided_long)) ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "sides", NULL, "two-sided-long-edge"); - if (!_cups_strcasecmp(choice->choice, pc->sides_2sided_short)) + else if (pc->sides_2sided_short && !_cups_strcasecmp(choice->choice, pc->sides_2sided_short)) ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "sides", NULL, "two-sided-short-edge"); } @@ -361,18 +368,63 @@ _cupsConvertOptions(ipp_t *request, /* I - IPP request */ * Map finishing options... */ - num_finishings = _ppdCacheGetFinishingValues(pc, num_options, options, (int)(sizeof(finishings) / sizeof(finishings[0])), finishings); - if (num_finishings > 0) + if (copies != finishings_copies) + { + // Figure out the proper job-pages-per-set value... + if ((value = cupsGetOption("job-pages", num_options, options)) == NULL) + value = cupsGetOption("com.apple.print.PrintSettings.PMTotalBeginPages..n.", num_options, options); + + if (value) + job_pages = atoi(value); + + // Adjust for number-up + if ((value = cupsGetOption("number-up", num_options, options)) != NULL) + number_up = atoi(value); + + job_pages = (job_pages + number_up - 1) / number_up; + + // When duplex printing, raster data will include an extra (blank) page to + // make the total number of pages even. Make sure this is reflected in the + // page count... + if ((job_pages & 1) && (keyword = cupsGetOption("sides", num_options, options)) != NULL && strcmp(keyword, "one-sided")) + job_pages ++; + } + + if ((finishing_template = cupsGetOption("cupsFinishingTemplate", num_options, options)) == NULL) + finishing_template = cupsGetOption("finishing-template", num_options, options); + + if (finishing_template && strcmp(finishing_template, "none")) { - ippAddIntegers(request, IPP_TAG_JOB, IPP_TAG_ENUM, "finishings", num_finishings, finishings); + ipp_t *fin_col = ippNew(); /* finishings-col value */ + + ippAddString(fin_col, IPP_TAG_JOB, IPP_TAG_KEYWORD, "finishing-template", NULL, finishing_template); + ippAddCollection(request, IPP_TAG_JOB, "finishings-col", fin_col); + ippDelete(fin_col); - if (copies > 1 && (keyword = cupsGetOption("job-impressions", num_options, options)) != NULL) + if (copies != finishings_copies && job_pages > 0) { /* * Send job-pages-per-set attribute to apply finishings correctly... */ - ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-pages-per-set", atoi(keyword) / copies); + ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-pages-per-set", job_pages); + } + } + else + { + num_finishings = _ppdCacheGetFinishingValues(ppd, pc, (int)(sizeof(finishings) / sizeof(finishings[0])), finishings); + if (num_finishings > 0) + { + ippAddIntegers(request, IPP_TAG_JOB, IPP_TAG_ENUM, "finishings", num_finishings, finishings); + + if (copies != finishings_copies && job_pages > 0) + { + /* + * Send job-pages-per-set attribute to apply finishings correctly... + */ + + ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-pages-per-set", job_pages); + } } } @@ -503,74 +555,23 @@ _ppdCacheCreateWithFile( _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1); goto create_error; } - else if (!_cups_strcasecmp(line, "3D")) - { - pc->cups_3d = _cupsStrAlloc(value); - } - else if (!_cups_strcasecmp(line, "LayerOrder")) - { - pc->cups_layer_order = _cupsStrAlloc(value); - } - else if (!_cups_strcasecmp(line, "Accuracy")) - { - sscanf(value, "%d%d%d", pc->cups_accuracy + 0, pc->cups_accuracy + 1, pc->cups_accuracy + 2); - } - else if (!_cups_strcasecmp(line, "Volume")) - { - sscanf(value, "%d%d%d", pc->cups_volume + 0, pc->cups_volume + 1, pc->cups_volume + 2); - } - else if (!_cups_strcasecmp(line, "Material")) - { - /* - * Material key "name" name=value ... name=value - */ - - if ((valueptr = strchr(value, ' ')) != NULL) - { - _pwg_material_t *material = (_pwg_material_t *)calloc(1, sizeof(_pwg_material_t)); - - *valueptr++ = '\0'; - - material->key = _cupsStrAlloc(value); - - if (*valueptr == '\"') - { - value = valueptr + 1; - if ((valueptr = strchr(value, '\"')) != NULL) - { - *valueptr++ = '\0'; - material->name = _cupsStrAlloc(value); - material->num_props = cupsParseOptions(valueptr, 0, &material->props); - } - } - - if (!pc->materials) - pc->materials = cupsArrayNew3(NULL, NULL, NULL, 0, NULL, (cups_afree_func_t)pwg_free_material); - - cupsArrayAdd(pc->materials, material); - } - } else if (!_cups_strcasecmp(line, "Filter")) { if (!pc->filters) - pc->filters = cupsArrayNew3(NULL, NULL, NULL, 0, - (cups_acopy_func_t)_cupsStrAlloc, - (cups_afree_func_t)_cupsStrFree); + pc->filters = cupsArrayNew3(NULL, NULL, NULL, 0, (cups_acopy_func_t)strdup, (cups_afree_func_t)free); cupsArrayAdd(pc->filters, value); } else if (!_cups_strcasecmp(line, "PreFilter")) { if (!pc->prefilters) - pc->prefilters = cupsArrayNew3(NULL, NULL, NULL, 0, - (cups_acopy_func_t)_cupsStrAlloc, - (cups_afree_func_t)_cupsStrFree); + pc->prefilters = cupsArrayNew3(NULL, NULL, NULL, 0, (cups_acopy_func_t)strdup, (cups_afree_func_t)free); cupsArrayAdd(pc->prefilters, value); } else if (!_cups_strcasecmp(line, "Product")) { - pc->product = _cupsStrAlloc(value); + pc->product = strdup(value); } else if (!_cups_strcasecmp(line, "SingleFile")) { @@ -670,8 +671,8 @@ _ppdCacheCreateWithFile( } map = pc->bins + pc->num_bins; - map->pwg = _cupsStrAlloc(pwg_keyword); - map->ppd = _cupsStrAlloc(ppd_keyword); + map->pwg = strdup(pwg_keyword); + map->ppd = strdup(ppd_keyword); pc->num_bins ++; } @@ -725,8 +726,8 @@ _ppdCacheCreateWithFile( goto create_error; } - size->map.pwg = _cupsStrAlloc(pwg_keyword); - size->map.ppd = _cupsStrAlloc(ppd_keyword); + size->map.pwg = strdup(pwg_keyword); + size->map.ppd = strdup(ppd_keyword); pc->num_sizes ++; } @@ -754,15 +755,15 @@ _ppdCacheCreateWithFile( pwgFormatSizeName(pwg_keyword, sizeof(pwg_keyword), "custom", "max", pc->custom_max_width, pc->custom_max_length, NULL); - pc->custom_max_keyword = _cupsStrAlloc(pwg_keyword); + pc->custom_max_keyword = strdup(pwg_keyword); pwgFormatSizeName(pwg_keyword, sizeof(pwg_keyword), "custom", "min", pc->custom_min_width, pc->custom_min_length, NULL); - pc->custom_min_keyword = _cupsStrAlloc(pwg_keyword); + pc->custom_min_keyword = strdup(pwg_keyword); } else if (!_cups_strcasecmp(line, "SourceOption")) { - pc->source_option = _cupsStrAlloc(value); + pc->source_option = strdup(value); } else if (!_cups_strcasecmp(line, "NumSources")) { @@ -809,8 +810,8 @@ _ppdCacheCreateWithFile( } map = pc->sources + pc->num_sources; - map->pwg = _cupsStrAlloc(pwg_keyword); - map->ppd = _cupsStrAlloc(ppd_keyword); + map->pwg = strdup(pwg_keyword); + map->ppd = strdup(ppd_keyword); pc->num_sources ++; } @@ -858,8 +859,8 @@ _ppdCacheCreateWithFile( } map = pc->types + pc->num_types; - map->pwg = _cupsStrAlloc(pwg_keyword); - map->ppd = _cupsStrAlloc(ppd_keyword); + map->pwg = strdup(pwg_keyword); + map->ppd = strdup(ppd_keyword); pc->num_types ++; } @@ -889,13 +890,13 @@ _ppdCacheCreateWithFile( pc->presets[print_color_mode] + print_quality); } else if (!_cups_strcasecmp(line, "SidesOption")) - pc->sides_option = _cupsStrAlloc(value); + pc->sides_option = strdup(value); else if (!_cups_strcasecmp(line, "Sides1Sided")) - pc->sides_1sided = _cupsStrAlloc(value); + pc->sides_1sided = strdup(value); else if (!_cups_strcasecmp(line, "Sides2SidedLong")) - pc->sides_2sided_long = _cupsStrAlloc(value); + pc->sides_2sided_long = strdup(value); else if (!_cups_strcasecmp(line, "Sides2SidedShort")) - pc->sides_2sided_short = _cupsStrAlloc(value); + pc->sides_2sided_short = strdup(value); else if (!_cups_strcasecmp(line, "Finishings")) { if (!pc->finishings) @@ -913,16 +914,23 @@ _ppdCacheCreateWithFile( cupsArrayAdd(pc->finishings, finishings); } + else if (!_cups_strcasecmp(line, "FinishingTemplate")) + { + if (!pc->templates) + pc->templates = cupsArrayNew3((cups_array_func_t)strcmp, NULL, NULL, 0, (cups_acopy_func_t)strdup, (cups_afree_func_t)free); + + cupsArrayAdd(pc->templates, value); + } else if (!_cups_strcasecmp(line, "MaxCopies")) pc->max_copies = atoi(value); else if (!_cups_strcasecmp(line, "ChargeInfoURI")) - pc->charge_info_uri = _cupsStrAlloc(value); + pc->charge_info_uri = strdup(value); else if (!_cups_strcasecmp(line, "JobAccountId")) pc->account_id = !_cups_strcasecmp(value, "true"); else if (!_cups_strcasecmp(line, "JobAccountingUserId")) pc->accounting_user_id = !_cups_strcasecmp(value, "true"); else if (!_cups_strcasecmp(line, "JobPassword")) - pc->password = _cupsStrAlloc(value); + pc->password = strdup(value); else if (!_cups_strcasecmp(line, "Mandatory")) { if (pc->mandatory) @@ -933,9 +941,7 @@ _ppdCacheCreateWithFile( else if (!_cups_strcasecmp(line, "SupportFile")) { if (!pc->support_files) - pc->support_files = cupsArrayNew3(NULL, NULL, NULL, 0, - (cups_acopy_func_t)_cupsStrAlloc, - (cups_afree_func_t)_cupsStrFree); + pc->support_files = cupsArrayNew3(NULL, NULL, NULL, 0, (cups_acopy_func_t)strdup, (cups_afree_func_t)free); cupsArrayAdd(pc->support_files, value); } @@ -1006,7 +1012,8 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ *media_type, /* MediaType option */ *output_bin, /* OutputBin option */ *color_model, /* ColorModel option */ - *duplex; /* Duplex option */ + *duplex, /* Duplex option */ + *ppd_option; /* Other PPD option */ ppd_choice_t *choice; /* Current InputSlot/MediaType */ pwg_map_t *map; /* Current source/type map */ ppd_attr_t *ppd_attr; /* Current PPD preset attribute */ @@ -1041,6 +1048,7 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ pwg_size_t *new_size; /* New size to add, if any */ const char *filter; /* Current filter */ _pwg_finishings_t *finishings; /* Current finishings value */ + char msg_id[256]; /* Message identifier */ DEBUG_printf(("_ppdCacheCreateWithPPD(ppd=%p)", ppd)); @@ -1062,6 +1070,8 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ goto create_error; } + pc->strings = _cupsMessageNew(NULL); + /* * Copy and convert size data... */ @@ -1090,7 +1100,7 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ * Convert the PPD size name to the corresponding PWG keyword name. */ - if ((pwg_media = pwgMediaForPPD(ppd_size->name)) != NULL) + if ((pwg_media = pwgMediaForSize(PWG_FROM_POINTS(ppd_size->width), PWG_FROM_POINTS(ppd_size->length))) != NULL) { /* * Standard name, do we have conflicts? @@ -1175,8 +1185,8 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ */ new_size = old_size; - _cupsStrFree(old_size->map.ppd); - _cupsStrFree(old_size->map.pwg); + free(old_size->map.ppd); + free(old_size->map.pwg); } } @@ -1197,8 +1207,8 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ * Save this size... */ - new_size->map.ppd = _cupsStrAlloc(ppd_size->name); - new_size->map.pwg = _cupsStrAlloc(pwg_name); + new_size->map.ppd = strdup(ppd_size->name); + new_size->map.pwg = strdup(pwg_name); new_size->width = new_width; new_size->length = new_length; new_size->left = new_left; @@ -1218,14 +1228,14 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ pwgFormatSizeName(pwg_keyword, sizeof(pwg_keyword), "custom", "max", PWG_FROM_POINTS(ppd->custom_max[0]), PWG_FROM_POINTS(ppd->custom_max[1]), NULL); - pc->custom_max_keyword = _cupsStrAlloc(pwg_keyword); + pc->custom_max_keyword = strdup(pwg_keyword); pc->custom_max_width = PWG_FROM_POINTS(ppd->custom_max[0]); pc->custom_max_length = PWG_FROM_POINTS(ppd->custom_max[1]); pwgFormatSizeName(pwg_keyword, sizeof(pwg_keyword), "custom", "min", PWG_FROM_POINTS(ppd->custom_min[0]), PWG_FROM_POINTS(ppd->custom_min[1]), NULL); - pc->custom_min_keyword = _cupsStrAlloc(pwg_keyword); + pc->custom_min_keyword = strdup(pwg_keyword); pc->custom_min_width = PWG_FROM_POINTS(ppd->custom_min[0]); pc->custom_min_length = PWG_FROM_POINTS(ppd->custom_min[1]); @@ -1244,7 +1254,7 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ if (input_slot) { - pc->source_option = _cupsStrAlloc(input_slot->keyword); + pc->source_option = strdup(input_slot->keyword); if ((pc->sources = calloc((size_t)input_slot->num_choices, sizeof(pwg_map_t))) == NULL) { @@ -1296,8 +1306,15 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ "_"); } - map->pwg = _cupsStrAlloc(pwg_name); - map->ppd = _cupsStrAlloc(choice->choice); + map->pwg = strdup(pwg_name); + map->ppd = strdup(choice->choice); + + /* + * Add localized text for PWG keyword to message catalog... + */ + + snprintf(msg_id, sizeof(msg_id), "media-source.%s", pwg_name); + pwg_add_message(pc->strings, msg_id, choice->text); } } @@ -1360,8 +1377,15 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ "_"); } - map->pwg = _cupsStrAlloc(pwg_name); - map->ppd = _cupsStrAlloc(choice->choice); + map->pwg = strdup(pwg_name); + map->ppd = strdup(choice->choice); + + /* + * Add localized text for PWG keyword to message catalog... + */ + + snprintf(msg_id, sizeof(msg_id), "media-type.%s", pwg_name); + pwg_add_message(pc->strings, msg_id, choice->text); } } @@ -1387,8 +1411,15 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ { pwg_unppdize_name(choice->choice, pwg_keyword, sizeof(pwg_keyword), "_"); - map->pwg = _cupsStrAlloc(pwg_keyword); - map->ppd = _cupsStrAlloc(choice->choice); + map->pwg = strdup(pwg_keyword); + map->ppd = strdup(choice->choice); + + /* + * Add localized text for PWG keyword to message catalog... + */ + + snprintf(msg_id, sizeof(msg_id), "output-bin.%s", pwg_keyword); + pwg_add_message(pc->strings, msg_id, choice->text); } } @@ -1406,6 +1437,17 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ do { + /* + * Add localized text for PWG keyword to message catalog... + */ + + snprintf(msg_id, sizeof(msg_id), "preset-name.%s", ppd_attr->spec); + pwg_add_message(pc->strings, msg_id, ppd_attr->text); + + /* + * Get the options for this preset... + */ + num_options = _ppdParseOptions(ppd_attr->value, 0, &options, _PPD_PARSE_ALL); @@ -1603,7 +1645,7 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ if (duplex) { - pc->sides_option = _cupsStrAlloc(duplex->keyword); + pc->sides_option = strdup(duplex->keyword); for (i = duplex->num_choices, choice = duplex->choices; i > 0; @@ -1611,16 +1653,16 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ { if ((!_cups_strcasecmp(choice->choice, "None") || !_cups_strcasecmp(choice->choice, "False")) && !pc->sides_1sided) - pc->sides_1sided = _cupsStrAlloc(choice->choice); + pc->sides_1sided = strdup(choice->choice); else if ((!_cups_strcasecmp(choice->choice, "DuplexNoTumble") || !_cups_strcasecmp(choice->choice, "LongEdge") || !_cups_strcasecmp(choice->choice, "Top")) && !pc->sides_2sided_long) - pc->sides_2sided_long = _cupsStrAlloc(choice->choice); + pc->sides_2sided_long = strdup(choice->choice); else if ((!_cups_strcasecmp(choice->choice, "DuplexTumble") || !_cups_strcasecmp(choice->choice, "ShortEdge") || !_cups_strcasecmp(choice->choice, "Bottom")) && !pc->sides_2sided_short) - pc->sides_2sided_short = _cupsStrAlloc(choice->choice); + pc->sides_2sided_short = strdup(choice->choice); } } @@ -1628,9 +1670,7 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ * Copy filters and pre-filters... */ - pc->filters = cupsArrayNew3(NULL, NULL, NULL, 0, - (cups_acopy_func_t)_cupsStrAlloc, - (cups_afree_func_t)_cupsStrFree); + pc->filters = cupsArrayNew3(NULL, NULL, NULL, 0, (cups_acopy_func_t)strdup, (cups_afree_func_t)free); cupsArrayAdd(pc->filters, "application/vnd.cups-raw application/octet-stream 0 -"); @@ -1687,9 +1727,7 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ if ((ppd_attr = ppdFindAttr(ppd, "cupsPreFilter", NULL)) != NULL) { - pc->prefilters = cupsArrayNew3(NULL, NULL, NULL, 0, - (cups_acopy_func_t)_cupsStrAlloc, - (cups_afree_func_t)_cupsStrFree); + pc->prefilters = cupsArrayNew3(NULL, NULL, NULL, 0, (cups_acopy_func_t)strdup, (cups_afree_func_t)free); do { @@ -1706,7 +1744,7 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ */ if (ppd->product) - pc->product = _cupsStrAlloc(ppd->product); + pc->product = strdup(ppd->product); /* * Copy finishings mapping data... @@ -1714,6 +1752,10 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ if ((ppd_attr = ppdFindAttr(ppd, "cupsIPPFinishings", NULL)) != NULL) { + /* + * Have proper vendor mapping of IPP finishings values to PPD options... + */ + pc->finishings = cupsArrayNew3((cups_array_func_t)pwg_compare_finishings, NULL, NULL, 0, NULL, (cups_afree_func_t)pwg_free_finishings); @@ -1733,6 +1775,129 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ while ((ppd_attr = ppdFindNextAttr(ppd, "cupsIPPFinishings", NULL)) != NULL); } + else + { + /* + * No IPP mapping data, try to map common/standard PPD keywords... + */ + + pc->finishings = cupsArrayNew3((cups_array_func_t)pwg_compare_finishings, NULL, NULL, 0, NULL, (cups_afree_func_t)pwg_free_finishings); + + if ((ppd_option = ppdFindOption(ppd, "StapleLocation")) != NULL) + { + /* + * Add staple finishings... + */ + + if (ppdFindChoice(ppd_option, "SinglePortrait")) + pwg_add_finishing(pc->finishings, IPP_FINISHINGS_STAPLE_TOP_LEFT, "StapleLocation", "SinglePortrait"); + if (ppdFindChoice(ppd_option, "UpperLeft")) /* Ricoh extension */ + pwg_add_finishing(pc->finishings, IPP_FINISHINGS_STAPLE_TOP_LEFT, "StapleLocation", "UpperLeft"); + if (ppdFindChoice(ppd_option, "UpperRight")) /* Ricoh extension */ + pwg_add_finishing(pc->finishings, IPP_FINISHINGS_STAPLE_TOP_RIGHT, "StapleLocation", "UpperRight"); + if (ppdFindChoice(ppd_option, "SingleLandscape")) + pwg_add_finishing(pc->finishings, IPP_FINISHINGS_STAPLE_BOTTOM_LEFT, "StapleLocation", "SingleLandscape"); + if (ppdFindChoice(ppd_option, "DualLandscape")) + pwg_add_finishing(pc->finishings, IPP_FINISHINGS_STAPLE_DUAL_LEFT, "StapleLocation", "DualLandscape"); + } + + if ((ppd_option = ppdFindOption(ppd, "RIPunch")) != NULL) + { + /* + * Add (Ricoh) punch finishings... + */ + + if (ppdFindChoice(ppd_option, "Left2")) + pwg_add_finishing(pc->finishings, IPP_FINISHINGS_PUNCH_DUAL_LEFT, "RIPunch", "Left2"); + if (ppdFindChoice(ppd_option, "Left3")) + pwg_add_finishing(pc->finishings, IPP_FINISHINGS_PUNCH_TRIPLE_LEFT, "RIPunch", "Left3"); + if (ppdFindChoice(ppd_option, "Left4")) + pwg_add_finishing(pc->finishings, IPP_FINISHINGS_PUNCH_QUAD_LEFT, "RIPunch", "Left4"); + if (ppdFindChoice(ppd_option, "Right2")) + pwg_add_finishing(pc->finishings, IPP_FINISHINGS_PUNCH_DUAL_RIGHT, "RIPunch", "Right2"); + if (ppdFindChoice(ppd_option, "Right3")) + pwg_add_finishing(pc->finishings, IPP_FINISHINGS_PUNCH_TRIPLE_RIGHT, "RIPunch", "Right3"); + if (ppdFindChoice(ppd_option, "Right4")) + pwg_add_finishing(pc->finishings, IPP_FINISHINGS_PUNCH_QUAD_RIGHT, "RIPunch", "Right4"); + if (ppdFindChoice(ppd_option, "Upper2")) + pwg_add_finishing(pc->finishings, IPP_FINISHINGS_PUNCH_DUAL_TOP, "RIPunch", "Upper2"); + if (ppdFindChoice(ppd_option, "Upper3")) + pwg_add_finishing(pc->finishings, IPP_FINISHINGS_PUNCH_TRIPLE_TOP, "RIPunch", "Upper3"); + if (ppdFindChoice(ppd_option, "Upper4")) + pwg_add_finishing(pc->finishings, IPP_FINISHINGS_PUNCH_QUAD_TOP, "RIPunch", "Upper4"); + } + + if ((ppd_option = ppdFindOption(ppd, "BindEdge")) != NULL) + { + /* + * Add bind finishings... + */ + + if (ppdFindChoice(ppd_option, "Left")) + pwg_add_finishing(pc->finishings, IPP_FINISHINGS_BIND_LEFT, "BindEdge", "Left"); + if (ppdFindChoice(ppd_option, "Right")) + pwg_add_finishing(pc->finishings, IPP_FINISHINGS_BIND_RIGHT, "BindEdge", "Right"); + if (ppdFindChoice(ppd_option, "Top")) + pwg_add_finishing(pc->finishings, IPP_FINISHINGS_BIND_TOP, "BindEdge", "Top"); + if (ppdFindChoice(ppd_option, "Bottom")) + pwg_add_finishing(pc->finishings, IPP_FINISHINGS_BIND_BOTTOM, "BindEdge", "Bottom"); + } + + if ((ppd_option = ppdFindOption(ppd, "FoldType")) != NULL) + { + /* + * Add (Adobe) fold finishings... + */ + + if (ppdFindChoice(ppd_option, "ZFold")) + pwg_add_finishing(pc->finishings, IPP_FINISHINGS_FOLD_Z, "FoldType", "ZFold"); + if (ppdFindChoice(ppd_option, "Saddle")) + pwg_add_finishing(pc->finishings, IPP_FINISHINGS_FOLD_HALF, "FoldType", "Saddle"); + if (ppdFindChoice(ppd_option, "DoubleGate")) + pwg_add_finishing(pc->finishings, IPP_FINISHINGS_FOLD_DOUBLE_GATE, "FoldType", "DoubleGate"); + if (ppdFindChoice(ppd_option, "LeftGate")) + pwg_add_finishing(pc->finishings, IPP_FINISHINGS_FOLD_LEFT_GATE, "FoldType", "LeftGate"); + if (ppdFindChoice(ppd_option, "RightGate")) + pwg_add_finishing(pc->finishings, IPP_FINISHINGS_FOLD_RIGHT_GATE, "FoldType", "RightGate"); + if (ppdFindChoice(ppd_option, "Letter")) + pwg_add_finishing(pc->finishings, IPP_FINISHINGS_FOLD_LETTER, "FoldType", "Letter"); + if (ppdFindChoice(ppd_option, "XFold")) + pwg_add_finishing(pc->finishings, IPP_FINISHINGS_FOLD_POSTER, "FoldType", "XFold"); + } + + if ((ppd_option = ppdFindOption(ppd, "RIFoldType")) != NULL) + { + /* + * Add (Ricoh) fold finishings... + */ + + if (ppdFindChoice(ppd_option, "OutsideTwoFold")) + pwg_add_finishing(pc->finishings, IPP_FINISHINGS_FOLD_LETTER, "RIFoldType", "OutsideTwoFold"); + } + + if (cupsArrayCount(pc->finishings) == 0) + { + cupsArrayDelete(pc->finishings); + pc->finishings = NULL; + } + } + + if ((ppd_option = ppdFindOption(ppd, "cupsFinishingTemplate")) != NULL) + { + pc->templates = cupsArrayNew3((cups_array_func_t)strcmp, NULL, NULL, 0, (cups_acopy_func_t)strdup, (cups_afree_func_t)free); + + for (choice = ppd_option->choices, i = ppd_option->num_choices; i > 0; choice ++, i --) + { + cupsArrayAdd(pc->templates, (void *)choice->choice); + + /* + * Add localized text for PWG keyword to message catalog... + */ + + snprintf(msg_id, sizeof(msg_id), "finishing-template.%s", choice->choice); + pwg_add_message(pc->strings, msg_id, choice->text); + } + } /* * Max copies... @@ -1751,7 +1916,7 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ */ if ((ppd_attr = ppdFindAttr(ppd, "cupsChargeInfoURI", NULL)) != NULL) - pc->charge_info_uri = _cupsStrAlloc(ppd_attr->value); + pc->charge_info_uri = strdup(ppd_attr->value); if ((ppd_attr = ppdFindAttr(ppd, "cupsJobAccountId", NULL)) != NULL) pc->account_id = !_cups_strcasecmp(ppd_attr->value, "true"); @@ -1760,7 +1925,7 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ pc->accounting_user_id = !_cups_strcasecmp(ppd_attr->value, "true"); if ((ppd_attr = ppdFindAttr(ppd, "cupsJobPassword", NULL)) != NULL) - pc->password = _cupsStrAlloc(ppd_attr->value); + pc->password = strdup(ppd_attr->value); if ((ppd_attr = ppdFindAttr(ppd, "cupsMandatory", NULL)) != NULL) pc->mandatory = _cupsArrayNewStrings(ppd_attr->value, ' '); @@ -1769,9 +1934,7 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ * Support files... */ - pc->support_files = cupsArrayNew3(NULL, NULL, NULL, 0, - (cups_acopy_func_t)_cupsStrAlloc, - (cups_afree_func_t)_cupsStrFree); + pc->support_files = cupsArrayNew3(NULL, NULL, NULL, 0, (cups_acopy_func_t)strdup, (cups_afree_func_t)free); for (ppd_attr = ppdFindAttr(ppd, "cupsICCProfile", NULL); ppd_attr; @@ -1781,42 +1944,6 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ if ((ppd_attr = ppdFindAttr(ppd, "APPrinterIconPath", NULL)) != NULL) cupsArrayAdd(pc->support_files, ppd_attr->value); - /* - * 3D stuff... - */ - - if ((ppd_attr = ppdFindAttr(ppd, "cups3D", NULL)) != NULL) - pc->cups_3d = _cupsStrAlloc(ppd_attr->value); - - if ((ppd_attr = ppdFindAttr(ppd, "cupsLayerOrder", NULL)) != NULL) - pc->cups_layer_order = _cupsStrAlloc(ppd_attr->value); - - if ((ppd_attr = ppdFindAttr(ppd, "cupsAccuracy", NULL)) != NULL) - sscanf(ppd_attr->value, "%d%d%d", pc->cups_accuracy + 0, pc->cups_accuracy + 1, pc->cups_accuracy + 2); - - if ((ppd_attr = ppdFindAttr(ppd, "cupsVolume", NULL)) != NULL) - sscanf(ppd_attr->value, "%d%d%d", pc->cups_volume + 0, pc->cups_volume + 1, pc->cups_volume + 2); - - for (ppd_attr = ppdFindAttr(ppd, "cupsMaterial", NULL); - ppd_attr; - ppd_attr = ppdFindNextAttr(ppd, "cupsMaterial", NULL)) - { - /* - * *cupsMaterial key/name: "name=value ... name=value" - */ - - _pwg_material_t *material = (_pwg_material_t *)calloc(1, sizeof(_pwg_material_t)); - - material->key = _cupsStrAlloc(ppd_attr->name); - material->name = _cupsStrAlloc(ppd_attr->text); - material->num_props = cupsParseOptions(ppd_attr->value, 0, &material->props); - - if (!pc->materials) - pc->materials = cupsArrayNew3(NULL, NULL, NULL, 0, NULL, (cups_afree_func_t)pwg_free_material); - - cupsArrayAdd(pc->materials, material); - } - /* * Return the cache data... */ @@ -1863,8 +1990,8 @@ _ppdCacheDestroy(_ppd_cache_t *pc) /* I - PPD cache and mapping data */ { for (i = pc->num_bins, map = pc->bins; i > 0; i --, map ++) { - _cupsStrFree(map->pwg); - _cupsStrFree(map->ppd); + free(map->pwg); + free(map->ppd); } free(pc->bins); @@ -1874,22 +2001,21 @@ _ppdCacheDestroy(_ppd_cache_t *pc) /* I - PPD cache and mapping data */ { for (i = pc->num_sizes, size = pc->sizes; i > 0; i --, size ++) { - _cupsStrFree(size->map.pwg); - _cupsStrFree(size->map.ppd); + free(size->map.pwg); + free(size->map.ppd); } free(pc->sizes); } - if (pc->source_option) - _cupsStrFree(pc->source_option); + free(pc->source_option); if (pc->sources) { for (i = pc->num_sources, map = pc->sources; i > 0; i --, map ++) { - _cupsStrFree(map->pwg); - _cupsStrFree(map->ppd); + free(map->pwg); + free(map->ppd); } free(pc->sources); @@ -1899,35 +2025,29 @@ _ppdCacheDestroy(_ppd_cache_t *pc) /* I - PPD cache and mapping data */ { for (i = pc->num_types, map = pc->types; i > 0; i --, map ++) { - _cupsStrFree(map->pwg); - _cupsStrFree(map->ppd); + free(map->pwg); + free(map->ppd); } free(pc->types); } - if (pc->custom_max_keyword) - _cupsStrFree(pc->custom_max_keyword); + free(pc->custom_max_keyword); + free(pc->custom_min_keyword); - if (pc->custom_min_keyword) - _cupsStrFree(pc->custom_min_keyword); - - _cupsStrFree(pc->product); + free(pc->product); cupsArrayDelete(pc->filters); cupsArrayDelete(pc->prefilters); cupsArrayDelete(pc->finishings); - _cupsStrFree(pc->charge_info_uri); - _cupsStrFree(pc->password); + free(pc->charge_info_uri); + free(pc->password); cupsArrayDelete(pc->mandatory); cupsArrayDelete(pc->support_files); - _cupsStrFree(pc->cups_3d); - _cupsStrFree(pc->cups_layer_order); - - cupsArrayDelete(pc->materials); + cupsArrayDelete(pc->strings); free(pc); } @@ -2041,9 +2161,8 @@ _ppdCacheGetFinishingOptions( int /* O - Number of finishings values */ _ppdCacheGetFinishingValues( + ppd_file_t *ppd, /* I - Marked PPD file */ _ppd_cache_t *pc, /* I - PPD cache and mapping data */ - int num_options, /* I - Number of options */ - cups_option_t *options, /* I - Options */ int max_values, /* I - Maximum number of finishings values */ int *values) /* O - Finishings values */ { @@ -2051,20 +2170,25 @@ _ppdCacheGetFinishingValues( num_values = 0; /* Number of values */ _pwg_finishings_t *f; /* Current finishings option */ cups_option_t *option; /* Current option */ - const char *val; /* Value for option */ + ppd_choice_t *choice; /* Marked PPD choice */ /* * Range check input... */ - DEBUG_printf(("_ppdCacheGetFinishingValues(pc=%p, num_options=%d, options=%p, max_values=%d, values=%p)", pc, num_options, options, max_values, values)); + DEBUG_printf(("_ppdCacheGetFinishingValues(ppd=%p, pc=%p, max_values=%d, values=%p)", ppd, pc, max_values, values)); - if (!pc || !pc->finishings || num_options < 1 || max_values < 1 || !values) + if (!ppd || !pc || max_values < 1 || !values) { DEBUG_puts("_ppdCacheGetFinishingValues: Bad arguments, returning 0."); return (0); } + else if (!pc->finishings) + { + DEBUG_puts("_ppdCacheGetFinishingValues: No finishings support, returning 0."); + return (0); + } /* * Go through the finishings options and see what is set... @@ -2074,14 +2198,13 @@ _ppdCacheGetFinishingValues( f; f = (_pwg_finishings_t *)cupsArrayNext(pc->finishings)) { - DEBUG_printf(("_ppdCacheGetFinishingValues: Checking %d (%s)", f->value, ippEnumString("finishings", f->value))); + DEBUG_printf(("_ppdCacheGetFinishingValues: Checking %d (%s)", (int)f->value, ippEnumString("finishings", (int)f->value))); for (i = f->num_options, option = f->options; i > 0; i --, option ++) { DEBUG_printf(("_ppdCacheGetFinishingValues: %s=%s?", option->name, option->value)); - if ((val = cupsGetOption(option->name, num_options, options)) == NULL || - _cups_strcasecmp(option->value, val)) + if ((choice = ppdFindMarkedChoice(ppd, option->name)) == NULL || _cups_strcasecmp(option->value, choice->choice)) { DEBUG_puts("_ppdCacheGetFinishingValues: NO"); break; @@ -2090,15 +2213,26 @@ _ppdCacheGetFinishingValues( if (i == 0) { - DEBUG_printf(("_ppdCacheGetFinishingValues: Adding %d.", f->value)); + DEBUG_printf(("_ppdCacheGetFinishingValues: Adding %d (%s)", (int)f->value, ippEnumString("finishings", (int)f->value))); - values[num_values ++] = f->value; + values[num_values ++] = (int)f->value; if (num_values >= max_values) break; } } + if (num_values == 0) + { + /* + * Always have at least "finishings" = 'none'... + */ + + DEBUG_puts("_ppdCacheGetFinishingValues: Adding 3 (none)."); + values[0] = IPP_FINISHINGS_NONE; + num_values ++; + } + DEBUG_printf(("_ppdCacheGetFinishingValues: Returning %d.", num_values)); return (num_values); @@ -2684,9 +2818,8 @@ _ppdCacheWriteFile( pwg_map_t *map; /* Current map */ _pwg_finishings_t *f; /* Current finishing option */ cups_option_t *option; /* Current option */ - const char *value; /* Filter/pre-filter value */ + const char *value; /* String value */ char newfile[1024]; /* New filename */ - _pwg_material_t *m; /* Material */ /* @@ -2833,6 +2966,9 @@ _ppdCacheWriteFile( cupsFilePutChar(fp, '\n'); } + for (value = (const char *)cupsArrayFirst(pc->templates); value; value = (const char *)cupsArrayNext(pc->templates)) + cupsFilePutConf(fp, "FinishingTemplate", value); + /* * Max copies... */ @@ -2846,12 +2982,12 @@ _ppdCacheWriteFile( if (pc->charge_info_uri) cupsFilePutConf(fp, "ChargeInfoURI", pc->charge_info_uri); - cupsFilePrintf(fp, "AccountId %s\n", pc->account_id ? "true" : "false"); - cupsFilePrintf(fp, "AccountingUserId %s\n", + cupsFilePrintf(fp, "JobAccountId %s\n", pc->account_id ? "true" : "false"); + cupsFilePrintf(fp, "JobAccountingUserId %s\n", pc->accounting_user_id ? "true" : "false"); if (pc->password) - cupsFilePutConf(fp, "Password", pc->password); + cupsFilePutConf(fp, "JobPassword", pc->password); for (value = (char *)cupsArrayFirst(pc->mandatory); value; @@ -2867,32 +3003,6 @@ _ppdCacheWriteFile( value = (char *)cupsArrayNext(pc->support_files)) cupsFilePutConf(fp, "SupportFile", value); - /* - * 3D stuff... - */ - - if (pc->cups_3d) - cupsFilePutConf(fp, "3D", pc->cups_3d); - - if (pc->cups_layer_order) - cupsFilePutConf(fp, "LayerOrder", pc->cups_layer_order); - - if (pc->cups_accuracy[0] || pc->cups_accuracy[0] || pc->cups_accuracy[2]) - cupsFilePrintf(fp, "Accuracy %d %d %d\n", pc->cups_accuracy[0], pc->cups_accuracy[1], pc->cups_accuracy[2]); - - if (pc->cups_volume[0] || pc->cups_volume[0] || pc->cups_volume[2]) - cupsFilePrintf(fp, "Volume %d %d %d\n", pc->cups_volume[0], pc->cups_volume[1], pc->cups_volume[2]); - - for (m = (_pwg_material_t *)cupsArrayFirst(pc->materials); - m; - m = (_pwg_material_t *)cupsArrayNext(pc->materials)) - { - cupsFilePrintf(fp, "Material %s \"%s\"", m->key, m->name); - for (i = 0; i < m->num_props; i ++) - cupsFilePrintf(fp, " %s=%s", m->props[i].name, m->props[i].value); - cupsFilePuts(fp, "\n"); - } - /* * IPP attributes, if any... */ @@ -2931,11 +3041,14 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ ipp_t *response) /* I - Get-Printer-Attributes response */ { cups_file_t *fp; /* PPD file */ - cups_array_t *sizes; /* Media sizes we've added */ + cups_array_t *sizes; /* Media sizes supported by printer */ + cups_size_t *size; /* Current media size */ ipp_attribute_t *attr, /* xxx-supported */ *defattr, /* xxx-default */ + *quality, /* print-quality-supported */ *x_dim, *y_dim; /* Media dimensions */ - ipp_t *media_size; /* Media size collection */ + ipp_t *media_col, /* Media collection */ + *media_size; /* Media size collection */ char make[256], /* Make and model */ *model, /* Model name */ ppdname[PPD_MAX_NAME]; @@ -2946,83 +3059,28 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ left, /* Largest left margin */ right, /* Largest right margin */ top, /* Largest top margin */ + max_length = 0, /* Maximum custom size */ + max_width = 0, + min_length = INT_MAX, + /* Minimum custom size */ + min_width = INT_MAX, is_apple = 0, /* Does the printer support Apple raster? */ is_pdf = 0, /* Does the printer support PDF? */ is_pwg = 0; /* Does the printer support PWG Raster? */ pwg_media_t *pwg; /* PWG media size */ int xres, yres; /* Resolution values */ + int resolutions[1000]; + /* Array of resolution indices */ + char msgid[256]; /* Message identifier (attr.value) */ + const char *keyword, /* Keyword value */ + *msgstr; /* Localized string */ cups_lang_t *lang = cupsLangDefault(); /* Localization info */ + cups_array_t *strings = NULL;/* Printer strings file */ struct lconv *loc = localeconv(); /* Locale data */ - static const char * const finishings[][2] = - { /* Finishings strings */ - { "bale", _("Bale") }, - { "bind", _("Bind") }, - { "bind-bottom", _("Bind (Reverse Landscape)") }, - { "bind-left", _("Bind (Portrait)") }, - { "bind-right", _("Bind (Reverse Portrait)") }, - { "bind-top", _("Bind (Landscape)") }, - { "booklet-maker", _("Booklet Maker") }, - { "coat", _("Coat") }, - { "cover", _("Cover") }, - { "edge-stitch", _("Staple Edge") }, - { "edge-stitch-bottom", _("Staple Edge (Reverse Landscape)") }, - { "edge-stitch-left", _("Staple Edge (Portrait)") }, - { "edge-stitch-right", _("Staple Edge (Reverse Portrait)") }, - { "edge-stitch-top", _("Staple Edge (Landscape)") }, - { "fold", _("Fold") }, - { "fold-accordian", _("Accordian Fold") }, - { "fold-double-gate", _("Double Gate Fold") }, - { "fold-engineering-z", _("Engineering Z Fold") }, - { "fold-gate", _("Gate Fold") }, - { "fold-half", _("Half Fold") }, - { "fold-half-z", _("Half Z Fold") }, - { "fold-left-gate", _("Left Gate Fold") }, - { "fold-letter", _("Letter Fold") }, - { "fold-parallel", _("Parallel Fold") }, - { "fold-poster", _("Poster Fold") }, - { "fold-right-gate", _("Right Gate Fold") }, - { "fold-z", _("Z Fold") }, - { "jog-offset", _("Jog") }, - { "laminate", _("Laminate") }, - { "punch", _("Punch") }, - { "punch-bottom-left", _("Single Punch (Reverse Landscape)") }, - { "punch-bottom-right", _("Single Punch (Reverse Portrait)") }, - { "punch-double-bottom", _("2-Hole Punch (Reverse Portrait)") }, - { "punch-double-left", _("2-Hole Punch (Reverse Landscape)") }, - { "punch-double-right", _("2-Hole Punch (Landscape)") }, - { "punch-double-top", _("2-Hole Punch (Portrait)") }, - { "punch-quad-bottom", _("4-Hole Punch (Reverse Landscape)") }, - { "punch-quad-left", _("4-Hole Punch (Portrait)") }, - { "punch-quad-right", _("4-Hole Punch (Reverse Portrait)") }, - { "punch-quad-top", _("4-Hole Punch (Landscape)") }, - { "punch-top-left", _("Single Punch (Portrait)") }, - { "punch-top-right", _("Single Punch (Landscape)") }, - { "punch-triple-bottom", _("3-Hole Punch (Reverse Landscape)") }, - { "punch-triple-left", _("3-Hole Punch (Portrait)") }, - { "punch-triple-right", _("3-Hole Punch (Reverse Portrait)") }, - { "punch-triple-top", _("3-Hole Punch (Landscape)") }, - { "punch-multiple-bottom", _("Multi-Hole Punch (Reverse Landscape)") }, - { "punch-multiple-left", _("Multi-Hole Punch (Portrait)") }, - { "punch-multiple-right", _("Multi-Hole Punch (Reverse Portrait)") }, - { "punch-multiple-top", _("Multi-Hole Punch (Landscape)") }, - { "saddle-stitch", _("Saddle Stitch") }, - { "staple", _("Staple") }, - { "staple-bottom-left", _("Single Staple (Reverse Landscape)") }, - { "staple-bottom-right", _("Single Staple (Reverse Portrait)") }, - { "staple-dual-bottom", _("Double Staple (Reverse Landscape)") }, - { "staple-dual-left", _("Double Staple (Portrait)") }, - { "staple-dual-right", _("Double Staple (Reverse Portrait)") }, - { "staple-dual-top", _("Double Staple (Landscape)") }, - { "staple-top-left", _("Single Staple (Portrait)") }, - { "staple-top-right", _("Single Staple (Landscape)") }, - { "staple-triple-bottom", _("Triple Staple (Reverse Landscape)") }, - { "staple-triple-left", _("Triple Staple (Portrait)") }, - { "staple-triple-right", _("Triple Staple (Reverse Portrait)") }, - { "staple-triple-top", _("Triple Staple (Landscape)") }, - { "trim", _("Cut Media") } - }; + cups_array_t *fin_options = NULL; + /* Finishing options */ /* @@ -3032,15 +3090,27 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ if (buffer) *buffer = '\0'; - if (!buffer || bufsize < 1 || !response) + if (!buffer || bufsize < 1) + { + _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); + return (NULL); + } + + if (!response) + { + _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("No IPP attributes."), 1); return (NULL); + } /* * Open a temporary file for the PPD... */ if ((fp = cupsTempFile2(buffer, (int)bufsize)) == NULL) + { + _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); return (NULL); + } /* * Standard stuff for PPD file... @@ -3075,8 +3145,8 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ cupsFilePrintf(fp, "*Manufacturer: \"%s\"\n", make); cupsFilePrintf(fp, "*ModelName: \"%s\"\n", model); cupsFilePrintf(fp, "*Product: \"(%s)\"\n", model); - cupsFilePrintf(fp, "*NickName: \"%s\"\n", model); - cupsFilePrintf(fp, "*ShortNickName: \"%s\"\n", model); + cupsFilePrintf(fp, "*NickName: \"%s - IPP Everywhere\"\n", model); + cupsFilePrintf(fp, "*ShortNickName: \"%s - IPP Everywhere\"\n", model); if ((attr = ippFindAttribute(response, "color-supported", IPP_TAG_BOOLEAN)) != NULL && ippGetBoolean(attr, 0)) cupsFilePuts(fp, "*ColorDevice: True\n"); @@ -3085,7 +3155,76 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ cupsFilePrintf(fp, "*cupsVersion: %d.%d\n", CUPS_VERSION_MAJOR, CUPS_VERSION_MINOR); cupsFilePuts(fp, "*cupsSNMPSupplies: False\n"); - cupsFilePuts(fp, "*cupsLanguages: \"en\"\n"); + cupsFilePrintf(fp, "*cupsLanguages: \"%s\"\n", lang->language); + + if ((attr = ippFindAttribute(response, "printer-more-info", IPP_TAG_URI)) != NULL) + cupsFilePrintf(fp, "*APSupplies: \"%s\"\n", ippGetString(attr, 0, NULL)); + + if ((attr = ippFindAttribute(response, "printer-charge-info-uri", IPP_TAG_URI)) != NULL) + cupsFilePrintf(fp, "*cupsChargeInfoURI: \"%s\"\n", ippGetString(attr, 0, NULL)); + + if ((attr = ippFindAttribute(response, "printer-strings-uri", IPP_TAG_URI)) != NULL) + { + http_t *http = NULL; /* Connection to printer */ + char stringsfile[1024]; /* Temporary strings file */ + + if (cups_get_url(&http, ippGetString(attr, 0, NULL), stringsfile, sizeof(stringsfile))) + { + cupsFilePrintf(fp, "*cupsStringsURI: \"%s\"\n", ippGetString(attr, 0, NULL)); + + strings = _cupsMessageLoad(stringsfile, _CUPS_MESSAGE_STRINGS | _CUPS_MESSAGE_UNQUOTE); + + unlink(stringsfile); + } + + if (http) + httpClose(http); + } + + /* + * Accounting... + */ + + if (ippGetBoolean(ippFindAttribute(response, "job-account-id-supported", IPP_TAG_BOOLEAN), 0)) + cupsFilePuts(fp, "*cupsJobAccountId: True\n"); + + if (ippGetBoolean(ippFindAttribute(response, "job-accounting-user-id-supported", IPP_TAG_BOOLEAN), 0)) + cupsFilePuts(fp, "*cupsJobAccountingUserId: True\n"); + + /* + * Password/PIN printing... + */ + + if ((attr = ippFindAttribute(response, "job-password-supported", IPP_TAG_INTEGER)) != NULL) + { + char pattern[33]; /* Password pattern */ + int maxlen = ippGetInteger(attr, 0); + /* Maximum length */ + const char *repertoire = ippGetString(ippFindAttribute(response, "job-password-repertoire-configured", IPP_TAG_KEYWORD), 0, NULL); + /* Type of password */ + + if (maxlen > (int)(sizeof(pattern) - 1)) + maxlen = (int)sizeof(pattern) - 1; + + if (!repertoire || !strcmp(repertoire, "iana_us-ascii_digits")) + memset(pattern, '1', (size_t)maxlen); + else if (!strcmp(repertoire, "iana_us-ascii_letters")) + memset(pattern, 'A', (size_t)maxlen); + else if (!strcmp(repertoire, "iana_us-ascii_complex")) + memset(pattern, 'C', (size_t)maxlen); + else if (!strcmp(repertoire, "iana_us-ascii_any")) + memset(pattern, '.', (size_t)maxlen); + else if (!strcmp(repertoire, "iana_utf-8_digits")) + memset(pattern, 'N', (size_t)maxlen); + else if (!strcmp(repertoire, "iana_utf-8_letters")) + memset(pattern, 'U', (size_t)maxlen); + else + memset(pattern, '*', (size_t)maxlen); + + pattern[maxlen] = '\0'; + + cupsFilePrintf(fp, "*cupsJobPassword: \"%s\"\n", pattern); + } /* * Filters... @@ -3095,24 +3234,30 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ { is_apple = ippContainsString(attr, "image/urf"); is_pdf = ippContainsString(attr, "application/pdf"); - is_pwg = ippContainsString(attr, "image/pwg-raster"); + is_pwg = ippContainsString(attr, "image/pwg-raster") && !is_apple; - for (i = 0, count = ippGetCount(attr); i < count; i ++) + if (ippContainsString(attr, "image/jpeg")) + cupsFilePuts(fp, "*cupsFilter2: \"image/jpeg image/jpeg 0 -\"\n"); + if (ippContainsString(attr, "image/png")) + cupsFilePuts(fp, "*cupsFilter2: \"image/png image/png 0 -\"\n"); + if (is_pdf) { - const char *format = ippGetString(attr, i, NULL); - /* PDL */ - /* - * Write cupsFilter2 lines for supported formats... + * Don't locally filter PDF content when printing to a CUPS shared + * printer, otherwise the options will be applied twice... */ - if (!_cups_strcasecmp(format, "application/pdf")) + if (ippContainsString(attr, "application/vnd.cups-pdf")) + cupsFilePuts(fp, "*cupsFilter2: \"application/pdf application/pdf 0 -\"\n"); + else cupsFilePuts(fp, "*cupsFilter2: \"application/vnd.cups-pdf application/pdf 10 -\"\n"); - else if (!_cups_strcasecmp(format, "image/jpeg") || !_cups_strcasecmp(format, "image/png")) - cupsFilePrintf(fp, "*cupsFilter2: \"%s %s 0 -\"\n", format, format); - else if (!_cups_strcasecmp(format, "image/pwg-raster") || !_cups_strcasecmp(format, "image/urf")) - cupsFilePrintf(fp, "*cupsFilter2: \"%s %s 100 -\"\n", format, format); } + else + cupsFilePuts(fp, "*cupsManualCopies: True\n"); + if (is_apple) + cupsFilePuts(fp, "*cupsFilter2: \"image/urf image/urf 100 -\"\n"); + if (is_pwg) + cupsFilePuts(fp, "*cupsFilter2: \"image/pwg-raster image/pwg-raster 100 -\"\n"); } if (!is_apple && !is_pdf && !is_pwg) @@ -3179,135 +3324,319 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ else strlcpy(ppdname, "Unknown", sizeof(ppdname)); - if ((attr = ippFindAttribute(response, "media-size-supported", IPP_TAG_BEGIN_COLLECTION)) == NULL) - attr = ippFindAttribute(response, "media-supported", IPP_TAG_ZERO); - if (attr) - { - cupsFilePrintf(fp, "*OpenUI *PageSize: PickOne\n" - "*OrderDependency: 10 AnySetup *PageSize\n" - "*DefaultPageSize: %s\n", ppdname); - - sizes = cupsArrayNew3((cups_array_func_t)strcmp, NULL, NULL, 0, (cups_acopy_func_t)strdup, (cups_afree_func_t)free); + sizes = cupsArrayNew3((cups_array_func_t)pwg_compare_sizes, NULL, NULL, 0, (cups_acopy_func_t)pwg_copy_size, (cups_afree_func_t)free); + if ((attr = ippFindAttribute(response, "media-col-database", IPP_TAG_BEGIN_COLLECTION)) != NULL) + { for (i = 0, count = ippGetCount(attr); i < count; i ++) { - if (ippGetValueTag(attr) == IPP_TAG_BEGIN_COLLECTION) - { - media_size = ippGetCollection(attr, i); - x_dim = ippFindAttribute(media_size, "x-dimension", IPP_TAG_INTEGER); - y_dim = ippFindAttribute(media_size, "y-dimension", IPP_TAG_INTEGER); + cups_size_t temp; /* Current size */ + ipp_attribute_t *margin; /* media-xxx-margin attribute */ - pwg = pwgMediaForSize(ippGetInteger(x_dim, 0), ippGetInteger(y_dim, 0)); - } - else - pwg = pwgMediaForPWG(ippGetString(attr, i, NULL)); + media_col = ippGetCollection(attr, i); + media_size = ippGetCollection(ippFindAttribute(media_col, "media-size", IPP_TAG_BEGIN_COLLECTION), 0); + x_dim = ippFindAttribute(media_size, "x-dimension", IPP_TAG_ZERO); + y_dim = ippFindAttribute(media_size, "y-dimension", IPP_TAG_ZERO); + pwg = pwgMediaForSize(ippGetInteger(x_dim, 0), ippGetInteger(y_dim, 0)); if (pwg) { - char twidth[256], /* Width string */ - tlength[256]; /* Length string */ - - if (cupsArrayFind(sizes, (void *)pwg->ppd)) - { - cupsFilePrintf(fp, "*%% warning: Duplicate size '%s' reported by printer.\n", pwg->ppd); - continue; - } + temp.width = pwg->width; + temp.length = pwg->length; - cupsArrayAdd(sizes, (void *)pwg->ppd); + if ((margin = ippFindAttribute(media_col, "media-bottom-margin", IPP_TAG_INTEGER)) != NULL) + temp.bottom = ippGetInteger(margin, 0); + else + temp.bottom = bottom; - _cupsStrFormatd(twidth, twidth + sizeof(twidth), pwg->width * 72.0 / 2540.0, loc); - _cupsStrFormatd(tlength, tlength + sizeof(tlength), pwg->length * 72.0 / 2540.0, loc); + if ((margin = ippFindAttribute(media_col, "media-left-margin", IPP_TAG_INTEGER)) != NULL) + temp.left = ippGetInteger(margin, 0); + else + temp.left = left; - cupsFilePrintf(fp, "*PageSize %s: \"<>setpagedevice\"\n", pwg->ppd, twidth, tlength); - } - } - cupsFilePuts(fp, "*CloseUI: *PageSize\n"); + if ((margin = ippFindAttribute(media_col, "media-right-margin", IPP_TAG_INTEGER)) != NULL) + temp.right = ippGetInteger(margin, 0); + else + temp.right = right; - cupsArrayDelete(sizes); - sizes = cupsArrayNew3((cups_array_func_t)strcmp, NULL, NULL, 0, (cups_acopy_func_t)strdup, (cups_afree_func_t)free); + if ((margin = ippFindAttribute(media_col, "media-top-margin", IPP_TAG_INTEGER)) != NULL) + temp.top = ippGetInteger(margin, 0); + else + temp.top = top; - cupsFilePrintf(fp, "*OpenUI *PageRegion: PickOne\n" - "*OrderDependency: 10 AnySetup *PageRegion\n" - "*DefaultPageRegion: %s\n", ppdname); - for (i = 0, count = ippGetCount(attr); i < count; i ++) - { - if (ippGetValueTag(attr) == IPP_TAG_BEGIN_COLLECTION) - { - media_size = ippGetCollection(attr, i); - x_dim = ippFindAttribute(media_size, "x-dimension", IPP_TAG_INTEGER); - y_dim = ippFindAttribute(media_size, "y-dimension", IPP_TAG_INTEGER); + if (temp.bottom == 0 && temp.left == 0 && temp.right == 0 && temp.top == 0) + snprintf(temp.media, sizeof(temp.media), "%s.Borderless", pwg->ppd); + else + strlcpy(temp.media, pwg->ppd, sizeof(temp.media)); - pwg = pwgMediaForSize(ippGetInteger(x_dim, 0), ippGetInteger(y_dim, 0)); + if (!cupsArrayFind(sizes, &temp)) + cupsArrayAdd(sizes, &temp); } - else - pwg = pwgMediaForPWG(ippGetString(attr, i, NULL)); - - if (pwg) + else if (ippGetValueTag(x_dim) == IPP_TAG_RANGE || ippGetValueTag(y_dim) == IPP_TAG_RANGE) { - char twidth[256], /* Width string */ - tlength[256]; /* Length string */ + /* + * Custom size - record the min/max values... + */ - if (cupsArrayFind(sizes, (void *)pwg->ppd)) - continue; + int lower, upper; /* Range values */ + + if (ippGetValueTag(x_dim) == IPP_TAG_RANGE) + lower = ippGetRange(x_dim, 0, &upper); + else + lower = upper = ippGetInteger(x_dim, 0); - cupsArrayAdd(sizes, (void *)pwg->ppd); + if (lower < min_width) + min_width = lower; + if (upper > max_width) + max_width = upper; - _cupsStrFormatd(twidth, twidth + sizeof(twidth), pwg->width * 72.0 / 2540.0, loc); - _cupsStrFormatd(tlength, tlength + sizeof(tlength), pwg->length * 72.0 / 2540.0, loc); + if (ippGetValueTag(y_dim) == IPP_TAG_RANGE) + lower = ippGetRange(y_dim, 0, &upper); + else + lower = upper = ippGetInteger(y_dim, 0); - cupsFilePrintf(fp, "*PageRegion %s: \"<>setpagedevice\"\n", pwg->ppd, twidth, tlength); + if (lower < min_length) + min_length = lower; + if (upper > max_length) + max_length = upper; } } - cupsFilePuts(fp, "*CloseUI: *PageRegion\n"); - - cupsArrayDelete(sizes); - sizes = cupsArrayNew3((cups_array_func_t)strcmp, NULL, NULL, 0, (cups_acopy_func_t)strdup, (cups_afree_func_t)free); - cupsFilePrintf(fp, "*DefaultImageableArea: %s\n" - "*DefaultPaperDimension: %s\n", ppdname, ppdname); - for (i = 0, count = ippGetCount(attr); i < count; i ++) + if ((max_width == 0 || max_length == 0) && (attr = ippFindAttribute(response, "media-size-supported", IPP_TAG_BEGIN_COLLECTION)) != NULL) { - if (ippGetValueTag(attr) == IPP_TAG_BEGIN_COLLECTION) + /* + * Some printers don't list custom size support in media-col-database... + */ + + for (i = 0, count = ippGetCount(attr); i < count; i ++) { - media_size = ippGetCollection(attr, i); - x_dim = ippFindAttribute(media_size, "x-dimension", IPP_TAG_INTEGER); - y_dim = ippFindAttribute(media_size, "y-dimension", IPP_TAG_INTEGER); + media_size = ippGetCollection(attr, i); + x_dim = ippFindAttribute(media_size, "x-dimension", IPP_TAG_ZERO); + y_dim = ippFindAttribute(media_size, "y-dimension", IPP_TAG_ZERO); - pwg = pwgMediaForSize(ippGetInteger(x_dim, 0), ippGetInteger(y_dim, 0)); + if (ippGetValueTag(x_dim) == IPP_TAG_RANGE || ippGetValueTag(y_dim) == IPP_TAG_RANGE) + { + /* + * Custom size - record the min/max values... + */ + + int lower, upper; /* Range values */ + + if (ippGetValueTag(x_dim) == IPP_TAG_RANGE) + lower = ippGetRange(x_dim, 0, &upper); + else + lower = upper = ippGetInteger(x_dim, 0); + + if (lower < min_width) + min_width = lower; + if (upper > max_width) + max_width = upper; + + if (ippGetValueTag(y_dim) == IPP_TAG_RANGE) + lower = ippGetRange(y_dim, 0, &upper); + else + lower = upper = ippGetInteger(y_dim, 0); + + if (lower < min_length) + min_length = lower; + if (upper > max_length) + max_length = upper; + } } - else - pwg = pwgMediaForPWG(ippGetString(attr, i, NULL)); + } + } + else if ((attr = ippFindAttribute(response, "media-size-supported", IPP_TAG_BEGIN_COLLECTION)) != NULL) + { + for (i = 0, count = ippGetCount(attr); i < count; i ++) + { + cups_size_t temp; /* Current size */ + + media_size = ippGetCollection(attr, i); + x_dim = ippFindAttribute(media_size, "x-dimension", IPP_TAG_ZERO); + y_dim = ippFindAttribute(media_size, "y-dimension", IPP_TAG_ZERO); + pwg = pwgMediaForSize(ippGetInteger(x_dim, 0), ippGetInteger(y_dim, 0)); if (pwg) { - char tleft[256], /* Left string */ + temp.width = pwg->width; + temp.length = pwg->length; + temp.bottom = bottom; + temp.left = left; + temp.right = right; + temp.top = top; + + if (temp.bottom == 0 && temp.left == 0 && temp.right == 0 && temp.top == 0) + snprintf(temp.media, sizeof(temp.media), "%s.Borderless", pwg->ppd); + else + strlcpy(temp.media, pwg->ppd, sizeof(temp.media)); + + if (!cupsArrayFind(sizes, &temp)) + cupsArrayAdd(sizes, &temp); + } + else if (ippGetValueTag(x_dim) == IPP_TAG_RANGE || ippGetValueTag(y_dim) == IPP_TAG_RANGE) + { + /* + * Custom size - record the min/max values... + */ + + int lower, upper; /* Range values */ + + if (ippGetValueTag(x_dim) == IPP_TAG_RANGE) + lower = ippGetRange(x_dim, 0, &upper); + else + lower = upper = ippGetInteger(x_dim, 0); + + if (lower < min_width) + min_width = lower; + if (upper > max_width) + max_width = upper; + + if (ippGetValueTag(y_dim) == IPP_TAG_RANGE) + lower = ippGetRange(y_dim, 0, &upper); + else + lower = upper = ippGetInteger(y_dim, 0); + + if (lower < min_length) + min_length = lower; + if (upper > max_length) + max_length = upper; + } + } + } + else if ((attr = ippFindAttribute(response, "media-supported", IPP_TAG_ZERO)) != NULL) + { + for (i = 0, count = ippGetCount(attr); i < count; i ++) + { + const char *pwg_size = ippGetString(attr, i, NULL); + /* PWG size name */ + cups_size_t temp; /* Current size */ + + if ((pwg = pwgMediaForPWG(pwg_size)) != NULL) + { + if (strstr(pwg_size, "_max_") || strstr(pwg_size, "_max.")) + { + if (pwg->width > max_width) + max_width = pwg->width; + if (pwg->length > max_length) + max_length = pwg->length; + } + else if (strstr(pwg_size, "_min_") || strstr(pwg_size, "_min.")) + { + if (pwg->width < min_width) + min_width = pwg->width; + if (pwg->length < min_length) + min_length = pwg->length; + } + else + { + temp.width = pwg->width; + temp.length = pwg->length; + temp.bottom = bottom; + temp.left = left; + temp.right = right; + temp.top = top; + + if (temp.bottom == 0 && temp.left == 0 && temp.right == 0 && temp.top == 0) + snprintf(temp.media, sizeof(temp.media), "%s.Borderless", pwg->ppd); + else + strlcpy(temp.media, pwg->ppd, sizeof(temp.media)); + + if (!cupsArrayFind(sizes, &temp)) + cupsArrayAdd(sizes, &temp); + } + } + } + } + + if (cupsArrayCount(sizes) > 0) + { + /* + * List all of the standard sizes... + */ + + char tleft[256], /* Left string */ tbottom[256], /* Bottom string */ tright[256], /* Right string */ ttop[256], /* Top string */ twidth[256], /* Width string */ tlength[256]; /* Length string */ - if (cupsArrayFind(sizes, (void *)pwg->ppd)) - continue; + cupsFilePrintf(fp, "*OpenUI *PageSize: PickOne\n" + "*OrderDependency: 10 AnySetup *PageSize\n" + "*DefaultPageSize: %s\n", ppdname); + for (size = (cups_size_t *)cupsArrayFirst(sizes); size; size = (cups_size_t *)cupsArrayNext(sizes)) + { + _cupsStrFormatd(twidth, twidth + sizeof(twidth), size->width * 72.0 / 2540.0, loc); + _cupsStrFormatd(tlength, tlength + sizeof(tlength), size->length * 72.0 / 2540.0, loc); + + cupsFilePrintf(fp, "*PageSize %s: \"<>setpagedevice\"\n", size->media, twidth, tlength); + } + cupsFilePuts(fp, "*CloseUI: *PageSize\n"); - cupsArrayAdd(sizes, (void *)pwg->ppd); + cupsFilePrintf(fp, "*OpenUI *PageRegion: PickOne\n" + "*OrderDependency: 10 AnySetup *PageRegion\n" + "*DefaultPageRegion: %s\n", ppdname); + for (size = (cups_size_t *)cupsArrayFirst(sizes); size; size = (cups_size_t *)cupsArrayNext(sizes)) + { + _cupsStrFormatd(twidth, twidth + sizeof(twidth), size->width * 72.0 / 2540.0, loc); + _cupsStrFormatd(tlength, tlength + sizeof(tlength), size->length * 72.0 / 2540.0, loc); - _cupsStrFormatd(tleft, tleft + sizeof(tleft), left * 72.0 / 2540.0, loc); - _cupsStrFormatd(tbottom, tbottom + sizeof(tbottom), bottom * 72.0 / 2540.0, loc); - _cupsStrFormatd(tright, tright + sizeof(tright), (pwg->width - right) * 72.0 / 2540.0, loc); - _cupsStrFormatd(ttop, ttop + sizeof(ttop), (pwg->length - top) * 72.0 / 2540.0, loc); - _cupsStrFormatd(twidth, twidth + sizeof(twidth), pwg->width * 72.0 / 2540.0, loc); - _cupsStrFormatd(tlength, tlength + sizeof(tlength), pwg->length * 72.0 / 2540.0, loc); + cupsFilePrintf(fp, "*PageRegion %s: \"<>setpagedevice\"\n", size->media, twidth, tlength); + } + cupsFilePuts(fp, "*CloseUI: *PageRegion\n"); - cupsFilePrintf(fp, "*ImageableArea %s: \"%s %s %s %s\"\n", pwg->ppd, tleft, tbottom, tright, ttop); - cupsFilePrintf(fp, "*PaperDimension %s: \"%s %s\"\n", pwg->ppd, twidth, tlength); - } + cupsFilePrintf(fp, "*DefaultImageableArea: %s\n" + "*DefaultPaperDimension: %s\n", ppdname, ppdname); + + for (size = (cups_size_t *)cupsArrayFirst(sizes); size; size = (cups_size_t *)cupsArrayNext(sizes)) + { + _cupsStrFormatd(tleft, tleft + sizeof(tleft), size->left * 72.0 / 2540.0, loc); + _cupsStrFormatd(tbottom, tbottom + sizeof(tbottom), size->bottom * 72.0 / 2540.0, loc); + _cupsStrFormatd(tright, tright + sizeof(tright), (size->width - size->right) * 72.0 / 2540.0, loc); + _cupsStrFormatd(ttop, ttop + sizeof(ttop), (size->length - size->top) * 72.0 / 2540.0, loc); + _cupsStrFormatd(twidth, twidth + sizeof(twidth), size->width * 72.0 / 2540.0, loc); + _cupsStrFormatd(tlength, tlength + sizeof(tlength), size->length * 72.0 / 2540.0, loc); + + cupsFilePrintf(fp, "*ImageableArea %s: \"%s %s %s %s\"\n", size->media, tleft, tbottom, tright, ttop); + cupsFilePrintf(fp, "*PaperDimension %s: \"%s %s\"\n", size->media, twidth, tlength); } cupsArrayDelete(sizes); + + /* + * Custom size support... + */ + + if (max_width > 0 && min_width < INT_MAX && max_length > 0 && min_length < INT_MAX) + { + char tmax[256], tmin[256]; /* Min/max values */ + + _cupsStrFormatd(tleft, tleft + sizeof(tleft), left * 72.0 / 2540.0, loc); + _cupsStrFormatd(tbottom, tbottom + sizeof(tbottom), bottom * 72.0 / 2540.0, loc); + _cupsStrFormatd(tright, tright + sizeof(tright), right * 72.0 / 2540.0, loc); + _cupsStrFormatd(ttop, ttop + sizeof(ttop), top * 72.0 / 2540.0, loc); + + cupsFilePrintf(fp, "*HWMargins: \"%s %s %s %s\"\n", tleft, tbottom, tright, ttop); + + _cupsStrFormatd(tmax, tmax + sizeof(tmax), max_width * 72.0 / 2540.0, loc); + _cupsStrFormatd(tmin, tmin + sizeof(tmin), min_width * 72.0 / 2540.0, loc); + cupsFilePrintf(fp, "*ParamCustomPageSize Width: 1 points %s %s\n", tmin, tmax); + + _cupsStrFormatd(tmax, tmax + sizeof(tmax), max_length * 72.0 / 2540.0, loc); + _cupsStrFormatd(tmin, tmin + sizeof(tmin), min_length * 72.0 / 2540.0, loc); + cupsFilePrintf(fp, "*ParamCustomPageSize Height: 2 points %s %s\n", tmin, tmax); + + cupsFilePuts(fp, "*ParamCustomPageSize WidthOffset: 3 points 0 0\n"); + cupsFilePuts(fp, "*ParamCustomPageSize HeightOffset: 4 points 0 0\n"); + cupsFilePuts(fp, "*ParamCustomPageSize Orientation: 5 int 0 3\n"); + cupsFilePuts(fp, "*CustomPageSize True: \"pop pop pop <>setpagedevice\"\n"); + } } else + { + cupsArrayDelete(sizes); goto bad_ppd; + } /* * InputSlot... @@ -3316,75 +3645,91 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ if ((attr = ippFindAttribute(ippGetCollection(defattr, 0), "media-source", IPP_TAG_ZERO)) != NULL) pwg_ppdize_name(ippGetString(attr, 0, NULL), ppdname, sizeof(ppdname)); else - strlcpy(ppdname, "Unknown", sizeof(ppdname)); + ppdname[0] = '\0'; if ((attr = ippFindAttribute(response, "media-source-supported", IPP_TAG_ZERO)) != NULL && (count = ippGetCount(attr)) > 1) { - static const char * const sources[][2] = - { /* "media-source" strings */ - { "Auto", _("Automatic") }, - { "Main", _("Main") }, - { "Alternate", _("Alternate") }, - { "LargeCapacity", _("Large Capacity") }, - { "Manual", _("Manual") }, - { "Envelope", _("Envelope") }, - { "Disc", _("Disc") }, - { "Photo", _("Photo") }, - { "Hagaki", _("Hagaki") }, - { "MainRoll", _("Main Roll") }, - { "AlternateRoll", _("Alternate Roll") }, - { "Top", _("Top") }, - { "Middle", _("Middle") }, - { "Bottom", _("Bottom") }, - { "Side", _("Side") }, - { "Left", _("Left") }, - { "Right", _("Right") }, - { "Center", _("Center") }, - { "Rear", _("Rear") }, - { "ByPassTray", _("Multipurpose") }, - { "Tray1", _("Tray 1") }, - { "Tray2", _("Tray 2") }, - { "Tray3", _("Tray 3") }, - { "Tray4", _("Tray 4") }, - { "Tray5", _("Tray 5") }, - { "Tray6", _("Tray 6") }, - { "Tray7", _("Tray 7") }, - { "Tray8", _("Tray 8") }, - { "Tray9", _("Tray 9") }, - { "Tray10", _("Tray 10") }, - { "Tray11", _("Tray 11") }, - { "Tray12", _("Tray 12") }, - { "Tray13", _("Tray 13") }, - { "Tray14", _("Tray 14") }, - { "Tray15", _("Tray 15") }, - { "Tray16", _("Tray 16") }, - { "Tray17", _("Tray 17") }, - { "Tray18", _("Tray 18") }, - { "Tray19", _("Tray 19") }, - { "Tray20", _("Tray 20") }, - { "Roll1", _("Roll 1") }, - { "Roll2", _("Roll 2") }, - { "Roll3", _("Roll 3") }, - { "Roll4", _("Roll 4") }, - { "Roll5", _("Roll 5") }, - { "Roll6", _("Roll 6") }, - { "Roll7", _("Roll 7") }, - { "Roll8", _("Roll 8") }, - { "Roll9", _("Roll 9") }, - { "Roll10", _("Roll 10") } + int have_default = ppdname[0] != '\0'; + /* Do we have a default InputSlot? */ + static const char * const sources[] = + { /* Standard "media-source" strings */ + "auto", + "main", + "alternate", + "large-capacity", + "manual", + "envelope", + "disc", + "photo", + "hagaki", + "main-roll", + "alternate-roll", + "top", + "middle", + "bottom", + "side", + "left", + "right", + "center", + "rear", + "by-pass-tray", + "tray-1", + "tray-2", + "tray-3", + "tray-4", + "tray-5", + "tray-6", + "tray-7", + "tray-8", + "tray-9", + "tray-10", + "tray-11", + "tray-12", + "tray-13", + "tray-14", + "tray-15", + "tray-16", + "tray-17", + "tray-18", + "tray-19", + "tray-20", + "roll-1", + "roll-2", + "roll-3", + "roll-4", + "roll-5", + "roll-6", + "roll-7", + "roll-8", + "roll-9", + "roll-10" }; - cupsFilePrintf(fp, "*OpenUI *InputSlot: PickOne\n" - "*OrderDependency: 10 AnySetup *InputSlot\n" - "*DefaultInputSlot: %s\n", ppdname); - for (i = 0, count = ippGetCount(attr); i < count; i ++) + cupsFilePuts(fp, "*OpenUI *InputSlot: PickOne\n" + "*OrderDependency: 10 AnySetup *InputSlot\n"); + if (have_default) + cupsFilePrintf(fp, "*DefaultInputSlot: %s\n", ppdname); + + for (i = 0; i < count; i ++) { - pwg_ppdize_name(ippGetString(attr, i, NULL), ppdname, sizeof(ppdname)); + keyword = ippGetString(attr, i, NULL); + + pwg_ppdize_name(keyword, ppdname, sizeof(ppdname)); + + if (i == 0 && !have_default) + cupsFilePrintf(fp, "*DefaultInputSlot: %s\n", ppdname); for (j = 0; j < (int)(sizeof(sources) / sizeof(sources[0])); j ++) - if (!strcmp(sources[j][0], ppdname)) + if (!strcmp(sources[j], keyword)) { - cupsFilePrintf(fp, "*InputSlot %s/%s: \"<>setpagedevice\"\n", ppdname, _cupsLangString(lang, sources[j][1]), j); + snprintf(msgid, sizeof(msgid), "media-source.%s", keyword); + + if ((msgstr = _cupsLangString(lang, msgid)) == msgid || !strcmp(msgid, msgstr)) + if ((msgstr = _cupsMessageLookup(strings, msgid)) == msgid) + msgstr = keyword; + + cupsFilePrintf(fp, "*InputSlot %s: \"<>setpagedevice\"\n", ppdname, j); + cupsFilePrintf(fp, "*%s.InputSlot %s/%s: \"\"\n", lang->language, ppdname, msgstr); break; } } @@ -3402,143 +3747,22 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ if ((attr = ippFindAttribute(response, "media-type-supported", IPP_TAG_ZERO)) != NULL && (count = ippGetCount(attr)) > 1) { - static const char * const media_types[][2] = - { /* "media-type" strings */ - { "aluminum", _("Aluminum") }, - { "auto", _("Automatic") }, - { "back-print-film", _("Back Print Film") }, - { "cardboard", _("Cardboard") }, - { "cardstock", _("Cardstock") }, - { "cd", _("CD") }, - { "continuous", _("Continuous") }, - { "continuous-long", _("Continuous Long") }, - { "continuous-short", _("Continuous Short") }, - { "disc", _("Optical Disc") }, - { "disc-glossy", _("Glossy Optical Disc") }, - { "disc-high-gloss", _("High Gloss Optical Disc") }, - { "disc-matte", _("Matte Optical Disc") }, - { "disc-satin", _("Satin Optical Disc") }, - { "disc-semi-gloss", _("Semi-Gloss Optical Disc") }, - { "double-wall", _("Double Wall Cardboard") }, - { "dry-film", _("Dry Film") }, - { "dvd", _("DVD") }, - { "embossing-foil", _("Embossing Foil") }, - { "end-board", _("End Board") }, - { "envelope", _("Envelope") }, - { "envelope-archival", _("Archival Envelope") }, - { "envelope-bond", _("Bond Envelope") }, - { "envelope-coated", _("Coated Envelope") }, - { "envelope-cotton", _("Cotton Envelope") }, - { "envelope-fine", _("Fine Envelope") }, - { "envelope-heavyweight", _("Heavyweight Envelope") }, - { "envelope-inkjet", _("Inkjet Envelope") }, - { "envelope-lightweight", _("Lightweight Envelope") }, - { "envelope-plain", _("Plain Envelope") }, - { "envelope-preprinted", _("Preprinted Envelope") }, - { "envelope-window", _("Windowed Envelope") }, - { "fabric", _("Fabric") }, - { "fabric-archival", _("Archival Fabric") }, - { "fabric-glossy", _("Glossy Fabric") }, - { "fabric-high-gloss", _("High Gloss Fabric") }, - { "fabric-matte", _("Matte Fabric") }, - { "fabric-semi-gloss", _("Semi-Gloss Fabric") }, - { "fabric-waterproof", _("Waterproof Fabric") }, - { "film", _("Film") }, - { "flexo-base", _("Flexo Base") }, - { "flexo-photo-polymer", _("Flexo Photo Polymer") }, - { "flute", _("Flute") }, - { "foil", _("Foil") }, - { "full-cut-tabs", _("Full Cut Tabs") }, - { "glass", _("Glass") }, - { "glass-colored", _("Glass Colored") }, - { "glass-opaque", _("Glass Opaque") }, - { "glass-surfaced", _("Glass Surfaced") }, - { "glass-textured", _("Glass Textured") }, - { "gravure-cylinder", _("Gravure Cylinder") }, - { "image-setter-paper", _("Image Setter Paper") }, - { "imaging-cylinder", _("Imaging Cylinder") }, - { "labels", _("Labels") }, - { "labels-colored", _("Colored Labels") }, - { "labels-glossy", _("Glossy Labels") }, - { "labels-high-gloss", _("High Gloss Labels") }, - { "labels-inkjet", _("Inkjet Labels") }, - { "labels-matte", _("Matte Labels") }, - { "labels-permanent", _("Permanent Labels") }, - { "labels-satin", _("Satin Labels") }, - { "labels-security", _("Security Labels") }, - { "labels-semi-gloss", _("Semi-Gloss Labels") }, - { "laminating-foil", _("Laminating Foil") }, - { "letterhead", _("Letterhead") }, - { "metal", _("Metal") }, - { "metal-glossy", _("Metal Glossy") }, - { "metal-high-gloss", _("Metal High Gloss") }, - { "metal-matte", _("Metal Matte") }, - { "metal-satin", _("Metal Satin") }, - { "metal-semi-gloss", _("Metal Semi Gloss") }, - { "mounting-tape", _("Mounting Tape") }, - { "multi-layer", _("Multi Layer") }, - { "multi-part-form", _("Multi Part Form") }, - { "other", _("Other") }, - { "paper", _("Paper") }, - { "photographic", _("Photo Paper") }, - { "photographic-archival", _("Photographic Archival") }, - { "photographic-film", _("Photo Film") }, - { "photographic-glossy", _("Glossy Photo Paper") }, - { "photographic-high-gloss", _("High Gloss Photo Paper") }, - { "photographic-matte", _("Matte Photo Paper") }, - { "photographic-satin", _("Satin Photo Paper") }, - { "photographic-semi-gloss", _("Semi-Gloss Photo Paper") }, - { "plastic", _("Plastic") }, - { "plastic-archival", _("Plastic Archival") }, - { "plastic-colored", _("Plastic Colored") }, - { "plastic-glossy", _("Plastic Glossy") }, - { "plastic-high-gloss", _("Plastic High Gloss") }, - { "plastic-matte", _("Plastic Matte") }, - { "plastic-satin", _("Plastic Satin") }, - { "plastic-semi-gloss", _("Plastic Semi Gloss") }, - { "plate", _("Plate") }, - { "polyester", _("Polyester") }, - { "pre-cut-tabs", _("Pre Cut Tabs") }, - { "roll", _("Roll") }, - { "screen", _("Screen") }, - { "screen-paged", _("Screen Paged") }, - { "self-adhesive", _("Self Adhesive") }, - { "self-adhesive-film", _("Self Adhesive Film") }, - { "shrink-foil", _("Shrink Foil") }, - { "single-face", _("Single Face") }, - { "single-wall", _("Single Wall Cardboard") }, - { "sleeve", _("Sleeve") }, - { "stationery", _("Stationery") }, - { "stationery-archival", _("Stationery Archival") }, - { "stationery-coated", _("Coated Paper") }, - { "stationery-cotton", _("Stationery Cotton") }, - { "stationery-fine", _("Vellum Paper") }, - { "stationery-heavyweight", _("Heavyweight Paper") }, - { "stationery-heavyweight-coated", _("Stationery Heavyweight Coated") }, - { "stationery-inkjet", _("Stationery Inkjet Paper") }, - { "stationery-letterhead", _("Letterhead") }, - { "stationery-lightweight", _("Lightweight Paper") }, - { "stationery-preprinted", _("Preprinted Paper") }, - { "stationery-prepunched", _("Punched Paper") }, - { "tab-stock", _("Tab Stock") }, - { "tractor", _("Tractor") }, - { "transfer", _("Transfer") }, - { "transparency", _("Transparency") }, - { "triple-wall", _("Triple Wall Cardboard") }, - { "wet-film", _("Wet Film") } - }; - cupsFilePrintf(fp, "*OpenUI *MediaType: PickOne\n" "*OrderDependency: 10 AnySetup *MediaType\n" "*DefaultMediaType: %s\n", ppdname); - for (i = 0; i < (int)(sizeof(media_types) / sizeof(media_types[0])); i ++) + for (i = 0; i < count; i ++) { - if (!ippContainsString(attr, media_types[i][0])) - continue; + keyword = ippGetString(attr, i, NULL); + + pwg_ppdize_name(keyword, ppdname, sizeof(ppdname)); - pwg_ppdize_name(media_types[i][0], ppdname, sizeof(ppdname)); + snprintf(msgid, sizeof(msgid), "media-type.%s", keyword); + if ((msgstr = _cupsLangString(lang, msgid)) == msgid || !strcmp(msgid, msgstr)) + if ((msgstr = _cupsMessageLookup(strings, msgid)) == msgid) + msgstr = keyword; - cupsFilePrintf(fp, "*MediaType %s/%s: \"<>setpagedevice\"\n", ppdname, _cupsLangString(lang, media_types[i][1]), ppdname); + cupsFilePrintf(fp, "*MediaType %s: \"<>setpagedevice\"\n", ppdname, ppdname); + cupsFilePrintf(fp, "*%s.MediaType %s/%s: \"\"\n", lang->language, ppdname, msgstr); } cupsFilePuts(fp, "*CloseUI: *MediaType\n"); } @@ -3547,70 +3771,130 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ * ColorModel... */ - if ((attr = ippFindAttribute(response, "pwg-raster-document-type-supported", IPP_TAG_KEYWORD)) == NULL) - if ((attr = ippFindAttribute(response, "urf-supported", IPP_TAG_KEYWORD)) == NULL) + if ((attr = ippFindAttribute(response, "urf-supported", IPP_TAG_KEYWORD)) == NULL) + if ((attr = ippFindAttribute(response, "pwg-raster-document-type-supported", IPP_TAG_KEYWORD)) == NULL) if ((attr = ippFindAttribute(response, "print-color-mode-supported", IPP_TAG_KEYWORD)) == NULL) attr = ippFindAttribute(response, "output-mode-supported", IPP_TAG_KEYWORD); if (attr) { + int wrote_color = 0; const char *default_color = NULL; /* Default */ + cupsFilePrintf(fp, "*%% ColorModel from %s\n", ippGetName(attr)); + for (i = 0, count = ippGetCount(attr); i < count; i ++) { - const char *keyword = ippGetString(attr, i, NULL); - /* Keyword for color/bit depth */ + keyword = ippGetString(attr, i, NULL); + +#define PRINTF_COLORMODEL if (!wrote_color) { cupsFilePrintf(fp, "*OpenUI *ColorModel: PickOne\n*OrderDependency: 10 AnySetup *ColorModel\n*%s.Translation ColorModel/%s: \"\"\n", lang->language, _cupsLangString(lang, _("Color Mode"))); wrote_color = 1; } +#define PRINTF_COLOROPTION(name,text,cspace,bpp) { cupsFilePrintf(fp, "*ColorModel %s: \"<>setpagedevice\"\n", name, cspace, bpp); cupsFilePrintf(fp, "*%s.ColorModel %s/%s: \"\"\n", lang->language, name, _cupsLangString(lang, text)); } - if (!strcmp(keyword, "black_1") || !strcmp(keyword, "bi-level") || !strcmp(keyword, "process-bi-level")) + if (!strcasecmp(keyword, "black_1") || !strcmp(keyword, "bi-level") || !strcmp(keyword, "process-bi-level")) { - if (!default_color) - cupsFilePrintf(fp, "*OpenUI *ColorModel/%s: PickOne\n" - "*OrderDependency: 10 AnySetup *ColorModel\n", _cupsLangString(lang, _("Color Mode"))); + PRINTF_COLORMODEL - cupsFilePrintf(fp, "*ColorModel FastGray/%s: \"<>setpagedevice\"\n", _cupsLangString(lang, _("Fast Grayscale"))); + PRINTF_COLOROPTION("FastGray", _("Fast Grayscale"), CUPS_CSPACE_K, 1) - if (!default_color) + if (!default_color) default_color = "FastGray"; } - else if (!strcmp(keyword, "sgray_8") || !strcmp(keyword, "W8") || !strcmp(keyword, "monochrome") || !strcmp(keyword, "process-monochrome")) + else if (!strcasecmp(keyword, "sgray_8") || !strcmp(keyword, "W8") || !strcmp(keyword, "monochrome") || !strcmp(keyword, "process-monochrome")) { - if (!default_color) - cupsFilePrintf(fp, "*OpenUI *ColorModel/%s: PickOne\n" - "*OrderDependency: 10 AnySetup *ColorModel\n", _cupsLangString(lang, _("Color Mode"))); + PRINTF_COLORMODEL - cupsFilePrintf(fp, "*ColorModel Gray/%s: \"<>setpagedevice\"\n", _cupsLangString(lang, _("Grayscale"))); + PRINTF_COLOROPTION("Gray", _("Grayscale"), CUPS_CSPACE_SW, 8) - if (!default_color || !strcmp(default_color, "FastGray")) + if (!default_color || !strcmp(default_color, "FastGray")) default_color = "Gray"; } - else if (!strcmp(keyword, "srgb_8") || !strcmp(keyword, "SRGB24") || !strcmp(keyword, "color")) + else if (!strcasecmp(keyword, "sgray_16") || !strcmp(keyword, "W8-16")) { - if (!default_color) - cupsFilePrintf(fp, "*OpenUI *ColorModel/%s: PickOne\n" - "*OrderDependency: 10 AnySetup *ColorModel\n", _cupsLangString(lang, _("Color Mode"))); + PRINTF_COLORMODEL + + if (!strcmp(keyword, "W8-16")) + { + PRINTF_COLOROPTION("Gray", _("Grayscale"), CUPS_CSPACE_SW, 8) - cupsFilePrintf(fp, "*ColorModel RGB/%s: \"<>setpagedevice\"\n", _cupsLangString(lang, _("Color"))); + if (!default_color || !strcmp(default_color, "FastGray")) + default_color = "Gray"; + } + + PRINTF_COLOROPTION("Gray16", _("Deep Gray"), CUPS_CSPACE_SW, 16) + } + else if (!strcasecmp(keyword, "srgb_8") || !strncmp(keyword, "SRGB24", 7) || !strcmp(keyword, "color")) + { + PRINTF_COLORMODEL + + PRINTF_COLOROPTION("RGB", _("Color"), CUPS_CSPACE_SRGB, 8) default_color = "RGB"; + + // Apparently some printers only advertise color support, so make sure + // we also do grayscale for these printers... + if (!ippContainsString(attr, "sgray_8") && !ippContainsString(attr, "black_1") && !ippContainsString(attr, "black_8") && !ippContainsString(attr, "W8") && !ippContainsString(attr, "W8-16")) + PRINTF_COLOROPTION("Gray", _("GrayScale"), CUPS_CSPACE_SW, 8) + } + else if (!strcasecmp(keyword, "adobe-rgb_16") || !strcmp(keyword, "ADOBERGB48") || !strcmp(keyword, "ADOBERGB24-48")) + { + PRINTF_COLORMODEL + + PRINTF_COLOROPTION("AdobeRGB", _("Deep Color"), CUPS_CSPACE_ADOBERGB, 16) + + if (!default_color) + default_color = "AdobeRGB"; } - else if (!strcmp(keyword, "adobe-rgb_16") || !strcmp(keyword, "ADOBERGB48")) + else if ((!strcasecmp(keyword, "adobe-rgb_8") && !ippContainsString(attr, "adobe-rgb_16")) || !strcmp(keyword, "ADOBERGB24")) { - if (!default_color) - cupsFilePrintf(fp, "*OpenUI *ColorModel/%s: PickOne\n" - "*OrderDependency: 10 AnySetup *ColorModel\n", _cupsLangString(lang, _("Color Mode"))); + PRINTF_COLORMODEL - cupsFilePrintf(fp, "*ColorModel AdobeRGB/%s: \"<>setpagedevice\"\n", _cupsLangString(lang, _("Deep Color"))); + PRINTF_COLOROPTION("AdobeRGB", _("Deep Color"), CUPS_CSPACE_ADOBERGB, 8) - if (!default_color) + if (!default_color) default_color = "AdobeRGB"; } + else if ((!strcasecmp(keyword, "black_8") && !ippContainsString(attr, "black_16")) || !strcmp(keyword, "DEVW8")) + { + PRINTF_COLORMODEL + + PRINTF_COLOROPTION("DeviceGray", _("Device Gray"), CUPS_CSPACE_W, 8) + } + else if (!strcasecmp(keyword, "black_16") || !strcmp(keyword, "DEVW16") || !strcmp(keyword, "DEVW8-16")) + { + PRINTF_COLORMODEL + + PRINTF_COLOROPTION("DeviceGray", _("Device Gray"), CUPS_CSPACE_W, 16) + } + else if ((!strcasecmp(keyword, "cmyk_8") && !ippContainsString(attr, "cmyk_16")) || !strcmp(keyword, "DEVCMYK32")) + { + PRINTF_COLORMODEL + + PRINTF_COLOROPTION("CMYK", _("Device CMYK"), CUPS_CSPACE_CMYK, 8) + } + else if (!strcasecmp(keyword, "cmyk_16") || !strcmp(keyword, "DEVCMYK32-64") || !strcmp(keyword, "DEVCMYK64")) + { + PRINTF_COLORMODEL + + PRINTF_COLOROPTION("CMYK", _("Device CMYK"), CUPS_CSPACE_CMYK, 16) + } + else if ((!strcasecmp(keyword, "rgb_8") && ippContainsString(attr, "rgb_16")) || !strcmp(keyword, "DEVRGB24")) + { + PRINTF_COLORMODEL + + PRINTF_COLOROPTION("DeviceRGB", _("Device RGB"), CUPS_CSPACE_RGB, 8) + } + else if (!strcasecmp(keyword, "rgb_16") || !strcmp(keyword, "DEVRGB24-48") || !strcmp(keyword, "DEVRGB48")) + { + PRINTF_COLORMODEL + + PRINTF_COLOROPTION("DeviceRGB", _("Device RGB"), CUPS_CSPACE_RGB, 16) + } } if (default_color) - { cupsFilePrintf(fp, "*DefaultColorModel: %s\n", default_color); + if (wrote_color) cupsFilePuts(fp, "*CloseUI: *ColorModel\n"); - } } /* @@ -3619,18 +3903,50 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ if ((attr = ippFindAttribute(response, "sides-supported", IPP_TAG_KEYWORD)) != NULL && ippContainsString(attr, "two-sided-long-edge")) { - cupsFilePrintf(fp, "*OpenUI *Duplex/%s: PickOne\n" + cupsFilePrintf(fp, "*OpenUI *Duplex: PickOne\n" "*OrderDependency: 10 AnySetup *Duplex\n" + "*%s.Translation Duplex/%s: \"\"\n" "*DefaultDuplex: None\n" - "*Duplex None/%s: \"<>setpagedevice\"\n" - "*Duplex DuplexNoTumble/%s: \"<>setpagedevice\"\n" - "*Duplex DuplexTumble/%s: \"<>setpagedevice\"\n" - "*CloseUI: *Duplex\n", _cupsLangString(lang, _("2-Sided Printing")), _cupsLangString(lang, _("Off (1-Sided)")), _cupsLangString(lang, _("Long-Edge (Portrait)")), _cupsLangString(lang, _("Short-Edge (Landscape)"))); + "*Duplex None: \"<>setpagedevice\"\n" + "*%s.Duplex None/%s: \"\"\n" + "*Duplex DuplexNoTumble: \"<>setpagedevice\"\n" + "*%s.Duplex DuplexNoTumble/%s: \"\"\n" + "*Duplex DuplexTumble: \"<>setpagedevice\"\n" + "*%s.Duplex DuplexTumble/%s: \"\"\n" + "*CloseUI: *Duplex\n", lang->language, _cupsLangString(lang, _("2-Sided Printing")), lang->language, _cupsLangString(lang, _("Off (1-Sided)")), lang->language, _cupsLangString(lang, _("Long-Edge (Portrait)")), lang->language, _cupsLangString(lang, _("Short-Edge (Landscape)"))); + + if ((attr = ippFindAttribute(response, "urf-supported", IPP_TAG_KEYWORD)) != NULL) + { + for (i = 0, count = ippGetCount(attr); i < count; i ++) + { + const char *dm = ippGetString(attr, i, NULL); + /* DM value */ - if ((attr = ippFindAttribute(response, "pwg-raster-document-sheet-back", IPP_TAG_KEYWORD)) != NULL) + if (!_cups_strcasecmp(dm, "DM1")) + { + cupsFilePuts(fp, "*cupsBackSide: Normal\n"); + break; + } + else if (!_cups_strcasecmp(dm, "DM2")) + { + cupsFilePuts(fp, "*cupsBackSide: Flipped\n"); + break; + } + else if (!_cups_strcasecmp(dm, "DM3")) + { + cupsFilePuts(fp, "*cupsBackSide: Rotated\n"); + break; + } + else if (!_cups_strcasecmp(dm, "DM4")) + { + cupsFilePuts(fp, "*cupsBackSide: ManualTumble\n"); + break; + } + } + } + else if ((attr = ippFindAttribute(response, "pwg-raster-document-sheet-back", IPP_TAG_KEYWORD)) != NULL) { - const char *keyword = ippGetString(attr, 0, NULL); - /* Keyword value */ + keyword = ippGetString(attr, 0, NULL); if (!strcmp(keyword, "flipped")) cupsFilePuts(fp, "*cupsBackSide: Flipped\n"); @@ -3641,35 +3957,6 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ else cupsFilePuts(fp, "*cupsBackSide: Rotated\n"); } - else if ((attr = ippFindAttribute(response, "urf-supported", IPP_TAG_KEYWORD)) != NULL) - { - for (i = 0, count = ippGetCount(attr); i < count; i ++) - { - const char *dm = ippGetString(attr, i, NULL); - /* DM value */ - - if (!_cups_strcasecmp(dm, "DM1")) - { - cupsFilePuts(fp, "*cupsBackSide: Normal\n"); - break; - } - else if (!_cups_strcasecmp(dm, "DM2")) - { - cupsFilePuts(fp, "*cupsBackSide: Flipped\n"); - break; - } - else if (!_cups_strcasecmp(dm, "DM3")) - { - cupsFilePuts(fp, "*cupsBackSide: Rotated\n"); - break; - } - else if (!_cups_strcasecmp(dm, "DM4")) - { - cupsFilePuts(fp, "*cupsBackSide: ManualTumble\n"); - break; - } - } - } } /* @@ -3681,66 +3968,54 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ else strlcpy(ppdname, "Unknown", sizeof(ppdname)); - if ((attr = ippFindAttribute(response, "outout-bin-supported", IPP_TAG_ZERO)) != NULL && (count = ippGetCount(attr)) > 1) + if ((attr = ippFindAttribute(response, "output-bin-supported", IPP_TAG_ZERO)) != NULL && (count = ippGetCount(attr)) > 0) { - static const char * const output_bins[][2] = - { /* "output-bin" strings */ - { "auto", _("Automatic") }, - { "bottom", _("Bottom Tray") }, - { "center", _("Center Tray") }, - { "face-down", _("Face Down") }, - { "face-up", _("Face Up") }, - { "large-capacity", _("Large Capacity Tray") }, - { "left", _("Left Tray") }, - { "mailbox-1", _("Mailbox 1") }, - { "mailbox-2", _("Mailbox 2") }, - { "mailbox-3", _("Mailbox 3") }, - { "mailbox-4", _("Mailbox 4") }, - { "mailbox-5", _("Mailbox 5") }, - { "mailbox-6", _("Mailbox 6") }, - { "mailbox-7", _("Mailbox 7") }, - { "mailbox-8", _("Mailbox 8") }, - { "mailbox-9", _("Mailbox 9") }, - { "mailbox-10", _("Mailbox 10") }, - { "middle", _("Middle") }, - { "my-mailbox", _("My Mailbox") }, - { "rear", _("Rear Tray") }, - { "right", _("Right Tray") }, - { "side", _("Side Tray") }, - { "stacker-1", _("Stacker 1") }, - { "stacker-2", _("Stacker 2") }, - { "stacker-3", _("Stacker 3") }, - { "stacker-4", _("Stacker 4") }, - { "stacker-5", _("Stacker 5") }, - { "stacker-6", _("Stacker 6") }, - { "stacker-7", _("Stacker 7") }, - { "stacker-8", _("Stacker 8") }, - { "stacker-9", _("Stacker 9") }, - { "stacker-10", _("Stacker 10") }, - { "top", _("Top Tray") }, - { "tray-1", _("Tray 1") }, - { "tray-2", _("Tray 2") }, - { "tray-3", _("Tray 3") }, - { "tray-4", _("Tray 4") }, - { "tray-5", _("Tray 5") }, - { "tray-6", _("Tray 6") }, - { "tray-7", _("Tray 7") }, - { "tray-8", _("Tray 8") }, - { "tray-9", _("Tray 9") }, - { "tray-10", _("Tray 10") } - }; + ipp_attribute_t *trays = ippFindAttribute(response, "printer-output-tray", IPP_TAG_STRING); + /* printer-output-tray attribute, if any */ + const char *tray_ptr; /* printer-output-tray value */ + int tray_len; /* Len of printer-output-tray value */ + char tray[IPP_MAX_OCTETSTRING]; + /* printer-output-tray string value */ cupsFilePrintf(fp, "*OpenUI *OutputBin: PickOne\n" "*OrderDependency: 10 AnySetup *OutputBin\n" "*DefaultOutputBin: %s\n", ppdname); - for (i = 0; i < (int)(sizeof(output_bins) / sizeof(output_bins[0])); i ++) + if (!strcmp(ppdname, "FaceUp")) + cupsFilePuts(fp, "*DefaultOutputOrder: Reverse\n"); + else + cupsFilePuts(fp, "*DefaultOutputOrder: Normal\n"); + + for (i = 0; i < count; i ++) { - if (!ippContainsString(attr, output_bins[i][0])) - continue; + keyword = ippGetString(attr, i, NULL); + + pwg_ppdize_name(keyword, ppdname, sizeof(ppdname)); - pwg_ppdize_name(output_bins[i][0], ppdname, sizeof(ppdname)); + snprintf(msgid, sizeof(msgid), "output-bin.%s", keyword); + if ((msgstr = _cupsLangString(lang, msgid)) == msgid || !strcmp(msgid, msgstr)) + if ((msgstr = _cupsMessageLookup(strings, msgid)) == msgid) + msgstr = keyword; - cupsFilePrintf(fp, "*OutputBin %s/%s: \"\"\n", ppdname, _cupsLangString(lang, output_bins[i][1])); + cupsFilePrintf(fp, "*OutputBin %s: \"\"\n", ppdname); + cupsFilePrintf(fp, "*%s.OutputBin %s/%s: \"\"\n", lang->language, ppdname, msgstr); + + if ((tray_ptr = ippGetOctetString(trays, i, &tray_len)) != NULL) + { + if (tray_len >= (int)sizeof(tray)) + tray_len = (int)sizeof(tray) - 1; + + memcpy(tray, tray_ptr, (size_t)tray_len); + tray[tray_len] = '\0'; + + if (strstr(tray, "stackingorder=lastToFirst;")) + cupsFilePrintf(fp, "*PageStackOrder %s: Reverse\n", ppdname); + else + cupsFilePrintf(fp, "*PageStackOrder %s: Normal\n", ppdname); + } + else if (!strcmp(ppdname, "FaceUp")) + cupsFilePrintf(fp, "*PageStackOrder %s: Reverse\n", ppdname); + else + cupsFilePrintf(fp, "*PageStackOrder %s: Normal\n", ppdname); } cupsFilePuts(fp, "*CloseUI: *OutputBin\n"); } @@ -3749,125 +4024,461 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ * Finishing options... */ - if ((attr = ippFindAttribute(response, "finishings-col-database", IPP_TAG_BEGIN_COLLECTION)) != NULL) + if ((attr = ippFindAttribute(response, "finishings-supported", IPP_TAG_ENUM)) != NULL) { - ipp_t *col; /* Collection value */ - ipp_attribute_t *template; /* "finishing-template" member */ - const char *name; /* String name */ - int value; /* Enum value, if any */ + int value; /* Enum value */ + const char *ppd_keyword; /* PPD keyword for enum */ cups_array_t *names; /* Names we've added */ + static const char * const base_keywords[] = + { /* Base STD 92 keywords */ + NULL, /* none */ + "SingleAuto", /* staple */ + "SingleAuto", /* punch */ + NULL, /* cover */ + "BindAuto", /* bind */ + "SaddleStitch", /* saddle-stitch */ + "EdgeStitchAuto", /* edge-stitch */ + "Auto", /* fold */ + NULL, /* trim */ + NULL, /* bale */ + NULL, /* booklet-maker */ + NULL, /* jog-offset */ + NULL, /* coat */ + NULL /* laminate */ + }; - count = ippGetCount(attr); - names = cupsArrayNew3((cups_array_func_t)strcmp, NULL, NULL, 0, (cups_acopy_func_t)strdup, (cups_afree_func_t)free); + count = ippGetCount(attr); + names = cupsArrayNew3((cups_array_func_t)strcmp, NULL, NULL, 0, (cups_acopy_func_t)strdup, (cups_afree_func_t)free); + fin_options = cupsArrayNew((cups_array_func_t)strcmp, NULL); - cupsFilePrintf(fp, "*OpenUI *cupsFinishingTemplate/%s: PickMany\n" - "*OrderDependency: 10 AnySetup *cupsFinishingTemplate\n" - "*DefaultcupsFinishingTemplate: none\n" - "*cupsFinishingTemplate none/%s: \"\"\n" - "*cupsIPPFinishings 3/none: \"*cupsFinishingTemplate none\"\n", _cupsLangString(lang, _("Finishing")), _cupsLangString(lang, _("No Finishing"))); + /* + * Staple/Bind/Stitch + */ for (i = 0; i < count; i ++) { - col = ippGetCollection(attr, i); - template = ippFindAttribute(col, "finishing-template", IPP_TAG_ZERO); + value = ippGetInteger(attr, i); + keyword = ippEnumString("finishings", value); - if ((name = ippGetString(template, 0, NULL)) == NULL || !strcmp(name, "none")) - continue; + if (!strncmp(keyword, "staple-", 7) || !strncmp(keyword, "bind-", 5) || !strncmp(keyword, "edge-stitch-", 12) || !strcmp(keyword, "saddle-stitch")) + break; + } + + if (i < count) + { + static const char * const staple_keywords[] = + { /* StapleLocation keywords */ + "SinglePortrait", + "SingleRevLandscape", + "SingleLandscape", + "SingleRevPortrait", + "EdgeStitchPortrait", + "EdgeStitchLandscape", + "EdgeStitchRevPortrait", + "EdgeStitchRevLandscape", + "DualPortrait", + "DualLandscape", + "DualRevPortrait", + "DualRevLandscape", + "TriplePortrait", + "TripleLandscape", + "TripleRevPortrait", + "TripleRevLandscape" + }; + static const char * const bind_keywords[] = + { /* StapleLocation binding keywords */ + "BindPortrait", + "BindLandscape", + "BindRevPortrait", + "BindRevLandscape" + }; + + cupsArrayAdd(fin_options, "*StapleLocation"); + + cupsFilePuts(fp, "*OpenUI *StapleLocation: PickOne\n"); + cupsFilePuts(fp, "*OrderDependency: 10 AnySetup *StapleLocation\n"); + cupsFilePrintf(fp, "*%s.Translation StapleLocation/%s: \"\"\n", lang->language, _cupsLangString(lang, _("Staple"))); + cupsFilePuts(fp, "*DefaultStapleLocation: None\n"); + cupsFilePuts(fp, "*StapleLocation None: \"\"\n"); + cupsFilePrintf(fp, "*%s.StapleLocation None/%s: \"\"\n", lang->language, _cupsLangString(lang, _("None"))); + + for (; i < count; i ++) + { + value = ippGetInteger(attr, i); + keyword = ippEnumString("finishings", value); - if (cupsArrayFind(names, (char *)name)) - continue; /* Already did this finishing template */ + if (strncmp(keyword, "staple-", 7) && strncmp(keyword, "bind-", 5) && strncmp(keyword, "edge-stitch-", 12) && strcmp(keyword, "saddle-stitch")) + continue; + + if (cupsArrayFind(names, (char *)keyword)) + continue; /* Already did this finishing template */ + + cupsArrayAdd(names, (char *)keyword); + + snprintf(msgid, sizeof(msgid), "finishings.%d", value); + if ((msgstr = _cupsLangString(lang, msgid)) == msgid || !strcmp(msgid, msgstr)) + if ((msgstr = _cupsMessageLookup(strings, msgid)) == msgid) + msgstr = keyword; - cupsArrayAdd(names, (char *)name); + if (value >= IPP_FINISHINGS_NONE && value <= IPP_FINISHINGS_LAMINATE) + ppd_keyword = base_keywords[value - IPP_FINISHINGS_NONE]; + else if (value >= IPP_FINISHINGS_STAPLE_TOP_LEFT && value <= IPP_FINISHINGS_STAPLE_TRIPLE_BOTTOM) + ppd_keyword = staple_keywords[value - IPP_FINISHINGS_STAPLE_TOP_LEFT]; + else if (value >= IPP_FINISHINGS_BIND_LEFT && value <= IPP_FINISHINGS_BIND_BOTTOM) + ppd_keyword = bind_keywords[value - IPP_FINISHINGS_BIND_LEFT]; + else + ppd_keyword = NULL; + + if (!ppd_keyword) + continue; + + cupsFilePrintf(fp, "*StapleLocation %s: \"\"\n", ppd_keyword); + cupsFilePrintf(fp, "*%s.StapleLocation %s/%s: \"\"\n", lang->language, ppd_keyword, msgstr); + cupsFilePrintf(fp, "*cupsIPPFinishings %d/%s: \"*StapleLocation %s\"\n", value, keyword, ppd_keyword); + } - for (j = 0; j < (int)(sizeof(finishings) / sizeof(finishings[0])); j ++) + cupsFilePuts(fp, "*CloseUI: *StapleLocation\n"); + } + + /* + * Fold + */ + + for (i = 0; i < count; i ++) + { + value = ippGetInteger(attr, i); + keyword = ippEnumString("finishings", value); + + if (!strncmp(keyword, "cups-fold-", 10) || !strcmp(keyword, "fold") || !strncmp(keyword, "fold-", 5)) + break; + } + + if (i < count) + { + static const char * const fold_keywords[] = + { /* FoldType keywords */ + "Accordion", + "DoubleGate", + "Gate", + "Half", + "HalfZ", + "LeftGate", + "Letter", + "Parallel", + "XFold", + "RightGate", + "ZFold", + "EngineeringZ" + }; + + cupsArrayAdd(fin_options, "*FoldType"); + + cupsFilePuts(fp, "*OpenUI *FoldType: PickOne\n"); + cupsFilePuts(fp, "*OrderDependency: 10 AnySetup *FoldType\n"); + cupsFilePrintf(fp, "*%s.Translation FoldType/%s: \"\"\n", lang->language, _cupsLangString(lang, _("Fold"))); + cupsFilePuts(fp, "*DefaultFoldType: None\n"); + cupsFilePuts(fp, "*FoldType None: \"\"\n"); + cupsFilePrintf(fp, "*%s.FoldType None/%s: \"\"\n", lang->language, _cupsLangString(lang, _("None"))); + + for (; i < count; i ++) { - if (!strcmp(finishings[j][0], name)) - { - cupsFilePrintf(fp, "*cupsFinishingTemplate %s/%s: \"\"\n", name, _cupsLangString(lang, finishings[j][1])); + value = ippGetInteger(attr, i); + keyword = ippEnumString("finishings", value); - value = ippEnumValue("finishings", name); + if (!strncmp(keyword, "cups-fold-", 10)) + keyword += 5; + else if (strcmp(keyword, "fold") && strncmp(keyword, "fold-", 5)) + continue; - if (value) - cupsFilePrintf(fp, "*cupsIPPFinishings %d/%s: \"*cupsFinishingTemplate %s\"\n", value, name, name); - break; - } + if (cupsArrayFind(names, (char *)keyword)) + continue; /* Already did this finishing template */ + + cupsArrayAdd(names, (char *)keyword); + + snprintf(msgid, sizeof(msgid), "finishings.%d", value); + if ((msgstr = _cupsLangString(lang, msgid)) == msgid || !strcmp(msgid, msgstr)) + if ((msgstr = _cupsMessageLookup(strings, msgid)) == msgid) + msgstr = keyword; + + if (value >= IPP_FINISHINGS_NONE && value <= IPP_FINISHINGS_LAMINATE) + ppd_keyword = base_keywords[value - IPP_FINISHINGS_NONE]; + else if (value >= IPP_FINISHINGS_FOLD_ACCORDION && value <= IPP_FINISHINGS_FOLD_ENGINEERING_Z) + ppd_keyword = fold_keywords[value - IPP_FINISHINGS_FOLD_ACCORDION]; + else if (value >= IPP_FINISHINGS_CUPS_FOLD_ACCORDION && value <= IPP_FINISHINGS_CUPS_FOLD_Z) + ppd_keyword = fold_keywords[value - IPP_FINISHINGS_CUPS_FOLD_ACCORDION]; + else + ppd_keyword = NULL; + + if (!ppd_keyword) + continue; + + cupsFilePrintf(fp, "*FoldType %s: \"\"\n", ppd_keyword); + cupsFilePrintf(fp, "*%s.FoldType %s/%s: \"\"\n", lang->language, ppd_keyword, msgstr); + cupsFilePrintf(fp, "*cupsIPPFinishings %d/%s: \"*FoldType %s\"\n", value, keyword, ppd_keyword); } + + cupsFilePuts(fp, "*CloseUI: *FoldType\n"); } - cupsArrayDelete(names); + /* + * Punch + */ - cupsFilePuts(fp, "*CloseUI: *cupsFinishingTemplate\n"); + for (i = 0; i < count; i ++) + { + value = ippGetInteger(attr, i); + keyword = ippEnumString("finishings", value); + + if (!strncmp(keyword, "cups-punch-", 11) || !strncmp(keyword, "punch-", 6)) + break; + } + + if (i < count) + { + static const char * const punch_keywords[] = + { /* PunchMedia keywords */ + "SinglePortrait", + "SingleRevLandscape", + "SingleLandscape", + "SingleRevPortrait", + "DualPortrait", + "DualLandscape", + "DualRevPortrait", + "DualRevLandscape", + "TriplePortrait", + "TripleLandscape", + "TripleRevPortrait", + "TripleRevLandscape", + "QuadPortrait", + "QuadLandscape", + "QuadRevPortrait", + "QuadRevLandscape", + "MultiplePortrait", + "MultipleLandscape", + "MultipleRevPortrait", + "MultipleRevLandscape" + }; + + cupsArrayAdd(fin_options, "*PunchMedia"); + + cupsFilePuts(fp, "*OpenUI *PunchMedia: PickOne\n"); + cupsFilePuts(fp, "*OrderDependency: 10 AnySetup *PunchMedia\n"); + cupsFilePrintf(fp, "*%s.Translation PunchMedia/%s: \"\"\n", lang->language, _cupsLangString(lang, _("Punch"))); + cupsFilePuts(fp, "*DefaultPunchMedia: None\n"); + cupsFilePuts(fp, "*PunchMedia None: \"\"\n"); + cupsFilePrintf(fp, "*%s.PunchMedia None/%s: \"\"\n", lang->language, _cupsLangString(lang, _("None"))); + + for (i = 0; i < count; i ++) + { + value = ippGetInteger(attr, i); + keyword = ippEnumString("finishings", value); + + if (!strncmp(keyword, "cups-punch-", 11)) + keyword += 5; + else if (strncmp(keyword, "punch-", 6)) + continue; + + if (cupsArrayFind(names, (char *)keyword)) + continue; /* Already did this finishing template */ + + cupsArrayAdd(names, (char *)keyword); + + snprintf(msgid, sizeof(msgid), "finishings.%d", value); + if ((msgstr = _cupsLangString(lang, msgid)) == msgid || !strcmp(msgid, msgstr)) + if ((msgstr = _cupsMessageLookup(strings, msgid)) == msgid) + msgstr = keyword; + + if (value >= IPP_FINISHINGS_NONE && value <= IPP_FINISHINGS_LAMINATE) + ppd_keyword = base_keywords[value - IPP_FINISHINGS_NONE]; + else if (value >= IPP_FINISHINGS_PUNCH_TOP_LEFT && value <= IPP_FINISHINGS_PUNCH_MULTIPLE_BOTTOM) + ppd_keyword = punch_keywords[value - IPP_FINISHINGS_PUNCH_TOP_LEFT]; + else if (value >= IPP_FINISHINGS_CUPS_PUNCH_TOP_LEFT && value <= IPP_FINISHINGS_CUPS_PUNCH_QUAD_BOTTOM) + ppd_keyword = punch_keywords[value - IPP_FINISHINGS_CUPS_PUNCH_TOP_LEFT]; + else + ppd_keyword = NULL; + + if (!ppd_keyword) + continue; + + cupsFilePrintf(fp, "*PunchMedia %s: \"\"\n", ppd_keyword); + cupsFilePrintf(fp, "*%s.PunchMedia %s/%s: \"\"\n", lang->language, ppd_keyword, msgstr); + cupsFilePrintf(fp, "*cupsIPPFinishings %d/%s: \"*PunchMedia %s\"\n", value, keyword, ppd_keyword); + } + + cupsFilePuts(fp, "*CloseUI: *PunchMedia\n"); + } + + /* + * Booklet + */ + + if (ippContainsInteger(attr, IPP_FINISHINGS_BOOKLET_MAKER)) + { + cupsArrayAdd(fin_options, "*Booklet"); + + cupsFilePuts(fp, "*OpenUI *Booklet: Boolean\n"); + cupsFilePuts(fp, "*OrderDependency: 10 AnySetup *Booklet\n"); + cupsFilePrintf(fp, "*%s.Translation Booklet/%s: \"\"\n", lang->language, _cupsLangString(lang, _("Booklet"))); + cupsFilePuts(fp, "*DefaultBooklet: False\n"); + cupsFilePuts(fp, "*Booklet False: \"\"\n"); + cupsFilePuts(fp, "*Booklet True: \"\"\n"); + cupsFilePrintf(fp, "*cupsIPPFinishings %d/booklet-maker: \"*Booklet True\"\n", IPP_FINISHINGS_BOOKLET_MAKER); + cupsFilePuts(fp, "*CloseUI: *Booklet\n"); + } + + /* + * CutMedia + */ + + for (i = 0; i < count; i ++) + { + value = ippGetInteger(attr, i); + keyword = ippEnumString("finishings", value); + + if (!strcmp(keyword, "trim") || !strncmp(keyword, "trim-", 5)) + break; + } + + if (i < count) + { + static const char * const trim_keywords[] = + { /* CutMedia keywords */ + "EndOfPage", + "EndOfDoc", + "EndOfSet", + "EndOfJob" + }; + + cupsArrayAdd(fin_options, "*CutMedia"); + + cupsFilePuts(fp, "*OpenUI *CutMedia: PickOne\n"); + cupsFilePuts(fp, "*OrderDependency: 10 AnySetup *CutMedia\n"); + cupsFilePrintf(fp, "*%s.Translation CutMedia/%s: \"\"\n", lang->language, _cupsLangString(lang, _("Cut"))); + cupsFilePuts(fp, "*DefaultCutMedia: None\n"); + cupsFilePuts(fp, "*CutMedia None: \"\"\n"); + cupsFilePrintf(fp, "*%s.CutMedia None/%s: \"\"\n", lang->language, _cupsLangString(lang, _("None"))); + + for (i = 0; i < count; i ++) + { + value = ippGetInteger(attr, i); + keyword = ippEnumString("finishings", value); + + if (strcmp(keyword, "trim") && strncmp(keyword, "trim-", 5)) + continue; + + if (cupsArrayFind(names, (char *)keyword)) + continue; /* Already did this finishing template */ + + cupsArrayAdd(names, (char *)keyword); + + snprintf(msgid, sizeof(msgid), "finishings.%d", value); + if ((msgstr = _cupsLangString(lang, msgid)) == msgid || !strcmp(msgid, msgstr)) + if ((msgstr = _cupsMessageLookup(strings, msgid)) == msgid) + msgstr = keyword; + + if (value == IPP_FINISHINGS_TRIM) + ppd_keyword = "Auto"; + else + ppd_keyword = trim_keywords[value - IPP_FINISHINGS_TRIM_AFTER_PAGES]; + + cupsFilePrintf(fp, "*CutMedia %s: \"\"\n", ppd_keyword); + cupsFilePrintf(fp, "*%s.CutMedia %s/%s: \"\"\n", lang->language, ppd_keyword, msgstr); + cupsFilePrintf(fp, "*cupsIPPFinishings %d/%s: \"*CutMedia %s\"\n", value, keyword, ppd_keyword); + } + + cupsFilePuts(fp, "*CloseUI: *CutMedia\n"); + } + + cupsArrayDelete(names); } - else if ((attr = ippFindAttribute(response, "finishings-supported", IPP_TAG_ENUM)) != NULL && (count = ippGetCount(attr)) > 1 ) + + if ((attr = ippFindAttribute(response, "finishings-col-database", IPP_TAG_BEGIN_COLLECTION)) != NULL) { - const char *name; /* String name */ - int value; /* Enum value, if any */ + ipp_t *finishing_col; /* Current finishing collection */ + ipp_attribute_t *finishing_attr; /* Current finishing member attribute */ + cups_array_t *templates; /* Finishing templates */ - count = ippGetCount(attr); + cupsFilePuts(fp, "*OpenUI *cupsFinishingTemplate: PickOne\n"); + cupsFilePuts(fp, "*OrderDependency: 10 AnySetup *cupsFinishingTemplate\n"); + cupsFilePrintf(fp, "*%s.Translation cupsFinishingTemplate/%s: \"\"\n", lang->language, _cupsLangString(lang, _("Finishing Preset"))); + cupsFilePuts(fp, "*DefaultcupsFinishingTemplate: none\n"); + cupsFilePuts(fp, "*cupsFinishingTemplate none: \"\"\n"); + cupsFilePrintf(fp, "*%s.cupsFinishingTemplate none/%s: \"\"\n", lang->language, _cupsLangString(lang, _("None"))); - cupsFilePrintf(fp, "*OpenUI *cupsFinishingTemplate/%s: PickMany\n" - "*OrderDependency: 10 AnySetup *cupsFinishingTemplate\n" - "*DefaultcupsFinishingTemplate: none\n" - "*cupsFinishingTemplate none/%s: \"\"\n" - "*cupsIPPFinishings 3/none: \"*cupsFinishingTemplate none\"\n", _cupsLangString(lang, _("Finishing")), _cupsLangString(lang, _("No Finishing"))); + templates = cupsArrayNew((cups_array_func_t)strcmp, NULL); + count = ippGetCount(attr); for (i = 0; i < count; i ++) { - if ((value = ippGetInteger(attr, i)) == 3) + finishing_col = ippGetCollection(attr, i); + keyword = ippGetString(ippFindAttribute(finishing_col, "finishing-template", IPP_TAG_ZERO), 0, NULL); + + if (!keyword || cupsArrayFind(templates, (void *)keyword)) + continue; + + if (!strcmp(keyword, "none")) continue; - name = ippEnumString("finishings", value); - for (j = 0; j < (int)(sizeof(finishings) / sizeof(finishings[0])); j ++) + cupsArrayAdd(templates, (void *)keyword); + + snprintf(msgid, sizeof(msgid), "finishing-template.%s", keyword); + if ((msgstr = _cupsLangString(lang, msgid)) == msgid || !strcmp(msgid, msgstr)) + if ((msgstr = _cupsMessageLookup(strings, msgid)) == msgid) + msgstr = keyword; + + cupsFilePrintf(fp, "*cupsFinishingTemplate %s: \"\n", keyword); + for (finishing_attr = ippFirstAttribute(finishing_col); finishing_attr; finishing_attr = ippNextAttribute(finishing_col)) { - if (!strcmp(finishings[j][0], name)) - { - cupsFilePrintf(fp, "*cupsFinishingTemplate %s/%s: \"\"\n", name, _cupsLangString(lang, finishings[j][1])); - cupsFilePrintf(fp, "*cupsIPPFinishings %d/%s: \"*cupsFinishingTemplate %s\"\n", value, name, name); - break; + if (ippGetValueTag(finishing_attr) == IPP_TAG_BEGIN_COLLECTION) + { + const char *name = ippGetName(finishing_attr); + /* Member attribute name */ + + if (strcmp(name, "media-size")) + cupsFilePrintf(fp, "%% %s\n", name); } } + cupsFilePuts(fp, "\"\n"); + cupsFilePrintf(fp, "*%s.cupsFinishingTemplate %s/%s: \"\"\n", lang->language, keyword, msgstr); + cupsFilePuts(fp, "*End\n"); } cupsFilePuts(fp, "*CloseUI: *cupsFinishingTemplate\n"); + + if (cupsArrayCount(fin_options)) + { + const char *fin_option; /* Current finishing option */ + + cupsFilePuts(fp, "*cupsUIConstraint finishing-template: \"*cupsFinishingTemplate"); + for (fin_option = (const char *)cupsArrayFirst(fin_options); fin_option; fin_option = (const char *)cupsArrayNext(fin_options)) + cupsFilePrintf(fp, " %s", fin_option); + cupsFilePuts(fp, "\"\n"); + + cupsFilePuts(fp, "*cupsUIResolver finishing-template: \"*cupsFinishingTemplate None"); + for (fin_option = (const char *)cupsArrayFirst(fin_options); fin_option; fin_option = (const char *)cupsArrayNext(fin_options)) + cupsFilePrintf(fp, " %s None", fin_option); + cupsFilePuts(fp, "\"\n"); + } + + cupsArrayDelete(templates); } + cupsArrayDelete(fin_options); + /* * cupsPrintQuality and DefaultResolution... */ - if ((attr = ippFindAttribute(response, "pwg-raster-document-resolution-supported", IPP_TAG_RESOLUTION)) != NULL) - { - count = ippGetCount(attr); - - pwg_ppdize_resolution(attr, count / 2, &xres, &yres, ppdname, sizeof(ppdname)); - cupsFilePrintf(fp, "*DefaultResolution: %s\n", ppdname); + quality = ippFindAttribute(response, "print-quality-supported", IPP_TAG_ENUM); - cupsFilePrintf(fp, "*OpenUI *cupsPrintQuality/%s: PickOne\n" - "*OrderDependency: 10 AnySetup *cupsPrintQuality\n" - "*DefaultcupsPrintQuality: Normal\n", _cupsLangString(lang, _("Print Quality"))); - if (count > 2) - { - pwg_ppdize_resolution(attr, 0, &xres, &yres, NULL, 0); - cupsFilePrintf(fp, "*cupsPrintQuality Draft/%s: \"<>setpagedevice\"\n", _cupsLangString(lang, _("Draft")), xres, yres); - } - pwg_ppdize_resolution(attr, count / 2, &xres, &yres, NULL, 0); - cupsFilePrintf(fp, "*cupsPrintQuality Normal/%s: \"<>setpagedevice\"\n", _cupsLangString(lang, _("Normal")), xres, yres); - if (count > 1) - { - pwg_ppdize_resolution(attr, count - 1, &xres, &yres, NULL, 0); - cupsFilePrintf(fp, "*cupsPrintQuality High/%s: \"<>setpagedevice\"\n", _cupsLangString(lang, _("High")), xres, yres); - } - - cupsFilePuts(fp, "*CloseUI: *cupsPrintQuality\n"); - } - else if ((attr = ippFindAttribute(response, "urf-supported", IPP_TAG_KEYWORD)) != NULL) + if ((attr = ippFindAttribute(response, "urf-supported", IPP_TAG_KEYWORD)) != NULL) { - int lowdpi = 0, hidpi = 0; /* Lower and higher resolution */ + int lowdpi = 0, hidpi = 0; /* Lower and higher resolution */ for (i = 0, count = ippGetCount(attr); i < count; i ++) { const char *rs = ippGetString(attr, i, NULL); - /* RS value */ + /* RS value */ if (_cups_strncasecmp(rs, "RS", 2)) continue; @@ -3896,26 +4507,265 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ cupsFilePrintf(fp, "*DefaultResolution: %ddpi\n", lowdpi); - cupsFilePrintf(fp, "*OpenUI *cupsPrintQuality/%s: PickOne\n" + cupsFilePrintf(fp, "*OpenUI *cupsPrintQuality: PickOne\n" "*OrderDependency: 10 AnySetup *cupsPrintQuality\n" - "*DefaultcupsPrintQuality: Normal\n", _cupsLangString(lang, _("Print Quality"))); + "*%s.Translation cupsPrintQuality/%s: \"\"\n" + "*DefaultcupsPrintQuality: Normal\n", lang->language, _cupsLangString(lang, _("Print Quality"))); if ((lowdpi & 1) == 0) - cupsFilePrintf(fp, "*cupsPrintQuality Draft/%s: \"<>setpagedevice\"\n", _cupsLangString(lang, _("Draft")), lowdpi, lowdpi / 2); - cupsFilePrintf(fp, "*cupsPrintQuality Normal/%s: \"<>setpagedevice\"\n", _cupsLangString(lang, _("Normal")), lowdpi, lowdpi); - if (hidpi > lowdpi) - cupsFilePrintf(fp, "*cupsPrintQuality High/%s: \"<>setpagedevice\"\n", _cupsLangString(lang, _("High")), hidpi, hidpi); + cupsFilePrintf(fp, "*cupsPrintQuality Draft: \"<>setpagedevice\"\n*%s.cupsPrintQuality Draft/%s: \"\"\n", lowdpi, lowdpi / 2, lang->language, _cupsLangString(lang, _("Draft"))); + else if (ippContainsInteger(quality, IPP_QUALITY_DRAFT)) + cupsFilePrintf(fp, "*cupsPrintQuality Draft: \"<>setpagedevice\"\n*%s.cupsPrintQuality Draft/%s: \"\"\n", lowdpi, lowdpi, lang->language, _cupsLangString(lang, _("Draft"))); + + cupsFilePrintf(fp, "*cupsPrintQuality Normal: \"<>setpagedevice\"\n*%s.cupsPrintQuality Normal/%s: \"\"\n", lowdpi, lowdpi, lang->language, _cupsLangString(lang, _("Normal"))); + + if (hidpi > lowdpi || ippContainsInteger(quality, IPP_QUALITY_HIGH)) + cupsFilePrintf(fp, "*cupsPrintQuality High: \"<>setpagedevice\"\n*%s.cupsPrintQuality High/%s: \"\"\n", hidpi, hidpi, lang->language, _cupsLangString(lang, _("High"))); cupsFilePuts(fp, "*CloseUI: *cupsPrintQuality\n"); } } + else if ((attr = ippFindAttribute(response, "pwg-raster-document-resolution-supported", IPP_TAG_RESOLUTION)) != NULL) + { + /* + * Make a sorted list of resolutions. + */ + + count = ippGetCount(attr); + if (count > (int)(sizeof(resolutions) / sizeof(resolutions[0]))) + count = (int)(sizeof(resolutions) / sizeof(resolutions[0])); + + resolutions[0] = 0; /* Not in loop to silence Clang static analyzer... */ + for (i = 1; i < count; i ++) + resolutions[i] = i; + + for (i = 0; i < (count - 1); i ++) + { + for (j = i + 1; j < count; j ++) + { + int ix, iy, /* First X and Y resolution */ + jx, jy, /* Second X and Y resolution */ + temp; /* Swap variable */ + ipp_res_t units; /* Resolution units */ + + ix = ippGetResolution(attr, resolutions[i], &iy, &units); + jx = ippGetResolution(attr, resolutions[j], &jy, &units); + + if (ix > jx || (ix == jx && iy > jy)) + { + /* + * Swap these two resolutions... + */ + + temp = resolutions[i]; + resolutions[i] = resolutions[j]; + resolutions[j] = temp; + } + } + } + + /* + * Generate print quality options... + */ + + pwg_ppdize_resolution(attr, resolutions[count / 2], &xres, &yres, ppdname, sizeof(ppdname)); + cupsFilePrintf(fp, "*DefaultResolution: %s\n", ppdname); + + cupsFilePrintf(fp, "*OpenUI *cupsPrintQuality: PickOne\n" + "*OrderDependency: 10 AnySetup *cupsPrintQuality\n" + "*%s.Translation cupsPrintQuality/%s: \"\"\n" + "*DefaultcupsPrintQuality: Normal\n", lang->language, _cupsLangString(lang, _("Print Quality"))); + if (count > 2 || ippContainsInteger(quality, IPP_QUALITY_DRAFT)) + { + pwg_ppdize_resolution(attr, resolutions[0], &xres, &yres, NULL, 0); + cupsFilePrintf(fp, "*cupsPrintQuality Draft: \"<>setpagedevice\"\n", xres, yres); + cupsFilePrintf(fp, "*%s.cupsPrintQuality Draft/%s: \"\"\n", lang->language, _cupsLangString(lang, _("Draft"))); + } + + pwg_ppdize_resolution(attr, resolutions[count / 2], &xres, &yres, NULL, 0); + cupsFilePrintf(fp, "*cupsPrintQuality Normal: \"<>setpagedevice\"\n", xres, yres); + cupsFilePrintf(fp, "*%s.cupsPrintQuality Normal/%s: \"\"\n", lang->language, _cupsLangString(lang, _("Normal"))); + + if (count > 1 || ippContainsInteger(quality, IPP_QUALITY_HIGH)) + { + pwg_ppdize_resolution(attr, resolutions[count - 1], &xres, &yres, NULL, 0); + cupsFilePrintf(fp, "*cupsPrintQuality High: \"<>setpagedevice\"\n", xres, yres); + cupsFilePrintf(fp, "*%s.cupsPrintQuality High/%s: \"\"\n", lang->language, _cupsLangString(lang, _("High"))); + } + + cupsFilePuts(fp, "*CloseUI: *cupsPrintQuality\n"); + } else if (is_apple || is_pwg) goto bad_ppd; - else if ((attr = ippFindAttribute(response, "printer-resolution-default", IPP_TAG_RESOLUTION)) != NULL) + else { - pwg_ppdize_resolution(attr, 0, &xres, &yres, ppdname, sizeof(ppdname)); + if ((attr = ippFindAttribute(response, "printer-resolution-default", IPP_TAG_RESOLUTION)) != NULL) + { + pwg_ppdize_resolution(attr, 0, &xres, &yres, ppdname, sizeof(ppdname)); + } + else + { + xres = yres = 300; + strlcpy(ppdname, "300dpi", sizeof(ppdname)); + } + cupsFilePrintf(fp, "*DefaultResolution: %s\n", ppdname); + + cupsFilePrintf(fp, "*OpenUI *cupsPrintQuality: PickOne\n" + "*OrderDependency: 10 AnySetup *cupsPrintQuality\n" + "*%s.Translation cupsPrintQuality/%s: \"\"\n" + "*DefaultcupsPrintQuality: Normal\n", lang->language, _cupsLangString(lang, _("Print Quality"))); + if (ippContainsInteger(quality, IPP_QUALITY_DRAFT)) + cupsFilePrintf(fp, "*cupsPrintQuality Draft: \"<>setpagedevice\"\n*%s.cupsPrintQuality Draft/%s: \"\"\n", xres, yres, lang->language, _cupsLangString(lang, _("Draft"))); + + cupsFilePrintf(fp, "*cupsPrintQuality Normal: \"<>setpagedevice\"\n*%s.cupsPrintQuality Normal/%s: \"\"\n", xres, yres, lang->language, _cupsLangString(lang, _("Normal"))); + + if (ippContainsInteger(quality, IPP_QUALITY_HIGH)) + cupsFilePrintf(fp, "*cupsPrintQuality High: \"<>setpagedevice\"\n*%s.cupsPrintQuality High/%s: \"\"\n", xres, yres, lang->language, _cupsLangString(lang, _("High"))); + cupsFilePuts(fp, "*CloseUI: *cupsPrintQuality\n"); + } + + /* + * Presets... + */ + + if ((attr = ippFindAttribute(response, "job-presets-supported", IPP_TAG_BEGIN_COLLECTION)) != NULL) + { + for (i = 0, count = ippGetCount(attr); i < count; i ++) + { + ipp_t *preset = ippGetCollection(attr, i); + /* Preset collection */ + const char *preset_name = ippGetString(ippFindAttribute(preset, "preset-name", IPP_TAG_ZERO), 0, NULL), + /* Preset name */ + *localized_name; /* Localized preset name */ + ipp_attribute_t *member; /* Member attribute in preset */ + const char *member_name; /* Member attribute name */ + char member_value[256]; /* Member attribute value */ + + if (!preset || !preset_name) + continue; + + cupsFilePrintf(fp, "*APPrinterPreset %s: \"\n", preset_name); + for (member = ippFirstAttribute(preset); member; member = ippNextAttribute(preset)) + { + member_name = ippGetName(member); + + if (!member_name || !strcmp(member_name, "preset-name")) + continue; + + if (!strcmp(member_name, "finishings")) + { + for (i = 0, count = ippGetCount(member); i < count; i ++) + { + const char *option = NULL; /* PPD option name */ + + keyword = ippEnumString("finishings", ippGetInteger(member, i)); + + if (!strcmp(keyword, "booklet-maker")) + { + option = "Booklet"; + keyword = "True"; + } + else if (!strncmp(keyword, "fold-", 5)) + option = "FoldType"; + else if (!strncmp(keyword, "punch-", 6)) + option = "PunchMedia"; + else if (!strncmp(keyword, "bind-", 5) || !strncmp(keyword, "edge-stitch-", 12) || !strcmp(keyword, "saddle-stitch") || !strncmp(keyword, "staple-", 7)) + option = "StapleLocation"; + + if (option && keyword) + cupsFilePrintf(fp, "*%s %s\n", option, keyword); + } + } + else if (!strcmp(member_name, "finishings-col")) + { + ipp_t *fin_col; /* finishings-col value */ + + for (i = 0, count = ippGetCount(member); i < count; i ++) + { + fin_col = ippGetCollection(member, i); + + if ((keyword = ippGetString(ippFindAttribute(fin_col, "finishing-template", IPP_TAG_ZERO), 0, NULL)) != NULL) + cupsFilePrintf(fp, "*cupsFinishingTemplate %s\n", keyword); + } + } + else if (!strcmp(member_name, "media")) + { + /* + * Map media to PageSize... + */ + + if ((pwg = pwgMediaForPWG(ippGetString(member, 0, NULL))) != NULL && pwg->ppd) + cupsFilePrintf(fp, "*PageSize %s\n", pwg->ppd); + } + else if (!strcmp(member_name, "media-col")) + { + media_col = ippGetCollection(member, 0); + + if ((media_size = ippGetCollection(ippFindAttribute(media_col, "media-size", IPP_TAG_BEGIN_COLLECTION), 0)) != NULL) + { + x_dim = ippFindAttribute(media_size, "x-dimension", IPP_TAG_INTEGER); + y_dim = ippFindAttribute(media_size, "y-dimension", IPP_TAG_INTEGER); + if ((pwg = pwgMediaForSize(ippGetInteger(x_dim, 0), ippGetInteger(y_dim, 0))) != NULL && pwg->ppd) + cupsFilePrintf(fp, "*PageSize %s\n", pwg->ppd); + } + + if ((keyword = ippGetString(ippFindAttribute(media_col, "media-source", IPP_TAG_ZERO), 0, NULL)) != NULL) + { + pwg_ppdize_name(keyword, ppdname, sizeof(ppdname)); + cupsFilePrintf(fp, "*InputSlot %s\n", keyword); + } + + if ((keyword = ippGetString(ippFindAttribute(media_col, "media-type", IPP_TAG_ZERO), 0, NULL)) != NULL) + { + pwg_ppdize_name(keyword, ppdname, sizeof(ppdname)); + cupsFilePrintf(fp, "*MediaType %s\n", keyword); + } + } + else if (!strcmp(member_name, "print-quality")) + { + /* + * Map print-quality to cupsPrintQuality... + */ + + int qval = ippGetInteger(member, 0); + /* print-quality value */ + static const char * const qualities[] = { "Draft", "Normal", "High" }; + /* cupsPrintQuality values */ + + if (qval >= IPP_QUALITY_DRAFT && qval <= IPP_QUALITY_HIGH) + cupsFilePrintf(fp, "*cupsPrintQuality %s\n", qualities[qval - IPP_QUALITY_DRAFT]); + } + else if (!strcmp(member_name, "output-bin")) + { + pwg_ppdize_name(ippGetString(member, 0, NULL), ppdname, sizeof(ppdname)); + cupsFilePrintf(fp, "*OutputBin %s\n", ppdname); + } + else if (!strcmp(member_name, "sides")) + { + keyword = ippGetString(member, 0, NULL); + if (keyword && !strcmp(keyword, "one-sided")) + cupsFilePuts(fp, "*Duplex None\n"); + else if (keyword && !strcmp(keyword, "two-sided-long-edge")) + cupsFilePuts(fp, "*Duplex DuplexNoTumble\n"); + else if (keyword && !strcmp(keyword, "two-sided-short-edge")) + cupsFilePuts(fp, "*Duplex DuplexTumble\n"); + } + else + { + /* + * Add attribute name and value as-is... + */ + + ippAttributeString(member, member_value, sizeof(member_value)); + cupsFilePrintf(fp, "*%s %s\n", member_name, member_value); + } + } + + cupsFilePuts(fp, "\"\n*End\n"); + + if ((localized_name = _cupsMessageLookup(strings, preset_name)) != preset_name) + cupsFilePrintf(fp, "*%s.APPrinterPreset %s/%s: \"\"\n", lang->language, preset_name, localized_name); + } } - else - cupsFilePuts(fp, "*DefaultResolution: 300dpi\n"); /* * Close up and return... @@ -3935,6 +4785,8 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ unlink(buffer); *buffer = '\0'; + _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Printer does not support required IPP attributes or document formats."), 1); + return (NULL); } @@ -4041,9 +4893,9 @@ _pwgMediaTypeForType( const char * /* O - PageSize name */ _pwgPageSizeForMedia( - pwg_media_t *media, /* I - Media */ - char *name, /* I - PageSize name buffer */ - size_t namesize) /* I - Size of name buffer */ + pwg_media_t *media, /* I - Media */ + char *name, /* I - PageSize name buffer */ + size_t namesize) /* I - Size of name buffer */ { const char *sizeptr, /* Pointer to size in PWG name */ *dimptr; /* Pointer to dimensions in PWG name */ @@ -4094,11 +4946,112 @@ _pwgPageSizeForMedia( } +/* + * 'cups_get_url()' - Get a copy of the file at the given URL. + */ + +static int /* O - 1 on success, 0 on failure */ +cups_get_url(http_t **http, /* IO - Current HTTP connection */ + const char *url, /* I - URL to get */ + char *name, /* I - Temporary filename */ + size_t namesize) /* I - Size of temporary filename buffer */ +{ + char scheme[32], /* URL scheme */ + userpass[256], /* URL username:password */ + host[256], /* URL host */ + curhost[256], /* Current host */ + resource[256]; /* URL resource */ + int port; /* URL port */ + http_encryption_t encryption; /* Type of encryption to use */ + http_status_t status; /* Status of GET request */ + int fd; /* Temporary file */ + + + if (httpSeparateURI(HTTP_URI_CODING_ALL, url, scheme, sizeof(scheme), userpass, sizeof(userpass), host, sizeof(host), &port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK) + return (0); + + if (port == 443 || !strcmp(scheme, "https")) + encryption = HTTP_ENCRYPTION_ALWAYS; + else + encryption = HTTP_ENCRYPTION_IF_REQUESTED; + + if (!*http || strcasecmp(host, httpGetHostname(*http, curhost, sizeof(curhost))) || httpAddrPort(httpGetAddress(*http)) != port) + { + httpClose(*http); + *http = httpConnect2(host, port, NULL, AF_UNSPEC, encryption, 1, 5000, NULL); + } + + if (!*http) + return (0); + + if ((fd = cupsTempFd(name, (int)namesize)) < 0) + return (0); + + status = cupsGetFd(*http, resource, fd); + + close(fd); + + if (status != HTTP_STATUS_OK) + { + unlink(name); + *name = '\0'; + return (0); + } + + return (1); +} + + +/* + * 'pwg_add_finishing()' - Add a finishings value. + */ + +static void +pwg_add_finishing( + cups_array_t *finishings, /* I - Finishings array */ + ipp_finishings_t template, /* I - Finishing template */ + const char *name, /* I - PPD option */ + const char *value) /* I - PPD choice */ +{ + _pwg_finishings_t *f; /* New finishings value */ + + + if ((f = (_pwg_finishings_t *)calloc(1, sizeof(_pwg_finishings_t))) != NULL) + { + f->value = template; + f->num_options = cupsAddOption(name, value, 0, &f->options); + + cupsArrayAdd(finishings, f); + } +} + + +/* + * 'pwg_add_message()' - Add a message to the PPD cached strings. + */ + +static void +pwg_add_message(cups_array_t *a, /* I - Message catalog */ + const char *msg, /* I - Message identifier */ + const char *str) /* I - Localized string */ +{ + _cups_message_t *m; /* New message */ + + + if ((m = calloc(1, sizeof(_cups_message_t))) != NULL) + { + m->msg = strdup(msg); + m->str = strdup(str); + cupsArrayAdd(a, m); + } +} + + /* * 'pwg_compare_finishings()' - Compare two finishings values. */ -static int /* O- Result of comparison */ +static int /* O - Result of comparison */ pwg_compare_finishings( _pwg_finishings_t *a, /* I - First finishings value */ _pwg_finishings_t *b) /* I - Second finishings value */ @@ -4108,31 +5061,44 @@ pwg_compare_finishings( /* - * 'pwg_free_finishings()' - Free a finishings value. + * 'pwg_compare_sizes()' - Compare two media sizes... */ -static void -pwg_free_finishings( - _pwg_finishings_t *f) /* I - Finishings value */ +static int /* O - Result of comparison */ +pwg_compare_sizes(cups_size_t *a, /* I - First media size */ + cups_size_t *b) /* I - Second media size */ { - cupsFreeOptions(f->num_options, f->options); - free(f); + return (strcmp(a->media, b->media)); } /* - * 'pwg_free_material()' - Free a material value. + * 'pwg_copy_size()' - Copy a media size. */ -static void -pwg_free_material(_pwg_material_t *m) /* I - Material value */ +static cups_size_t * /* O - New media size */ +pwg_copy_size(cups_size_t *size) /* I - Media size to copy */ { - _cupsStrFree(m->key); - _cupsStrFree(m->name); + cups_size_t *newsize = (cups_size_t *)calloc(1, sizeof(cups_size_t)); + /* New media size */ + + if (newsize) + memcpy(newsize, size, sizeof(cups_size_t)); + + return (newsize); +} - cupsFreeOptions(m->num_props, m->props); - free(m); +/* + * 'pwg_free_finishings()' - Free a finishings value. + */ + +static void +pwg_free_finishings( + _pwg_finishings_t *f) /* I - Finishings value */ +{ + cupsFreeOptions(f->num_options, f->options); + free(f); } @@ -4218,6 +5184,8 @@ pwg_unppdize_name(const char *ppd, /* I - PPD keyword */ { char *ptr, /* Pointer into name buffer */ *end; /* End of name buffer */ + int nodash = 1; /* Next char in IPP name cannot be a + dash (first char or after a dash) */ if (_cups_islower(*ppd)) @@ -4229,7 +5197,9 @@ pwg_unppdize_name(const char *ppd, /* I - PPD keyword */ const char *ppdptr; /* Pointer into PPD keyword */ for (ppdptr = ppd + 1; *ppdptr; ppdptr ++) - if (_cups_isupper(*ppdptr) || strchr(dashchars, *ppdptr)) + if (_cups_isupper(*ppdptr) || strchr(dashchars, *ppdptr) || + (*ppdptr == '-' && *(ppdptr - 1) == '-') || + (*ppdptr == '-' && *(ppdptr + 1) == '\0')) break; if (!*ppdptr) @@ -4241,19 +5211,44 @@ pwg_unppdize_name(const char *ppd, /* I - PPD keyword */ for (ptr = name, end = name + namesize - 1; *ppd && ptr < end; ppd ++) { - if (_cups_isalnum(*ppd) || *ppd == '-') + if (_cups_isalnum(*ppd)) + { *ptr++ = (char)tolower(*ppd & 255); - else if (strchr(dashchars, *ppd)) - *ptr++ = '-'; + nodash = 0; + } + else if (*ppd == '-' || strchr(dashchars, *ppd)) + { + if (nodash == 0) + { + *ptr++ = '-'; + nodash = 1; + } + } else + { *ptr++ = *ppd; + nodash = 0; + } - if (!_cups_isupper(*ppd) && _cups_isalnum(*ppd) && - _cups_isupper(ppd[1]) && ptr < end) - *ptr++ = '-'; - else if (!isdigit(*ppd & 255) && isdigit(ppd[1] & 255)) - *ptr++ = '-'; + if (nodash == 0) + { + if (!_cups_isupper(*ppd) && _cups_isalnum(*ppd) && + _cups_isupper(ppd[1]) && ptr < end) + { + *ptr++ = '-'; + nodash = 1; + } + else if (!isdigit(*ppd & 255) && isdigit(ppd[1] & 255)) + { + *ptr++ = '-'; + nodash = 1; + } + } } + /* Remove trailing dashes */ + while (ptr > name && *(ptr - 1) == '-') + ptr --; + *ptr = '\0'; }