X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=cups%2Fppd-cache.c;h=5965e382bb80b2108b7c9ebbf56451daa4af53fb;hb=HEAD;hp=bae64e059e67b0673277d8d6386eaa1b18501984;hpb=d128cfc60175914a5c92b3b72f1471e6343a211d;p=thirdparty%2Fcups.git diff --git a/cups/ppd-cache.c b/cups/ppd-cache.c index bae64e059..091f39f3c 100644 --- a/cups/ppd-cache.c +++ b/cups/ppd-cache.c @@ -1,7 +1,7 @@ /* * PPD cache implementation for CUPS. * - * Copyright © 2010-2018 by Apple Inc. + * Copyright © 2010-2019 by Apple Inc. * * Licensed under Apache License v2.0. See the file "LICENSE" for more * information. @@ -13,6 +13,7 @@ #include "cups-private.h" #include "ppd-private.h" +#include "debug-internal.h" #include @@ -77,8 +78,11 @@ _cupsConvertOptions( int num_finishings = 0, /* Number of finishing values */ finishings[10]; /* Finishing enum values */ ppd_choice_t *choice; /* Marked choice */ - int finishings_copies = copies; + 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 */ /* @@ -291,11 +295,11 @@ _cupsConvertOptions( 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"); } @@ -364,6 +368,28 @@ _cupsConvertOptions( * Map finishing options... */ + 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); @@ -375,13 +401,13 @@ _cupsConvertOptions( ippAddCollection(request, IPP_TAG_JOB, "finishings-col", fin_col); ippDelete(fin_col); - if (copies != finishings_copies && (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) / finishings_copies); + ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-pages-per-set", job_pages); } } else @@ -391,13 +417,13 @@ _cupsConvertOptions( { ippAddIntegers(request, IPP_TAG_JOB, IPP_TAG_ENUM, "finishings", num_finishings, finishings); - if (copies != finishings_copies && (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) / finishings_copies); + ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-pages-per-set", job_pages); } } } @@ -532,24 +558,20 @@ _ppdCacheCreateWithFile( 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")) { @@ -649,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 ++; } @@ -704,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 ++; } @@ -733,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")) { @@ -788,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 ++; } @@ -837,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 ++; } @@ -868,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) @@ -895,20 +917,20 @@ _ppdCacheCreateWithFile( else if (!_cups_strcasecmp(line, "FinishingTemplate")) { if (!pc->templates) - pc->templates = cupsArrayNew3((cups_array_func_t)strcmp, NULL, NULL, 0, (cups_acopy_func_t)_cupsStrAlloc, (cups_afree_func_t)_cupsStrFree); + 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) @@ -919,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); } @@ -1080,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? @@ -1165,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); } } @@ -1187,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; @@ -1208,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]); @@ -1234,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) { @@ -1286,8 +1306,8 @@ _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... @@ -1357,8 +1377,8 @@ _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... @@ -1391,14 +1411,14 @@ _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_name); + snprintf(msg_id, sizeof(msg_id), "output-bin.%s", pwg_keyword); pwg_add_message(pc->strings, msg_id, choice->text); } } @@ -1625,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; @@ -1633,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); } } @@ -1650,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 -"); @@ -1709,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 { @@ -1728,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... @@ -1868,7 +1884,7 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ if ((ppd_option = ppdFindOption(ppd, "cupsFinishingTemplate")) != NULL) { - pc->templates = cupsArrayNew3((cups_array_func_t)strcmp, NULL, NULL, 0, (cups_acopy_func_t)_cupsStrAlloc, (cups_afree_func_t)_cupsStrFree); + 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 --) { @@ -1900,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"); @@ -1909,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, ' '); @@ -1918,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; @@ -1976,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); @@ -1987,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); @@ -2012,26 +2025,23 @@ _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); - - if (pc->custom_min_keyword) - _cupsStrFree(pc->custom_min_keyword); + free(pc->custom_max_keyword); + free(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); @@ -2188,7 +2198,7 @@ _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 ++) { @@ -2203,9 +2213,9 @@ _ppdCacheGetFinishingValues( if (i == 0) { - DEBUG_printf(("_ppdCacheGetFinishingValues: Adding %d (%s)", f->value, ippEnumString("finishings", 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; @@ -2972,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; @@ -3171,6 +3181,16 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ 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... */ @@ -3184,26 +3204,26 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ /* Type of password */ if (maxlen > (int)(sizeof(pattern) - 1)) - maxlen = sizeof(pattern) - 1; + maxlen = (int)sizeof(pattern) - 1; if (!repertoire || !strcmp(repertoire, "iana_us-ascii_digits")) - memset(pattern, '1', maxlen); + memset(pattern, '1', (size_t)maxlen); else if (!strcmp(repertoire, "iana_us-ascii_letters")) - memset(pattern, 'A', maxlen); + memset(pattern, 'A', (size_t)maxlen); else if (!strcmp(repertoire, "iana_us-ascii_complex")) - memset(pattern, 'C', maxlen); + memset(pattern, 'C', (size_t)maxlen); else if (!strcmp(repertoire, "iana_us-ascii_any")) - memset(pattern, '.', maxlen); + memset(pattern, '.', (size_t)maxlen); else if (!strcmp(repertoire, "iana_utf-8_digits")) - memset(pattern, 'N', maxlen); + memset(pattern, 'N', (size_t)maxlen); else if (!strcmp(repertoire, "iana_utf-8_letters")) - memset(pattern, 'U', maxlen); + memset(pattern, 'U', (size_t)maxlen); else - memset(pattern, '*', maxlen); + memset(pattern, '*', (size_t)maxlen); pattern[maxlen] = '\0'; - cupsFilePrintf(fp, "*cupsPassword: \"%s\"\n", pattern); + cupsFilePrintf(fp, "*cupsJobPassword: \"%s\"\n", pattern); } /* @@ -3232,6 +3252,8 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ else cupsFilePuts(fp, "*cupsFilter2: \"application/vnd.cups-pdf application/pdf 10 -\"\n"); } + else + cupsFilePuts(fp, "*cupsManualCopies: True\n"); if (is_apple) cupsFilePuts(fp, "*cupsFilter2: \"image/urf image/urf 100 -\"\n"); if (is_pwg) @@ -3623,10 +3645,12 @@ _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) { + int have_default = ppdname[0] != '\0'; + /* Do we have a default InputSlot? */ static const char * const sources[] = { /* Standard "media-source" strings */ "auto", @@ -3681,21 +3705,31 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ "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 ++) { 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], keyword)) { 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, _cupsLangString(lang, msgid)); + cupsFilePrintf(fp, "*%s.InputSlot %s/%s: \"\"\n", lang->language, ppdname, msgstr); break; } } @@ -3747,6 +3781,8 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ 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 ++) { keyword = ippGetString(attr, i, NULL); @@ -3793,6 +3829,11 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ 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")) { @@ -3927,11 +3968,23 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ else strlcpy(ppdname, "Unknown", sizeof(ppdname)); - if ((attr = ippFindAttribute(response, "output-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) { + 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); + if (!strcmp(ppdname, "FaceUp")) + cupsFilePuts(fp, "*DefaultOutputOrder: Reverse\n"); + else + cupsFilePuts(fp, "*DefaultOutputOrder: Normal\n"); + for (i = 0; i < count; i ++) { keyword = ippGetString(attr, i, NULL); @@ -3945,6 +3998,24 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ 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"); } @@ -3956,7 +4027,25 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ if ((attr = ippFindAttribute(response, "finishings-supported", IPP_TAG_ENUM)) != NULL) { 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); @@ -3977,6 +4066,33 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ 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"); @@ -4004,9 +4120,21 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ if ((msgstr = _cupsMessageLookup(strings, msgid)) == msgid) msgstr = keyword; - cupsFilePrintf(fp, "*StapleLocation %s: \"\"\n", keyword); - cupsFilePrintf(fp, "*%s.StapleLocation %s/%s: \"\"\n", lang->language, keyword, msgstr); - cupsFilePrintf(fp, "*cupsIPPFinishings %d/%s: \"*StapleLocation %s\"\n", value, keyword, keyword); + 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); } cupsFilePuts(fp, "*CloseUI: *StapleLocation\n"); @@ -4021,12 +4149,28 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ value = ippGetInteger(attr, i); keyword = ippEnumString("finishings", value); - if (!strncmp(keyword, "fold-", 5)) + 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"); @@ -4041,7 +4185,9 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ value = ippGetInteger(attr, i); keyword = ippEnumString("finishings", value); - if (strncmp(keyword, "fold-", 5)) + if (!strncmp(keyword, "cups-fold-", 10)) + keyword += 5; + else if (strcmp(keyword, "fold") && strncmp(keyword, "fold-", 5)) continue; if (cupsArrayFind(names, (char *)keyword)) @@ -4054,9 +4200,21 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ if ((msgstr = _cupsMessageLookup(strings, msgid)) == msgid) msgstr = keyword; - cupsFilePrintf(fp, "*FoldType %s: \"\"\n", keyword); - cupsFilePrintf(fp, "*%s.FoldType %s/%s: \"\"\n", lang->language, keyword, msgstr); - cupsFilePrintf(fp, "*cupsIPPFinishings %d/%s: \"*FoldType %s\"\n", value, keyword, 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"); @@ -4071,12 +4229,36 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ value = ippGetInteger(attr, i); keyword = ippEnumString("finishings", value); - if (!strncmp(keyword, "punch-", 6)) + 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"); @@ -4091,7 +4273,9 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ value = ippGetInteger(attr, i); keyword = ippEnumString("finishings", value); - if (strncmp(keyword, "punch-", 6)) + if (!strncmp(keyword, "cups-punch-", 11)) + keyword += 5; + else if (strncmp(keyword, "punch-", 6)) continue; if (cupsArrayFind(names, (char *)keyword)) @@ -4104,9 +4288,21 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ if ((msgstr = _cupsMessageLookup(strings, msgid)) == msgid) msgstr = keyword; - cupsFilePrintf(fp, "*PunchMedia %s: \"\"\n", keyword); - cupsFilePrintf(fp, "*%s.PunchMedia %s/%s: \"\"\n", lang->language, keyword, msgstr); - cupsFilePrintf(fp, "*cupsIPPFinishings %d/%s: \"*PunchMedia %s\"\n", value, keyword, 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"); @@ -4130,6 +4326,69 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ 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); } @@ -4157,7 +4416,7 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ if (!keyword || cupsArrayFind(templates, (void *)keyword)) continue; - if (strncmp(keyword, "fold-", 5) && (strstr(keyword, "-bottom") || strstr(keyword, "-left") || strstr(keyword, "-right") || strstr(keyword, "-top"))) + if (!strcmp(keyword, "none")) continue; cupsArrayAdd(templates, (void *)keyword); @@ -4925,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)) @@ -4936,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) @@ -4948,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'; }