/*
- * "$Id$"
- *
* ipptool command for CUPS.
*
- * Copyright 2007-2014 by Apple Inc.
+ * Copyright 2007-2017 by Apple Inc.
* Copyright 1997-2007 by Easy Software Products.
*
- * These coded instructions, statements, and computer programs are the
- * property of Apple Inc. and are protected by Federal copyright
- * law. Distribution and use rights are outlined in the file "LICENSE.txt"
- * which should have been included with this file. If this file is
- * file is missing or damaged, see the license at "http://www.cups.org/".
- *
- * This file is subject to the Apple OS-Developed Software exception.
+ * Licensed under Apache License v2.0. See the file "LICENSE" for more information.
*/
/*
_CUPS_OUTPUT_QUIET, /* No output */
_CUPS_OUTPUT_TEST, /* Traditional CUPS test output */
_CUPS_OUTPUT_PLIST, /* XML plist test output */
+ _CUPS_OUTPUT_IPPSERVER, /* ippserver attribute file output */
_CUPS_OUTPUT_LIST, /* Tabular list output */
_CUPS_OUTPUT_CSV /* Comma-separated values output */
} _cups_output_t;
typedef struct _cups_expect_s /**** Expected attribute info ****/
{
int optional, /* Optional attribute? */
- not_expect; /* Don't expect attribute? */
+ not_expect, /* Don't expect attribute? */
+ expect_all; /* Expect all attributes to match/not match */
char *name, /* Attribute name */
*of_type, /* Type name */
*same_count_as, /* Parallel attribute name */
*if_defined, /* Only required if variable defined */
*if_not_defined, /* Only required if variable is not defined */
*with_value, /* Attribute must include this value */
+ *with_value_from, /* Attribute must have one of the values in this attribute */
*define_match, /* Variable to define on match */
*define_no_match, /* Variable to define on no-match */
*define_value; /* Variable to define with value */
IgnoreErrors = 0, /* Ignore errors? */
StopAfterIncludeError = 0,
/* Stop after include errors? */
- Verbosity = 0, /* Show all attributes? */
+ ValidateHeaders = 0, /* Validate HTTP headers in response? */
+ Verbosity = 0, /* Show all attributes? */
Version = 11, /* Default IPP version */
XMLHeader = 0, /* 1 if header is written */
TestCount = 0, /* Number of tests run */
* Local functions...
*/
-static void add_stringf(cups_array_t *a, const char *s, ...)
- __attribute__ ((__format__ (__printf__, 2, 3)));
+static void add_stringf(cups_array_t *a, const char *s, ...) __attribute__ ((__format__ (__printf__, 2, 3)));
+static int compare_uris(const char *a, const char *b);
static int compare_vars(_cups_var_t *a, _cups_var_t *b);
-static int do_tests(FILE *outfile, _cups_vars_t *vars, const char *testfile);
-static void expand_variables(_cups_vars_t *vars, char *dst, const char *src,
- size_t dstsize) __attribute__((nonnull(1,2,3)));
+static int do_tests(cups_file_t *outfile, _cups_vars_t *vars, const char *testfile);
+static void expand_variables(_cups_vars_t *vars, char *dst, const char *src, size_t dstsize) __attribute__((nonnull(1,2,3)));
static int expect_matches(_cups_expect_t *expect, ipp_tag_t value_tag);
-static ipp_t *get_collection(FILE *outfile, _cups_vars_t *vars, FILE *fp, int *linenum);
-static char *get_filename(const char *testfile, char *dst, const char *src,
- size_t dstsize);
-static char *get_string(ipp_attribute_t *attr, int element, int flags,
- char *buffer, size_t bufsize);
-static char *get_token(FILE *fp, char *buf, int buflen,
- int *linenum);
+static ipp_t *get_collection(cups_file_t *outfile, _cups_vars_t *vars, cups_file_t *fp, int *linenum);
+static char *get_filename(const char *testfile, char *dst, const char *src, size_t dstsize);
+static const char *get_string(ipp_attribute_t *attr, int element, int flags, char *buffer, size_t bufsize);
+static char *get_token(cups_file_t *fp, char *buf, int buflen, int *linenum);
static char *get_variable(_cups_vars_t *vars, const char *name);
-static char *iso_date(ipp_uchar_t *date);
+static char *iso_date(const ipp_uchar_t *date);
static const char *password_cb(const char *prompt);
static void pause_message(const char *message);
-static void print_attr(FILE *outfile, int format, ipp_attribute_t *attr, ipp_tag_t *group);
-static void print_csv(FILE *outfile, ipp_attribute_t *attr, int num_displayed,
- char **displayed, size_t *widths);
-static void print_fatal_error(FILE *outfile, const char *s, ...)
- __attribute__ ((__format__ (__printf__, 2, 3)));
-static void print_line(FILE *outfile, ipp_attribute_t *attr, int num_displayed,
- char **displayed, size_t *widths);
-static void print_xml_header(FILE *outfile);
-static void print_xml_string(FILE *outfile, const char *element, const char *s);
-static void print_xml_trailer(FILE *outfile, int success, const char *message);
-static void set_variable(FILE *outfile, _cups_vars_t *vars, const char *name, const char *value);
+static void print_attr(cups_file_t *outfile, int format, ipp_attribute_t *attr, ipp_tag_t *group);
+static void print_csv(cups_file_t *outfile, ipp_attribute_t *attr, int num_displayed, char **displayed, size_t *widths);
+static void print_fatal_error(cups_file_t *outfile, const char *s, ...) __attribute__ ((__format__ (__printf__, 2, 3)));
+static void print_ippserver_attr(cups_file_t *outfile, ipp_attribute_t *attr, int indent);
+static void print_ippserver_string(cups_file_t *outfile, const char *s, size_t len);
+static void print_line(cups_file_t *outfile, ipp_attribute_t *attr, int num_displayed, char **displayed, size_t *widths);
+static void print_xml_header(cups_file_t *outfile);
+static void print_xml_string(cups_file_t *outfile, const char *element, const char *s);
+static void print_xml_trailer(cups_file_t *outfile, int success, const char *message);
+static void set_variable(cups_file_t *outfile, _cups_vars_t *vars, const char *name, const char *value);
#ifndef WIN32
static void sigterm_handler(int sig);
#endif /* WIN32 */
static int timeout_cb(http_t *http, void *user_data);
static void usage(void) __attribute__((noreturn));
-static int validate_attr(FILE *outfile, cups_array_t *errors, ipp_attribute_t *attr);
-static int with_value(FILE *outfile, cups_array_t *errors, char *value, int flags,
- ipp_attribute_t *attr, char *matchbuf,
- size_t matchlen);
+static int validate_attr(cups_file_t *outfile, cups_array_t *errors, ipp_attribute_t *attr);
+static const char *with_flags_string(int flags);
+static int with_value(cups_file_t *outfile, cups_array_t *errors, char *value, int flags, ipp_attribute_t *attr, char *matchbuf, size_t matchlen);
+static int with_value_from(cups_array_t *errors, ipp_attribute_t *fromattr, ipp_attribute_t *attr, char *matchbuf, size_t matchlen);
/*
{
int i; /* Looping var */
int status; /* Status of tests... */
- FILE *outfile = stdout;
- /* Output file */
+ cups_file_t *outfile = cupsFileStdout();
+ /* Output file */
char *opt, /* Current option */
name[1024], /* Name/value buffer */
*value, /* Pointer to value */
{
usage();
}
+ else if (!strcmp(argv[i], "--ippserver"))
+ {
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPuts(stderr, _("ipptool: Missing filename for \"--ippserver\"."));
+ usage();
+ }
+
+ if (outfile != cupsFileStdout())
+ usage();
+
+ if ((outfile = cupsFileOpen(argv[i], "w")) == NULL)
+ {
+ _cupsLangPrintf(stderr, _("%s: Unable to open \"%s\": %s"), "ipptool", argv[i], strerror(errno));
+ exit(1);
+ }
+
+ Output = _CUPS_OUTPUT_IPPSERVER;
+ }
else if (!strcmp(argv[i], "--stop-after-include-error"))
{
StopAfterIncludeError = 1;
usage();
}
- if (outfile != stdout)
+ if (outfile != cupsFileStdout())
usage();
- if ((outfile = fopen(argv[i], "w")) == NULL)
+ if ((outfile = cupsFileOpen(argv[i], "w")) == NULL)
{
_cupsLangPrintf(stderr, _("%s: Unable to open \"%s\": %s"), "ipptool", argv[i], strerror(errno));
exit(1);
}
break;
+ case 'h' : /* Validate response headers */
+ ValidateHeaders = 1;
+ break;
+
case 'i' : /* Test every N seconds */
i ++;
}
}
- if (Output == _CUPS_OUTPUT_PLIST && interval)
+ if ((Output == _CUPS_OUTPUT_PLIST || Output == _CUPS_OUTPUT_IPPSERVER) && interval)
{
- _cupsLangPuts(stderr, _("ipptool: \"-i\" and \"-n\" are incompatible with \"-P\" and \"-X\"."));
+ _cupsLangPuts(stderr, _("ipptool: \"-i\" and \"-n\" are incompatible with \"--ippserver\", \"-P\", and \"-X\"."));
usage();
}
break;
else
repeat = atoi(argv[i]);
- if (Output == _CUPS_OUTPUT_PLIST && repeat)
+ if ((Output == _CUPS_OUTPUT_PLIST || Output == _CUPS_OUTPUT_IPPSERVER) && repeat)
{
- _cupsLangPuts(stderr, _("ipptool: \"-i\" and \"-n\" are incompatible with \"-P\" and \"-X\"."));
+ _cupsLangPuts(stderr, _("ipptool: \"-i\" and \"-n\" are incompatible with \"--ippserver\", \"-P\", and \"-X\"."));
usage();
}
break;
* Show a summary report if there were multiple tests...
*/
- printf("\nSummary: %d tests, %d passed, %d failed, %d skipped\n"
- "Score: %d%%\n", TestCount, PassCount, FailCount, SkipCount,
- 100 * (PassCount + SkipCount) / TestCount);
+ cupsFilePrintf(cupsFileStdout(), "\nSummary: %d tests, %d passed, %d failed, %d skipped\nScore: %d%%\n", TestCount, PassCount, FailCount, SkipCount, 100 * (PassCount + SkipCount) / TestCount);
}
- /*
+ cupsFileClose(outfile);
+
+/*
* Exit...
*/
}
+/*
+ * 'compare_uris()' - Compare two URIs...
+ */
+
+static int /* O - Result of comparison */
+compare_uris(const char *a, /* I - First URI */
+ const char *b) /* I - Second URI */
+{
+ char ascheme[32], /* Components of first URI */
+ auserpass[256],
+ ahost[256],
+ aresource[256];
+ int aport;
+ char bscheme[32], /* Components of second URI */
+ buserpass[256],
+ bhost[256],
+ bresource[256];
+ int bport;
+ char *ptr; /* Pointer into string */
+ int result; /* Result of comparison */
+
+
+ /*
+ * Separate the URIs into their components...
+ */
+
+ if (httpSeparateURI(HTTP_URI_CODING_ALL, a, ascheme, sizeof(ascheme), auserpass, sizeof(auserpass), ahost, sizeof(ahost), &aport, aresource, sizeof(aresource)) < HTTP_URI_STATUS_OK)
+ return (-1);
+
+ if (httpSeparateURI(HTTP_URI_CODING_ALL, b, bscheme, sizeof(bscheme), buserpass, sizeof(buserpass), bhost, sizeof(bhost), &bport, bresource, sizeof(bresource)) < HTTP_URI_STATUS_OK)
+ return (-1);
+
+ /*
+ * Strip trailing dots from the host components, if present...
+ */
+
+ if ((ptr = ahost + strlen(ahost) - 1) > ahost && *ptr == '.')
+ *ptr = '\0';
+
+ if ((ptr = bhost + strlen(bhost) - 1) > bhost && *ptr == '.')
+ *ptr = '\0';
+
+ /*
+ * Compare each component...
+ */
+
+ if ((result = _cups_strcasecmp(ascheme, bscheme)) != 0)
+ return (result);
+
+ if ((result = strcmp(auserpass, buserpass)) != 0)
+ return (result);
+
+ if ((result = _cups_strcasecmp(ahost, bhost)) != 0)
+ return (result);
+
+ if (aport != bport)
+ return (aport - bport);
+
+ if (!_cups_strcasecmp(ascheme, "mailto") || !_cups_strcasecmp(ascheme, "urn"))
+ return (_cups_strcasecmp(aresource, bresource));
+ else
+ return (strcmp(aresource, bresource));
+}
+
+
/*
* 'compare_vars()' - Compare two variables.
*/
*/
static int /* 1 = success, 0 = failure */
-do_tests(FILE *outfile, /* I - Output file */
+do_tests(cups_file_t *outfile, /* I - Output file */
_cups_vars_t *vars, /* I - Variables */
const char *testfile) /* I - Test file to use */
{
ignore_errors, /* Ignore test failures? */
skip_previous = 0, /* Skip on previous test failure? */
repeat_count, /* Repeat count */
- repeat_interval, /* Repeat interval */
- repeat_prev, /* Previous repeat interval */
repeat_test; /* Repeat a test? */
+ useconds_t delay, /* Initial delay */
+ repeat_interval; /* Repeat interval (delay) */
http_t *http = NULL; /* HTTP connection to server */
- FILE *fp = NULL; /* Test file */
+ cups_file_t *fp = NULL; /* Test file */
char resource[512], /* Resource for request */
token[1024], /* Token from file */
*tokenptr, /* Pointer into token */
temp[1024], /* Temporary string */
- buffer[8192], /* Copy buffer */
+ buffer[131072], /* Copy buffer */
compression[16]; /* COMPRESSION value */
ipp_t *request = NULL, /* IPP request */
*response = NULL; /* IPP response */
int num_statuses = 0; /* Number of valid status codes */
_cups_status_t statuses[100], /* Valid status codes */
*last_status; /* Last STATUS (for predicates) */
- int num_expects = 0; /* Number of expected attributes */
+ int status_ok, /* Did we get a matching status? */
+ num_expects = 0; /* Number of expected attributes */
_cups_expect_t expects[200], /* Expected attributes */
*expect, /* Current expected attribute */
*last_expect; /* Last EXPECT (for predicates) */
* Open the test file...
*/
- if ((fp = fopen(testfile, "r")) == NULL)
+ if ((fp = cupsFileOpen(testfile, "r")) == NULL)
{
print_fatal_error(outfile, "Unable to open test file %s - %s", testfile,
strerror(errno));
* Loop on tests...
*/
- CUPS_SRAND(time(NULL));
+ CUPS_SRAND((unsigned)time(NULL));
errors = cupsArrayNew3(NULL, NULL, NULL, 0, (cups_acopy_func_t)strdup,
(cups_afree_func_t)free);
file_id[0] = '\0';
pass = 1;
- linenum = 1;
+ linenum = 0;
request_id = (CUPS_RAND() % 1000) * 137 + 1;
while (!Cancel && get_token(fp, token, sizeof(token), &linenum) != NULL)
{
if (Output == _CUPS_OUTPUT_PLIST)
print_xml_header(outfile);
- if (Output == _CUPS_OUTPUT_TEST || (Output == _CUPS_OUTPUT_PLIST && outfile != stdout))
- printf("\"%s\":\n", testfile);
+ if (Output == _CUPS_OUTPUT_TEST || (Output == _CUPS_OUTPUT_PLIST && outfile != cupsFileStdout()))
+ cupsFilePrintf(cupsFileStdout(), "\"%s\":\n", testfile);
show_header = 0;
}
strlcpy(resource, vars->resource, sizeof(resource));
request_id ++;
- request = ippNew();
- op = (ipp_op_t)0;
- group = IPP_TAG_ZERO;
- ignore_errors = IgnoreErrors;
- last_expect = NULL;
- last_status = NULL;
- filename[0] = '\0';
- skip_previous = 0;
- skip_test = 0;
- test_id[0] = '\0';
- version = Version;
- transfer = Transfer;
- compression[0] = '\0';
+ request = ippNew();
+ op = (ipp_op_t)0;
+ group = IPP_TAG_ZERO;
+ ignore_errors = IgnoreErrors;
+ last_expect = NULL;
+ last_status = NULL;
+ filename[0] = '\0';
+ skip_previous = 0;
+ skip_test = 0;
+ test_id[0] = '\0';
+ version = Version;
+ transfer = Transfer;
+ compression[0] = '\0';
+ delay = 0;
+ repeat_count = 0;
+ repeat_interval = 5000000;
strlcpy(name, testfile, sizeof(name));
if (strrchr(name, '.') != NULL)
_cups_strcasecmp(token, "WITH-HOSTNAME") &&
_cups_strcasecmp(token, "WITH-RESOURCE") &&
_cups_strcasecmp(token, "WITH-SCHEME") &&
- _cups_strcasecmp(token, "WITH-VALUE"))
+ _cups_strcasecmp(token, "WITH-VALUE") &&
+ _cups_strcasecmp(token, "WITH-VALUE-FROM"))
last_expect = NULL;
if (_cups_strcasecmp(token, "DEFINE-MATCH") &&
goto test_exit;
}
- if ((value = ippTagValue(token)) < 0)
+ if ((value = ippTagValue(token)) == IPP_TAG_ZERO || value >= IPP_TAG_UNSUPPORTED_VALUE)
{
print_fatal_error(outfile, "Bad GROUP tag \"%s\" on line %d.", token, linenum);
pass = 0;
* Delay before operation...
*/
- double delay;
+ double dval; /* Delay value */
if (!get_token(fp, temp, sizeof(temp), &linenum))
{
expand_variables(vars, token, temp, sizeof(token));
- if ((delay = _cupsStrScand(token, NULL, localeconv())) <= 0.0)
+ if ((dval = _cupsStrScand(token, &tokenptr, localeconv())) < 0.0 || (*tokenptr && *tokenptr != ','))
{
print_fatal_error(outfile, "Bad DELAY value \"%s\" on line %d.", token,
linenum);
pass = 0;
goto test_exit;
}
- else
- {
- if (Output == _CUPS_OUTPUT_TEST)
- printf(" [%g second delay]\n", delay);
- usleep((useconds_t)(1000000.0 * delay));
- }
+ delay = (useconds_t)(1000000.0 * dval);
+
+ if (*tokenptr == ',')
+ {
+ if ((dval = _cupsStrScand(tokenptr + 1, &tokenptr, localeconv())) <= 0.0 || *tokenptr)
+ {
+ print_fatal_error(outfile, "Bad DELAY value \"%s\" on line %d.", token,
+ linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ repeat_interval = (useconds_t)(1000000.0 * dval);
+ }
+ else
+ repeat_interval = delay;
}
else if (!_cups_strcasecmp(token, "ATTR"))
{
goto test_exit;
}
- if ((value = ippTagValue(token)) == IPP_TAG_ZERO)
+ if ((value = ippTagValue(token)) < IPP_TAG_UNSUPPORTED_VALUE)
{
print_fatal_error(outfile, "Bad ATTR value tag \"%s\" on line %d.", token,
linenum);
goto test_exit;
}
- if (!get_token(fp, temp, sizeof(temp), &linenum))
+ if (value < IPP_TAG_INTEGER)
+ {
+ /*
+ * Add out-of-band value - no value string needed...
+ */
+
+ token[0] = '\0';
+ }
+ else if (!get_token(fp, temp, sizeof(temp), &linenum))
{
print_fatal_error(outfile, "Missing ATTR value on line %d.", linenum);
pass = 0;
goto test_exit;
}
+ else
+ {
+ expand_variables(vars, token, temp, sizeof(token));
+ }
- expand_variables(vars, token, temp, sizeof(token));
attrptr = NULL;
switch (value)
{
+ default :
+ if (value < IPP_TAG_INTEGER)
+ {
+ /*
+ * Add out-of-band value...
+ */
+
+ attrptr = ippAddOutOfBand(request, group, value, attr);
+ }
+ else
+ {
+ print_fatal_error(outfile, "Unsupported ATTR value tag %s for \"%s\" on line %d.", ippTagString(value), attr, linenum);
+ pass = 0;
+ goto test_exit;
+ }
+ break;
+
case IPP_TAG_BOOLEAN :
if (!_cups_strcasecmp(token, "true"))
attrptr = ippAddBoolean(request, group, attr, 1);
case IPP_TAG_INTEGER :
case IPP_TAG_ENUM :
if (!strchr(token, ','))
- attrptr = ippAddInteger(request, group, value, attr, (int)strtol(token, &tokenptr, 0));
+ {
+ if (isdigit(token[0] & 255) || token[0] == '-')
+ attrptr = ippAddInteger(request, group, value, attr, (int)strtol(token, &tokenptr, 0));
+ else
+ {
+ tokenptr = token;
+ if ((i = ippEnumValue(attr, tokenptr)) >= 0)
+ {
+ attrptr = ippAddInteger(request, group, value, attr, i);
+ tokenptr += strlen(tokenptr);
+ }
+ }
+ }
else
{
int values[100], /* Values */
num_values = 1; /* Number of values */
- values[0] = (int)strtol(token, &tokenptr, 10);
+ if (!isdigit(token[0] & 255) && token[0] != '-' && value == IPP_TAG_ENUM)
+ {
+ char *ptr; /* Pointer to next terminator */
+
+ if ((ptr = strchr(token, ',')) != NULL)
+ *ptr++ = '\0';
+ else
+ ptr = token + strlen(token);
+
+ if ((i = ippEnumValue(attr, token)) < 0)
+ tokenptr = NULL;
+ else
+ tokenptr = ptr;
+ }
+ else
+ i = (int)strtol(token, &tokenptr, 0);
+
+ values[0] = i;
+
while (tokenptr && *tokenptr &&
num_values < (int)(sizeof(values) / sizeof(values[0])))
{
if (*tokenptr == ',')
tokenptr ++;
- else if (!isdigit(*tokenptr & 255) && *tokenptr != '-')
- break;
- values[num_values] = (int)strtol(tokenptr, &tokenptr, 0);
- num_values ++;
+ if (!isdigit(*tokenptr & 255) && *tokenptr != '-')
+ {
+ char *ptr; /* Pointer to next terminator */
+
+ if (value != IPP_TAG_ENUM)
+ break;
+
+ if ((ptr = strchr(tokenptr, ',')) != NULL)
+ *ptr++ = '\0';
+ else
+ ptr = tokenptr + strlen(tokenptr);
+
+ if ((i = ippEnumValue(attr, tokenptr)) < 0)
+ break;
+
+ tokenptr = ptr;
+ }
+ else
+ i = (int)strtol(tokenptr, &tokenptr, 0);
+
+ values[num_values ++] = i;
}
attrptr = ippAddIntegers(request, group, value, attr, num_values, values);
}
- if (!tokenptr || *tokenptr)
+ if ((!token[0] || !tokenptr || *tokenptr) && !skip_test)
{
- print_fatal_error(outfile, "Bad %s value \"%s\" on line %d.",
- ippTagString(value), token, linenum);
+ print_fatal_error(outfile, "Bad %s value \'%s\' for \"%s\" on line %d.",
+ ippTagString(value), token, attr, linenum);
pass = 0;
goto test_exit;
}
_cups_strcasecmp(ptr, "dpcm") &&
_cups_strcasecmp(ptr, "other")))
{
- print_fatal_error(outfile, "Bad resolution value \"%s\" on line %d.",
- token, linenum);
+ if (skip_test)
+ break;
+
+ print_fatal_error(outfile, "Bad resolution value \'%s\' for \"%s\" on line %d.", token, attr, linenum);
pass = 0;
goto test_exit;
}
if ((num_vals & 1) || num_vals == 0)
{
- print_fatal_error(outfile, "Bad rangeOfInteger value \"%s\" on line "
- "%d.", token, linenum);
+ if (skip_test)
+ break;
+
+ print_fatal_error(outfile, "Bad rangeOfInteger value \'%s\' for \"%s\" on line %d.", token, attr, linenum);
pass = 0;
goto test_exit;
}
goto test_exit;
}
}
+ else if (skip_test)
+ break;
else
{
- print_fatal_error(outfile, "Bad ATTR collection value on line %d.",
- linenum);
+ print_fatal_error(outfile, "Bad ATTR collection value for \"%s\" on line %d.", attr, linenum);
pass = 0;
goto test_exit;
}
do
{
- ipp_t *col; /* Collection value */
- long pos = ftell(fp); /* Save position of file */
+ ipp_t *col; /* Collection value */
+ off_t savepos = cupsFileTell(fp); /* Save position of file */
+ int savelinenum = linenum; /* Save line number */
if (!get_token(fp, token, sizeof(token), &linenum))
break;
if (strcmp(token, ","))
{
- fseek(fp, pos, SEEK_SET);
+ cupsFileSeek(fp, savepos);
+ linenum = savelinenum;
break;
}
attrptr = ippAddOctetString(request, group, attr, token, (int)strlen(token));
break;
- default :
- print_fatal_error(outfile, "Unsupported ATTR value tag %s on line %d.",
- ippTagString(value), linenum);
- pass = 0;
- goto test_exit;
-
case IPP_TAG_TEXTLANG :
case IPP_TAG_NAMELANG :
case IPP_TAG_TEXT :
break;
}
- if (!attrptr)
+ if (!attrptr && !skip_test)
{
- print_fatal_error(outfile, "Unable to add attribute on line %d: %s", linenum,
- cupsLastErrorString());
+ print_fatal_error(outfile, "Unable to add attribute \"%s\" on line %d.", attr, linenum);
pass = 0;
goto test_exit;
}
last_status->repeat_match = 0;
last_status->repeat_no_match = 0;
}
- else if (!_cups_strcasecmp(token, "EXPECT"))
+ else if (!_cups_strcasecmp(token, "EXPECT") || !_cups_strcasecmp(token, "EXPECT-ALL"))
{
/*
* Expected attributes...
*/
+ int expect_all = !_cups_strcasecmp(token, "EXPECT-ALL");
+
if (num_expects >= (int)(sizeof(expects) / sizeof(expects[0])))
{
print_fatal_error(outfile, "Too many EXPECT's on line %d.", linenum);
memset(last_expect, 0, sizeof(_cups_expect_t));
last_expect->repeat_limit = 1000;
+ last_expect->expect_all = expect_all;
if (token[0] == '!')
{
goto test_exit;
}
- if ((in_group = ippTagValue(token)) == (ipp_tag_t)-1)
+ if ((in_group = ippTagValue(token)) == IPP_TAG_ZERO || in_group >= IPP_TAG_UNSUPPORTED_VALUE)
{
+ print_fatal_error(outfile, "Bad IN-GROUP group tag \"%s\" on line %d.", token, linenum);
+ pass = 0;
+ goto test_exit;
}
else if (last_expect)
last_expect->in_group = in_group;
else
{
- print_fatal_error(outfile, "IN-GROUP without a preceding EXPECT on line %d.",
- linenum);
+ print_fatal_error(outfile, "IN-GROUP without a preceding EXPECT on line %d.", linenum);
pass = 0;
goto test_exit;
}
last_expect->repeat_limit = atoi(token);
else
{
- print_fatal_error(outfile, "REPEAT-LIMIT without a preceding EXPECT or STATUS "
- "on line %d.", linenum);
+ print_fatal_error(outfile, "REPEAT-LIMIT without a preceding EXPECT or STATUS on line %d.", linenum);
pass = 0;
goto test_exit;
}
last_expect->repeat_match = 1;
else
{
- print_fatal_error(outfile, "REPEAT-MATCH without a preceding EXPECT or STATUS "
- "on line %d.", linenum);
+ print_fatal_error(outfile, "REPEAT-MATCH without a preceding EXPECT or STATUS on line %d.", linenum);
pass = 0;
goto test_exit;
}
last_expect->repeat_no_match = 1;
else
{
- print_fatal_error(outfile, "REPEAT-NO-MATCH without a preceding EXPECT or "
- "STATUS on ine %d.", linenum);
+ print_fatal_error(outfile, "REPEAT-NO-MATCH without a preceding EXPECT or STATUS on ine %d.", linenum);
pass = 0;
goto test_exit;
}
last_status->if_defined = strdup(token);
else
{
- print_fatal_error(outfile, "IF-DEFINED without a preceding EXPECT or STATUS "
- "on line %d.", linenum);
+ print_fatal_error(outfile, "IF-DEFINED without a preceding EXPECT or STATUS on line %d.", linenum);
pass = 0;
goto test_exit;
}
last_status->if_not_defined = strdup(token);
else
{
- print_fatal_error(outfile, "IF-NOT-DEFINED without a preceding EXPECT or STATUS "
- "on line %d.", linenum);
+ print_fatal_error(outfile, "IF-NOT-DEFINED without a preceding EXPECT or STATUS on line %d.", linenum);
pass = 0;
goto test_exit;
}
}
else
{
- print_fatal_error(outfile, "%s without a preceding EXPECT on line %d.", token,
- linenum);
+ print_fatal_error(outfile, "%s without a preceding EXPECT on line %d.", token, linenum);
+ pass = 0;
+ goto test_exit;
+ }
+ }
+ else if (!_cups_strcasecmp(token, "WITH-VALUE-FROM"))
+ {
+ if (!get_token(fp, temp, sizeof(temp), &linenum))
+ {
+ print_fatal_error(outfile, "Missing %s value on line %d.", token, linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ if (last_expect)
+ {
+ /*
+ * Expand any variables in the value and then save it.
+ */
+
+ expand_variables(vars, token, temp, sizeof(token));
+
+ last_expect->with_value_from = strdup(token);
+ last_expect->with_flags = _CUPS_WITH_LITERAL;
+ }
+ else
+ {
+ print_fatal_error(outfile, "%s without a preceding EXPECT on line %d.", token, linenum);
pass = 0;
goto test_exit;
}
}
else
{
- print_fatal_error(outfile, "Unexpected token %s seen on line %d.", token,
- linenum);
+ print_fatal_error(outfile, "Unexpected token %s seen on line %d.", token, linenum);
pass = 0;
goto test_exit;
}
if (Output == _CUPS_OUTPUT_PLIST)
{
- fputs("<dict>\n", outfile);
- fputs("<key>Name</key>\n", outfile);
+ cupsFilePuts(outfile, "<dict>\n");
+ cupsFilePuts(outfile, "<key>Name</key>\n");
print_xml_string(outfile, "string", name);
if (file_id[0])
{
- fputs("<key>FileId</key>\n", outfile);
+ cupsFilePuts(outfile, "<key>FileId</key>\n");
print_xml_string(outfile, "string", file_id);
}
if (test_id[0])
{
- fputs("<key>TestId</key>\n", outfile);
+ cupsFilePuts(outfile, "<key>TestId</key>\n");
print_xml_string(outfile, "string", test_id);
}
- fputs("<key>Version</key>\n", outfile);
- fprintf(outfile, "<string>%d.%d</string>\n", version / 10, version % 10);
- fputs("<key>Operation</key>\n", outfile);
+ cupsFilePuts(outfile, "<key>Version</key>\n");
+ cupsFilePrintf(outfile, "<string>%d.%d</string>\n", version / 10, version % 10);
+ cupsFilePuts(outfile, "<key>Operation</key>\n");
print_xml_string(outfile, "string", ippOpString(op));
- fputs("<key>RequestId</key>\n", outfile);
- fprintf(outfile, "<integer>%d</integer>\n", request_id);
- fputs("<key>RequestAttributes</key>\n", outfile);
- fputs("<array>\n", outfile);
+ cupsFilePuts(outfile, "<key>RequestId</key>\n");
+ cupsFilePrintf(outfile, "<integer>%d</integer>\n", request_id);
+ cupsFilePuts(outfile, "<key>RequestAttributes</key>\n");
+ cupsFilePuts(outfile, "<array>\n");
if (request->attrs)
{
- fputs("<dict>\n", outfile);
+ cupsFilePuts(outfile, "<dict>\n");
for (attrptr = request->attrs,
group = attrptr ? attrptr->group_tag : IPP_TAG_ZERO;
attrptr;
attrptr = attrptr->next)
print_attr(outfile, Output, attrptr, &group);
- fputs("</dict>\n", outfile);
+ cupsFilePuts(outfile, "</dict>\n");
}
- fputs("</array>\n", outfile);
+ cupsFilePuts(outfile, "</array>\n");
}
- if (Output == _CUPS_OUTPUT_TEST || (Output == _CUPS_OUTPUT_PLIST && outfile != stdout))
+ if (Output == _CUPS_OUTPUT_TEST || (Output == _CUPS_OUTPUT_PLIST && outfile != cupsFileStdout()))
{
if (Verbosity)
{
- printf(" %s:\n", ippOpString(op));
+ cupsFilePrintf(cupsFileStdout(), " %s:\n", ippOpString(op));
for (attrptr = request->attrs; attrptr; attrptr = attrptr->next)
- print_attr(stdout, _CUPS_OUTPUT_TEST, attrptr, NULL);
+ print_attr(cupsFileStdout(), _CUPS_OUTPUT_TEST, attrptr, NULL);
}
- printf(" %-68.68s [", name);
- fflush(stdout);
+ cupsFilePrintf(cupsFileStdout(), " %-68.68s [", name);
}
if ((skip_previous && !prev_pass) || skip_test)
if (Output == _CUPS_OUTPUT_PLIST)
{
- fputs("<key>Successful</key>\n", outfile);
- fputs("<true />\n", outfile);
- fputs("<key>Skipped</key>\n", outfile);
- fputs("<true />\n", outfile);
- fputs("<key>StatusCode</key>\n", outfile);
+ cupsFilePuts(outfile, "<key>Successful</key>\n");
+ cupsFilePuts(outfile, "<true />\n");
+ cupsFilePuts(outfile, "<key>Skipped</key>\n");
+ cupsFilePuts(outfile, "<true />\n");
+ cupsFilePuts(outfile, "<key>StatusCode</key>\n");
print_xml_string(outfile, "string", "skip");
- fputs("<key>ResponseAttributes</key>\n", outfile);
- fputs("<dict />\n", outfile);
+ cupsFilePuts(outfile, "<key>ResponseAttributes</key>\n");
+ cupsFilePuts(outfile, "<dict />\n");
}
- if (Output == _CUPS_OUTPUT_TEST || (Output == _CUPS_OUTPUT_PLIST && outfile != stdout))
- puts("SKIP]");
+ if (Output == _CUPS_OUTPUT_TEST || (Output == _CUPS_OUTPUT_PLIST && outfile != cupsFileStdout()))
+ cupsFilePuts(cupsFileStdout(), "SKIP]\n");
goto skip_error;
}
PasswordTries = 0;
- repeat_count = 0;
- repeat_interval = 1;
- repeat_prev = 1;
do
{
+ if (delay > 0)
+ usleep(delay);
+
+ delay = repeat_interval;
repeat_count ++;
status = HTTP_STATUS_OK;
http->error != ETIMEDOUT)
#endif /* WIN32 */
{
- if (httpReconnect(http))
+ if (httpReconnect2(http, 30000, NULL))
prev_pass = 0;
}
else if (status == HTTP_STATUS_ERROR || status == HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED)
http->error != ETIMEDOUT)
#endif /* WIN32 */
{
- if (httpReconnect(http))
+ if (httpReconnect2(http, 30000, NULL))
prev_pass = 0;
}
else if (status == HTTP_STATUS_ERROR)
{
if (!Cancel)
- httpReconnect(http);
+ httpReconnect2(http, 30000, NULL);
prev_pass = 0;
}
add_stringf(errors, "Bad HTTP version (%d.%d)", http->version / 100,
http->version % 100);
+ if (ValidateHeaders)
+ {
+ const char *header; /* HTTP header value */
+
+ if ((header = httpGetField(http, HTTP_FIELD_CONTENT_TYPE)) == NULL || _cups_strcasecmp(header, "application/ipp"))
+ add_stringf(errors, "Bad HTTP Content-Type in response (%s)", header && *header ? header : "<missing>");
+
+ if ((header = httpGetField(http, HTTP_FIELD_DATE)) != NULL && *header && httpGetDateTime(header) == 0)
+ add_stringf(errors, "Bad HTTP Date in response (%s)", header);
+ }
+
if (!response)
{
/*
* values...
*/
- for (i = 0; i < num_statuses; i ++)
+ for (i = 0, status_ok = 0; i < num_statuses; i ++)
{
if (statuses[i].if_defined &&
!get_variable(vars, statuses[i].if_defined))
get_variable(vars, statuses[i].if_not_defined))
continue;
- if (response->request.status.status_code == statuses[i].status)
+ if (ippGetStatusCode(response) == statuses[i].status)
{
- if (statuses[i].repeat_match &&
- repeat_count < statuses[i].repeat_limit)
- repeat_test = 1;
+ status_ok = 1;
+
+ if (statuses[i].repeat_match && repeat_count < statuses[i].repeat_limit)
+ repeat_test = 1;
if (statuses[i].define_match)
set_variable(outfile, vars, statuses[i].define_match, "1");
-
- break;
}
else
{
- if (statuses[i].repeat_no_match &&
- repeat_count < statuses[i].repeat_limit)
- repeat_test = 1;
+ if (statuses[i].repeat_no_match && repeat_count < statuses[i].repeat_limit)
+ repeat_test = 1;
if (statuses[i].define_no_match)
{
set_variable(outfile, vars, statuses[i].define_no_match, "1");
- break;
+ status_ok = 1;
}
}
}
- if (i == num_statuses && num_statuses > 0)
+ if (!status_ok && num_statuses > 0)
{
for (i = 0; i < num_statuses; i ++)
{
get_variable(vars, statuses[i].if_not_defined))
continue;
- if (!statuses[i].repeat_match)
+ if (!statuses[i].repeat_match || repeat_count >= statuses[i].repeat_limit)
add_stringf(errors, "EXPECTED: STATUS %s (got %s)",
ippErrorString(statuses[i].status),
ippErrorString(cupsLastError()));
get_variable(vars, expect->if_not_defined))
continue;
- found = ippFindAttribute(response, expect->name, IPP_TAG_ZERO);
+ found = ippFindAttribute(response, expect->name, IPP_TAG_ZERO);
- if ((found && expect->not_expect) ||
- (!found && !(expect->not_expect || expect->optional)) ||
- (found && !expect_matches(expect, found->value_tag)) ||
- (found && expect->in_group &&
- found->group_tag != expect->in_group))
- {
- if (expect->define_no_match)
- set_variable(outfile, vars, expect->define_no_match, "1");
- else if (!expect->define_match && !expect->define_value)
+ do
+ {
+ if ((found && expect->not_expect) ||
+ (!found && !(expect->not_expect || expect->optional)) ||
+ (found && !expect_matches(expect, found->value_tag)) ||
+ (found && expect->in_group &&
+ found->group_tag != expect->in_group))
{
- if (found && expect->not_expect)
- add_stringf(errors, "NOT EXPECTED: %s", expect->name);
- else if (!found && !(expect->not_expect || expect->optional))
- add_stringf(errors, "EXPECTED: %s", expect->name);
- else if (found)
+ if (expect->define_no_match)
+ set_variable(outfile, vars, expect->define_no_match, "1");
+ else if (!expect->define_match && !expect->define_value)
{
- if (!expect_matches(expect, found->value_tag))
- add_stringf(errors, "EXPECTED: %s OF-TYPE %s (got %s)",
- expect->name, expect->of_type,
- ippTagString(found->value_tag));
-
- if (expect->in_group && found->group_tag != expect->in_group)
- add_stringf(errors, "EXPECTED: %s IN-GROUP %s (got %s).",
- expect->name, ippTagString(expect->in_group),
- ippTagString(found->group_tag));
- }
- }
+ if (found && expect->not_expect)
+ add_stringf(errors, "NOT EXPECTED: %s", expect->name);
+ else if (!found && !(expect->not_expect || expect->optional))
+ add_stringf(errors, "EXPECTED: %s", expect->name);
+ else if (found)
+ {
+ if (!expect_matches(expect, found->value_tag))
+ add_stringf(errors, "EXPECTED: %s OF-TYPE %s (got %s)",
+ expect->name, expect->of_type,
+ ippTagString(found->value_tag));
+
+ if (expect->in_group && found->group_tag != expect->in_group)
+ add_stringf(errors, "EXPECTED: %s IN-GROUP %s (got %s).",
+ expect->name, ippTagString(expect->in_group),
+ ippTagString(found->group_tag));
+ }
+ }
- if (expect->repeat_no_match &&
- repeat_count < expect->repeat_limit)
- repeat_test = 1;
+ if (expect->repeat_no_match && repeat_count < expect->repeat_limit)
+ repeat_test = 1;
- continue;
- }
+ break;
+ }
- if (found)
- ippAttributeString(found, buffer, sizeof(buffer));
+ if (found)
+ ippAttributeString(found, buffer, sizeof(buffer));
- if (found &&
- !with_value(outfile, NULL, expect->with_value, expect->with_flags, found,
- buffer, sizeof(buffer)))
- {
- if (expect->define_no_match)
- set_variable(outfile, vars, expect->define_no_match, "1");
- else if (!expect->define_match && !expect->define_value &&
- !expect->repeat_match && !expect->repeat_no_match)
+ if (found && expect->with_value_from && !with_value_from(NULL, ippFindAttribute(response, expect->with_value_from, IPP_TAG_ZERO), found, buffer, sizeof(buffer)))
{
- if (expect->with_flags & _CUPS_WITH_REGEX)
- add_stringf(errors, "EXPECTED: %s %s /%s/",
- expect->name,
- (expect->with_flags & _CUPS_WITH_ALL) ?
- "WITH-ALL-VALUES" : "WITH-VALUE",
- expect->with_value);
- else
- add_stringf(errors, "EXPECTED: %s %s \"%s\"",
- expect->name,
- (expect->with_flags & _CUPS_WITH_ALL) ?
- "WITH-ALL-VALUES" : "WITH-VALUE",
- expect->with_value);
-
- with_value(outfile, errors, expect->with_value, expect->with_flags, found,
- buffer, sizeof(buffer));
- }
+ if (expect->define_no_match)
+ set_variable(outfile, vars, expect->define_no_match, "1");
+ else if (!expect->define_match && !expect->define_value && ((!expect->repeat_match && !expect->repeat_no_match) || repeat_count >= expect->repeat_limit))
+ {
+ add_stringf(errors, "EXPECTED: %s WITH-VALUES-FROM %s", expect->name, expect->with_value_from);
- if (expect->repeat_no_match &&
- repeat_count < expect->repeat_limit)
- repeat_test = 1;
+ with_value_from(errors, ippFindAttribute(response, expect->with_value_from, IPP_TAG_ZERO), found, buffer, sizeof(buffer));
+ }
- continue;
- }
+ if (expect->repeat_no_match && repeat_count < expect->repeat_limit)
+ repeat_test = 1;
- if (found && expect->count > 0 &&
- found->num_values != expect->count)
- {
- if (expect->define_no_match)
- set_variable(outfile, vars, expect->define_no_match, "1");
- else if (!expect->define_match && !expect->define_value)
- {
- add_stringf(errors, "EXPECTED: %s COUNT %d (got %d)", expect->name,
- expect->count, found->num_values);
+ break;
}
+ else if (found && !with_value(outfile, NULL, expect->with_value, expect->with_flags, found, buffer, sizeof(buffer)))
+ {
+ if (expect->define_no_match)
+ set_variable(outfile, vars, expect->define_no_match, "1");
+ else if (!expect->define_match && !expect->define_value &&
+ !expect->repeat_match && (!expect->repeat_no_match || repeat_count >= expect->repeat_limit))
+ {
+ if (expect->with_flags & _CUPS_WITH_REGEX)
+ add_stringf(errors, "EXPECTED: %s %s /%s/", expect->name, with_flags_string(expect->with_flags), expect->with_value);
+ else
+ add_stringf(errors, "EXPECTED: %s %s \"%s\"", expect->name, with_flags_string(expect->with_flags), expect->with_value);
- if (expect->repeat_no_match &&
- repeat_count < expect->repeat_limit)
- repeat_test = 1;
+ with_value(outfile, errors, expect->with_value, expect->with_flags, found, buffer, sizeof(buffer));
+ }
- continue;
- }
+ if (expect->repeat_no_match &&
+ repeat_count < expect->repeat_limit)
+ repeat_test = 1;
- if (found && expect->same_count_as)
- {
- attrptr = ippFindAttribute(response, expect->same_count_as,
- IPP_TAG_ZERO);
+ break;
+ }
- if (!attrptr || attrptr->num_values != found->num_values)
+ if (found && expect->count > 0 &&
+ found->num_values != expect->count)
{
if (expect->define_no_match)
set_variable(outfile, vars, expect->define_no_match, "1");
else if (!expect->define_match && !expect->define_value)
{
- if (!attrptr)
- add_stringf(errors,
- "EXPECTED: %s (%d values) SAME-COUNT-AS %s "
- "(not returned)", expect->name,
- found->num_values, expect->same_count_as);
- else if (attrptr->num_values != found->num_values)
- add_stringf(errors,
- "EXPECTED: %s (%d values) SAME-COUNT-AS %s "
- "(%d values)", expect->name, found->num_values,
- expect->same_count_as, attrptr->num_values);
+ add_stringf(errors, "EXPECTED: %s COUNT %d (got %d)", expect->name,
+ expect->count, found->num_values);
}
if (expect->repeat_no_match &&
- repeat_count < expect->repeat_limit)
+ repeat_count < expect->repeat_limit)
repeat_test = 1;
- continue;
+ break;
}
- }
- if (found && expect->define_match)
- set_variable(outfile, vars, expect->define_match, "1");
-
- if (found && expect->define_value)
- {
- if (!expect->with_value)
+ if (found && expect->same_count_as)
{
- int last = ippGetCount(found) - 1;
- /* Last element in attribute */
+ attrptr = ippFindAttribute(response, expect->same_count_as,
+ IPP_TAG_ZERO);
- switch (ippGetValueTag(found))
+ if (!attrptr || attrptr->num_values != found->num_values)
{
- case IPP_TAG_ENUM :
- case IPP_TAG_INTEGER :
- snprintf(buffer, sizeof(buffer), "%d", ippGetInteger(found, last));
- break;
-
- case IPP_TAG_BOOLEAN :
- if (ippGetBoolean(found, last))
- strlcpy(buffer, "true", sizeof(buffer));
- else
- strlcpy(buffer, "false", sizeof(buffer));
- break;
+ if (expect->define_no_match)
+ set_variable(outfile, vars, expect->define_no_match, "1");
+ else if (!expect->define_match && !expect->define_value)
+ {
+ if (!attrptr)
+ add_stringf(errors,
+ "EXPECTED: %s (%d values) SAME-COUNT-AS %s "
+ "(not returned)", expect->name,
+ found->num_values, expect->same_count_as);
+ else if (attrptr->num_values != found->num_values)
+ add_stringf(errors,
+ "EXPECTED: %s (%d values) SAME-COUNT-AS %s "
+ "(%d values)", expect->name, found->num_values,
+ expect->same_count_as, attrptr->num_values);
+ }
- case IPP_TAG_RESOLUTION :
- {
- int xres, /* Horizontal resolution */
- yres; /* Vertical resolution */
- ipp_res_t units; /* Resolution units */
+ if (expect->repeat_no_match &&
+ repeat_count < expect->repeat_limit)
+ repeat_test = 1;
- xres = ippGetResolution(found, last, &yres, &units);
+ break;
+ }
+ }
- if (xres == yres)
- snprintf(buffer, sizeof(buffer), "%d%s", xres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm");
- else
- snprintf(buffer, sizeof(buffer), "%dx%d%s", xres, yres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm");
- }
- break;
+ if (found && expect->define_match)
+ set_variable(outfile, vars, expect->define_match, "1");
- case IPP_TAG_CHARSET :
- case IPP_TAG_KEYWORD :
- case IPP_TAG_LANGUAGE :
- case IPP_TAG_MIMETYPE :
- case IPP_TAG_NAME :
- case IPP_TAG_NAMELANG :
- case IPP_TAG_TEXT :
- case IPP_TAG_TEXTLANG :
- case IPP_TAG_URI :
- case IPP_TAG_URISCHEME :
- strlcpy(buffer, ippGetString(found, last, NULL), sizeof(buffer));
- break;
+ if (found && expect->define_value)
+ {
+ if (!expect->with_value)
+ {
+ int last = ippGetCount(found) - 1;
+ /* Last element in attribute */
- default :
- ippAttributeString(found, buffer, sizeof(buffer));
- break;
+ switch (ippGetValueTag(found))
+ {
+ case IPP_TAG_ENUM :
+ case IPP_TAG_INTEGER :
+ snprintf(buffer, sizeof(buffer), "%d", ippGetInteger(found, last));
+ break;
+
+ case IPP_TAG_BOOLEAN :
+ if (ippGetBoolean(found, last))
+ strlcpy(buffer, "true", sizeof(buffer));
+ else
+ strlcpy(buffer, "false", sizeof(buffer));
+ break;
+
+ case IPP_TAG_RESOLUTION :
+ {
+ int xres, /* Horizontal resolution */
+ yres; /* Vertical resolution */
+ ipp_res_t units; /* Resolution units */
+
+ xres = ippGetResolution(found, last, &yres, &units);
+
+ if (xres == yres)
+ snprintf(buffer, sizeof(buffer), "%d%s", xres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm");
+ else
+ snprintf(buffer, sizeof(buffer), "%dx%d%s", xres, yres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm");
+ }
+ break;
+
+ case IPP_TAG_CHARSET :
+ case IPP_TAG_KEYWORD :
+ case IPP_TAG_LANGUAGE :
+ case IPP_TAG_MIMETYPE :
+ case IPP_TAG_NAME :
+ case IPP_TAG_NAMELANG :
+ case IPP_TAG_TEXT :
+ case IPP_TAG_TEXTLANG :
+ case IPP_TAG_URI :
+ case IPP_TAG_URISCHEME :
+ strlcpy(buffer, ippGetString(found, last, NULL), sizeof(buffer));
+ break;
+
+ default :
+ ippAttributeString(found, buffer, sizeof(buffer));
+ break;
+ }
}
- }
- set_variable(outfile, vars, expect->define_value, buffer);
- }
+ set_variable(outfile, vars, expect->define_value, buffer);
+ }
- if (found && expect->repeat_match &&
- repeat_count < expect->repeat_limit)
- repeat_test = 1;
+ if (found && expect->repeat_match &&
+ repeat_count < expect->repeat_limit)
+ repeat_test = 1;
+ }
+ while (expect->expect_all && (found = ippFindNextAttribute(response, expect->name, IPP_TAG_ZERO)) != NULL);
}
}
/*
- * If we are going to repeat this test, sleep 1 second so we don't flood
- * the printer with requests...
+ * If we are going to repeat this test, display intermediate results...
*/
if (repeat_test)
{
- if (Output == _CUPS_OUTPUT_TEST || (Output == _CUPS_OUTPUT_PLIST && outfile != stdout))
+ if (Output == _CUPS_OUTPUT_TEST || (Output == _CUPS_OUTPUT_PLIST && outfile != cupsFileStdout()))
{
- printf("%04d]\n", repeat_count);
- fflush(stdout);
-
+ cupsFilePrintf(cupsFileStdout(), "%04d]\n", repeat_count);
+\
if (num_displayed > 0)
{
for (attrptr = ippFirstAttribute(response); attrptr; attrptr = ippNextAttribute(response))
{
if (!strcmp(displayed[i], attrname))
{
- print_attr(stdout, _CUPS_OUTPUT_TEST, attrptr, NULL);
+ print_attr(cupsFileStdout(), _CUPS_OUTPUT_TEST, attrptr, NULL);
break;
}
}
}
}
- sleep((unsigned)repeat_interval);
- repeat_interval = _cupsNextDelay(repeat_interval, &repeat_prev);
-
- if (Output == _CUPS_OUTPUT_TEST || (Output == _CUPS_OUTPUT_PLIST && outfile != stdout))
+ if (Output == _CUPS_OUTPUT_TEST || (Output == _CUPS_OUTPUT_PLIST && outfile != cupsFileStdout()))
{
- printf(" %-68.68s [", name);
- fflush(stdout);
+ cupsFilePrintf(cupsFileStdout(), " %-68.68s [", name);
}
+
+ ippDelete(response);
+ response = NULL;
}
}
while (repeat_test);
if (Output == _CUPS_OUTPUT_PLIST)
{
- fputs("<key>Successful</key>\n", outfile);
- fputs(prev_pass ? "<true />\n" : "<false />\n", outfile);
- fputs("<key>StatusCode</key>\n", outfile);
+ cupsFilePuts(outfile, "<key>Successful</key>\n");
+ cupsFilePuts(outfile, prev_pass ? "<true />\n" : "<false />\n");
+ cupsFilePuts(outfile, "<key>StatusCode</key>\n");
print_xml_string(outfile, "string", ippErrorString(cupsLastError()));
- fputs("<key>ResponseAttributes</key>\n", outfile);
- fputs("<array>\n", outfile);
- fputs("<dict>\n", outfile);
+ cupsFilePuts(outfile, "<key>ResponseAttributes</key>\n");
+ cupsFilePuts(outfile, "<array>\n");
+ cupsFilePuts(outfile, "<dict>\n");
for (attrptr = response ? response->attrs : NULL,
group = attrptr ? attrptr->group_tag : IPP_TAG_ZERO;
attrptr;
attrptr = attrptr->next)
print_attr(outfile, Output, attrptr, &group);
- fputs("</dict>\n", outfile);
- fputs("</array>\n", outfile);
+ cupsFilePuts(outfile, "</dict>\n");
+ cupsFilePuts(outfile, "</array>\n");
+ }
+ else if (Output == _CUPS_OUTPUT_IPPSERVER && response)
+ {
+ for (attrptr = ippFirstAttribute(response), group = IPP_TAG_ZERO; attrptr; attrptr = ippNextAttribute(response))
+ {
+ if (!ippGetName(attrptr) || ippGetGroupTag(attrptr) != IPP_TAG_PRINTER)
+ continue;
+
+ print_ippserver_attr(outfile, attrptr, 0);
+ }
}
- if (Output == _CUPS_OUTPUT_TEST || (Output == _CUPS_OUTPUT_PLIST && outfile != stdout))
+ if (Output == _CUPS_OUTPUT_TEST || (Output == _CUPS_OUTPUT_PLIST && outfile != cupsFileStdout()))
{
- puts(prev_pass ? "PASS]" : "FAIL]");
+ cupsFilePuts(cupsFileStdout(), prev_pass ? "PASS]\n" : "FAIL]\n");
if (!prev_pass || (Verbosity && response))
{
- printf(" RECEIVED: %lu bytes in response\n",
- (unsigned long)ippLength(response));
- printf(" status-code = %s (%s)\n", ippErrorString(cupsLastError()),
- cupsLastErrorString());
+ cupsFilePrintf(cupsFileStdout(), " RECEIVED: %lu bytes in response\n", (unsigned long)ippLength(response));
+ cupsFilePrintf(cupsFileStdout(), " status-code = %s (%s)\n", ippErrorString(cupsLastError()), cupsLastErrorString());
if (Verbosity && response)
{
for (attrptr = response->attrs;
attrptr != NULL;
attrptr = attrptr->next)
- print_attr(stdout, _CUPS_OUTPUT_TEST, attrptr, NULL);
+ print_attr(cupsFileStdout(), _CUPS_OUTPUT_TEST, attrptr, NULL);
}
}
}
{
if (Output == _CUPS_OUTPUT_PLIST)
{
- fputs("<key>Errors</key>\n", outfile);
- fputs("<array>\n", outfile);
+ cupsFilePuts(outfile, "<key>Errors</key>\n");
+ cupsFilePuts(outfile, "<array>\n");
for (error = (char *)cupsArrayFirst(errors);
error;
error = (char *)cupsArrayNext(errors))
print_xml_string(outfile, "string", error);
- fputs("</array>\n", outfile);
+ cupsFilePuts(outfile, "</array>\n");
}
- if (Output == _CUPS_OUTPUT_TEST || (Output == _CUPS_OUTPUT_PLIST && outfile != stdout))
+ if (Output == _CUPS_OUTPUT_TEST || (Output == _CUPS_OUTPUT_PLIST && outfile != cupsFileStdout()))
{
for (error = (char *)cupsArrayFirst(errors);
error;
error = (char *)cupsArrayNext(errors))
- printf(" %s\n", error);
+ cupsFilePrintf(cupsFileStdout(), " %s\n", error);
}
}
- if (num_displayed > 0 && !Verbosity && response && (Output == _CUPS_OUTPUT_TEST || (Output == _CUPS_OUTPUT_PLIST && outfile != stdout)))
+ if (num_displayed > 0 && !Verbosity && response && (Output == _CUPS_OUTPUT_TEST || (Output == _CUPS_OUTPUT_PLIST && outfile != cupsFileStdout())))
{
for (attrptr = response->attrs;
attrptr != NULL;
skip_error:
if (Output == _CUPS_OUTPUT_PLIST)
- fputs("</dict>\n", outfile);
-
- fflush(stdout);
+ cupsFilePuts(outfile, "</dict>\n");
ippDelete(response);
response = NULL;
cupsArrayDelete(errors);
if (fp)
- fclose(fp);
+ cupsFileClose(fp);
httpClose(http);
ippDelete(request);
free(statuses[i].if_defined);
if (statuses[i].if_not_defined)
free(statuses[i].if_not_defined);
- if (statuses[i].define_match)
- free(statuses[i].define_match);
- if (statuses[i].define_no_match)
- free(statuses[i].define_no_match);
+ if (statuses[i].define_match)
+ free(statuses[i].define_match);
+ if (statuses[i].define_no_match)
+ free(statuses[i].define_no_match);
}
for (i = num_expects, expect = expects; i > 0; i --, expect ++)
value = getenv(temp);
src += tempptr - temp + 5;
}
- else if (vars)
+ else
{
if (src[1] == '{')
{
src += tempptr - temp + 1;
}
- else
- {
- value = "$";
- src ++;
- }
if (value)
{
*/
static ipp_t * /* O - Collection value */
-get_collection(FILE *outfile, /* I - Output file */
+get_collection(cups_file_t *outfile, /* I - Output file */
_cups_vars_t *vars, /* I - Variables */
- FILE *fp, /* I - File to read from */
+ cups_file_t *fp, /* I - File to read from */
int *linenum) /* IO - Line number */
{
char token[1024], /* Token from file */
goto col_error;
}
- if ((value = ippTagValue(token)) == IPP_TAG_ZERO)
+ if ((value = ippTagValue(token)) < IPP_TAG_UNSUPPORTED_VALUE)
{
print_fatal_error(outfile, "Bad MEMBER value tag \"%s\" on line %d.", token,
*linenum);
goto col_error;
}
- if (!get_token(fp, temp, sizeof(temp), linenum))
+ if (value < IPP_TAG_INTEGER)
+ {
+ /*
+ * Out-of-band member attributes have no value...
+ */
+
+ token[0] = '\0';
+ }
+ else if (!get_token(fp, temp, sizeof(temp), linenum))
{
print_fatal_error(outfile, "Missing MEMBER value on line %d.", *linenum);
goto col_error;
}
-
- expand_variables(vars, token, temp, sizeof(token));
+ else
+ {
+ expand_variables(vars, token, temp, sizeof(token));
+ }
switch (value)
{
- case IPP_TAG_BOOLEAN :
- if (!_cups_strcasecmp(token, "true"))
- ippAddBoolean(col, IPP_TAG_ZERO, attr, 1);
- else
- ippAddBoolean(col, IPP_TAG_ZERO, attr, (char)atoi(token));
- break;
+ default :
+ if (value < IPP_TAG_INTEGER)
+ {
+ /*
+ * Add out-of-band value...
+ */
+
+ ippAddOutOfBand(col, IPP_TAG_ZERO, value, attr);
+ }
+ else
+ {
+ print_fatal_error(outfile, "Unsupported MEMBER value tag %s for \"%s\" on line %d.", ippTagString(value), attr, *linenum);
+ goto col_error;
+ }
+ break;
+
+ case IPP_TAG_BOOLEAN :
+ if (!_cups_strcasecmp(token, "true"))
+ ippAddBoolean(col, IPP_TAG_ZERO, attr, 1);
+ else
+ ippAddBoolean(col, IPP_TAG_ZERO, attr, (char)atoi(token));
+ break;
case IPP_TAG_INTEGER :
case IPP_TAG_ENUM :
goto col_error;
}
break;
- case IPP_TAG_STRING :
+
+ case IPP_TAG_STRING :
ippAddOctetString(col, IPP_TAG_ZERO, attr, token, (int)strlen(token));
break;
- default :
+ 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 (!strchr(token, ','))
ippAddString(col, IPP_TAG_ZERO, value, attr, NULL, token);
else
for (ptr = strchr(token, ','); ptr; ptr = strchr(ptr, ','))
{
- *ptr++ = '\0';
- values[num_values] = ptr;
- num_values ++;
+ if (ptr > token && ptr[-1] == '\\')
+ _cups_strcpy(ptr - 1, ptr);
+ else
+ {
+ *ptr++ = '\0';
+ values[num_values] = ptr;
+ num_values ++;
+ }
}
ippAddStrings(col, IPP_TAG_ZERO, value, attr, num_values,
break;
}
}
+ else
+ {
+ print_fatal_error(outfile, "Unexpected token %s seen on line %d.", token, *linenum);
+ goto col_error;
+ }
}
return (col);
* 'get_string()' - Get a pointer to a string value or the portion of interest.
*/
-static char * /* O - Pointer to string */
+static const char * /* O - Pointer to string */
get_string(ipp_attribute_t *attr, /* I - IPP attribute */
int element, /* I - Element to fetch */
int flags, /* I - Value ("with") flags */
char *buffer, /* I - Temporary buffer */
size_t bufsize) /* I - Size of temporary buffer */
{
- char *ptr, /* Value */
- scheme[256], /* URI scheme */
- userpass[256], /* Username/password */
- hostname[256], /* Hostname */
- resource[1024]; /* Resource */
- int port; /* Port number */
+ const char *value; /* Value */
+ char *ptr, /* Pointer into value */
+ scheme[256], /* URI scheme */
+ userpass[256], /* Username/password */
+ hostname[256], /* Hostname */
+ resource[1024]; /* Resource */
+ int port; /* Port number */
- ptr = attr->values[element].string.text;
+ value = ippGetString(attr, element, NULL);
if (flags & _CUPS_WITH_HOSTNAME)
{
- if (httpSeparateURI(HTTP_URI_CODING_ALL, ptr, scheme, sizeof(scheme), userpass, sizeof(userpass), buffer, (int)bufsize, &port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK)
+ if (httpSeparateURI(HTTP_URI_CODING_ALL, value, scheme, sizeof(scheme), userpass, sizeof(userpass), buffer, (int)bufsize, &port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK)
buffer[0] = '\0';
+ ptr = buffer + strlen(buffer) - 1;
+ if (ptr >= buffer && *ptr == '.')
+ *ptr = '\0'; /* Drop trailing "." */
+
return (buffer);
}
else if (flags & _CUPS_WITH_RESOURCE)
{
- if (httpSeparateURI(HTTP_URI_CODING_ALL, ptr, scheme, sizeof(scheme), userpass, sizeof(userpass), hostname, sizeof(hostname), &port, buffer, (int)bufsize) < HTTP_URI_STATUS_OK)
+ if (httpSeparateURI(HTTP_URI_CODING_ALL, value, scheme, sizeof(scheme), userpass, sizeof(userpass), hostname, sizeof(hostname), &port, buffer, (int)bufsize) < HTTP_URI_STATUS_OK)
buffer[0] = '\0';
return (buffer);
}
else if (flags & _CUPS_WITH_SCHEME)
{
- if (httpSeparateURI(HTTP_URI_CODING_ALL, ptr, buffer, (int)bufsize, userpass, sizeof(userpass), hostname, sizeof(hostname), &port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK)
+ if (httpSeparateURI(HTTP_URI_CODING_ALL, value, buffer, (int)bufsize, userpass, sizeof(userpass), hostname, sizeof(hostname), &port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK)
buffer[0] = '\0';
return (buffer);
}
+ else if (ippGetValueTag(attr) == IPP_TAG_URI && (!strncmp(value, "ipp://", 6) || !strncmp(value, "http://", 7) || !strncmp(value, "ipps://", 7) || !strncmp(value, "https://", 8)))
+ {
+ http_uri_status_t status = httpSeparateURI(HTTP_URI_CODING_ALL, value, scheme, sizeof(scheme), userpass, sizeof(userpass), hostname, sizeof(hostname), &port, resource, sizeof(resource));
+
+ if (status < HTTP_URI_STATUS_OK)
+ {
+ /*
+ * Bad URI...
+ */
+
+ buffer[0] = '\0';
+ }
+ else
+ {
+ /*
+ * Normalize URI with no trailing dot...
+ */
+
+ if ((ptr = hostname + strlen(hostname) - 1) >= hostname && *ptr == '.')
+ *ptr = '\0';
+
+ httpAssembleURI(HTTP_URI_CODING_ALL, buffer, (int)bufsize, scheme, userpass, hostname, port, resource);
+ }
+
+ return (buffer);
+ }
else
- return (ptr);
+ return (value);
}
*/
static char * /* O - Token from file or NULL on EOF */
-get_token(FILE *fp, /* I - File to read from */
- char *buf, /* I - Buffer to read into */
- int buflen, /* I - Length of buffer */
- int *linenum) /* IO - Current line number */
+get_token(cups_file_t *fp, /* I - File to read from */
+ char *buf, /* I - Buffer to read into */
+ int buflen, /* I - Length of buffer */
+ int *linenum) /* IO - Current line number */
{
int ch, /* Character from file */
quote; /* Quoting character */
* Skip whitespace...
*/
- while (isspace(ch = getc(fp)))
+ while (isspace(ch = cupsFileGetChar(fp)))
{
if (ch == '\n')
(*linenum) ++;
bufptr = buf;
bufend = buf + buflen - 1;
- while ((ch = getc(fp)) != EOF)
+ while ((ch = cupsFileGetChar(fp)) != EOF)
{
if (ch == '\\')
{
if (bufptr < bufend)
*bufptr++ = (char)ch;
- if ((ch = getc(fp)) != EOF && bufptr < bufend)
+ if ((ch = cupsFileGetChar(fp)) != EOF && bufptr < bufend)
*bufptr++ = (char)ch;
}
else if (ch == quote)
* Comment...
*/
- while ((ch = getc(fp)) != EOF)
+ while ((ch = cupsFileGetChar(fp)) != EOF)
if (ch == '\n')
break;
* Whitespace delimited text...
*/
- ungetc(ch, fp);
+ cupsFileSeek(fp, cupsFileTell(fp) - 1);
bufptr = buf;
bufend = buf + buflen - 1;
- while ((ch = getc(fp)) != EOF)
+ while ((ch = cupsFileGetChar(fp)) != EOF)
if (isspace(ch) || ch == '#')
break;
else if (bufptr < bufend)
*bufptr++ = (char)ch;
if (ch == '#')
- ungetc(ch, fp);
+ cupsFileSeek(fp, cupsFileTell(fp) - 1);
else if (ch == '\n')
(*linenum) ++;
*/
static char * /* O - ISO 8601 date/time string */
-iso_date(ipp_uchar_t *date) /* I - IPP (RFC 1903) date/time value */
+iso_date(const ipp_uchar_t *date) /* I - IPP (RFC 1903) date/time value */
{
time_t utctime; /* UTC time since 1970 */
struct tm *utcdate; /* UTC date/time */
* Display the prompt...
*/
- printf("%s\n---- PRESS ANY KEY ----", message);
- fflush(stdout);
+ cupsFilePrintf(cupsFileStdout(), "%s\n---- PRESS ANY KEY ----", message);
#ifdef WIN32
/*
* Erase the "press any key" prompt...
*/
- fputs("\r \r", stdout);
- fflush(stdout);
+ cupsFilePuts(cupsFileStdout(), "\r \r");
}
*/
static void
-print_attr(FILE *outfile, /* I - Output file */
+print_attr(cups_file_t *outfile, /* I - Output file */
int format, /* I - Output format */
ipp_attribute_t *attr, /* I - Attribute to print */
ipp_tag_t *group) /* IO - Current group */
{
if (attr->group_tag != IPP_TAG_ZERO)
{
- fputs("</dict>\n", outfile);
- fputs("<dict>\n", outfile);
+ cupsFilePuts(outfile, "</dict>\n");
+ cupsFilePuts(outfile, "<dict>\n");
}
if (group)
print_xml_string(outfile, "key", attr->name);
if (attr->num_values > 1)
- fputs("<array>\n", outfile);
+ cupsFilePuts(outfile, "<array>\n");
switch (attr->value_tag)
{
case IPP_TAG_INTEGER :
case IPP_TAG_ENUM :
for (i = 0; i < attr->num_values; i ++)
- fprintf(outfile, "<integer>%d</integer>\n", attr->values[i].integer);
+ cupsFilePrintf(outfile, "<integer>%d</integer>\n", attr->values[i].integer);
break;
case IPP_TAG_BOOLEAN :
for (i = 0; i < attr->num_values; i ++)
- fputs(attr->values[i].boolean ? "<true />\n" : "<false />\n", outfile);
+ cupsFilePuts(outfile, attr->values[i].boolean ? "<true />\n" : "<false />\n");
break;
case IPP_TAG_RANGE :
for (i = 0; i < attr->num_values; i ++)
- fprintf(outfile, "<dict><key>lower</key><integer>%d</integer>"
+ cupsFilePrintf(outfile, "<dict><key>lower</key><integer>%d</integer>"
"<key>upper</key><integer>%d</integer></dict>\n",
attr->values[i].range.lower, attr->values[i].range.upper);
break;
case IPP_TAG_RESOLUTION :
for (i = 0; i < attr->num_values; i ++)
- fprintf(outfile, "<dict><key>xres</key><integer>%d</integer>"
+ cupsFilePrintf(outfile, "<dict><key>xres</key><integer>%d</integer>"
"<key>yres</key><integer>%d</integer>"
"<key>units</key><string>%s</string></dict>\n",
attr->values[i].resolution.xres,
case IPP_TAG_DATE :
for (i = 0; i < attr->num_values; i ++)
- fprintf(outfile, "<date>%s</date>\n", iso_date(attr->values[i].date));
+ cupsFilePrintf(outfile, "<date>%s</date>\n", iso_date(attr->values[i].date));
break;
case IPP_TAG_STRING :
char buffer[IPP_MAX_LENGTH * 5 / 4 + 1];
/* Output buffer */
- fprintf(outfile, "<data>%s</data>\n",
+ cupsFilePrintf(outfile, "<data>%s</data>\n",
httpEncode64_2(buffer, sizeof(buffer),
attr->values[i].unknown.data,
attr->values[i].unknown.length));
case IPP_TAG_TEXT :
case IPP_TAG_NAME :
case IPP_TAG_KEYWORD :
- case IPP_TAG_CHARSET :
case IPP_TAG_URI :
- case IPP_TAG_MIMETYPE :
+ case IPP_TAG_URISCHEME :
+ case IPP_TAG_CHARSET :
case IPP_TAG_LANGUAGE :
+ case IPP_TAG_MIMETYPE :
for (i = 0; i < attr->num_values; i ++)
print_xml_string(outfile, "string", attr->values[i].string.text);
break;
case IPP_TAG_NAMELANG :
for (i = 0; i < attr->num_values; i ++)
{
- fputs("<dict><key>language</key><string>", outfile);
+ cupsFilePuts(outfile, "<dict><key>language</key><string>");
print_xml_string(outfile, NULL, attr->values[i].string.language);
- fputs("</string><key>string</key><string>", outfile);
+ cupsFilePuts(outfile, "</string><key>string</key><string>");
print_xml_string(outfile, NULL, attr->values[i].string.text);
- fputs("</string></dict>\n", outfile);
+ cupsFilePuts(outfile, "</string></dict>\n");
}
break;
case IPP_TAG_BEGIN_COLLECTION :
for (i = 0; i < attr->num_values; i ++)
{
- fputs("<dict>\n", outfile);
+ cupsFilePuts(outfile, "<dict>\n");
for (colattr = attr->values[i].collection->attrs;
colattr;
colattr = colattr->next)
print_attr(outfile, format, colattr, NULL);
- fputs("</dict>\n", outfile);
+ cupsFilePuts(outfile, "</dict>\n");
}
break;
default :
- fprintf(outfile, "<string><<%s>></string>\n", ippTagString(attr->value_tag));
+ cupsFilePrintf(outfile, "<string><<%s>></string>\n", ippTagString(attr->value_tag));
break;
}
if (attr->num_values > 1)
- fputs("</array>\n", outfile);
+ cupsFilePuts(outfile, "</array>\n");
}
else
{
- char buffer[8192]; /* Value buffer */
+ char buffer[131072]; /* Value buffer */
if (format == _CUPS_OUTPUT_TEST)
{
if (!attr->name)
{
- fputs(" -- separator --\n", outfile);
+ cupsFilePuts(outfile, " -- separator --\n");
return;
}
- fprintf(outfile, " %s (%s%s) = ", attr->name, attr->num_values > 1 ? "1setOf " : "", ippTagString(attr->value_tag));
+ cupsFilePrintf(outfile, " %s (%s%s) = ", attr->name, attr->num_values > 1 ? "1setOf " : "", ippTagString(attr->value_tag));
}
ippAttributeString(attr, buffer, sizeof(buffer));
- fprintf(outfile, "%s\n", buffer);
+ cupsFilePrintf(outfile, "%s\n", buffer);
}
}
static void
print_csv(
- FILE *outfile, /* I - Output file */
+ cups_file_t *outfile, /* I - Output file */
ipp_attribute_t *attr, /* I - First attribute for line */
int num_displayed, /* I - Number of attributes to display */
char **displayed, /* I - Attributes to display */
for (i = 0; i < num_displayed; i ++)
{
if (i)
- fputc(',', outfile);
+ cupsFilePutChar(outfile, ',');
buffer[0] = '\0';
if (strchr(buffer, ',') != NULL || strchr(buffer, '\"') != NULL ||
strchr(buffer, '\\') != NULL)
{
- putc('\"', outfile);
+ cupsFilePutChar(cupsFileStdout(), '\"');
for (bufptr = buffer; *bufptr; bufptr ++)
{
if (*bufptr == '\\' || *bufptr == '\"')
- putc('\\', outfile);
- putc(*bufptr, outfile);
+ cupsFilePutChar(cupsFileStdout(), '\\');
+ cupsFilePutChar(cupsFileStdout(), *bufptr);
}
- putc('\"', outfile);
+ cupsFilePutChar(cupsFileStdout(), '\"');
}
else
- fputs(buffer, outfile);
+ cupsFilePuts(outfile, buffer);
}
- putc('\n', outfile);
+ cupsFilePutChar(cupsFileStdout(), '\n');
}
else
{
for (i = 0; i < num_displayed; i ++)
{
if (i)
- putc(',', outfile);
+ cupsFilePutChar(cupsFileStdout(), ',');
- fputs(displayed[i], outfile);
+ cupsFilePuts(outfile, displayed[i]);
}
- putc('\n', outfile);
+ cupsFilePutChar(cupsFileStdout(), '\n');
}
free(buffer);
*/
static void
-print_fatal_error(FILE *outfile, /* I - Output file */
- const char *s, /* I - Printf-style format string */
+print_fatal_error(cups_file_t *outfile, /* I - Output file */
+ const char *s, /* I - Printf-style format string */
...) /* I - Additional arguments as needed */
{
char buffer[10240]; /* Format buffer */
}
+/*
+ * 'print_ippserver_attr()' - Print a attribute suitable for use by ippserver.
+ */
+
+static void
+print_ippserver_attr(
+ cups_file_t *outfile, /* I - Output file */
+ ipp_attribute_t *attr, /* I - Attribute to print */
+ int indent) /* I - Indentation level */
+{
+ int i, /* Looping var */
+ count = ippGetCount(attr);
+ /* Number of values */
+ ipp_attribute_t *colattr; /* Collection attribute */
+
+
+ if (indent == 0)
+ cupsFilePrintf(outfile, "ATTR %s %s", ippTagString(ippGetValueTag(attr)), ippGetName(attr));
+ else
+ cupsFilePrintf(outfile, "%*sMEMBER %s %s", indent, "", ippTagString(ippGetValueTag(attr)), ippGetName(attr));
+
+ switch (ippGetValueTag(attr))
+ {
+ case IPP_TAG_INTEGER :
+ case IPP_TAG_ENUM :
+ for (i = 0; i < count; i ++)
+ cupsFilePrintf(outfile, "%s%d", i ? "," : " ", ippGetInteger(attr, i));
+ break;
+
+ case IPP_TAG_BOOLEAN :
+ cupsFilePuts(outfile, ippGetBoolean(attr, 0) ? " true" : " false");
+
+ for (i = 1; i < count; i ++)
+ cupsFilePuts(outfile, ippGetBoolean(attr, 1) ? ",true" : ",false");
+ break;
+
+ case IPP_TAG_RANGE :
+ for (i = 0; i < count; i ++)
+ {
+ int upper, lower = ippGetRange(attr, i, &upper);
+
+ cupsFilePrintf(outfile, "%s%d-%d", i ? "," : " ", lower, upper);
+ }
+ break;
+
+ case IPP_TAG_RESOLUTION :
+ for (i = 0; i < count; i ++)
+ {
+ ipp_res_t units;
+ int yres, xres = ippGetResolution(attr, i, &yres, &units);
+
+ cupsFilePrintf(outfile, "%s%dx%d%s", i ? "," : " ", xres, yres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm");
+ }
+ break;
+
+ case IPP_TAG_DATE :
+ for (i = 0; i < count; i ++)
+ cupsFilePrintf(outfile, "%s%s", i ? "," : " ", iso_date(ippGetDate(attr, i)));
+ break;
+
+ case IPP_TAG_STRING :
+ for (i = 0; i < count; i ++)
+ {
+ int len;
+ const char *s = (const char *)ippGetOctetString(attr, i, &len);
+
+ cupsFilePuts(outfile, i ? "," : " ");
+ print_ippserver_string(outfile, s, (size_t)len);
+ }
+ break;
+
+ case IPP_TAG_TEXT :
+ case IPP_TAG_TEXTLANG :
+ case IPP_TAG_NAME :
+ case IPP_TAG_NAMELANG :
+ 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 < count; i ++)
+ {
+ const char *s = ippGetString(attr, i, NULL);
+
+ cupsFilePuts(outfile, i ? "," : " ");
+ print_ippserver_string(outfile, s, strlen(s));
+ }
+ break;
+
+ case IPP_TAG_BEGIN_COLLECTION :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ ipp_t *col = ippGetCollection(attr, i);
+
+ cupsFilePuts(outfile, i ? ",{\n" : " {\n");
+ for (colattr = ippFirstAttribute(col); colattr; colattr = ippNextAttribute(col))
+ print_ippserver_attr(outfile, colattr, indent + 4);
+ cupsFilePrintf(outfile, "%*s}", indent, "");
+ }
+ break;
+
+ default :
+ cupsFilePuts(outfile, " \"\"");
+ break;
+ }
+
+ cupsFilePuts(outfile, "\n");
+}
+
+
+/*
+ * 'print_ippserver_string()' - Print a string suitable for use by ippserver.
+ */
+
+static void
+print_ippserver_string(
+ cups_file_t *outfile, /* I - Output file */
+ const char *s, /* I - String to print */
+ size_t len) /* I - Length of string */
+{
+ cupsFilePutChar(outfile, '\"');
+ while (len > 0)
+ {
+ if (*s == '\"')
+ cupsFilePutChar(outfile, '\\');
+ cupsFilePutChar(outfile, *s);
+
+ s ++;
+ len --;
+ }
+ cupsFilePutChar(outfile, '\"');
+}
+
+
/*
* 'print_line()' - Print a line of formatted or CSV text.
*/
static void
print_line(
- FILE *outfile, /* I - Output file */
+ cups_file_t *outfile, /* I - Output file */
ipp_attribute_t *attr, /* I - First attribute for line */
int num_displayed, /* I - Number of attributes to display */
char **displayed, /* I - Attributes to display */
for (i = 0; i < num_displayed; i ++)
{
if (i)
- putc(' ', outfile);
+ cupsFilePutChar(cupsFileStdout(), ' ');
buffer[0] = '\0';
}
}
- fprintf(outfile, "%*s", (int)-widths[i], buffer);
+ cupsFilePrintf(outfile, "%*s", (int)-widths[i], buffer);
}
- putc('\n', outfile);
+ cupsFilePutChar(cupsFileStdout(), '\n');
}
else
{
for (i = 0; i < num_displayed; i ++)
{
if (i)
- putc(' ', outfile);
+ cupsFilePutChar(cupsFileStdout(), ' ');
- fprintf(outfile, "%*s", (int)-widths[i], displayed[i]);
+ cupsFilePrintf(outfile, "%*s", (int)-widths[i], displayed[i]);
}
- putc('\n', outfile);
+ cupsFilePutChar(cupsFileStdout(), '\n');
for (i = 0; i < num_displayed; i ++)
{
if (i)
- putc(' ', outfile);
+ cupsFilePutChar(cupsFileStdout(), ' ');
memset(buffer, '-', widths[i]);
buffer[widths[i]] = '\0';
- fputs(buffer, outfile);
+ cupsFilePuts(outfile, buffer);
}
- putc('\n', outfile);
+ cupsFilePutChar(cupsFileStdout(), '\n');
}
free(buffer);
*/
static void
-print_xml_header(FILE *outfile) /* I - Output file */
+print_xml_header(cups_file_t *outfile) /* I - Output file */
{
if (!XMLHeader)
{
- fputs("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", outfile);
- fputs("<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" "
- "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n", outfile);
- fputs("<plist version=\"1.0\">\n", outfile);
- fputs("<dict>\n", outfile);
- fputs("<key>ipptoolVersion</key>\n", outfile);
- fputs("<string>" CUPS_SVERSION "</string>\n", outfile);
- fputs("<key>Transfer</key>\n", outfile);
- fprintf(outfile, "<string>%s</string>\n",
+ cupsFilePuts(outfile, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+ cupsFilePuts(outfile, "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" "
+ "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n");
+ cupsFilePuts(outfile, "<plist version=\"1.0\">\n");
+ cupsFilePuts(outfile, "<dict>\n");
+ cupsFilePuts(outfile, "<key>ipptoolVersion</key>\n");
+ cupsFilePuts(outfile, "<string>" CUPS_SVERSION "</string>\n");
+ cupsFilePuts(outfile, "<key>Transfer</key>\n");
+ cupsFilePrintf(outfile, "<string>%s</string>\n",
Transfer == _CUPS_TRANSFER_AUTO ? "auto" :
Transfer == _CUPS_TRANSFER_CHUNKED ? "chunked" : "length");
- fputs("<key>Tests</key>\n", outfile);
- fputs("<array>\n", outfile);
+ cupsFilePuts(outfile, "<key>Tests</key>\n");
+ cupsFilePuts(outfile, "<array>\n");
XMLHeader = 1;
}
*/
static void
-print_xml_string(FILE *outfile, /* I - Output file */
- const char *element, /* I - Element name or NULL */
- const char *s) /* I - String to print */
+print_xml_string(cups_file_t *outfile, /* I - Output file */
+ const char *element, /* I - Element name or NULL */
+ const char *s) /* I - String to print */
{
if (element)
- fprintf(outfile, "<%s>", element);
+ cupsFilePrintf(outfile, "<%s>", element);
while (*s)
{
if (*s == '&')
- fputs("&", outfile);
+ cupsFilePuts(outfile, "&");
else if (*s == '<')
- fputs("<", outfile);
+ cupsFilePuts(outfile, "<");
else if (*s == '>')
- fputs(">", outfile);
+ cupsFilePuts(outfile, ">");
else if ((*s & 0xe0) == 0xc0)
{
/*
if ((s[1] & 0xc0) != 0x80)
{
- putc('?', outfile);
+ cupsFilePutChar(outfile, '?');
s ++;
}
else
{
- putc(*s++, outfile);
- putc(*s, outfile);
+ cupsFilePutChar(outfile, *s++);
+ cupsFilePutChar(outfile, *s);
}
}
else if ((*s & 0xf0) == 0xe0)
if ((s[1] & 0xc0) != 0x80 || (s[2] & 0xc0) != 0x80)
{
- putc('?', outfile);
+ cupsFilePutChar(outfile, '?');
s += 2;
}
else
{
- putc(*s++, outfile);
- putc(*s++, outfile);
- putc(*s, outfile);
+ cupsFilePutChar(outfile, *s++);
+ cupsFilePutChar(outfile, *s++);
+ cupsFilePutChar(outfile, *s);
}
}
else if ((*s & 0xf8) == 0xf0)
if ((s[1] & 0xc0) != 0x80 || (s[2] & 0xc0) != 0x80 ||
(s[3] & 0xc0) != 0x80)
{
- putc('?', outfile);
+ cupsFilePutChar(outfile, '?');
s += 3;
}
else
{
- putc(*s++, outfile);
- putc(*s++, outfile);
- putc(*s++, outfile);
- putc(*s, outfile);
+ cupsFilePutChar(outfile, *s++);
+ cupsFilePutChar(outfile, *s++);
+ cupsFilePutChar(outfile, *s++);
+ cupsFilePutChar(outfile, *s);
}
}
else if ((*s & 0x80) || (*s < ' ' && !isspace(*s & 255)))
* Invalid control character...
*/
- putc('?', outfile);
+ cupsFilePutChar(outfile, '?');
}
else
- putc(*s, outfile);
+ cupsFilePutChar(outfile, *s);
s ++;
}
if (element)
- fprintf(outfile, "</%s>\n", element);
+ cupsFilePrintf(outfile, "</%s>\n", element);
}
*/
static void
-print_xml_trailer(FILE *outfile, /* I - Output file */
- int success, /* I - 1 on success, 0 on failure */
- const char *message) /* I - Error message or NULL */
+print_xml_trailer(cups_file_t *outfile, /* I - Output file */
+ int success, /* I - 1 on success, 0 on failure */
+ const char *message) /* I - Error message or NULL */
{
if (XMLHeader)
{
- fputs("</array>\n", outfile);
- fputs("<key>Successful</key>\n", outfile);
- fputs(success ? "<true />\n" : "<false />\n", outfile);
+ cupsFilePuts(outfile, "</array>\n");
+ cupsFilePuts(outfile, "<key>Successful</key>\n");
+ cupsFilePuts(outfile, success ? "<true />\n" : "<false />\n");
if (message)
{
- fputs("<key>ErrorMessage</key>\n", outfile);
+ cupsFilePuts(outfile, "<key>ErrorMessage</key>\n");
print_xml_string(outfile, "string", message);
}
- fputs("</dict>\n", outfile);
- fputs("</plist>\n", outfile);
+ cupsFilePuts(outfile, "</dict>\n");
+ cupsFilePuts(outfile, "</plist>\n");
XMLHeader = 0;
}
*/
static void
-set_variable(FILE *outfile, /* I - Output file */
+set_variable(cups_file_t *outfile, /* I - Output file */
_cups_vars_t *vars, /* I - Variables */
const char *name, /* I - Variable name */
const char *value) /* I - Value string */
* buffer is empty...
*/
-#ifdef SO_NWRITE /* OS X and some versions of Linux */
+#ifdef SO_NWRITE /* macOS and some versions of Linux */
socklen_t len = sizeof(buffered); /* Size of return value */
if (getsockopt(httpGetFd(http), SOL_SOCKET, SO_NWRITE, &buffered, &len))
static void
usage(void)
{
- _cupsLangPuts(stderr, _("Usage: ipptool [options] URI filename [ ... "
- "filenameN ]"));
+ _cupsLangPuts(stderr, _("Usage: ipptool [options] URI filename [ ... filenameN ]"));
_cupsLangPuts(stderr, _("Options:"));
_cupsLangPuts(stderr, _(" --help Show help."));
+ _cupsLangPuts(stderr, _(" --ippserver filename Produce ippserver attribute file."));
_cupsLangPuts(stderr, _(" --stop-after-include-error\n"
" Stop tests after a failed INCLUDE."));
_cupsLangPuts(stderr, _(" --version Show version."));
_cupsLangPuts(stderr, _(" -6 Connect using IPv6."));
_cupsLangPuts(stderr, _(" -C Send requests using "
"chunking (default)."));
- _cupsLangPuts(stdout, _(" -E Test with HTTP Upgrade to "
- "TLS."));
+ _cupsLangPuts(stderr, _(" -E Test with encryption using HTTP Upgrade to TLS."));
_cupsLangPuts(stderr, _(" -I Ignore errors."));
- _cupsLangPuts(stderr, _(" -L Send requests using "
- "content-length."));
+ _cupsLangPuts(stderr, _(" -L Send requests using content-length."));
_cupsLangPuts(stderr, _(" -P filename.plist Produce XML plist to a file and test report to standard output."));
- _cupsLangPuts(stderr, _(" -S Test with SSL "
- "encryption."));
- _cupsLangPuts(stderr, _(" -T seconds Set the receive/send "
- "timeout in seconds."));
- _cupsLangPuts(stderr, _(" -V version Set default IPP "
- "version."));
- _cupsLangPuts(stderr, _(" -X Produce XML plist instead "
- "of plain text."));
+ _cupsLangPuts(stderr, _(" -S Test with encryption using HTTPS."));
+ _cupsLangPuts(stderr, _(" -T seconds Set the receive/send timeout in seconds."));
+ _cupsLangPuts(stderr, _(" -V version Set default IPP version."));
+ _cupsLangPuts(stderr, _(" -X Produce XML plist instead of plain text."));
_cupsLangPuts(stderr, _(" -c Produce CSV output."));
- _cupsLangPuts(stderr, _(" -d name=value Set named variable to "
- "value."));
- _cupsLangPuts(stderr, _(" -f filename Set default request "
- "filename."));
- _cupsLangPuts(stderr, _(" -i seconds Repeat the last file with "
- "the given time interval."));
+ _cupsLangPuts(stderr, _(" -d name=value Set named variable to value."));
+ _cupsLangPuts(stderr, _(" -f filename Set default request filename."));
+ _cupsLangPuts(stderr, _(" -h Validate HTTP response headers."));
+ _cupsLangPuts(stderr, _(" -i seconds Repeat the last file with the given time interval."));
_cupsLangPuts(stderr, _(" -l Produce plain text output."));
- _cupsLangPuts(stderr, _(" -n count Repeat the last file the "
- "given number of times."));
+ _cupsLangPuts(stderr, _(" -n count Repeat the last file the given number of times."));
_cupsLangPuts(stderr, _(" -q Run silently."));
_cupsLangPuts(stderr, _(" -t Produce a test report."));
_cupsLangPuts(stderr, _(" -v Be verbose."));
*/
static int /* O - 1 if valid, 0 otherwise */
-validate_attr(FILE *outfile, /* I - Output file */
+validate_attr(cups_file_t *outfile, /* I - Output file */
cups_array_t *errors, /* I - Errors array */
ipp_attribute_t *attr) /* I - Attribute to validate */
{
}
+/*
+ * 'with_flags_string()' - Return the "WITH-xxx" predicate that corresponds to
+ the flags.
+ */
+
+static const char * /* O - WITH-xxx string */
+with_flags_string(int flags) /* I - WITH flags */
+{
+ if (flags & _CUPS_WITH_ALL)
+ {
+ if (flags & _CUPS_WITH_HOSTNAME)
+ return ("WITH-ALL-HOSTNAMES");
+ else if (flags & _CUPS_WITH_RESOURCE)
+ return ("WITH-ALL-RESOURCES");
+ else if (flags & _CUPS_WITH_SCHEME)
+ return ("WITH-ALL-SCHEMES");
+ else
+ return ("WITH-ALL-VALUES");
+ }
+ else if (flags & _CUPS_WITH_HOSTNAME)
+ return ("WITH-HOSTNAME");
+ else if (flags & _CUPS_WITH_RESOURCE)
+ return ("WITH-RESOURCE");
+ else if (flags & _CUPS_WITH_SCHEME)
+ return ("WITH-SCHEME");
+ else
+ return ("WITH-VALUE");
+}
+
+
/*
* 'with_value()' - Test a WITH-VALUE predicate.
*/
static int /* O - 1 on match, 0 on non-match */
-with_value(FILE *outfile, /* I - Output file */
+with_value(cups_file_t *outfile, /* I - Output file */
cups_array_t *errors, /* I - Errors array */
char *value, /* I - Value string */
int flags, /* I - Flags for match */
case IPP_TAG_BOOLEAN :
for (i = 0; i < attr->num_values; i ++)
{
- if (!strcmp(value, "true") == attr->values[i].boolean)
+ if ((!strcmp(value, "true")) == attr->values[i].boolean)
{
if (!matchbuf[0])
strlcpy(matchbuf, value, matchlen);
regfree(&re);
}
+ else if (ippGetValueTag(attr) == IPP_TAG_URI && !(flags & (_CUPS_WITH_SCHEME | _CUPS_WITH_HOSTNAME | _CUPS_WITH_RESOURCE)))
+ {
+ /*
+ * Value is a literal URI string, see if the value(s) match...
+ */
+
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (!compare_uris(value, get_string(attr, i, flags, temp, sizeof(temp))))
+ {
+ if (!matchbuf[0])
+ strlcpy(matchbuf,
+ get_string(attr, i, flags, temp, sizeof(temp)),
+ matchlen);
+
+ if (!(flags & _CUPS_WITH_ALL))
+ {
+ match = 1;
+ break;
+ }
+ }
+ else if (flags & _CUPS_WITH_ALL)
+ {
+ match = 0;
+ break;
+ }
+ }
+ }
else
{
/*
for (i = 0; i < attr->num_values; i ++)
{
- if (!strcmp(value, get_string(attr, i, flags, temp, sizeof(temp))))
+ int result;
+
+ switch (ippGetValueTag(attr))
+ {
+ case IPP_TAG_URI :
+ /*
+ * Some URI components are case-sensitive, some not...
+ */
+
+ if (flags & (_CUPS_WITH_SCHEME | _CUPS_WITH_HOSTNAME))
+ result = _cups_strcasecmp(value, get_string(attr, i, flags, temp, sizeof(temp)));
+ else
+ result = strcmp(value, get_string(attr, i, flags, temp, sizeof(temp)));
+ break;
+
+ case IPP_TAG_MIMETYPE :
+ case IPP_TAG_NAME :
+ case IPP_TAG_NAMELANG :
+ case IPP_TAG_TEXT :
+ case IPP_TAG_TEXTLANG :
+ /*
+ * mimeMediaType, nameWithoutLanguage, nameWithLanguage,
+ * textWithoutLanguage, and textWithLanguage are defined to
+ * be case-insensitive strings...
+ */
+
+ result = _cups_strcasecmp(value, get_string(attr, i, flags, temp, sizeof(temp)));
+ break;
+
+ default :
+ /*
+ * Other string syntaxes are defined as lowercased so we use
+ * case-sensitive comparisons to catch problems...
+ */
+
+ result = strcmp(value, get_string(attr, i, flags, temp, sizeof(temp)));
+ break;
+ }
+
+ if (!result)
{
if (!matchbuf[0])
strlcpy(matchbuf,
/*
- * End of "$Id$".
+ * 'with_value_from()' - Test a WITH-VALUE-FROM predicate.
*/
+
+static int /* O - 1 on match, 0 on non-match */
+with_value_from(
+ cups_array_t *errors, /* I - Errors array */
+ ipp_attribute_t *fromattr, /* I - "From" attribute */
+ ipp_attribute_t *attr, /* I - Attribute to compare */
+ char *matchbuf, /* I - Buffer to hold matching value */
+ size_t matchlen) /* I - Length of match buffer */
+{
+ int i, j, /* Looping vars */
+ count = ippGetCount(attr), /* Number of attribute values */
+ match = 1; /* Match? */
+
+
+ *matchbuf = '\0';
+
+ /*
+ * Compare the from value(s) to the attribute value(s)...
+ */
+
+ switch (ippGetValueTag(attr))
+ {
+ case IPP_TAG_INTEGER :
+ if (ippGetValueTag(fromattr) != IPP_TAG_INTEGER && ippGetValueTag(fromattr) != IPP_TAG_RANGE)
+ goto wrong_value_tag;
+
+ for (i = 0; i < count; i ++)
+ {
+ int value = ippGetInteger(attr, i);
+ /* Current integer value */
+
+ if (ippContainsInteger(fromattr, value))
+ {
+ if (!matchbuf[0])
+ snprintf(matchbuf, matchlen, "%d", value);
+ }
+ else
+ {
+ add_stringf(errors, "GOT: %s=%d", ippGetName(attr), value);
+ match = 0;
+ }
+ }
+ break;
+
+ case IPP_TAG_ENUM :
+ if (ippGetValueTag(fromattr) != IPP_TAG_ENUM)
+ goto wrong_value_tag;
+
+ for (i = 0; i < count; i ++)
+ {
+ int value = ippGetInteger(attr, i);
+ /* Current integer value */
+
+ if (ippContainsInteger(fromattr, value))
+ {
+ if (!matchbuf[0])
+ snprintf(matchbuf, matchlen, "%d", value);
+ }
+ else
+ {
+ add_stringf(errors, "GOT: %s=%d", ippGetName(attr), value);
+ match = 0;
+ }
+ }
+ break;
+
+ case IPP_TAG_RESOLUTION :
+ if (ippGetValueTag(fromattr) != IPP_TAG_RESOLUTION)
+ goto wrong_value_tag;
+
+ for (i = 0; i < count; i ++)
+ {
+ int xres, yres;
+ ipp_res_t units;
+ int fromcount = ippGetCount(fromattr);
+ int fromxres, fromyres;
+ ipp_res_t fromunits;
+
+ xres = ippGetResolution(attr, i, &yres, &units);
+
+ for (j = 0; j < fromcount; j ++)
+ {
+ fromxres = ippGetResolution(fromattr, j, &fromyres, &fromunits);
+ if (fromxres == xres && fromyres == yres && fromunits == units)
+ break;
+ }
+
+ if (j < fromcount)
+ {
+ if (!matchbuf[0])
+ {
+ if (xres == yres)
+ snprintf(matchbuf, matchlen, "%d%s", xres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm");
+ else
+ snprintf(matchbuf, matchlen, "%dx%d%s", xres, yres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm");
+ }
+ }
+ else
+ {
+ if (xres == yres)
+ add_stringf(errors, "GOT: %s=%d%s", ippGetName(attr), xres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm");
+ else
+ add_stringf(errors, "GOT: %s=%dx%d%s", ippGetName(attr), xres, yres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm");
+
+ match = 0;
+ }
+ }
+ break;
+
+ case IPP_TAG_NOVALUE :
+ case IPP_TAG_UNKNOWN :
+ return (1);
+
+ case IPP_TAG_CHARSET :
+ case IPP_TAG_KEYWORD :
+ case IPP_TAG_LANGUAGE :
+ case IPP_TAG_MIMETYPE :
+ case IPP_TAG_NAME :
+ case IPP_TAG_NAMELANG :
+ case IPP_TAG_TEXT :
+ case IPP_TAG_TEXTLANG :
+ case IPP_TAG_URISCHEME :
+ for (i = 0; i < count; i ++)
+ {
+ const char *value = ippGetString(attr, i, NULL);
+ /* Current string value */
+
+ if (ippContainsString(fromattr, value))
+ {
+ if (!matchbuf[0])
+ strlcpy(matchbuf, value, matchlen);
+ }
+ else
+ {
+ add_stringf(errors, "GOT: %s='%s'", ippGetName(attr), value);
+ match = 0;
+ }
+ }
+ break;
+
+ case IPP_TAG_URI :
+ for (i = 0; i < count; i ++)
+ {
+ const char *value = ippGetString(attr, i, NULL);
+ /* Current string value */
+ int fromcount = ippGetCount(fromattr);
+
+ for (j = 0; j < fromcount; j ++)
+ {
+ if (!compare_uris(value, ippGetString(fromattr, j, NULL)))
+ {
+ if (!matchbuf[0])
+ strlcpy(matchbuf, value, matchlen);
+ break;
+ }
+ }
+
+ if (j >= fromcount)
+ {
+ add_stringf(errors, "GOT: %s='%s'", ippGetName(attr), value);
+ match = 0;
+ }
+ }
+ break;
+
+ default :
+ match = 0;
+ break;
+ }
+
+ return (match);
+
+ /* value tag mismatch between fromattr and attr */
+ wrong_value_tag :
+
+ add_stringf(errors, "GOT: %s OF-TYPE %s", ippGetName(attr), ippTagString(ippGetValueTag(attr)));
+
+ return (0);
+}