X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=cups%2Fdest-options.c;h=8c5fe666c457f13353141cc4b3ba5d7de1b1162b;hb=986daa034e1e378ba14c25fd6104fc4eb50573ae;hp=51705a50cb5e5744deec04a8443bfd9f42fb6b97;hpb=058582b4b54f1eb966cdb586133bedfb8cb69c86;p=thirdparty%2Fcups.git diff --git a/cups/dest-options.c b/cups/dest-options.c index 51705a50c..8c5fe666c 100644 --- a/cups/dest-options.c +++ b/cups/dest-options.c @@ -1,15 +1,10 @@ /* * Destination option/media support for CUPS. * - * Copyright 2012-2017 by Apple Inc. + * Copyright © 2012-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 - * 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. */ /* @@ -17,6 +12,7 @@ */ #include "cups-private.h" +#include "debug-internal.h" /* @@ -31,6 +27,8 @@ */ static void cups_add_dconstres(cups_array_t *a, ipp_t *collection); +static int cups_collection_contains(ipp_t *test, ipp_t *match); +static size_t cups_collection_string(ipp_attribute_t *attr, char *buffer, size_t bufsize) _CUPS_NONNULL((1,2)); static int cups_compare_dconstres(_cups_dconstres_t *a, _cups_dconstres_t *b); static int cups_compare_media_db(_cups_media_db_t *a, @@ -58,6 +56,104 @@ static cups_array_t *cups_test_constraints(cups_dinfo_t *dinfo, static void cups_update_ready(http_t *http, cups_dinfo_t *dinfo); +/* + * 'cupsAddDestMediaOptions()' - Add the option corresponding to the specified media size. + * + * @since CUPS 2.3/macOS 10.14@ + */ + +int /* O - New number of options */ +cupsAddDestMediaOptions( + http_t *http, /* I - Connection to destination */ + cups_dest_t *dest, /* I - Destination */ + cups_dinfo_t *dinfo, /* I - Destination information */ + unsigned flags, /* I - Media matching flags */ + cups_size_t *size, /* I - Media size */ + int num_options, /* I - Current number of options */ + cups_option_t **options) /* IO - Options */ +{ + cups_array_t *db; /* Media database */ + _cups_media_db_t *mdb; /* Media database entry */ + char value[2048]; /* Option value */ + + + /* + * Range check input... + */ + + if (!http || !dest || !dinfo || !size || !options) + { + _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); + return (num_options); + } + + /* + * Find the matching media size... + */ + + if (flags & CUPS_MEDIA_FLAGS_READY) + db = dinfo->ready_db; + else + db = dinfo->media_db; + + DEBUG_printf(("1cupsAddDestMediaOptions: size->media=\"%s\"", size->media)); + + for (mdb = (_cups_media_db_t *)cupsArrayFirst(db); mdb; mdb = (_cups_media_db_t *)cupsArrayNext(db)) + { + if (mdb->key && !strcmp(mdb->key, size->media)) + break; + else if (mdb->size_name && !strcmp(mdb->size_name, size->media)) + break; + } + + if (!mdb) + { + for (mdb = (_cups_media_db_t *)cupsArrayFirst(db); mdb; mdb = (_cups_media_db_t *)cupsArrayNext(db)) + { + if (mdb->width == size->width && mdb->length == size->length && mdb->bottom == size->bottom && mdb->left == size->left && mdb->right == size->right && mdb->top == size->top) + break; + } + } + + if (!mdb) + { + for (mdb = (_cups_media_db_t *)cupsArrayFirst(db); mdb; mdb = (_cups_media_db_t *)cupsArrayNext(db)) + { + if (mdb->width == size->width && mdb->length == size->length) + break; + } + } + + if (!mdb) + { + DEBUG_puts("1cupsAddDestMediaOptions: Unable to find matching size."); + return (num_options); + } + + DEBUG_printf(("1cupsAddDestMediaOptions: MATCH mdb%p [key=\"%s\" size_name=\"%s\" source=\"%s\" type=\"%s\" width=%d length=%d B%d L%d R%d T%d]", (void *)mdb, mdb->key, mdb->size_name, mdb->source, mdb->type, mdb->width, mdb->length, mdb->bottom, mdb->left, mdb->right, mdb->top)); + + if (mdb->source) + { + if (mdb->type) + snprintf(value, sizeof(value), "{media-size={x-dimension=%d y-dimension=%d} media-bottom-margin=%d media-left-margin=%d media-right-margin=%d media-top-margin=%d media-source=\"%s\" media-type=\"%s\"}", mdb->width, mdb->length, mdb->bottom, mdb->left, mdb->right, mdb->top, mdb->source, mdb->type); + else + snprintf(value, sizeof(value), "{media-size={x-dimension=%d y-dimension=%d} media-bottom-margin=%d media-left-margin=%d media-right-margin=%d media-top-margin=%d media-source=\"%s\"}", mdb->width, mdb->length, mdb->bottom, mdb->left, mdb->right, mdb->top, mdb->source); + } + else if (mdb->type) + { + snprintf(value, sizeof(value), "{media-size={x-dimension=%d y-dimension=%d} media-bottom-margin=%d media-left-margin=%d media-right-margin=%d media-top-margin=%d media-type=\"%s\"}", mdb->width, mdb->length, mdb->bottom, mdb->left, mdb->right, mdb->top, mdb->type); + } + else + { + snprintf(value, sizeof(value), "{media-size={x-dimension=%d y-dimension=%d} media-bottom-margin=%d media-left-margin=%d media-right-margin=%d media-top-margin=%d}", mdb->width, mdb->length, mdb->bottom, mdb->left, mdb->right, mdb->top); + } + + num_options = cupsAddOption("media-col", value, num_options, options); + + return (num_options); +} + + /* * 'cupsCheckDestSupported()' - Check that the option and value are supported * by the destination. @@ -83,6 +179,7 @@ cupsCheckDestSupported( ipp_res_t units_value; /* Resolution units */ ipp_attribute_t *attr; /* Attribute */ _ipp_value_t *attrval; /* Current attribute value */ + _ipp_option_t *map; /* Option mapping information */ /* @@ -128,10 +225,10 @@ cupsCheckDestSupported( */ pwg_media_t *pwg; /* Current PWG media size info */ - int min_width, /* Minimum width */ - min_length, /* Minimum length */ - max_width, /* Maximum width */ - max_length; /* Maximum length */ + int min_width, /* Minimum width */ + min_length, /* Minimum length */ + max_width, /* Maximum width */ + max_length; /* Maximum length */ /* * Get the minimum and maximum size... @@ -174,9 +271,14 @@ cupsCheckDestSupported( * Check literal values... */ + map = _ippFindOption(option); + switch (attr->value_tag) { case IPP_TAG_INTEGER : + if (map && map->value_tag == IPP_TAG_STRING) + return (strlen(value) <= (size_t)attr->values[0].integer); + case IPP_TAG_ENUM : int_value = atoi(value); @@ -189,7 +291,10 @@ cupsCheckDestSupported( return (attr->values[0].boolean); case IPP_TAG_RANGE : - int_value = atoi(value); + if (map && map->value_tag == IPP_TAG_STRING) + int_value = (int)strlen(value); + else + int_value = atoi(value); for (i = 0; i < attr->num_values; i ++) if (int_value >= attr->values[i].range.lower && @@ -572,6 +677,7 @@ cupsCopyDestInfo( cups_dest_t *dest) /* I - Destination */ { cups_dinfo_t *dinfo; /* Destination information */ + unsigned dflags; /* Destination flags */ ipp_t *request, /* Get-Printer-Attributes request */ *response; /* Supported attributes */ int tries, /* Number of tries so far */ @@ -581,6 +687,7 @@ cupsCopyDestInfo( char resource[1024]; /* Resource path */ int version; /* IPP version */ ipp_status_t status; /* Status of request */ + _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ static const char * const requested_attrs[] = { /* Requested attributes */ "job-template", @@ -589,14 +696,35 @@ cupsCopyDestInfo( }; - DEBUG_printf(("cupsCopyDestSupported(http=%p, dest=%p(%s))", (void *)http, (void *)dest, dest ? dest->name : "")); + DEBUG_printf(("cupsCopyDestInfo(http=%p, dest=%p(%s))", (void *)http, (void *)dest, dest ? dest->name : "")); /* * Get the default connection as needed... */ if (!http) - http = _cupsConnect(); + { + DEBUG_puts("1cupsCopyDestInfo: Default server connection."); + http = _cupsConnect(); + dflags = CUPS_DEST_FLAGS_NONE; + } +#ifdef AF_LOCAL + else if (httpAddrFamily(http->hostaddr) == AF_LOCAL) + { + DEBUG_puts("1cupsCopyDestInfo: Connection to server (domain socket)."); + dflags = CUPS_DEST_FLAGS_NONE; + } +#endif /* AF_LOCAL */ + else if ((strcmp(http->hostname, cg->server) && cg->server[0] != '/') || cg->ipp_port != httpAddrPort(http->hostaddr)) + { + DEBUG_printf(("1cupsCopyDestInfo: Connection to device (%s).", http->hostname)); + dflags = CUPS_DEST_FLAGS_DEVICE; + } + else + { + DEBUG_printf(("1cupsCopyDestInfo: Connection to server (%s).", http->hostname)); + dflags = CUPS_DEST_FLAGS_NONE; + } /* * Range check input... @@ -609,8 +737,11 @@ cupsCopyDestInfo( * Get the printer URI and resource path... */ - if ((uri = _cupsGetDestResource(dest, resource, sizeof(resource))) == NULL) + if ((uri = _cupsGetDestResource(dest, dflags, resource, sizeof(resource))) == NULL) + { + DEBUG_puts("1cupsCopyDestInfo: Unable to get resource."); return (NULL); + } /* * Get the supported attributes... @@ -628,28 +759,25 @@ cupsCopyDestInfo( */ request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES); - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, - uri); - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, - "requesting-user-name", NULL, cupsUser()); - ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, - "requested-attributes", - (int)(sizeof(requested_attrs) / sizeof(requested_attrs[0])), - NULL, requested_attrs); + + ippSetVersion(request, version / 10, version % 10); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); + ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", (int)(sizeof(requested_attrs) / sizeof(requested_attrs[0])), NULL, requested_attrs); response = cupsDoRequest(http, request, resource); status = cupsLastError(); if (status > IPP_STATUS_OK_IGNORED_OR_SUBSTITUTED) { - DEBUG_printf(("cupsCopyDestSupported: Get-Printer-Attributes for '%s' " - "returned %s (%s)", dest->name, ippErrorString(status), - cupsLastErrorString())); + DEBUG_printf(("1cupsCopyDestInfo: Get-Printer-Attributes for '%s' returned %s (%s)", dest->name, ippErrorString(status), cupsLastErrorString())); ippDelete(response); response = NULL; - if (status == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED && version > 11) + if ((status == IPP_STATUS_ERROR_BAD_REQUEST || status == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED) && version > 11) + { version = 11; + } else if (status == IPP_STATUS_ERROR_BUSY) { sleep((unsigned)delay); @@ -665,7 +793,10 @@ cupsCopyDestInfo( while (!response && tries < 10); if (!response) + { + DEBUG_puts("1cupsCopyDestInfo: Unable to get printer attributes."); return (NULL); + } /* * Allocate a cups_dinfo_t structure and return it... @@ -678,6 +809,8 @@ cupsCopyDestInfo( return (NULL); } + DEBUG_printf(("1cupsCopyDestInfo: version=%d, uri=\"%s\", resource=\"%s\".", version, uri, resource)); + dinfo->version = version; dinfo->uri = uri; dinfo->resource = _cupsStrAlloc(resource); @@ -938,10 +1071,10 @@ cupsGetDestMediaByIndex( return (0); } - if (nsize->size_name) - strlcpy(size->media, nsize->size_name, sizeof(size->media)); - else if (nsize->key) + if (nsize->key) strlcpy(size->media, nsize->key, sizeof(size->media)); + else if (nsize->size_name) + strlcpy(size->media, nsize->size_name, sizeof(size->media)); else if ((pwg = pwgMediaForSize(nsize->width, nsize->length)) != NULL) strlcpy(size->media, pwg->pwg, sizeof(size->media)); else @@ -1202,25 +1335,19 @@ cupsGetDestMediaDefault( * Get the default media size, if any... */ - if ((media = cupsGetOption("media", dest->num_options, - dest->options)) == NULL) + if ((media = cupsGetOption("media", dest->num_options, dest->options)) == NULL) media = "na_letter_8.5x11in"; if (cupsGetDestMediaByName(http, dest, dinfo, media, flags, size)) return (1); - if (strcmp(media, "na_letter_8.5x11in") && - cupsGetDestMediaByName(http, dest, dinfo, "iso_a4_210x297mm", flags, - size)) + if (strcmp(media, "na_letter_8.5x11in") && cupsGetDestMediaByName(http, dest, dinfo, "iso_a4_210x297mm", flags, size)) return (1); - if (strcmp(media, "iso_a4_210x297mm") && - cupsGetDestMediaByName(http, dest, dinfo, "na_letter_8.5x11in", flags, - size)) + if (strcmp(media, "iso_a4_210x297mm") && cupsGetDestMediaByName(http, dest, dinfo, "na_letter_8.5x11in", flags, size)) return (1); - if ((flags & CUPS_MEDIA_FLAGS_BORDERLESS) && - cupsGetDestMediaByName(http, dest, dinfo, "na_index_4x6in", flags, size)) + if ((flags & CUPS_MEDIA_FLAGS_BORDERLESS) && cupsGetDestMediaByName(http, dest, dinfo, "na_index_4x6in", flags, size)) return (1); /* @@ -1258,6 +1385,346 @@ cups_add_dconstres( } +/* + * 'cups_collection_contains()' - Check whether test collection is contained in the matching collection. + */ + +static int /* O - 1 on a match, 0 on a non-match */ +cups_collection_contains(ipp_t *test, /* I - Collection to test */ + ipp_t *match) /* I - Matching values */ +{ + int i, j, /* Looping vars */ + mcount, /* Number of match values */ + tcount; /* Number of test values */ + ipp_attribute_t *tattr, /* Testing attribute */ + *mattr; /* Matching attribute */ + const char *tval; /* Testing string value */ + + + for (mattr = ippFirstAttribute(match); mattr; mattr = ippNextAttribute(match)) + { + if ((tattr = ippFindAttribute(test, ippGetName(mattr), IPP_TAG_ZERO)) == NULL) + return (0); + + tcount = ippGetCount(tattr); + + switch (ippGetValueTag(mattr)) + { + case IPP_TAG_INTEGER : + case IPP_TAG_ENUM : + if (ippGetValueTag(tattr) != ippGetValueTag(mattr)) + return (0); + + for (i = 0; i < tcount; i ++) + { + if (!ippContainsInteger(mattr, ippGetInteger(tattr, i))) + return (0); + } + break; + + case IPP_TAG_RANGE : + if (ippGetValueTag(tattr) != IPP_TAG_INTEGER) + return (0); + + for (i = 0; i < tcount; i ++) + { + if (!ippContainsInteger(mattr, ippGetInteger(tattr, i))) + return (0); + } + break; + + case IPP_TAG_BOOLEAN : + if (ippGetValueTag(tattr) != IPP_TAG_BOOLEAN || ippGetBoolean(tattr, 0) != ippGetBoolean(mattr, 0)) + return (0); + break; + + case IPP_TAG_TEXTLANG : + case IPP_TAG_NAMELANG : + case IPP_TAG_TEXT : + case IPP_TAG_NAME : + case IPP_TAG_KEYWORD : + case IPP_TAG_URI : + case IPP_TAG_URISCHEME : + case IPP_TAG_CHARSET : + case IPP_TAG_LANGUAGE : + case IPP_TAG_MIMETYPE : + for (i = 0; i < tcount; i ++) + { + if ((tval = ippGetString(tattr, i, NULL)) == NULL || !ippContainsString(mattr, tval)) + return (0); + } + break; + + case IPP_TAG_BEGIN_COLLECTION : + for (i = 0; i < tcount; i ++) + { + ipp_t *tcol = ippGetCollection(tattr, i); + /* Testing collection */ + + for (j = 0, mcount = ippGetCount(mattr); j < mcount; j ++) + if (!cups_collection_contains(tcol, ippGetCollection(mattr, j))) + return (0); + } + break; + + default : + return (0); + } + } + + return (1); +} + + +/* + * 'cups_collection_string()' - Convert an IPP collection to an option string. + */ + +static size_t /* O - Number of bytes needed */ +cups_collection_string( + ipp_attribute_t *attr, /* I - Collection attribute */ + char *buffer, /* I - String buffer */ + size_t bufsize) /* I - Size of buffer */ +{ + int i, j, /* Looping vars */ + count, /* Number of collection values */ + mcount; /* Number of member values */ + ipp_t *col; /* Collection */ + ipp_attribute_t *first, /* First member attribute */ + *member; /* Member attribute */ + char *bufptr, /* Pointer into buffer */ + *bufend, /* End of buffer */ + temp[100]; /* Temporary string */ + const char *mptr; /* Pointer into member value */ + int mlen; /* Length of octetString */ + + + bufptr = buffer; + bufend = buffer + bufsize - 1; + + for (i = 0, count = ippGetCount(attr); i < count; i ++) + { + col = ippGetCollection(attr, i); + + if (i) + { + if (bufptr < bufend) + *bufptr++ = ','; + else + bufptr ++; + } + + if (bufptr < bufend) + *bufptr++ = '{'; + else + bufptr ++; + + for (member = first = ippFirstAttribute(col); member; member = ippNextAttribute(col)) + { + const char *mname = ippGetName(member); + + if (member != first) + { + if (bufptr < bufend) + *bufptr++ = ' '; + else + bufptr ++; + } + + if (ippGetValueTag(member) == IPP_TAG_BOOLEAN) + { + if (!ippGetBoolean(member, 0)) + { + if (bufptr < bufend) + strlcpy(bufptr, "no", (size_t)(bufend - bufptr + 1)); + bufptr += 2; + } + + if (bufptr < bufend) + strlcpy(bufptr, mname, (size_t)(bufend - bufptr + 1)); + bufptr += strlen(mname); + continue; + } + + if (bufptr < bufend) + strlcpy(bufptr, mname, (size_t)(bufend - bufptr + 1)); + bufptr += strlen(mname); + + if (bufptr < bufend) + *bufptr++ = '='; + else + bufptr ++; + + if (ippGetValueTag(member) == IPP_TAG_BEGIN_COLLECTION) + { + /* + * Convert sub-collection... + */ + + bufptr += cups_collection_string(member, bufptr, bufptr < bufend ? (size_t)(bufend - bufptr + 1) : 0); + } + else + { + /* + * Convert simple type... + */ + + for (j = 0, mcount = ippGetCount(member); j < mcount; j ++) + { + if (j) + { + if (bufptr < bufend) + *bufptr++ = ','; + else + bufptr ++; + } + + switch (ippGetValueTag(member)) + { + case IPP_TAG_INTEGER : + case IPP_TAG_ENUM : + bufptr += snprintf(bufptr, bufptr < bufend ? (size_t)(bufend - bufptr + 1) : 0, "%d", ippGetInteger(member, j)); + break; + + case IPP_TAG_STRING : + if (bufptr < bufend) + *bufptr++ = '\"'; + else + bufptr ++; + + for (mptr = (const char *)ippGetOctetString(member, j, &mlen); mlen > 0; mlen --, mptr ++) + { + if (*mptr == '\"' || *mptr == '\\') + { + if (bufptr < bufend) + *bufptr++ = '\\'; + else + bufptr ++; + } + + if (bufptr < bufend) + *bufptr++ = *mptr; + else + bufptr ++; + } + + if (bufptr < bufend) + *bufptr++ = '\"'; + else + bufptr ++; + break; + + case IPP_TAG_DATE : + { + unsigned year; /* Year */ + const ipp_uchar_t *date = ippGetDate(member, j); + /* Date value */ + + year = ((unsigned)date[0] << 8) + (unsigned)date[1]; + + if (date[9] == 0 && date[10] == 0) + snprintf(temp, sizeof(temp), "%04u-%02u-%02uT%02u:%02u:%02uZ", year, date[2], date[3], date[4], date[5], date[6]); + else + snprintf(temp, sizeof(temp), "%04u-%02u-%02uT%02u:%02u:%02u%c%02u%02u", year, date[2], date[3], date[4], date[5], date[6], date[8], date[9], date[10]); + + if (bufptr < bufend) + strlcpy(bufptr, temp, (size_t)(bufend - bufptr + 1)); + + bufptr += strlen(temp); + } + break; + + case IPP_TAG_RESOLUTION : + { + int xres, /* Horizontal resolution */ + yres; /* Vertical resolution */ + ipp_res_t units; /* Resolution units */ + + xres = ippGetResolution(member, j, &yres, &units); + + if (xres == yres) + snprintf(temp, sizeof(temp), "%d%s", xres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm"); + else + snprintf(temp, sizeof(temp), "%dx%d%s", xres, yres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm"); + + if (bufptr < bufend) + strlcpy(bufptr, temp, (size_t)(bufend - bufptr + 1)); + + bufptr += strlen(temp); + } + break; + + case IPP_TAG_RANGE : + { + int lower, /* Lower bound */ + upper; /* Upper bound */ + + lower = ippGetRange(member, j, &upper); + + snprintf(temp, sizeof(temp), "%d-%d", lower, upper); + + if (bufptr < bufend) + strlcpy(bufptr, temp, (size_t)(bufend - bufptr + 1)); + + bufptr += strlen(temp); + } + break; + + case IPP_TAG_TEXTLANG : + case IPP_TAG_NAMELANG : + case IPP_TAG_TEXT : + case IPP_TAG_NAME : + case IPP_TAG_KEYWORD : + case IPP_TAG_URI : + case IPP_TAG_URISCHEME : + case IPP_TAG_CHARSET : + case IPP_TAG_LANGUAGE : + case IPP_TAG_MIMETYPE : + if (bufptr < bufend) + *bufptr++ = '\"'; + else + bufptr ++; + + for (mptr = ippGetString(member, j, NULL); *mptr; mptr ++) + { + if (*mptr == '\"' || *mptr == '\\') + { + if (bufptr < bufend) + *bufptr++ = '\\'; + else + bufptr ++; + } + + if (bufptr < bufend) + *bufptr++ = *mptr; + else + bufptr ++; + } + + if (bufptr < bufend) + *bufptr++ = '\"'; + else + bufptr ++; + break; + + default : + break; + } + } + } + } + + if (bufptr < bufend) + *bufptr++ = '}'; + else + bufptr ++; + } + + *bufptr = '\0'; + return ((size_t)(bufptr - buffer + 1)); +} + + /* * 'cups_compare_dconstres()' - Compare to resolver entries. */ @@ -1445,8 +1912,6 @@ cups_create_constraints( /* * 'cups_create_defaults()' - Create the -default option array. - * - * TODO: Need to support collection defaults... */ static void @@ -1465,32 +1930,26 @@ cups_create_defaults( * xxx=value to the defaults option array. */ - for (attr = ippFirstAttribute(dinfo->attrs); - attr; - attr = ippNextAttribute(dinfo->attrs)) + for (attr = ippFirstAttribute(dinfo->attrs); attr; attr = ippNextAttribute(dinfo->attrs)) { - if (!attr->name || attr->group_tag != IPP_TAG_PRINTER) - continue; - - if (attr->value_tag == IPP_TAG_BEGIN_COLLECTION) - continue; /* TODO: STR #4096 */ - - if ((nameptr = attr->name + strlen(attr->name) - 8) <= attr->name || - strcmp(nameptr, "-default")) + if (!ippGetName(attr) || ippGetGroupTag(attr) != IPP_TAG_PRINTER) continue; - strlcpy(name, attr->name, sizeof(name)); - if ((nameptr = name + strlen(name) - 8) <= name || - strcmp(nameptr, "-default")) + strlcpy(name, ippGetName(attr), sizeof(name)); + if ((nameptr = name + strlen(name) - 8) <= name || strcmp(nameptr, "-default")) continue; *nameptr = '\0'; - if (ippAttributeString(attr, value, sizeof(value)) >= sizeof(value)) + if (ippGetValueTag(attr) == IPP_TAG_BEGIN_COLLECTION) + { + if (cups_collection_string(attr, value, sizeof(value)) >= sizeof(value)) + continue; + } + else if (ippAttributeString(attr, value, sizeof(value)) >= sizeof(value)) continue; - dinfo->num_defaults = cupsAddOption(name, value, dinfo->num_defaults, - &dinfo->defaults); + dinfo->num_defaults = cupsAddOption(name, value, dinfo->num_defaults, &dinfo->defaults); } } @@ -1513,6 +1972,7 @@ cups_create_media_db( pwg_media_t *pwg; /* PWG media info */ cups_array_t *db; /* New media database array */ _cups_media_db_t mdb; /* Media entry */ + char media_key[256]; /* Synthesized media-key value */ db = cupsArrayNew3((cups_array_func_t)cups_compare_media_db, @@ -1613,61 +2073,92 @@ cups_create_media_db( } } - if ((media_attr = ippFindAttribute(val->collection, "media-color", - IPP_TAG_ZERO)) != NULL && - (media_attr->value_tag == IPP_TAG_NAME || - media_attr->value_tag == IPP_TAG_NAMELANG || - media_attr->value_tag == IPP_TAG_KEYWORD)) + if ((media_attr = ippFindAttribute(val->collection, "media-color", IPP_TAG_ZERO)) != NULL && (media_attr->value_tag == IPP_TAG_NAME || media_attr->value_tag == IPP_TAG_NAMELANG || media_attr->value_tag == IPP_TAG_KEYWORD)) mdb.color = media_attr->values[0].string.text; - if ((media_attr = ippFindAttribute(val->collection, "media-info", - IPP_TAG_TEXT)) != NULL) + if ((media_attr = ippFindAttribute(val->collection, "media-info", IPP_TAG_TEXT)) != NULL) mdb.info = media_attr->values[0].string.text; - if ((media_attr = ippFindAttribute(val->collection, "media-key", - IPP_TAG_ZERO)) != NULL && - (media_attr->value_tag == IPP_TAG_NAME || - media_attr->value_tag == IPP_TAG_NAMELANG || - media_attr->value_tag == IPP_TAG_KEYWORD)) + if ((media_attr = ippFindAttribute(val->collection, "media-key", IPP_TAG_ZERO)) != NULL && (media_attr->value_tag == IPP_TAG_NAME || media_attr->value_tag == IPP_TAG_NAMELANG || media_attr->value_tag == IPP_TAG_KEYWORD)) mdb.key = media_attr->values[0].string.text; - if ((media_attr = ippFindAttribute(val->collection, "media-size-name", - IPP_TAG_ZERO)) != NULL && - (media_attr->value_tag == IPP_TAG_NAME || - media_attr->value_tag == IPP_TAG_NAMELANG || - media_attr->value_tag == IPP_TAG_KEYWORD)) + if ((media_attr = ippFindAttribute(val->collection, "media-size-name", IPP_TAG_ZERO)) != NULL && (media_attr->value_tag == IPP_TAG_NAME || media_attr->value_tag == IPP_TAG_NAMELANG || media_attr->value_tag == IPP_TAG_KEYWORD)) mdb.size_name = media_attr->values[0].string.text; - if ((media_attr = ippFindAttribute(val->collection, "media-source", - IPP_TAG_ZERO)) != NULL && - (media_attr->value_tag == IPP_TAG_NAME || - media_attr->value_tag == IPP_TAG_NAMELANG || - media_attr->value_tag == IPP_TAG_KEYWORD)) + if ((media_attr = ippFindAttribute(val->collection, "media-source", IPP_TAG_ZERO)) != NULL && (media_attr->value_tag == IPP_TAG_NAME || media_attr->value_tag == IPP_TAG_NAMELANG || media_attr->value_tag == IPP_TAG_KEYWORD)) mdb.source = media_attr->values[0].string.text; - if ((media_attr = ippFindAttribute(val->collection, "media-type", - IPP_TAG_ZERO)) != NULL && - (media_attr->value_tag == IPP_TAG_NAME || - media_attr->value_tag == IPP_TAG_NAMELANG || - media_attr->value_tag == IPP_TAG_KEYWORD)) + if ((media_attr = ippFindAttribute(val->collection, "media-type", IPP_TAG_ZERO)) != NULL && (media_attr->value_tag == IPP_TAG_NAME || media_attr->value_tag == IPP_TAG_NAMELANG || media_attr->value_tag == IPP_TAG_KEYWORD)) mdb.type = media_attr->values[0].string.text; - if ((media_attr = ippFindAttribute(val->collection, "media-bottom-margin", - IPP_TAG_INTEGER)) != NULL) + if ((media_attr = ippFindAttribute(val->collection, "media-bottom-margin", IPP_TAG_INTEGER)) != NULL) mdb.bottom = media_attr->values[0].integer; - if ((media_attr = ippFindAttribute(val->collection, "media-left-margin", - IPP_TAG_INTEGER)) != NULL) + if ((media_attr = ippFindAttribute(val->collection, "media-left-margin", IPP_TAG_INTEGER)) != NULL) mdb.left = media_attr->values[0].integer; - if ((media_attr = ippFindAttribute(val->collection, "media-right-margin", - IPP_TAG_INTEGER)) != NULL) + if ((media_attr = ippFindAttribute(val->collection, "media-right-margin", IPP_TAG_INTEGER)) != NULL) mdb.right = media_attr->values[0].integer; - if ((media_attr = ippFindAttribute(val->collection, "media-top-margin", - IPP_TAG_INTEGER)) != NULL) + if ((media_attr = ippFindAttribute(val->collection, "media-top-margin", IPP_TAG_INTEGER)) != NULL) mdb.top = media_attr->values[0].integer; + if (!mdb.key) + { + if (!mdb.size_name && (pwg = pwgMediaForSize(mdb.width, mdb.length)) != NULL) + mdb.size_name = (char *)pwg->pwg; + + if (!mdb.size_name) + { + /* + * Use a CUPS-specific identifier if we don't have a size name... + */ + + if (flags & CUPS_MEDIA_FLAGS_READY) + snprintf(media_key, sizeof(media_key), "cups-media-ready-%d", i + 1); + else + snprintf(media_key, sizeof(media_key), "cups-media-%d", i + 1); + } + else if (mdb.source) + { + /* + * Generate key using size name, source, and type (if set)... + */ + + if (mdb.type) + snprintf(media_key, sizeof(media_key), "%s_%s_%s", mdb.size_name, mdb.source, mdb.type); + else + snprintf(media_key, sizeof(media_key), "%s_%s", mdb.size_name, mdb.source); + } + else if (mdb.type) + { + /* + * Generate key using size name and type... + */ + + snprintf(media_key, sizeof(media_key), "%s_%s", mdb.size_name, mdb.type); + } + else + { + /* + * Key is just the size name... + */ + + strlcpy(media_key, mdb.size_name, sizeof(media_key)); + } + + /* + * Append "_borderless" for borderless media... + */ + + if (!mdb.bottom && !mdb.left && !mdb.right && !mdb.top) + strlcat(media_key, "_borderless", sizeof(media_key)); + + mdb.key = media_key; + } + + DEBUG_printf(("1cups_create_media_db: Adding media: key=\"%s\", width=%d, length=%d, source=\"%s\", type=\"%s\".", mdb.key, mdb.width, mdb.length, mdb.source, mdb.type)); + cupsArrayAdd(db, &mdb); } @@ -2027,12 +2518,14 @@ cups_get_media_db(http_t *http, /* I - Connection to destination */ * Return the matching size... */ - if (best->size_name) - strlcpy(size->media, best->size_name, sizeof(size->media)); - else if (best->key) + if (best->key) strlcpy(size->media, best->key, sizeof(size->media)); - else + else if (best->size_name) + strlcpy(size->media, best->size_name, sizeof(size->media)); + else if (pwg && pwg->pwg) strlcpy(size->media, pwg->pwg, sizeof(size->media)); + else + strlcpy(size->media, "unknown", sizeof(size->media)); size->width = best->width; size->length = best->length; @@ -2074,8 +2567,6 @@ cups_is_close_media_db( /* * 'cups_test_constraints()' - Test constraints. - * - * TODO: STR #4096 - Need to properly support media-col contraints... */ static cups_array_t * /* O - Active constraints */ @@ -2089,11 +2580,13 @@ cups_test_constraints( cups_option_t **conflicts) /* O - Conflicting options */ { int i, /* Looping var */ + count, /* Number of values */ match; /* Value matches? */ int num_matching; /* Number of matching options */ cups_option_t *matching; /* Matching options */ _cups_dconstres_t *c; /* Current constraint */ cups_array_t *active = NULL; /* Active constraints */ + ipp_t *col; /* Collection value */ ipp_attribute_t *attr; /* Current attribute */ _ipp_value_t *attrval; /* Current attribute value */ const char *value; /* Current value */ @@ -2115,17 +2608,13 @@ cups_test_constraints( attr; attr = ippNextAttribute(c->collection)) { - if (attr->value_tag == IPP_TAG_BEGIN_COLLECTION) - break; /* TODO: STR #4096 */ - /* * Get the value for the current attribute in the constraint... */ if (new_option && new_value && !strcmp(attr->name, new_option)) value = new_value; - else if ((value = cupsGetOption(attr->name, num_options, - options)) == NULL) + else if ((value = cupsGetOption(attr->name, num_options, options)) == NULL) value = cupsGetOption(attr->name, dinfo->num_defaults, dinfo->defaults); if (!value) @@ -2240,6 +2729,22 @@ cups_test_constraints( } break; + case IPP_TAG_BEGIN_COLLECTION : + col = ippNew(); + _cupsEncodeOption(col, IPP_TAG_ZERO, NULL, ippGetName(attr), value); + + for (i = 0, count = ippGetCount(attr); i < count; i ++) + { + if (cups_collection_contains(col, ippGetCollection(attr, i))) + { + match = 1; + break; + } + } + + ippDelete(col); + break; + default : break; } @@ -2262,8 +2767,7 @@ cups_test_constraints( cups_option_t *moption; /* Matching option */ for (i = num_matching, moption = matching; i > 0; i --, moption ++) - *num_conflicts = cupsAddOption(moption->name, moption->value, - *num_conflicts, conflicts); + *num_conflicts = cupsAddOption(moption->name, moption->value, *num_conflicts, conflicts); } }