diff options
Diffstat (limited to 'cups/ppd-cache.c')
-rw-r--r-- | cups/ppd-cache.c | 886 |
1 files changed, 610 insertions, 276 deletions
diff --git a/cups/ppd-cache.c b/cups/ppd-cache.c index 9ce5cfc3..e7123410 100644 --- a/cups/ppd-cache.c +++ b/cups/ppd-cache.c @@ -1,13 +1,13 @@ /* * PPD cache implementation for CUPS. * - * Copyright 2010-2016 by Apple Inc. + * Copyright 2010-2017 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/". + * missing or damaged, see the license at "http://www.cups.org/". * * This file is subject to the Apple OS-Developed Software exception. */ @@ -32,10 +32,10 @@ * Local functions... */ +static void pwg_add_finishing(cups_array_t *finishings, ipp_finishings_t template, const char *name, const char *value); static int pwg_compare_finishings(_pwg_finishings_t *a, _pwg_finishings_t *b); 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 +49,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 */ @@ -198,41 +197,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); } @@ -503,53 +503,6 @@ _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) @@ -1714,6 +1667,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 +1690,114 @@ _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... + */ + + ppd_option_t *ppd_option; /* PPD option */ + + 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; + } + } /* * Max copies... @@ -1782,42 +1847,6 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ 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... */ @@ -1924,11 +1953,6 @@ _ppdCacheDestroy(_ppd_cache_t *pc) /* I - PPD cache and mapping data */ cupsArrayDelete(pc->support_files); - _cupsStrFree(pc->cups_3d); - _cupsStrFree(pc->cups_layer_order); - - cupsArrayDelete(pc->materials); - free(pc); } @@ -2686,7 +2710,6 @@ _ppdCacheWriteFile( cups_option_t *option; /* Current option */ const char *value; /* Filter/pre-filter value */ char newfile[1024]; /* New filename */ - _pwg_material_t *m; /* Material */ /* @@ -2868,32 +2891,6 @@ _ppdCacheWriteFile( 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... */ @@ -2925,14 +2922,16 @@ _ppdCacheWriteFile( * of an IPP printer. */ -char * /* O - PPD filename or NULL on error */ +char * /* O - PPD filename or @code NULL@ on error */ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ size_t bufsize, /* I - Size of 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 */ 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 */ char make[256], /* Make and model */ @@ -2944,7 +2943,10 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ bottom, /* Largest bottom margin */ left, /* Largest left margin */ right, /* Largest right margin */ - top; /* Largest top margin */ + top, /* Largest top margin */ + 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 */ cups_lang_t *lang = cupsLangDefault(); @@ -2970,6 +2972,7 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ { "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") }, @@ -2998,6 +3001,10 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ { "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)") }, @@ -3023,15 +3030,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... @@ -3084,20 +3103,31 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ if ((attr = ippFindAttribute(response, "document-format-supported", IPP_TAG_MIMETYPE)) != NULL) { + is_apple = ippContainsString(attr, "image/urf"); + is_pdf = ippContainsString(attr, "application/pdf"); + is_pwg = ippContainsString(attr, "image/pwg-raster"); + for (i = 0, count = ippGetCount(attr); i < count; i ++) { const char *format = ippGetString(attr, i, NULL); /* PDL */ + /* + * Write cupsFilter2 lines for supported formats... + */ + if (!_cups_strcasecmp(format, "application/pdf")) cupsFilePuts(fp, "*cupsFilter2: \"application/vnd.cups-pdf application/pdf 10 -\"\n"); - else if (!_cups_strcasecmp(format, "application/postscript")) - cupsFilePuts(fp, "*cupsFilter2: \"application/vnd.cups-postscript application/postscript 10 -\"\n"); - else if (_cups_strcasecmp(format, "application/octet-stream") && _cups_strcasecmp(format, "application/vnd.hp-pcl") && _cups_strcasecmp(format, "text/plain")) - cupsFilePrintf(fp, "*cupsFilter2: \"%s %s 10 -\"\n", format, format); + 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); } } + if (!is_apple && !is_pdf && !is_pwg) + goto bad_ppd; + /* * PageSize/PageRegion/ImageableArea/PaperDimension */ @@ -3146,35 +3176,54 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ x_dim = ippFindAttribute(media_size, "x-dimension", IPP_TAG_INTEGER); y_dim = ippFindAttribute(media_size, "y-dimension", IPP_TAG_INTEGER); - if (x_dim && y_dim) - { - pwg = pwgMediaForSize(ippGetInteger(x_dim, 0), ippGetInteger(y_dim, 0)); + if (x_dim && y_dim && (pwg = pwgMediaForSize(ippGetInteger(x_dim, 0), ippGetInteger(y_dim, 0))) != NULL) strlcpy(ppdname, pwg->ppd, sizeof(ppdname)); - } else strlcpy(ppdname, "Unknown", sizeof(ppdname)); } else strlcpy(ppdname, "Unknown", sizeof(ppdname)); } + else if ((pwg = pwgMediaForPWG(ippGetString(ippFindAttribute(response, "media-default", IPP_TAG_ZERO), 0, NULL))) != NULL) + strlcpy(ppdname, pwg->ppd, sizeof(ppdname)); + else + strlcpy(ppdname, "Unknown", sizeof(ppdname)); - if ((attr = ippFindAttribute(response, "media-size-supported", IPP_TAG_BEGIN_COLLECTION)) != NULL) + 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); + 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); + 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 (x_dim && y_dim) + pwg = pwgMediaForSize(ippGetInteger(x_dim, 0), ippGetInteger(y_dim, 0)); + } + else + pwg = pwgMediaForPWG(ippGetString(attr, i, NULL)); + + if (pwg) { char twidth[256], /* Width string */ tlength[256]; /* Length string */ - pwg = pwgMediaForSize(ippGetInteger(x_dim, 0), ippGetInteger(y_dim, 0)); + if (cupsArrayFind(sizes, (void *)pwg->ppd)) + { + cupsFilePrintf(fp, "*%% warning: Duplicate size '%s' reported by printer.\n", pwg->ppd); + continue; + } + + cupsArrayAdd(sizes, (void *)pwg->ppd); _cupsStrFormatd(twidth, twidth + sizeof(twidth), pwg->width * 72.0 / 2540.0, loc); _cupsStrFormatd(tlength, tlength + sizeof(tlength), pwg->length * 72.0 / 2540.0, loc); @@ -3184,21 +3233,34 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ } cupsFilePuts(fp, "*CloseUI: *PageSize\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, "*OpenUI *PageRegion: PickOne\n" "*OrderDependency: 10 AnySetup *PageRegion\n" "*DefaultPageRegion: %s\n", ppdname); 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); + 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); + + pwg = pwgMediaForSize(ippGetInteger(x_dim, 0), ippGetInteger(y_dim, 0)); + } + else + pwg = pwgMediaForPWG(ippGetString(attr, i, NULL)); - if (x_dim && y_dim) + if (pwg) { char twidth[256], /* Width string */ tlength[256]; /* Length string */ - pwg = pwgMediaForSize(ippGetInteger(x_dim, 0), ippGetInteger(y_dim, 0)); + if (cupsArrayFind(sizes, (void *)pwg->ppd)) + continue; + + cupsArrayAdd(sizes, (void *)pwg->ppd); _cupsStrFormatd(twidth, twidth + sizeof(twidth), pwg->width * 72.0 / 2540.0, loc); _cupsStrFormatd(tlength, tlength + sizeof(tlength), pwg->length * 72.0 / 2540.0, loc); @@ -3208,15 +3270,25 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ } 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 ++) { - 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 (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); + + pwg = pwgMediaForSize(ippGetInteger(x_dim, 0), ippGetInteger(y_dim, 0)); + } + else + pwg = pwgMediaForPWG(ippGetString(attr, i, NULL)); - if (x_dim && y_dim) + if (pwg) { char tleft[256], /* Left string */ tbottom[256], /* Bottom string */ @@ -3225,7 +3297,10 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ twidth[256], /* Width string */ tlength[256]; /* Length string */ - pwg = pwgMediaForSize(ippGetInteger(x_dim, 0), ippGetInteger(y_dim, 0)); + if (cupsArrayFind(sizes, (void *)pwg->ppd)) + continue; + + cupsArrayAdd(sizes, (void *)pwg->ppd); _cupsStrFormatd(tleft, tleft + sizeof(tleft), left * 72.0 / 2540.0, loc); _cupsStrFormatd(tbottom, tbottom + sizeof(tbottom), bottom * 72.0 / 2540.0, loc); @@ -3238,18 +3313,22 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ cupsFilePrintf(fp, "*PaperDimension %s: \"%s %s\"\n", pwg->ppd, twidth, tlength); } } + + cupsArrayDelete(sizes); } + else + goto bad_ppd; /* * InputSlot... */ - if ((attr = ippFindAttribute(ippGetCollection(defattr, 0), "media-source", IPP_TAG_KEYWORD)) != NULL) + 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)); - if ((attr = ippFindAttribute(response, "media-source-supported", IPP_TAG_KEYWORD)) != NULL && (count = ippGetCount(attr)) > 1) + if ((attr = ippFindAttribute(response, "media-source-supported", IPP_TAG_ZERO)) != NULL && (count = ippGetCount(attr)) > 1) { static const char * const sources[][2] = { /* "media-source" strings */ @@ -3326,12 +3405,12 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ * MediaType... */ - if ((attr = ippFindAttribute(ippGetCollection(defattr, 0), "media-type", IPP_TAG_KEYWORD)) != NULL) + if ((attr = ippFindAttribute(ippGetCollection(defattr, 0), "media-type", IPP_TAG_ZERO)) != NULL) pwg_ppdize_name(ippGetString(attr, 0, NULL), ppdname, sizeof(ppdname)); else strlcpy(ppdname, "Unknown", sizeof(ppdname)); - if ((attr = ippFindAttribute(response, "media-type-supported", IPP_TAG_KEYWORD)) != NULL && (count = ippGetCount(attr)) > 1) + 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 */ @@ -3341,6 +3420,19 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ { "cardboard", _("Cardboard") }, { "cardstock", _("Cardstock") }, { "cd", _("CD") }, + { "com.hp.advanced-photo", _("Advanced Photo Paper") }, /* HP */ + { "com.hp.brochure-glossy", _("Glossy Brochure Paper") }, /* HP */ + { "com.hp.brochure-matte", _("Matte Brochure Paper") }, /* HP */ + { "com.hp.cover-matte", _("Matte Cover Paper") }, /* HP */ + { "com.hp.ecosmart-lite", _("Office Recycled Paper") }, /* HP */ + { "com.hp.everyday-glossy", _("Everyday Glossy Photo Paper") }, /* HP */ + { "com.hp.everyday-matte", _("Everyday Matte Paper") }, /* HP */ + { "com.hp.extra-heavy", _("Extra Heavyweight Paper") }, /* HP */ + { "com.hp.intermediate", _("Multipurpose Paper") }, /* HP */ + { "com.hp.mid-weight", _("Mid-Weight Paper") }, /* HP */ + { "com.hp.premium-inkjet", _("Premium Inkjet Paper") }, /* HP */ + { "com.hp.premium-photo", _("Premium Photo Glossy Paper") }, /* HP */ + { "com.hp.premium-presentation-matte", _("Premium Presentation Matte Paper") }, /* HP */ { "continuous", _("Continuous") }, { "continuous-long", _("Continuous Long") }, { "continuous-short", _("Continuous Short") }, @@ -3388,6 +3480,10 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ { "gravure-cylinder", _("Gravure Cylinder") }, { "image-setter-paper", _("Image Setter Paper") }, { "imaging-cylinder", _("Imaging Cylinder") }, + { "jp.co.canon_photo-paper-plus-glossy-ii", _("Photo Paper Plus Glossy II") }, /* Canon */ + { "jp.co.canon_photo-paper-pro-platinum", _("Photo Paper Pro Platinum") }, /* Canon */ + { "jp.co.canon-photo-paper-plus-glossy-ii", _("Photo Paper Plus Glossy II") }, /* Canon */ + { "jp.co.canon-photo-paper-pro-platinum", _("Photo Paper Pro Platinum") }, /* Canon */ { "labels", _("Labels") }, { "labels-colored", _("Colored Labels") }, { "labels-glossy", _("Glossy Labels") }, @@ -3411,8 +3507,9 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ { "multi-part-form", _("Multi Part Form") }, { "other", _("Other") }, { "paper", _("Paper") }, + { "photo", _("Photo Paper") }, /* HP mis-spelling */ { "photographic", _("Photo Paper") }, - { "photographic-archival", _("Photographic Archival") }, + { "photographic-archival", _("Archival Photo Paper") }, { "photographic-film", _("Photo Film") }, { "photographic-glossy", _("Glossy Photo Paper") }, { "photographic-high-gloss", _("High Gloss Photo Paper") }, @@ -3439,14 +3536,14 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ { "single-face", _("Single Face") }, { "single-wall", _("Single Wall Cardboard") }, { "sleeve", _("Sleeve") }, - { "stationery", _("Stationery") }, - { "stationery-archival", _("Stationery Archival") }, + { "stationery", _("Plain Paper") }, + { "stationery-archival", _("Archival Paper") }, { "stationery-coated", _("Coated Paper") }, - { "stationery-cotton", _("Stationery Cotton") }, + { "stationery-cotton", _("Cotton Paper") }, { "stationery-fine", _("Vellum Paper") }, { "stationery-heavyweight", _("Heavyweight Paper") }, - { "stationery-heavyweight-coated", _("Stationery Heavyweight Coated") }, - { "stationery-inkjet", _("Stationery Inkjet Paper") }, + { "stationery-heavyweight-coated", _("Heavyweight Coated Paper") }, + { "stationery-inkjet", _("Inkjet Paper") }, { "stationery-letterhead", _("Letterhead") }, { "stationery-lightweight", _("Lightweight Paper") }, { "stationery-preprinted", _("Preprinted Paper") }, @@ -3462,14 +3559,20 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ 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; + const char *keyword = ippGetString(attr, i, NULL); - pwg_ppdize_name(media_types[i][0], ppdname, sizeof(ppdname)); + pwg_ppdize_name(keyword, ppdname, sizeof(ppdname)); - cupsFilePrintf(fp, "*MediaType %s/%s: \"<</MediaType(%s)>>setpagedevice\"\n", ppdname, _cupsLangString(lang, media_types[i][1]), ppdname); + for (j = 0; j < (int)(sizeof(media_types) / sizeof(media_types[0])); j ++) + if (!strcmp(keyword, media_types[j][0])) + break; + + if (j < (int)(sizeof(media_types) / sizeof(media_types[0]))) + cupsFilePrintf(fp, "*MediaType %s/%s: \"<</MediaType(%s)>>setpagedevice\"\n", ppdname, _cupsLangString(lang, media_types[j][1]), ppdname); + else + cupsFilePrintf(fp, "*MediaType %s/%s: \"<</MediaType(%s)>>setpagedevice\"\n", ppdname, keyword, ppdname); } cupsFilePuts(fp, "*CloseUI: *MediaType\n"); } @@ -3479,7 +3582,9 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ */ if ((attr = ippFindAttribute(response, "pwg-raster-document-type-supported", IPP_TAG_KEYWORD)) == NULL) - attr = ippFindAttribute(response, "print-color-mode-supported", IPP_TAG_KEYWORD); + if ((attr = ippFindAttribute(response, "urf-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) { @@ -3501,7 +3606,7 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ if (!default_color) default_color = "FastGray"; } - else if (!strcmp(keyword, "sgray_8") || !strcmp(keyword, "monochrome") || !strcmp(keyword, "process-monochrome")) + else if (!strcmp(keyword, "sgray_8") || !strcmp(keyword, "W8") || !strcmp(keyword, "monochrome") || !strcmp(keyword, "process-monochrome")) { if (!default_color) cupsFilePrintf(fp, "*OpenUI *ColorModel/%s: PickOne\n" @@ -3512,7 +3617,7 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ if (!default_color || !strcmp(default_color, "FastGray")) default_color = "Gray"; } - else if (!strcmp(keyword, "srgb_8") || !strcmp(keyword, "color")) + else if (!strcmp(keyword, "srgb_8") || !strcmp(keyword, "SRGB24") || !strcmp(keyword, "color")) { if (!default_color) cupsFilePrintf(fp, "*OpenUI *ColorModel/%s: PickOne\n" @@ -3522,6 +3627,17 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ default_color = "RGB"; } + else if (!strcmp(keyword, "adobe-rgb_16") || !strcmp(keyword, "ADOBERGB48")) + { + if (!default_color) + cupsFilePrintf(fp, "*OpenUI *ColorModel/%s: PickOne\n" + "*OrderDependency: 10 AnySetup *ColorModel\n", _cupsLangString(lang, _("Color Mode"))); + + cupsFilePrintf(fp, "*ColorModel AdobeRGB/%s: \"<</cupsColorSpace 20/cupsBitsPerColor 16/cupsColorOrder 0/cupsCompression 0>>setpagedevice\"\n", _cupsLangString(lang, _("Deep Color"))); + + if (!default_color) + default_color = "AdobeRGB"; + } } if (default_color) @@ -3591,95 +3707,261 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ } /* + * Output bin... + */ + + if ((attr = ippFindAttribute(response, "output-bin-default", IPP_TAG_ZERO)) != NULL) + pwg_ppdize_name(ippGetString(attr, 0, NULL), ppdname, sizeof(ppdname)); + else + strlcpy(ppdname, "Unknown", sizeof(ppdname)); + + if ((attr = ippFindAttribute(response, "output-bin-supported", IPP_TAG_ZERO)) != NULL && (count = ippGetCount(attr)) > 1) + { + 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") } + }; + + 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 (!ippContainsString(attr, output_bins[i][0])) + continue; + + pwg_ppdize_name(output_bins[i][0], ppdname, sizeof(ppdname)); + + cupsFilePrintf(fp, "*OutputBin %s/%s: \"\"\n", ppdname, _cupsLangString(lang, output_bins[i][1])); + } + cupsFilePuts(fp, "*CloseUI: *OutputBin\n"); + } + + /* * Finishing options... + * + * Eventually need to re-add support for finishings-col-database, however + * it is difficult to map arbitrary finishing-template values to PPD options + * and have the right constraints apply (e.g. stapling vs. folding vs. + * punching, etc.) */ - 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 */ cups_array_t *names; /* Names we've added */ count = ippGetCount(attr); names = cupsArrayNew3((cups_array_func_t)strcmp, NULL, NULL, 0, (cups_acopy_func_t)strdup, (cups_afree_func_t)free); - 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); - - if ((name = ippGetString(template, 0, NULL)) == NULL || !strcmp(name, "none")) - continue; + value = ippGetInteger(attr, i); + name = ippEnumString("finishings", value); - if (cupsArrayFind(names, (char *)name)) - continue; /* Already did this finishing template */ + if (!strncmp(name, "staple-", 7) || !strncmp(name, "bind-", 5) || !strncmp(name, "edge-stitch-", 12) || !strcmp(name, "saddle-stitch")) + break; + } - cupsArrayAdd(names, (char *)name); + if (i < count) + { + cupsFilePrintf(fp, "*OpenUI *StapleLocation/%s: PickOne\n", _cupsLangString(lang, _("Staple"))); + cupsFilePuts(fp, "*OrderDependency: 10 AnySetup *StapleLocation\n"); + cupsFilePuts(fp, "*DefaultStapleLocation: None\n"); + cupsFilePrintf(fp, "*StapleLocation None/%s: \"\"\n", _cupsLangString(lang, _("None"))); - for (j = 0; j < (int)(sizeof(finishings) / sizeof(finishings[0])); j ++) + 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); + name = ippEnumString("finishings", value); + + if (strncmp(name, "staple-", 7) && strncmp(name, "bind-", 5) && strncmp(name, "edge-stitch-", 12) && strcmp(name, "saddle-stitch")) + continue; + + if (cupsArrayFind(names, (char *)name)) + continue; /* Already did this finishing template */ + + cupsArrayAdd(names, (char *)name); + + for (j = 0; j < (int)(sizeof(finishings) / sizeof(finishings[0])); j ++) + { + if (!strcmp(finishings[j][0], name)) + { + cupsFilePrintf(fp, "*StapleLocation %s/%s: \"\"\n", name, _cupsLangString(lang, finishings[j][1])); + cupsFilePrintf(fp, "*cupsIPPFinishings %d/%s: \"*StapleLocation %s\"\n", value, name, name); + break; + } + } + } - value = ippEnumValue("finishings", name); + cupsFilePuts(fp, "*CloseUI: *StapleLocation\n"); + } - if (value) - cupsFilePrintf(fp, "*cupsIPPFinishings %d/%s: \"*cupsFinishingTemplate %s\"\n", value, name, name); - break; - } - } + /* + * Fold + */ + + for (i = 0; i < count; i ++) + { + value = ippGetInteger(attr, i); + name = ippEnumString("finishings", value); + + if (!strncmp(name, "fold-", 5)) + break; } - cupsArrayDelete(names); + if (i < count) + { + cupsFilePrintf(fp, "*OpenUI *FoldType/%s: PickOne\n", _cupsLangString(lang, _("Fold"))); + cupsFilePuts(fp, "*OrderDependency: 10 AnySetup *FoldType\n"); + cupsFilePuts(fp, "*DefaultFoldType: None\n"); + cupsFilePrintf(fp, "*FoldType None/%s: \"\"\n", _cupsLangString(lang, _("None"))); - cupsFilePuts(fp, "*CloseUI: *cupsFinishingTemplate\n"); - } - else if ((attr = ippFindAttribute(response, "finishings-supported", IPP_TAG_ENUM)) != NULL && (count = ippGetCount(attr)) > 1 ) - { - const char *name; /* String name */ - int value; /* Enum value, if any */ + for (; i < count; i ++) + { + value = ippGetInteger(attr, i); + name = ippEnumString("finishings", value); + + if (strncmp(name, "fold-", 5)) + continue; + + if (cupsArrayFind(names, (char *)name)) + continue; /* Already did this finishing template */ + + cupsArrayAdd(names, (char *)name); + + for (j = 0; j < (int)(sizeof(finishings) / sizeof(finishings[0])); j ++) + { + if (!strcmp(finishings[j][0], name)) + { + cupsFilePrintf(fp, "*FoldType %s/%s: \"\"\n", name, _cupsLangString(lang, finishings[j][1])); + cupsFilePrintf(fp, "*cupsIPPFinishings %d/%s: \"*FoldType %s\"\n", value, name, name); + break; + } + } + } - count = ippGetCount(attr); + cupsFilePuts(fp, "*CloseUI: *FoldType\n"); + } - 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"))); + /* + * Punch + */ for (i = 0; i < count; i ++) { - if ((value = ippGetInteger(attr, i)) == 3) - continue; + value = ippGetInteger(attr, i); + name = ippEnumString("finishings", value); + + if (!strncmp(name, "punch-", 6)) + break; + } - name = ippEnumString("finishings", value); - for (j = 0; j < (int)(sizeof(finishings) / sizeof(finishings[0])); j ++) + if (i < count) + { + cupsFilePrintf(fp, "*OpenUI *PunchMedia/%s: PickOne\n", _cupsLangString(lang, _("Punch"))); + cupsFilePuts(fp, "*OrderDependency: 10 AnySetup *PunchMedia\n"); + cupsFilePuts(fp, "*DefaultPunchMedia: None\n"); + cupsFilePrintf(fp, "*PunchMedia None/%s: \"\"\n", _cupsLangString(lang, _("None"))); + + for (i = 0; i < count; i ++) { - 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; - } + value = ippGetInteger(attr, i); + name = ippEnumString("finishings", value); + + if (strncmp(name, "punch-", 6)) + continue; + + if (cupsArrayFind(names, (char *)name)) + continue; /* Already did this finishing template */ + + cupsArrayAdd(names, (char *)name); + + for (j = 0; j < (int)(sizeof(finishings) / sizeof(finishings[0])); j ++) + { + if (!strcmp(finishings[j][0], name)) + { + cupsFilePrintf(fp, "*PunchMedia %s/%s: \"\"\n", name, _cupsLangString(lang, finishings[j][1])); + cupsFilePrintf(fp, "*cupsIPPFinishings %d/%s: \"*PunchMedia %s\"\n", value, name, name); + break; + } + } } + + cupsFilePuts(fp, "*CloseUI: *PunchMedia\n"); } - cupsFilePuts(fp, "*CloseUI: *cupsFinishingTemplate\n"); + /* + * Booklet + */ + + if (ippContainsInteger(attr, IPP_FINISHINGS_BOOKLET_MAKER)) + { + cupsFilePrintf(fp, "*OpenUI *Booklet/%s: Boolean\n", _cupsLangString(lang, _("Booklet"))); + cupsFilePuts(fp, "*OrderDependency: 10 AnySetup *Booklet\n"); + 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"); + } + + cupsArrayDelete(names); } /* * cupsPrintQuality and DefaultResolution... */ + quality = ippFindAttribute(response, "print-quality-supported", IPP_TAG_ENUM); + if ((attr = ippFindAttribute(response, "pwg-raster-document-resolution-supported", IPP_TAG_RESOLUTION)) != NULL) { count = ippGetCount(attr); @@ -3690,16 +3972,19 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ cupsFilePrintf(fp, "*OpenUI *cupsPrintQuality/%s: PickOne\n" "*OrderDependency: 10 AnySetup *cupsPrintQuality\n" "*DefaultcupsPrintQuality: Normal\n", _cupsLangString(lang, _("Print Quality"))); - if (count > 2) + if (count > 2 || ippContainsInteger(quality, IPP_QUALITY_DRAFT)) { pwg_ppdize_resolution(attr, 0, &xres, &yres, NULL, 0); cupsFilePrintf(fp, "*cupsPrintQuality Draft/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n", _cupsLangString(lang, _("Draft")), xres, yres); } pwg_ppdize_resolution(attr, count / 2, &xres, &yres, NULL, 0); cupsFilePrintf(fp, "*cupsPrintQuality Normal/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n", _cupsLangString(lang, _("Normal")), xres, yres); - if (count > 1) + if (count > 1 || ippContainsInteger(quality, IPP_QUALITY_HIGH)) { - pwg_ppdize_resolution(attr, count - 1, &xres, &yres, NULL, 0); + if (count > 1) + pwg_ppdize_resolution(attr, count - 1, &xres, &yres, NULL, 0); + else + pwg_ppdize_resolution(attr, 0, &xres, &yres, NULL, 0); cupsFilePrintf(fp, "*cupsPrintQuality High/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n", _cupsLangString(lang, _("High")), xres, yres); } @@ -3731,7 +4016,7 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ * Invalid "urf-supported" value... */ - cupsFilePuts(fp, "*DefaultResolution: 300dpi\n"); + goto bad_ppd; } else { @@ -3746,19 +4031,40 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ "*DefaultcupsPrintQuality: Normal\n", _cupsLangString(lang, _("Print Quality"))); if ((lowdpi & 1) == 0) cupsFilePrintf(fp, "*cupsPrintQuality Draft/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n", _cupsLangString(lang, _("Draft")), lowdpi, lowdpi / 2); + else if (ippContainsInteger(quality, IPP_QUALITY_DRAFT)) + cupsFilePrintf(fp, "*cupsPrintQuality Draft/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n", _cupsLangString(lang, _("Draft")), lowdpi, lowdpi); cupsFilePrintf(fp, "*cupsPrintQuality Normal/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n", _cupsLangString(lang, _("Normal")), lowdpi, lowdpi); - if (hidpi > lowdpi) + if (hidpi > lowdpi || ippContainsInteger(quality, IPP_QUALITY_HIGH)) cupsFilePrintf(fp, "*cupsPrintQuality High/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n", _cupsLangString(lang, _("High")), hidpi, hidpi); cupsFilePuts(fp, "*CloseUI: *cupsPrintQuality\n"); } } - else if ((attr = ippFindAttribute(response, "printer-resolution-default", IPP_TAG_RESOLUTION)) != NULL) + else if (is_apple || is_pwg) + goto bad_ppd; + 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/%s: PickOne\n" + "*OrderDependency: 10 AnySetup *cupsPrintQuality\n" + "*DefaultcupsPrintQuality: Normal\n", _cupsLangString(lang, _("Print Quality"))); + if (ippContainsInteger(quality, IPP_QUALITY_DRAFT)) + cupsFilePrintf(fp, "*cupsPrintQuality Draft/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n", _cupsLangString(lang, _("Draft")), xres, yres); + cupsFilePrintf(fp, "*cupsPrintQuality Normal/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n", _cupsLangString(lang, _("Normal")), xres, yres); + if (ippContainsInteger(quality, IPP_QUALITY_HIGH)) + cupsFilePrintf(fp, "*cupsPrintQuality High/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n", _cupsLangString(lang, _("High")), xres, yres); + cupsFilePuts(fp, "*CloseUI: *cupsPrintQuality\n"); } - else - cupsFilePuts(fp, "*DefaultResolution: 300dpi\n"); /* * Close up and return... @@ -3767,6 +4073,20 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ cupsFileClose(fp); return (buffer); + + /* + * If we get here then there was a problem creating the PPD... + */ + + bad_ppd: + + cupsFileClose(fp); + unlink(buffer); + *buffer = '\0'; + + _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Printer does not support required IPP attributes or document formats."), 1); + + return (NULL); } @@ -3926,10 +4246,34 @@ _pwgPageSizeForMedia( /* + * '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_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 */ @@ -3952,22 +4296,6 @@ pwg_free_finishings( /* - * 'pwg_free_material()' - Free a material value. - */ - -static void -pwg_free_material(_pwg_material_t *m) /* I - Material value */ -{ - _cupsStrFree(m->key); - _cupsStrFree(m->name); - - cupsFreeOptions(m->num_props, m->props); - - free(m); -} - - -/* * 'pwg_ppdize_name()' - Convert an IPP keyword to a PPD keyword. */ @@ -3980,11 +4308,17 @@ pwg_ppdize_name(const char *ipp, /* I - IPP keyword */ *end; /* End of name buffer */ + if (!ipp) + { + *name = '\0'; + return; + } + *name = (char)toupper(*ipp++); for (ptr = name + 1, end = name + namesize - 1; *ipp && ptr < end;) { - if (*ipp == '-' && _cups_isalpha(ipp[1])) + if (*ipp == '-' && _cups_isalnum(ipp[1])) { ipp ++; *ptr++ = (char)toupper(*ipp++ & 255); |