/*
* 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.
*/
/*
*/
#include "cups-private.h"
+#include "debug-internal.h"
/*
*/
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,
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.
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 */
/*
*/
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...
* 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);
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 &&
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 */
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",
};
- 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...
* 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...
*/
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);
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...
return (NULL);
}
+ DEBUG_printf(("1cupsCopyDestInfo: version=%d, uri=\"%s\", resource=\"%s\".", version, uri, resource));
+
dinfo->version = version;
dinfo->uri = uri;
dinfo->resource = _cupsStrAlloc(resource);
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
* 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);
/*
}
+/*
+ * '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.
*/
/*
* 'cups_create_defaults()' - Create the -default option array.
- *
- * TODO: Need to support collection defaults...
*/
static void
* 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);
}
}
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,
}
}
- 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);
}
* 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;
/*
* 'cups_test_constraints()' - Test constraints.
- *
- * TODO: STR #4096 - Need to properly support media-col contraints...
*/
static cups_array_t * /* O - Active 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 */
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)
}
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;
}
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);
}
}