*
* ipptool command for CUPS.
*
- * Copyright 2007-2010 by Apple Inc.
+ * Copyright 2007-2011 by Apple Inc.
* Copyright 1997-2007 by Easy Software Products.
*
* These coded instructions, statements, and computer programs are the
* 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.
+ *
* Contents:
*
* main() - Parse options and do tests.
* get_variable() - Get the value of a variable.
* iso_date() - Return an ISO 8601 date/time string for the given IPP
* dateTime value.
+ * password_cb() - Password callback for authenticated tests.
* print_attr() - Print an attribute on the screen.
* print_col() - Print a collection attribute on the screen.
* print_csv() - Print a line of CSV text.
* print_fatal_error() - Print a fatal error message.
- * print_line() - Print a line of formatted text.
+ * print_line() - Print a line of formatted or CSV text.
* print_test_error() - Print a test error message.
* print_xml_header() - Print a standard XML plist header.
* print_xml_string() - Print an XML string with escaping.
* print_xml_trailer() - Print the XML trailer with success/fail value.
* set_variable() - Set a variable value.
+ * sigterm_handler() - Handle SIGINT and SIGTERM.
+ * timeout_cb() - Handle HTTP timeouts.
* usage() - Show program usage.
* validate_attr() - Determine whether an attribute is valid.
* with_value() - Test a WITH-VALUE predicate.
#include <cups/cups-private.h>
#include <cups/file-private.h>
#include <regex.h>
+#include <sys/stat.h>
#ifndef O_BINARY
# define O_BINARY 0
*of_type, /* Type name */
*same_count_as, /* Parallel attribute name */
*if_defined, /* Only required if variable defined */
- *if_undefined, /* Only required if variable is not defined */
- *with_value; /* Attribute must include this value */
+ *if_not_defined, /* Only required if variable is not defined */
+ *with_value, /* Attribute must include this value */
+ *define_match, /* Variable to define on match */
+ *define_no_match, /* Variable to define on no-match */
+ *define_value; /* Variable to define with value */
int with_regex, /* WITH-VALUE is a regular expression */
count; /* Expected count if > 0 */
ipp_tag_t in_group; /* IN-GROUP value */
{
ipp_status_t status; /* Expected status code */
char *if_defined, /* Only if variable is defined */
- *if_undefined; /* Only if variable is not defined */
+ *if_not_defined; /* Only if variable is not defined */
} _cups_status_t;
typedef struct _cups_var_s /**** Variable ****/
resource[1024]; /* Resource path from URI */
int port; /* Port number from URI */
http_encryption_t encryption; /* Encryption for connection? */
+ double timeout; /* Timeout for connection */
+ int family; /* Address family */
cups_array_t *vars; /* Array of variables */
} _cups_vars_t;
/* How to transfer requests */
_cups_output_t Output = _CUPS_OUTPUT_LIST;
/* Output mode */
-int Verbosity = 0, /* Show all attributes? */
+int Cancel = 0, /* Cancel test? */
+ IgnoreErrors = 0, /* Ignore errors? */
+ Verbosity = 0, /* Show all attributes? */
Version = 11, /* Default IPP version */
XMLHeader = 0; /* 1 if header is written */
+char *Password = NULL; /* Password from URI */
const char * const URIStatusStrings[] = /* URI status strings */
{
"URI too large",
static int compare_vars(_cups_var_t *a, _cups_var_t *b);
static int do_tests(_cups_vars_t *vars, const char *testfile);
static void expand_variables(_cups_vars_t *vars, char *dst, const char *src,
- size_t dstsize)
-#ifdef __GNUC__
-__attribute((nonnull(1,2,3)))
-#endif /* __GNUC__ */
-;
+ 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(_cups_vars_t *vars, FILE *fp, int *linenum);
static char *get_filename(const char *testfile, char *dst, const char *src,
int *linenum);
static char *get_variable(_cups_vars_t *vars, const char *name);
static char *iso_date(ipp_uchar_t *date);
-static void print_attr(ipp_attribute_t *attr);
+static const char *password_cb(const char *prompt);
+static void print_attr(ipp_attribute_t *attr, ipp_tag_t *group);
static void print_col(ipp_t *col);
static void print_csv(ipp_attribute_t *attr, int num_displayed,
char **displayed, size_t *widths);
static void print_fatal_error(const char *s, ...)
-#ifdef __GNUC__
-__attribute__ ((__format__ (__printf__, 1, 2)))
-#endif /* __GNUC__ */
-;
+ __attribute__ ((__format__ (__printf__, 1, 2)));
static void print_line(ipp_attribute_t *attr, int num_displayed,
char **displayed, size_t *widths);
static void print_test_error(const char *s, ...)
-#ifdef __GNUC__
-__attribute__ ((__format__ (__printf__, 1, 2)))
-#endif /* __GNUC__ */
-;
+ __attribute__ ((__format__ (__printf__, 1, 2)));
static void print_xml_header(void);
static void print_xml_string(const char *element, const char *s);
static void print_xml_trailer(int success, const char *message);
static void set_variable(_cups_vars_t *vars, const char *name,
const char *value);
-static void usage(void);
+static void sigterm_handler(int sig);
+static int timeout_cb(http_t *http, void *user_data);
+static void usage(void) __attribute__((noreturn));
static int validate_attr(ipp_attribute_t *attr, int print);
-static int with_value(char *value, int regex, ipp_attribute_t *attr);
+static int with_value(char *value, int regex, ipp_attribute_t *attr,
+ int report);
/*
filename[1024], /* Real filename */
testname[1024]; /* Real test filename */
const char *testfile; /* Test file to use */
- int interval, /* Test interval */
+ int interval, /* Test interval in microseconds */
repeat; /* Repeat count */
_cups_vars_t vars; /* Variables */
http_uri_status_t uri_status; /* URI separation status */
/* Global data */
+ /*
+ * Catch SIGINT and SIGTERM...
+ */
+
+ signal(SIGINT, sigterm_handler);
+ signal(SIGTERM, sigterm_handler);
/*
* Initialize the locale and variables...
_cupsSetLocale(argv);
memset(&vars, 0, sizeof(vars));
- vars.vars = cupsArrayNew((cups_array_func_t)compare_vars, NULL);
+ vars.family = AF_UNSPEC;
+ vars.vars = cupsArrayNew((cups_array_func_t)compare_vars, NULL);
/*
* We need at least:
{
switch (*opt)
{
+ case '4' : /* Connect using IPv4 only */
+ vars.family = AF_INET;
+ break;
+
+#ifdef AF_INET6
+ case '6' : /* Connect using IPv6 only */
+ vars.family = AF_INET6;
+ break;
+#endif /* AF_INET6 */
+
case 'C' : /* Enable HTTP chunking */
Transfer = _CUPS_TRANSFER_CHUNKED;
break;
#ifdef HAVE_SSL
vars.encryption = HTTP_ENCRYPT_REQUIRED;
#else
- _cupsLangPrintf(stderr,
- _("%s: Sorry, no encryption support compiled in\n"),
+ _cupsLangPrintf(stderr, _("%s: Sorry, no encryption support."),
argv[0]);
#endif /* HAVE_SSL */
break;
+ case 'I' : /* Ignore errors */
+ IgnoreErrors = 1;
+ break;
+
case 'L' : /* Disable HTTP chunking */
Transfer = _CUPS_TRANSFER_LENGTH;
break;
#ifdef HAVE_SSL
vars.encryption = HTTP_ENCRYPT_ALWAYS;
#else
- _cupsLangPrintf(stderr,
- _("%s: Sorry, no encryption support compiled in\n"),
+ _cupsLangPrintf(stderr, _("%s: Sorry, no encryption support."),
argv[0]);
#endif /* HAVE_SSL */
break;
+ case 'T' : /* Set timeout */
+ i ++;
+
+ if (i >= argc)
+ {
+ _cupsLangPuts(stderr,
+ _("ipptool: Missing timeout for \"-T\"."));
+ usage();
+ }
+
+ vars.timeout = _cupsStrScand(argv[i], NULL, localeconv());
+ break;
+
case 'V' : /* Set IPP version */
i ++;
if (i >= argc)
{
_cupsLangPuts(stderr,
- _("ipptool: Missing version for \"-V\".\n"));
+ _("ipptool: Missing version for \"-V\"."));
usage();
}
else
{
_cupsLangPrintf(stderr,
- _("ipptool: Bad version %s for \"-V\".\n"),
+ _("ipptool: Bad version %s for \"-V\"."),
argv[i]);
usage();
}
if (interval || repeat)
{
_cupsLangPuts(stderr, _("ipptool: \"-i\" and \"-n\" are "
- "incompatible with -X\".\n"));
+ "incompatible with -X\"."));
usage();
}
break;
if (i >= argc)
{
_cupsLangPuts(stderr,
- _("ipptool: Missing name=value for \"-d\".\n"));
+ _("ipptool: Missing name=value for \"-d\"."));
usage();
}
if (i >= argc)
{
_cupsLangPuts(stderr,
- _("ipptool: Missing filename for \"-f\".\n"));
+ _("ipptool: Missing filename for \"-f\"."));
usage();
}
if (i >= argc)
{
_cupsLangPuts(stderr,
- _("ipptool: Missing seconds for \"-i\".\n"));
+ _("ipptool: Missing seconds for \"-i\"."));
usage();
}
else
- interval = atoi(argv[i]);
+ {
+ interval = (int)(_cupsStrScand(argv[i], NULL, localeconv()) *
+ 1000000.0);
+ if (interval <= 0)
+ {
+ _cupsLangPuts(stderr,
+ _("ipptool: Invalid seconds for \"-i\"."));
+ usage();
+ }
+ }
if (Output == _CUPS_OUTPUT_PLIST && interval)
{
_cupsLangPuts(stderr, _("ipptool: \"-i\" is incompatible with "
- "\"-X\".\n"));
+ "\"-X\"."));
usage();
}
break;
if (i >= argc)
{
_cupsLangPuts(stderr,
- _("ipptool: Missing count for \"-n\".\n"));
+ _("ipptool: Missing count for \"-n\"."));
usage();
}
else
if (Output == _CUPS_OUTPUT_PLIST && repeat)
{
_cupsLangPuts(stderr, _("ipptool: \"-n\" is incompatible with "
- "\"-X\".\n"));
+ "\"-X\"."));
usage();
}
break;
break;
default :
- _cupsLangPrintf(stderr, _("ipptool: Unknown option \"-%c\".\n"),
+ _cupsLangPrintf(stderr, _("ipptool: Unknown option \"-%c\"."),
*opt);
usage();
break;
}
}
}
- else if (!strncmp(argv[i], "ipp://", 6) ||
- !strncmp(argv[i], "http://", 7) ||
- !strncmp(argv[i], "https://", 8))
+ else if (!strncmp(argv[i], "ipp://", 6) || !strncmp(argv[i], "http://", 7)
+#ifdef HAVE_SSL
+ || !strncmp(argv[i], "ipps://", 7)
+ || !strncmp(argv[i], "https://", 8)
+#endif /* HAVE_SSL */
+ )
{
/*
* Set URI...
if (vars.uri)
{
- _cupsLangPuts(stderr, _("ipptool: May only specify a single URI.\n"));
+ _cupsLangPuts(stderr, _("ipptool: May only specify a single URI."));
usage();
}
+#ifdef HAVE_SSL
+ if (!strncmp(argv[i], "ipps://", 7) || !strncmp(argv[i], "https://", 8))
+ vars.encryption = HTTP_ENCRYPT_ALWAYS;
+#endif /* HAVE_SSL */
+
vars.uri = argv[i];
uri_status = httpSeparateURI(HTTP_URI_CODING_ALL, vars.uri,
vars.scheme, sizeof(vars.scheme),
if (uri_status != HTTP_URI_OK)
{
- _cupsLangPrintf(stderr, _("ipptool: Bad URI - %s.\n"),
+ _cupsLangPrintf(stderr, _("ipptool: Bad URI - %s."),
URIStatusStrings[uri_status - HTTP_URI_OVERFLOW]);
return (1);
}
- if (strcmp(vars.scheme, "http") && strcmp(vars.scheme, "https") &&
- strcmp(vars.scheme, "ipp"))
+ if (vars.userpass[0])
{
- _cupsLangPuts(stderr, _("ipptool: Only http, https, and ipp URIs are "
- "supported."));
- return (1);
+ if ((Password = strchr(vars.userpass, ':')) != NULL)
+ *Password++ = '\0';
+
+ cupsSetUser(vars.userpass);
+ cupsSetPasswordCB(password_cb);
+ set_variable(&vars, "uriuser", vars.userpass);
}
}
else
if (Output == _CUPS_OUTPUT_PLIST)
print_xml_trailer(!status, NULL);
- else if (interval && repeat > 0)
+ else if (interval > 0 && repeat > 0)
{
while (repeat > 1)
{
- sleep(interval);
+ usleep(interval);
do_tests(&vars, testfile);
repeat --;
}
}
- else if (interval)
+ else if (interval > 0)
{
for (;;)
{
- sleep(interval);
+ usleep(interval);
do_tests(&vars, testfile);
}
}
compare_vars(_cups_var_t *a, /* I - First variable */
_cups_var_t *b) /* I - Second variable */
{
- return (strcasecmp(a->name, b->name));
+ return (_cups_strcasecmp(a->name, b->name));
}
int i, /* Looping var */
linenum, /* Current line number */
pass, /* Did we pass the test? */
+ prev_pass = 1, /* Did we pass the previous test? */
request_id, /* Current request ID */
- show_header = 1; /* Show the test header? */
+ show_header = 1, /* Show the test header? */
+ ignore_errors, /* Ignore test failures? */
+ skip_previous = 0; /* Skip on previous test failure? */
http_t *http = NULL; /* HTTP connection to server */
FILE *fp = NULL; /* Test file */
char resource[512], /* Resource for request */
token[1024], /* Token from file */
*tokenptr, /* Pointer into token */
- temp[1024]; /* Temporary string */
- ipp_t *request = NULL; /* IPP request */
- ipp_t *response = NULL; /* IPP response */
+ temp[1024], /* Temporary string */
+ buffer[8192]; /* Copy buffer */
+ ipp_t *request = NULL, /* IPP request */
+ *response = NULL; /* IPP response */
+ size_t length; /* Length of IPP request */
+ http_status_t status; /* HTTP status */
+ int fd; /* File to send */
+ ssize_t bytes; /* Bytes read/written */
char attr[128]; /* Attribute name */
ipp_op_t op; /* Operation */
ipp_tag_t group; /* Current group */
char name[1024]; /* Name of test */
char filename[1024]; /* Filename */
_cups_transfer_t transfer; /* To chunk or not to chunk */
- int version; /* IPP version number to use */
+ int version, /* IPP version number to use */
+ skip_test; /* Skip this test? */
int num_statuses = 0; /* Number of valid status codes */
_cups_status_t statuses[100], /* Valid status codes */
*last_status; /* Last STATUS (for predicates) */
{
print_fatal_error("Unable to open test file %s - %s", testfile,
strerror(errno));
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
/*
* Connect to the server...
*/
- if ((http = httpConnectEncrypt(vars->hostname, vars->port,
- vars->encryption)) == NULL)
+ if ((http = _httpCreate(vars->hostname, vars->port, NULL, vars->encryption,
+ vars->family)) == NULL)
+ {
+ print_fatal_error("Unable to connect to %s on port %d - %s", vars->hostname,
+ vars->port, cupsLastErrorString());
+ pass = 0;
+ goto test_exit;
+ }
+
+ if (httpReconnect(http))
{
print_fatal_error("Unable to connect to %s on port %d - %s", vars->hostname,
- vars->port, strerror(errno));
- goto test_error;
+ vars->port, cupsLastErrorString());
+ pass = 0;
+ goto test_exit;
}
+ if (vars->timeout > 0.0)
+ httpSetTimeout(http, vars->timeout, timeout_cb, NULL);
+
/*
* Loop on tests...
*/
linenum = 1;
request_id = (CUPS_RAND() % 1000) * 137 + 1;
- while (get_token(fp, token, sizeof(token), &linenum) != NULL)
+ while (!Cancel && get_token(fp, token, sizeof(token), &linenum) != NULL)
{
/*
* Expect an open brace...
{
print_fatal_error("Missing DEFINE name and/or value on line %d.",
linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
+ }
+
+ continue;
+ }
+ else if (!strcmp(token, "DEFINE-DEFAULT"))
+ {
+ /*
+ * DEFINE-DEFAULT name value
+ */
+
+ if (get_token(fp, attr, sizeof(attr), &linenum) &&
+ get_token(fp, temp, sizeof(temp), &linenum))
+ {
+ expand_variables(vars, token, temp, sizeof(token));
+ if (!get_variable(vars, attr))
+ set_variable(vars, attr, token);
+ }
+ else
+ {
+ print_fatal_error("Missing DEFINE-DEFAULT name and/or value on line "
+ "%d.", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ continue;
+ }
+ else if (!strcmp(token, "IGNORE-ERRORS"))
+ {
+ /*
+ * IGNORE-ERRORS yes
+ * IGNORE-ERRORS no
+ */
+
+ if (get_token(fp, temp, sizeof(temp), &linenum) &&
+ (!_cups_strcasecmp(temp, "yes") || !_cups_strcasecmp(temp, "no")))
+ {
+ IgnoreErrors = !_cups_strcasecmp(temp, "yes");
+ }
+ else
+ {
+ print_fatal_error("Missing IGNORE-ERRORS value on line %d.", linenum);
+ pass = 0;
+ goto test_exit;
}
continue;
if (!do_tests(vars, get_filename(testfile, filename, temp,
sizeof(filename))))
- goto test_error;
+ {
+ pass = 0;
+
+ if (!IgnoreErrors)
+ goto test_exit;
+ }
}
else
{
print_fatal_error("Missing INCLUDE filename on line %d.", linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
show_header = 1;
continue;
}
+ else if (!strcmp(token, "INCLUDE-IF-DEFINED"))
+ {
+ /*
+ * INCLUDE-IF-DEFINED name "filename"
+ * INCLUDE-IF-DEFINED name <filename>
+ */
+
+ if (get_token(fp, attr, sizeof(attr), &linenum) &&
+ get_token(fp, temp, sizeof(temp), &linenum))
+ {
+ /*
+ * Map the filename to and then run the tests...
+ */
+
+ if (get_variable(vars, attr) &&
+ !do_tests(vars, get_filename(testfile, filename, temp,
+ sizeof(filename))))
+ {
+ pass = 0;
+
+ if (!IgnoreErrors)
+ goto test_exit;
+ }
+ }
+ else
+ {
+ print_fatal_error("Missing INCLUDE-IF-DEFINED name or filename on line "
+ "%d.", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ show_header = 1;
+ continue;
+ }
+ else if (!strcmp(token, "INCLUDE-IF-NOT-DEFINED"))
+ {
+ /*
+ * INCLUDE-IF-NOT-DEFINED name "filename"
+ * INCLUDE-IF-NOT-DEFINED name <filename>
+ */
+
+ if (get_token(fp, attr, sizeof(attr), &linenum) &&
+ get_token(fp, temp, sizeof(temp), &linenum))
+ {
+ /*
+ * Map the filename to and then run the tests...
+ */
+
+ if (!get_variable(vars, attr) &&
+ !do_tests(vars, get_filename(testfile, filename, temp,
+ sizeof(filename))))
+ {
+ pass = 0;
+
+ if (!IgnoreErrors)
+ goto test_exit;
+ }
+ }
+ else
+ {
+ print_fatal_error("Missing INCLUDE-IF-NOT-DEFINED name or filename on "
+ "line %d.", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ show_header = 1;
+ continue;
+ }
+ else if (!strcmp(token, "SKIP-IF-DEFINED"))
+ {
+ /*
+ * SKIP-IF-DEFINED variable
+ */
+
+ if (get_token(fp, temp, sizeof(temp), &linenum))
+ {
+ if (get_variable(vars, temp))
+ goto test_exit;
+ }
+ else
+ {
+ print_fatal_error("Missing SKIP-IF-DEFINED variable on line %d.",
+ linenum);
+ pass = 0;
+ goto test_exit;
+ }
+ }
+ else if (!strcmp(token, "SKIP-IF-NOT-DEFINED"))
+ {
+ /*
+ * SKIP-IF-NOT-DEFINED variable
+ */
+
+ if (get_token(fp, temp, sizeof(temp), &linenum))
+ {
+ if (!get_variable(vars, temp))
+ goto test_exit;
+ }
+ else
+ {
+ print_fatal_error("Missing SKIP-IF-NOT-DEFINED variable on line %d.",
+ linenum);
+ pass = 0;
+ goto test_exit;
+ }
+ }
else if (!strcmp(token, "TRANSFER"))
{
/*
{
print_fatal_error("Bad TRANSFER value \"%s\" on line %d.", temp,
linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
}
else
{
print_fatal_error("Missing TRANSFER value on line %d.", linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
continue;
else
{
print_fatal_error("Bad VERSION \"%s\" on line %d.", temp, linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
}
else
{
print_fatal_error("Missing VERSION number on line %d.", linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
continue;
else if (strcmp(token, "{"))
{
print_fatal_error("Unexpected token %s seen on line %d.", token, linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
/*
request = ippNew();
op = (ipp_op_t)0;
group = IPP_TAG_ZERO;
+ ignore_errors = IgnoreErrors;
last_expect = NULL;
last_status = NULL;
filename[0] = '\0';
+ skip_test = 0;
version = Version;
transfer = Transfer;
while (get_token(fp, token, sizeof(token), &linenum) != NULL)
{
- if (strcasecmp(token, "COUNT") &&
- strcasecmp(token, "IF-DEFINED") &&
- strcasecmp(token, "IF-UNDEFINED") &&
- strcasecmp(token, "IN-GROUP") &&
- strcasecmp(token, "OF-TYPE") &&
- strcasecmp(token, "SAME-COUNT-AS") &&
- strcasecmp(token, "WITH-VALUE"))
+ if (_cups_strcasecmp(token, "COUNT") &&
+ _cups_strcasecmp(token, "DEFINE-MATCH") &&
+ _cups_strcasecmp(token, "DEFINE-NO-MATCH") &&
+ _cups_strcasecmp(token, "DEFINE-VALUE") &&
+ _cups_strcasecmp(token, "IF-DEFINED") &&
+ _cups_strcasecmp(token, "IF-NOT-DEFINED") &&
+ _cups_strcasecmp(token, "IN-GROUP") &&
+ _cups_strcasecmp(token, "OF-TYPE") &&
+ _cups_strcasecmp(token, "SAME-COUNT-AS") &&
+ _cups_strcasecmp(token, "WITH-VALUE"))
last_expect = NULL;
- if (strcasecmp(token, "IF-DEFINED") &&
- strcasecmp(token, "IF-UNDEFINED"))
+ if (_cups_strcasecmp(token, "IF-DEFINED") &&
+ _cups_strcasecmp(token, "IF-NOT-DEFINED"))
last_status = NULL;
if (!strcmp(token, "}"))
sizeof(ipp_value_t))) == NULL)
{
print_fatal_error("Unable to allocate memory on line %d.", linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
if (tempcol != lastcol)
lastcol->num_values ++;
}
else
- goto test_error;
+ {
+ pass = 0;
+ goto test_exit;
+ }
}
else if (!strcmp(token, "DEFINE"))
{
{
print_fatal_error("Missing DEFINE name and/or value on line %d.",
linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
}
- else if (!strcasecmp(token, "NAME"))
+ else if (!strcmp(token, "IGNORE-ERRORS"))
+ {
+ /*
+ * IGNORE-ERRORS yes
+ * IGNORE-ERRORS no
+ */
+
+ if (get_token(fp, temp, sizeof(temp), &linenum) &&
+ (!_cups_strcasecmp(temp, "yes") || !_cups_strcasecmp(temp, "no")))
+ {
+ ignore_errors = !_cups_strcasecmp(temp, "yes");
+ }
+ else
+ {
+ print_fatal_error("Missing IGNORE-ERRORS value on line %d.", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ continue;
+ }
+ else if (!_cups_strcasecmp(token, "NAME"))
{
/*
* Name of test...
{
if (isdigit(temp[0] & 255))
request_id = atoi(temp);
- else if (!strcasecmp(temp, "random"))
+ else if (!_cups_strcasecmp(temp, "random"))
request_id = (CUPS_RAND() % 1000) * 137 + 1;
else
{
print_fatal_error("Bad REQUEST-ID value \"%s\" on line %d.", temp,
linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
}
else
{
print_fatal_error("Missing REQUEST-ID value on line %d.", linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
+ }
+ }
+ else if (!strcmp(token, "SKIP-IF-DEFINED"))
+ {
+ /*
+ * SKIP-IF-DEFINED variable
+ */
+
+ if (get_token(fp, temp, sizeof(temp), &linenum))
+ {
+ if (get_variable(vars, temp))
+ skip_test = 1;
+ }
+ else
+ {
+ print_fatal_error("Missing SKIP-IF-DEFINED value on line %d.",
+ linenum);
+ pass = 0;
+ goto test_exit;
+ }
+ }
+ else if (!strcmp(token, "SKIP-IF-NOT-DEFINED"))
+ {
+ /*
+ * SKIP-IF-NOT-DEFINED variable
+ */
+
+ if (get_token(fp, temp, sizeof(temp), &linenum))
+ {
+ if (!get_variable(vars, temp))
+ skip_test = 1;
+ }
+ else
+ {
+ print_fatal_error("Missing SKIP-IF-NOT-DEFINED value on line %d.",
+ linenum);
+ pass = 0;
+ goto test_exit;
}
}
+ else if (!strcmp(token, "SKIP-PREVIOUS-ERROR"))
+ {
+ /*
+ * SKIP-PREVIOUS-ERROR yes
+ * SKIP-PREVIOUS-ERROR no
+ */
+
+ if (get_token(fp, temp, sizeof(temp), &linenum) &&
+ (!_cups_strcasecmp(temp, "yes") || !_cups_strcasecmp(temp, "no")))
+ {
+ skip_previous = !_cups_strcasecmp(temp, "yes");
+ }
+ else
+ {
+ print_fatal_error("Missing SKIP-PREVIOUS-ERROR value on line %d.", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ continue;
+ }
else if (!strcmp(token, "TRANSFER"))
{
/*
{
print_fatal_error("Bad TRANSFER value \"%s\" on line %d.", temp,
linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
}
else
{
print_fatal_error("Missing TRANSFER value on line %d.", linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
}
- else if (!strcasecmp(token, "VERSION"))
+ else if (!_cups_strcasecmp(token, "VERSION"))
{
if (get_token(fp, temp, sizeof(temp), &linenum))
{
else
{
print_fatal_error("Bad VERSION \"%s\" on line %d.", temp, linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
}
else
{
print_fatal_error("Missing VERSION number on line %d.", linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
}
- else if (!strcasecmp(token, "RESOURCE"))
+ else if (!_cups_strcasecmp(token, "RESOURCE"))
{
/*
* Resource name...
if (!get_token(fp, resource, sizeof(resource), &linenum))
{
print_fatal_error("Missing RESOURCE path on line %d.", linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
}
- else if (!strcasecmp(token, "OPERATION"))
+ else if (!_cups_strcasecmp(token, "OPERATION"))
{
/*
* Operation...
if (!get_token(fp, token, sizeof(token), &linenum))
{
print_fatal_error("Missing OPERATION code on line %d.", linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
- if ((op = ippOpValue(token)) < 0 && (op = strtol(token, NULL, 0)) == 0)
+ if ((op = ippOpValue(token)) == (ipp_op_t)-1 &&
+ (op = strtol(token, NULL, 0)) == 0)
{
print_fatal_error("Bad OPERATION code \"%s\" on line %d.", token,
linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
}
- else if (!strcasecmp(token, "GROUP"))
+ else if (!_cups_strcasecmp(token, "GROUP"))
{
/*
* Attribute group...
if (!get_token(fp, token, sizeof(token), &linenum))
{
print_fatal_error("Missing GROUP tag on line %d.", linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
if ((value = ippTagValue(token)) < 0)
{
print_fatal_error("Bad GROUP tag \"%s\" on line %d.", token, linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
if (value == group)
group = value;
}
- else if (!strcasecmp(token, "DELAY"))
+ else if (!_cups_strcasecmp(token, "DELAY"))
{
/*
* Delay before operation...
*/
- int delay;
+ double delay;
if (!get_token(fp, token, sizeof(token), &linenum))
{
print_fatal_error("Missing DELAY value on line %d.", linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
- if ((delay = atoi(token)) <= 0)
+ if ((delay = _cupsStrScand(token, NULL, localeconv())) <= 0.0)
{
print_fatal_error("Bad DELAY value \"%s\" on line %d.", token,
linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
else
- sleep(delay);
+ {
+ if (Output == _CUPS_OUTPUT_TEST)
+ printf(" [%g second delay]\n", delay);
+
+ usleep((int)(1000000.0 * delay));
+ }
}
- else if (!strcasecmp(token, "ATTR"))
+ else if (!_cups_strcasecmp(token, "ATTR"))
{
/*
* Attribute...
if (!get_token(fp, token, sizeof(token), &linenum))
{
print_fatal_error("Missing ATTR value tag on line %d.", linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
if ((value = ippTagValue(token)) == IPP_TAG_ZERO)
{
print_fatal_error("Bad ATTR value tag \"%s\" on line %d.", token,
linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
if (!get_token(fp, attr, sizeof(attr), &linenum))
{
print_fatal_error("Missing ATTR name on line %d.", linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
if (!get_token(fp, temp, sizeof(temp), &linenum))
{
print_fatal_error("Missing ATTR value on line %d.", linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
expand_variables(vars, token, temp, sizeof(token));
switch (value)
{
case IPP_TAG_BOOLEAN :
- if (!strcasecmp(token, "true"))
+ if (!_cups_strcasecmp(token, "true"))
ippAddBoolean(request, group, attr, 1);
else
ippAddBoolean(request, group, attr, atoi(token));
case IPP_TAG_INTEGER :
case IPP_TAG_ENUM :
- ippAddInteger(request, group, value, attr, atoi(token));
+ if (!strchr(token, ','))
+ ippAddInteger(request, group, value, attr,
+ strtol(token, &tokenptr, 0));
+ else
+ {
+ int values[100], /* Values */
+ num_values = 1; /* Number of values */
+
+ values[0] = strtol(token, &tokenptr, 10);
+ while (tokenptr && *tokenptr &&
+ num_values < (int)(sizeof(values) / sizeof(values[0])))
+ {
+ if (*tokenptr == ',')
+ tokenptr ++;
+ else if (!isdigit(*tokenptr & 255) && *tokenptr != '-')
+ break;
+
+ values[num_values] = strtol(tokenptr, &tokenptr, 0);
+ num_values ++;
+ }
+
+ ippAddIntegers(request, group, value, attr, num_values, values);
+ }
+
+ if (!tokenptr || *tokenptr)
+ {
+ print_fatal_error("Bad %s value \"%s\" on line %d.",
+ ippTagString(value), token, linenum);
+ pass = 0;
+ goto test_exit;
+ }
break;
case IPP_TAG_RESOLUTION :
{
int xres, /* X resolution */
- yres; /* Y resolution */
- char *ptr; /* Pointer into value */
+ yres; /* Y resolution */
+ char *ptr; /* Pointer into value */
xres = yres = strtol(token, (char **)&ptr, 10);
if (ptr > token && xres > 0)
}
if (ptr <= token || xres <= 0 || yres <= 0 || !ptr ||
- (strcasecmp(ptr, "dpi") && strcasecmp(ptr, "dpc") &&
- strcasecmp(ptr, "other")))
+ (_cups_strcasecmp(ptr, "dpi") && _cups_strcasecmp(ptr, "dpc") &&
+ _cups_strcasecmp(ptr, "other")))
{
print_fatal_error("Bad resolution value \"%s\" on line %d.",
token, linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
- if (!strcasecmp(ptr, "dpi"))
+ if (!_cups_strcasecmp(ptr, "dpi"))
ippAddResolution(request, group, attr, IPP_RES_PER_INCH,
xres, yres);
- else if (!strcasecmp(ptr, "dpc"))
+ else if (!_cups_strcasecmp(ptr, "dpc"))
ippAddResolution(request, group, attr, IPP_RES_PER_CM,
xres, yres);
else
{
print_fatal_error("Bad rangeOfInteger value \"%s\" on line "
"%d.", token, linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
ippAddRanges(request, group, attr, num_vals / 2, lowers,
ippDelete(col);
}
else
- goto test_error;
+ {
+ pass = 0;
+ goto test_exit;
+ }
}
else
{
print_fatal_error("Bad ATTR collection value on line %d.",
linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
break;
default :
print_fatal_error("Unsupported ATTR value tag %s on line %d.",
ippTagString(value), linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
case IPP_TAG_TEXTLANG :
case IPP_TAG_NAMELANG :
break;
}
}
- else if (!strcasecmp(token, "FILE"))
+ else if (!_cups_strcasecmp(token, "FILE"))
{
/*
* File...
if (!get_token(fp, temp, sizeof(temp), &linenum))
{
print_fatal_error("Missing FILE filename on line %d.", linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
expand_variables(vars, token, temp, sizeof(token));
get_filename(testfile, filename, token, sizeof(filename));
}
- else if (!strcasecmp(token, "STATUS"))
+ else if (!_cups_strcasecmp(token, "STATUS"))
{
/*
* Status...
if (num_statuses >= (int)(sizeof(statuses) / sizeof(statuses[0])))
{
print_fatal_error("Too many STATUS's on line %d.", linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
if (!get_token(fp, token, sizeof(token), &linenum))
{
print_fatal_error("Missing STATUS code on line %d.", linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
- if ((statuses[num_statuses].status = ippErrorValue(token)) < 0)
+ if ((statuses[num_statuses].status = ippErrorValue(token))
+ == (ipp_status_t)-1 &&
+ (statuses[num_statuses].status = strtol(token, NULL, 0)) == 0)
{
print_fatal_error("Bad STATUS code \"%s\" on line %d.", token,
linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
last_status = statuses + num_statuses;
num_statuses ++;
last_status->if_defined = NULL;
- last_status->if_undefined = NULL;
+ last_status->if_not_defined = NULL;
}
- else if (!strcasecmp(token, "EXPECT"))
+ else if (!_cups_strcasecmp(token, "EXPECT"))
{
/*
* Expected attributes...
if (num_expects >= (int)(sizeof(expects) / sizeof(expects[0])))
{
print_fatal_error("Too many EXPECT's on line %d.", linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
if (!get_token(fp, token, sizeof(token), &linenum))
{
print_fatal_error("Missing EXPECT name on line %d.", linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
last_expect = expects + num_expects;
else
last_expect->name = strdup(token);
}
- else if (!strcasecmp(token, "COUNT"))
+ else if (!_cups_strcasecmp(token, "COUNT"))
{
if (!get_token(fp, token, sizeof(token), &linenum))
{
print_fatal_error("Missing COUNT number on line %d.", linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
if ((i = atoi(token)) <= 0)
{
print_fatal_error("Bad COUNT \"%s\" on line %d.", token, linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
if (last_expect)
{
print_fatal_error("COUNT without a preceding EXPECT on line %d.",
linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
+ }
+ }
+ else if (!_cups_strcasecmp(token, "DEFINE-MATCH"))
+ {
+ if (!get_token(fp, token, sizeof(token), &linenum))
+ {
+ print_fatal_error("Missing DEFINE-MATCH variable on line %d.",
+ linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ if (last_expect)
+ last_expect->define_match = strdup(token);
+ else
+ {
+ print_fatal_error("DEFINE-MATCH without a preceding EXPECT on line "
+ "%d.", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+ }
+ else if (!_cups_strcasecmp(token, "DEFINE-NO-MATCH"))
+ {
+ if (!get_token(fp, token, sizeof(token), &linenum))
+ {
+ print_fatal_error("Missing DEFINE-NO-MATCH variable on line %d.",
+ linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ if (last_expect)
+ last_expect->define_no_match = strdup(token);
+ else
+ {
+ print_fatal_error("DEFINE-NO-MATCH without a preceding EXPECT on "
+ "line %d.", linenum);
+ pass = 0;
+ goto test_exit;
+ }
+ }
+ else if (!_cups_strcasecmp(token, "DEFINE-VALUE"))
+ {
+ if (!get_token(fp, token, sizeof(token), &linenum))
+ {
+ print_fatal_error("Missing DEFINE-VALUE variable on line %d.",
+ linenum);
+ pass = 0;
+ goto test_exit;
+ }
+
+ if (last_expect)
+ last_expect->define_value = strdup(token);
+ else
+ {
+ print_fatal_error("DEFINE-VALUE without a preceding EXPECT on line "
+ "%d.", linenum);
+ pass = 0;
+ goto test_exit;
}
}
- else if (!strcasecmp(token, "OF-TYPE"))
+ else if (!_cups_strcasecmp(token, "OF-TYPE"))
{
if (!get_token(fp, token, sizeof(token), &linenum))
{
print_fatal_error("Missing OF-TYPE value tag(s) on line %d.",
linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
if (last_expect)
{
print_fatal_error("OF-TYPE without a preceding EXPECT on line %d.",
linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
}
- else if (!strcasecmp(token, "IN-GROUP"))
+ else if (!_cups_strcasecmp(token, "IN-GROUP"))
{
ipp_tag_t in_group; /* IN-GROUP value */
if (!get_token(fp, token, sizeof(token), &linenum))
{
print_fatal_error("Missing IN-GROUP group tag on line %d.", linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
if ((in_group = ippTagValue(token)) == (ipp_tag_t)-1)
{
print_fatal_error("IN-GROUP without a preceding EXPECT on line %d.",
linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
}
- else if (!strcasecmp(token, "SAME-COUNT-AS"))
+ else if (!_cups_strcasecmp(token, "SAME-COUNT-AS"))
{
if (!get_token(fp, token, sizeof(token), &linenum))
{
print_fatal_error("Missing SAME-COUNT-AS name on line %d.", linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
if (last_expect)
{
print_fatal_error("SAME-COUNT-AS without a preceding EXPECT on line "
"%d.", linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
}
- else if (!strcasecmp(token, "IF-DEFINED"))
+ else if (!_cups_strcasecmp(token, "IF-DEFINED"))
{
if (!get_token(fp, token, sizeof(token), &linenum))
{
print_fatal_error("Missing IF-DEFINED name on line %d.", linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
if (last_expect)
{
print_fatal_error("IF-DEFINED without a preceding EXPECT or STATUS "
"on line %d.", linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
}
- else if (!strcasecmp(token, "IF-UNDEFINED"))
+ else if (!_cups_strcasecmp(token, "IF-NOT-DEFINED"))
{
if (!get_token(fp, token, sizeof(token), &linenum))
{
- print_fatal_error("Missing IF-UNDEFINED name on line %d.", linenum);
- goto test_error;
+ print_fatal_error("Missing IF-NOT-DEFINED name on line %d.", linenum);
+ pass = 0;
+ goto test_exit;
}
if (last_expect)
- last_expect->if_undefined = strdup(token);
+ last_expect->if_not_defined = strdup(token);
else if (last_status)
- last_status->if_undefined = strdup(token);
+ last_status->if_not_defined = strdup(token);
else
{
- print_fatal_error("IF-UNDEFINED without a preceding EXPECT or STATUS "
+ print_fatal_error("IF-NOT-DEFINED without a preceding EXPECT or STATUS "
"on line %d.", linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
}
- else if (!strcasecmp(token, "WITH-VALUE"))
+ else if (!_cups_strcasecmp(token, "WITH-VALUE"))
{
- if (!get_token(fp, token, sizeof(token), &linenum))
+ if (!get_token(fp, temp, sizeof(temp), &linenum))
{
print_fatal_error("Missing WITH-VALUE value on line %d.", linenum);
- goto test_error;
+ 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));
+
tokenptr = token + strlen(token) - 1;
+
if (token[0] == '/' && tokenptr > token && *tokenptr == '/')
{
/*
{
print_fatal_error("WITH-VALUE without a preceding EXPECT on line %d.",
linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
}
- else if (!strcasecmp(token, "DISPLAY"))
+ else if (!_cups_strcasecmp(token, "DISPLAY"))
{
/*
* Display attributes...
if (num_displayed >= (int)(sizeof(displayed) / sizeof(displayed[0])))
{
print_fatal_error("Too many DISPLAY's on line %d", linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
if (!get_token(fp, token, sizeof(token), &linenum))
{
print_fatal_error("Missing DISPLAY name on line %d.", linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
displayed[num_displayed] = strdup(token);
{
print_fatal_error("Unexpected token %s seen on line %d.", token,
linenum);
- goto test_error;
+ pass = 0;
+ goto test_exit;
}
}
puts("<key>Operation</key>");
print_xml_string("string", ippOpString(op));
puts("<key>RequestAttributes</key>");
- puts("<dict>");
- for (attrptr = request->attrs; attrptr; attrptr = attrptr->next)
- print_attr(attrptr);
- puts("</dict>");
+ puts("<array>");
+ if (request->attrs)
+ {
+ puts("<dict>");
+ for (attrptr = request->attrs, group = attrptr->group_tag;
+ attrptr;
+ attrptr = attrptr->next)
+ print_attr(attrptr, &group);
+ puts("</dict>");
+ }
+ puts("</array>");
}
else if (Output == _CUPS_OUTPUT_TEST)
{
printf(" %s:\n", ippOpString(op));
for (attrptr = request->attrs; attrptr; attrptr = attrptr->next)
- print_attr(attrptr);
+ print_attr(attrptr, NULL);
}
printf(" %-69.69s [", name);
fflush(stdout);
}
+ if ((skip_previous && !prev_pass) || skip_test)
+ {
+ ippDelete(request);
+ request = NULL;
+
+ if (Output == _CUPS_OUTPUT_PLIST)
+ {
+ puts("<key>Successful</key>");
+ puts("<true />");
+ puts("<key>StatusCode</key>");
+ print_xml_string("string", "skip");
+ puts("<key>ResponseAttributes</key>");
+ puts("<dict>");
+ puts("</dict>");
+ }
+ else if (Output == _CUPS_OUTPUT_TEST)
+ puts("SKIP]");
+
+ goto skip_error;
+ }
+
+ status = HTTP_OK;
+
if (transfer == _CUPS_TRANSFER_CHUNKED ||
(transfer == _CUPS_TRANSFER_AUTO && filename[0]))
{
/*
- * Send request using chunking...
+ * Send request using chunking - a 0 length means "chunk".
*/
- http_status_t status = cupsSendRequest(http, request, resource, 0);
+ length = 0;
+ }
+ else
+ {
+ /*
+ * Send request using content length...
+ */
+
+ length = ippLength(request);
- if (status == HTTP_CONTINUE && filename[0])
+ if (filename[0])
{
- int fd; /* File to send */
- char buffer[8192]; /* Copy buffer */
- ssize_t bytes; /* Bytes read/written */
+ struct stat fileinfo; /* File information */
- if ((fd = open(filename, O_RDONLY | O_BINARY)) >= 0)
+ if (stat(filename, &fileinfo))
{
- while ((bytes = read(fd, buffer, sizeof(buffer))) > 0)
- if ((status = cupsWriteRequestData(http, buffer,
- bytes)) != HTTP_CONTINUE)
- break;
- }
- else
- {
snprintf(buffer, sizeof(buffer), "%s: %s", filename, strerror(errno));
_cupsSetError(IPP_INTERNAL_ERROR, buffer, 0);
status = HTTP_ERROR;
- }
+ }
+ else
+ length += fileinfo.st_size;
}
+ }
- ippDelete(request);
+ /*
+ * Send the request...
+ */
- if (status == HTTP_CONTINUE)
- response = cupsGetResponse(http, resource);
- else
- response = NULL;
+ response = NULL;
+
+ if (status != HTTP_ERROR)
+ {
+ while (!response && !Cancel)
+ {
+ status = cupsSendRequest(http, request, resource, length);
+
+ if (!Cancel && status == HTTP_CONTINUE && request->state == IPP_DATA &&
+ filename[0])
+ {
+ if ((fd = open(filename, O_RDONLY | O_BINARY)) >= 0)
+ {
+ while (!Cancel && (bytes = read(fd, buffer, sizeof(buffer))) > 0)
+ if ((status = cupsWriteRequestData(http, buffer,
+ bytes)) != HTTP_CONTINUE)
+ break;
+ }
+ else
+ {
+ snprintf(buffer, sizeof(buffer), "%s: %s", filename,
+ strerror(errno));
+ _cupsSetError(IPP_INTERNAL_ERROR, buffer, 0);
+
+ status = HTTP_ERROR;
+ }
+ }
+
+ /*
+ * Get the server's response...
+ */
+
+ if (!Cancel && (status == HTTP_CONTINUE || status == HTTP_OK))
+ {
+ response = cupsGetResponse(http, resource);
+ status = http->status;
+ }
+ else
+ httpFlush(http);
+
+ if ((status == HTTP_ERROR && cupsLastError() != IPP_INTERNAL_ERROR) ||
+ (status >= HTTP_BAD_REQUEST && status != HTTP_UNAUTHORIZED &&
+ status != HTTP_UPGRADE_REQUIRED))
+ {
+ _cupsSetHTTPError(status);
+ break;
+ }
+
+ if (http->state != HTTP_WAITING)
+ {
+ /*
+ * Flush any remaining data...
+ */
+
+ httpFlush(http);
+ }
+ }
}
- else if (filename[0])
- response = cupsDoFileRequest(http, request, resource, filename);
- else
- response = cupsDoRequest(http, request, resource);
- request = NULL;
+ ippDelete(request);
+
+ request = NULL;
+ prev_pass = 1;
if (!response)
- pass = 0;
+ prev_pass = pass = 0;
else
{
if (http->version != HTTP_1_1)
- pass = 0;
+ prev_pass = pass = 0;
+
+ if (response->request.status.request_id != request_id)
+ prev_pass = pass = 0;
- if (response->request.status.version[0] != (version / 10) ||
- response->request.status.version[1] != (version % 10) ||
- response->request.status.request_id != request_id)
- pass = 0;
+ if (version &&
+ (response->request.status.version[0] != (version / 10) ||
+ response->request.status.version[1] != (version % 10)))
+ prev_pass = pass = 0;
if ((attrptr = ippFindAttribute(response, "job-id",
IPP_TAG_INTEGER)) != NULL)
attrptr->group_tag != IPP_TAG_OPERATION ||
attrptr->num_values != 1 ||
strcmp(attrptr->name, "attributes-charset"))
- pass = 0;
+ prev_pass = pass = 0;
if (attrptr)
{
attrptr->group_tag != IPP_TAG_OPERATION ||
attrptr->num_values != 1 ||
strcmp(attrptr->name, "attributes-natural-language"))
- pass = 0;
+ prev_pass = pass = 0;
}
if ((attrptr = ippFindAttribute(response, "status-message",
attrptr->num_values != 1 ||
(attrptr->value_tag == IPP_TAG_TEXT &&
strlen(attrptr->values[0].string.text) > 255)))
- pass = 0;
+ prev_pass = pass = 0;
if ((attrptr = ippFindAttribute(response, "detailed-status-message",
IPP_TAG_ZERO)) != NULL &&
attrptr->num_values != 1 ||
(attrptr->value_tag == IPP_TAG_TEXT &&
strlen(attrptr->values[0].string.text) > 1023)))
- pass = 0;
+ prev_pass = pass = 0;
for (attrptr = response->attrs, group = attrptr->group_tag;
attrptr;
{
if (attrptr->group_tag < group && attrptr->group_tag != IPP_TAG_ZERO)
{
- pass = 0;
+ prev_pass = pass = 0;
break;
}
if (!validate_attr(attrptr, 0))
{
- pass = 0;
+ prev_pass = pass = 0;
break;
}
}
!get_variable(vars, statuses[i].if_defined))
continue;
- if (statuses[i].if_undefined &&
- get_variable(vars, statuses[i].if_undefined))
+ if (statuses[i].if_not_defined &&
+ get_variable(vars, statuses[i].if_not_defined))
continue;
if (response->request.status.status_code == statuses[i].status)
}
if (i == num_statuses && num_statuses > 0)
- pass = 0;
+ prev_pass = pass = 0;
else
{
for (i = num_expects, expect = expects; i > 0; i --, expect ++)
if (expect->if_defined && !get_variable(vars, expect->if_defined))
continue;
- if (expect->if_undefined && get_variable(vars, expect->if_undefined))
+ if (expect->if_not_defined &&
+ get_variable(vars, expect->if_not_defined))
continue;
found = ippFindAttribute(response, expect->name, IPP_TAG_ZERO);
(found && expect->in_group &&
found->group_tag != expect->in_group))
{
- pass = 0;
- break;
+ if (expect->define_no_match)
+ set_variable(vars, expect->define_no_match, "1");
+ else if (!expect->define_match)
+ prev_pass = pass = 0;
+
+ continue;
}
if (found &&
- !with_value(expect->with_value, expect->with_regex, found))
+ !with_value(expect->with_value, expect->with_regex, found, 0))
{
- pass = 0;
- break;
+ if (expect->define_no_match)
+ set_variable(vars, expect->define_no_match, "1");
+ else if (!expect->define_match)
+ prev_pass = pass = 0;
+
+ continue;
}
if (found && expect->count > 0 && found->num_values != expect->count)
{
- pass = 0;
- break;
+ if (expect->define_no_match)
+ set_variable(vars, expect->define_no_match, "1");
+ else if (!expect->define_match)
+ prev_pass = pass = 0;
+
+ continue;
}
if (found && expect->same_count_as)
if (!attrptr || attrptr->num_values != found->num_values)
{
- pass = 0;
- break;
+ if (expect->define_no_match)
+ set_variable(vars, expect->define_no_match, "1");
+ else if (!expect->define_match)
+ prev_pass = pass = 0;
+
+ continue;
}
}
+
+ if (found && expect->define_match)
+ set_variable(vars, expect->define_match, "1");
+
+ if (found && expect->define_value)
+ {
+ _ippAttrString(found, token, sizeof(token));
+ set_variable(vars, expect->define_value, token);
+ }
}
}
}
if (Output == _CUPS_OUTPUT_PLIST)
{
puts("<key>Successful</key>");
- puts(pass ? "<true />" : "<false />");
+ puts(prev_pass ? "<true />" : "<false />");
puts("<key>StatusCode</key>");
print_xml_string("string", ippErrorString(cupsLastError()));
puts("<key>ResponseAttributes</key>");
+ puts("<array>");
puts("<dict>");
- for (attrptr = response ? response->attrs : NULL;
+ for (attrptr = response ? response->attrs : NULL,
+ group = attrptr ? attrptr->group_tag : IPP_TAG_ZERO;
attrptr;
attrptr = attrptr->next)
- print_attr(attrptr);
+ print_attr(attrptr, &group);
puts("</dict>");
+ puts("</array>");
}
else if (Output == _CUPS_OUTPUT_TEST)
{
- puts(pass ? "PASS]" : "FAIL]");
+ puts(prev_pass ? "PASS]" : "FAIL]");
if (Verbosity && response)
{
attrptr != NULL;
attrptr = attrptr->next)
{
- print_attr(attrptr);
+ print_attr(attrptr, NULL);
}
}
}
- else if (!pass)
+ else if (!prev_pass)
fprintf(stderr, "%s\n", cupsLastErrorString());
- if (pass && Output != _CUPS_OUTPUT_PLIST && Output != _CUPS_OUTPUT_QUIET &&
- !Verbosity && num_displayed > 0)
+ if (prev_pass && Output != _CUPS_OUTPUT_PLIST &&
+ Output != _CUPS_OUTPUT_QUIET && !Verbosity && num_displayed > 0)
{
if (Output >= _CUPS_OUTPUT_LIST)
{
{
if (!strcmp(displayed[i], attrptr->name))
{
- print_attr(attrptr);
+ print_attr(attrptr, NULL);
break;
}
}
}
}
}
- else if (!pass)
+ else if (!prev_pass)
{
if (Output == _CUPS_OUTPUT_PLIST)
{
cupsLastErrorString());
else
{
- if (response->request.status.version[0] != (version / 10) ||
- response->request.status.version[1] != (version % 10))
+ if (version &&
+ (response->request.status.version[0] != (version / 10) ||
+ response->request.status.version[1] != (version % 10)))
print_test_error("Bad version %d.%d in response - expected %d.%d "
"(RFC 2911 section 3.1.8).",
response->request.status.version[0],
!get_variable(vars, statuses[i].if_defined))
continue;
- if (statuses[i].if_undefined &&
- get_variable(vars, statuses[i].if_undefined))
+ if (statuses[i].if_not_defined &&
+ get_variable(vars, statuses[i].if_not_defined))
continue;
if (response->request.status.status_code == statuses[i].status)
if (i == num_statuses && num_statuses > 0)
{
- print_test_error("Bad status-code (%s)",
- ippErrorString(cupsLastError()));
- print_test_error("status-message=\"%s\"", cupsLastErrorString());
+ for (i = 0; i < num_statuses; i ++)
+ {
+ if (statuses[i].if_defined &&
+ !get_variable(vars, statuses[i].if_defined))
+ continue;
+
+ if (statuses[i].if_not_defined &&
+ get_variable(vars, statuses[i].if_not_defined))
+ continue;
+
+ print_test_error("EXPECTED: STATUS %s (got %s)",
+ ippErrorString(statuses[i].status),
+ ippErrorString(cupsLastError()));
+ }
+
+ if ((attrptr = ippFindAttribute(response, "status-message",
+ IPP_TAG_TEXT)) != NULL)
+ print_test_error("status-message=\"%s\"",
+ attrptr->values[0].string.text);
}
for (i = num_expects, expect = expects; i > 0; i --, expect ++)
{
+ if (expect->define_match || expect->define_no_match)
+ continue;
+
if (expect->if_defined && !get_variable(vars, expect->if_defined))
continue;
- if (expect->if_undefined && get_variable(vars, expect->if_undefined))
+ if (expect->if_not_defined &&
+ get_variable(vars, expect->if_not_defined))
continue;
found = ippFindAttribute(response, expect->name, IPP_TAG_ZERO);
expect->name, ippTagString(expect->in_group),
ippTagString(found->group_tag));
- if (!with_value(expect->with_value, expect->with_regex, found))
+ if (!with_value(expect->with_value, expect->with_regex, found, 0))
{
if (expect->with_regex)
print_test_error("EXPECTED: %s WITH-VALUE /%s/",
else
print_test_error("EXPECTED: %s WITH-VALUE \"%s\"",
expect->name, expect->with_value);
+
+ with_value(expect->with_value, expect->with_regex, found, 1);
}
if (expect->count > 0 && found->num_values != expect->count)
puts("</array>");
}
+ skip_error:
+
if (Output == _CUPS_OUTPUT_PLIST)
puts("</dict>");
{
if (statuses[i].if_defined)
free(statuses[i].if_defined);
- if (statuses[i].if_undefined)
- free(statuses[i].if_undefined);
+ if (statuses[i].if_not_defined)
+ free(statuses[i].if_not_defined);
}
num_statuses = 0;
free(expect->same_count_as);
if (expect->if_defined)
free(expect->if_defined);
- if (expect->if_undefined)
- free(expect->if_undefined);
+ if (expect->if_not_defined)
+ free(expect->if_not_defined);
if (expect->with_value)
free(expect->with_value);
+ if (expect->define_match)
+ free(expect->define_match);
+ if (expect->define_no_match)
+ free(expect->define_no_match);
+ if (expect->define_value)
+ free(expect->define_value);
}
num_expects = 0;
free(displayed[i]);
num_displayed = 0;
- if (!pass)
+ if (!ignore_errors && !prev_pass)
break;
}
- fclose(fp);
- httpClose(http);
-
- return (pass);
-
- /*
- * If we get here there was a fatal test error...
- */
-
- test_error:
+ test_exit:
if (fp)
fclose(fp);
{
if (statuses[i].if_defined)
free(statuses[i].if_defined);
- if (statuses[i].if_undefined)
- free(statuses[i].if_undefined);
+ if (statuses[i].if_not_defined)
+ free(statuses[i].if_not_defined);
}
for (i = num_expects, expect = expects; i > 0; i --, expect ++)
free(expect->same_count_as);
if (expect->if_defined)
free(expect->if_defined);
- if (expect->if_undefined)
- free(expect->if_undefined);
+ if (expect->if_not_defined)
+ free(expect->if_not_defined);
if (expect->with_value)
free(expect->with_value);
+ if (expect->define_match)
+ free(expect->define_match);
+ if (expect->define_no_match)
+ free(expect->define_no_match);
+ if (expect->define_value)
+ free(expect->define_value);
}
for (i = 0; i < num_displayed; i ++)
free(displayed[i]);
- return (0);
+ return (pass);
}
else
goto col_error;
}
- else if (!strcasecmp(token, "MEMBER"))
+ else if (!_cups_strcasecmp(token, "MEMBER"))
{
/*
* Attribute...
switch (value)
{
case IPP_TAG_BOOLEAN :
- if (!strcasecmp(token, "true"))
+ if (!_cups_strcasecmp(token, "true"))
ippAddBoolean(col, IPP_TAG_ZERO, attr, 1);
else
ippAddBoolean(col, IPP_TAG_ZERO, attr, atoi(token));
char units[6]; /* Units */
if (sscanf(token, "%dx%d%5s", &xres, &yres, units) != 3 ||
- (strcasecmp(units, "dpi") && strcasecmp(units, "dpc") &&
- strcasecmp(units, "other")))
+ (_cups_strcasecmp(units, "dpi") && _cups_strcasecmp(units, "dpc") &&
+ _cups_strcasecmp(units, "other")))
{
print_fatal_error("Bad resolution value \"%s\" on line %d.",
token, *linenum);
goto col_error;
}
- if (!strcasecmp(units, "dpi"))
+ if (!_cups_strcasecmp(units, "dpi"))
ippAddResolution(col, IPP_TAG_ZERO, attr, xres, yres,
IPP_RES_PER_INCH);
- else if (!strcasecmp(units, "dpc"))
+ else if (!_cups_strcasecmp(units, "dpc"))
ippAddResolution(col, IPP_TAG_ZERO, attr, xres, yres,
IPP_RES_PER_CM);
else
static char * /* O - ISO 8601 date/time string */
iso_date(ipp_uchar_t *date) /* I - IPP (RFC 1903) date/time value */
{
- unsigned year = (date[0] << 8) + date[1];
- /* Year */
+ time_t utctime; /* UTC time since 1970 */
+ struct tm *utcdate; /* UTC date/time */
static char buffer[255]; /* String buffer */
- if (date[9] == 0 && date[10] == 0)
- snprintf(buffer, sizeof(buffer), "%04u-%02u-%02uT%02u:%02u:%02uZ",
- year, date[2], date[3], date[4], date[5], date[6]);
- else
- snprintf(buffer, sizeof(buffer), "%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]);
+ utctime = ippDateToTime(date);
+ utcdate = gmtime(&utctime);
+
+ snprintf(buffer, sizeof(buffer), "%04d-%02d-%02dT%02d:%02d:%02dZ",
+ utcdate->tm_year + 1900, utcdate->tm_mon + 1, utcdate->tm_mday,
+ utcdate->tm_hour, utcdate->tm_min, utcdate->tm_sec);
return (buffer);
}
+/*
+ * 'password_cb()' - Password callback for authenticated tests.
+ */
+
+static const char * /* O - Password */
+password_cb(const char *prompt) /* I - Prompt (unused) */
+{
+ (void)prompt;
+
+ return (Password);
+}
+
+
/*
* 'print_attr()' - Print an attribute on the screen.
*/
static void
-print_attr(ipp_attribute_t *attr) /* I - Attribute to print */
+print_attr(ipp_attribute_t *attr, /* I - Attribute to print */
+ ipp_tag_t *group) /* IO - Current group */
{
int i; /* Looping var */
ipp_attribute_t *colattr; /* Collection attribute */
if (Output == _CUPS_OUTPUT_PLIST)
{
- if (!attr->name)
+ if (!attr->name || (group && *group != attr->group_tag))
{
- printf("<key>%s</key>\n<true />\n", ippTagString(attr->group_tag));
- return;
+ puts("</dict>");
+ puts("<dict>");
+
+ if (group)
+ *group = attr->group_tag;
}
+ if (!attr->name)
+ return;
+
print_xml_string("key", attr->name);
if (attr->num_values > 1)
puts("<array>");
puts("</string></dict>");
}
else
- printf("\"%s\",%s ", attr->values[i].string.text,
+ printf("\"%s\"(%s) ", attr->values[i].string.text,
attr->values[i].string.charset);
break;
for (colattr = attr->values[i].collection->attrs;
colattr;
colattr = colattr->next)
- print_attr(colattr);
+ print_attr(colattr, NULL);
puts("</dict>");
}
else
print_xml_trailer(0, buffer);
}
else
- _cupsLangPrintf(stderr, "ipptool: %s\n", buffer);
+ _cupsLangPrintf(stderr, "ipptool: %s", buffer);
}
fputs("<", stdout);
else if (*s == '>')
fputs(">", stdout);
+ else if ((*s & 0xe0) == 0xc0)
+ {
+ /*
+ * Validate UTF-8 two-byte sequence...
+ */
+
+ if ((s[1] & 0xc0) != 0x80)
+ {
+ putchar('?');
+ s ++;
+ }
+ else
+ {
+ putchar(*s++);
+ putchar(*s);
+ }
+ }
+ else if ((*s & 0xf0) == 0xe0)
+ {
+ /*
+ * Validate UTF-8 three-byte sequence...
+ */
+
+ if ((s[1] & 0xc0) != 0x80 || (s[2] & 0xc0) != 0x80)
+ {
+ putchar('?');
+ s += 2;
+ }
+ else
+ {
+ putchar(*s++);
+ putchar(*s++);
+ putchar(*s);
+ }
+ }
+ else if ((*s & 0xf8) == 0xf0)
+ {
+ /*
+ * Validate UTF-8 four-byte sequence...
+ */
+
+ if ((s[1] & 0xc0) != 0x80 || (s[2] & 0xc0) != 0x80 ||
+ (s[3] & 0xc0) != 0x80)
+ {
+ putchar('?');
+ s += 3;
+ }
+ else
+ {
+ putchar(*s++);
+ putchar(*s++);
+ putchar(*s++);
+ putchar(*s);
+ }
+ }
+ else if ((*s & 0x80) || (*s < ' ' && !isspace(*s & 255)))
+ {
+ /*
+ * Invalid control character...
+ */
+
+ putchar('?');
+ }
else
putchar(*s);
}
+/*
+ * 'sigterm_handler()' - Handle SIGINT and SIGTERM.
+ */
+
+static void
+sigterm_handler(int sig) /* I - Signal number (unused) */
+{
+ (void)sig;
+
+ Cancel = 1;
+}
+
+
+/*
+ * 'timeout_cb()' - Handle HTTP timeouts.
+ */
+
+static int /* O - 1 to continue, 0 to cancel */
+timeout_cb(http_t *http, /* I - Connection to server (unused) */
+ void *user_data) /* I - User data (unused) */
+{
+ (void)http;
+ (void)user_data;
+
+ /* Always cancel on timeout */
+ return (0);
+}
+
+
/*
* 'usage()' - Show program usage.
*/
static void
usage(void)
{
- _cupsLangPuts(stderr,
- _("Usage: ipptool [options] URI filename [ ... "
- "filenameN ]\n"
- "\n"
- "Options:\n"
- "\n"
- "-C Send requests using chunking (default)\n"
- "-E Test with TLS encryption.\n"
- "-L Send requests using content-length\n"
- "-S Test with SSL encryption.\n"
- "-V version Set default IPP version.\n"
- "-X Produce XML plist instead of plain text.\n"
- "-d name=value Define variable.\n"
- "-f filename Set default request filename.\n"
- "-i seconds Repeat the last file with the given time "
- "interval.\n"
- "-n count Repeat the last file the given number of "
- "times.\n"
- "-q Be quiet - no output except errors.\n"
- "-t Produce a test report.\n"
- "-v Show all attributes sent and received.\n"));
+ _cupsLangPuts(stderr, _("Usage: ipptool [options] URI filename [ ... "
+ "filenameN ]"));
+ _cupsLangPuts(stderr, _("Options:"));
+ _cupsLangPuts(stderr, _(" -4 Connect using IPv4."));
+ _cupsLangPuts(stderr, _(" -6 Connect using IPv6."));
+ _cupsLangPuts(stderr, _(" -C Send requests using "
+ "chunking (default)."));
+ _cupsLangPuts(stderr, _(" -E Test with TLS "
+ "encryption."));
+ _cupsLangPuts(stderr, _(" -I Ignore errors."));
+ _cupsLangPuts(stderr, _(" -L Send requests using "
+ "content-length."));
+ _cupsLangPuts(stderr, _(" -S Test with SSL "
+ "encryption."));
+ _cupsLangPuts(stderr, _(" -T 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, _(" -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, _(" -n count Repeat the last file the "
+ "given number of times."));
+ _cupsLangPuts(stderr, _(" -q Be quiet - no output "
+ "except errors."));
+ _cupsLangPuts(stderr, _(" -t Produce a test report."));
+ _cupsLangPuts(stderr, _(" -v Show all attributes sent "
+ "and received."));
exit(1);
}
static int /* O - 1 on match, 0 on non-match */
with_value(char *value, /* I - Value string */
int regex, /* I - Value is a regular expression */
- ipp_attribute_t *attr) /* I - Attribute to compare */
+ ipp_attribute_t *attr, /* I - Attribute to compare */
+ int report) /* I - 1 = report failures */
{
int i; /* Looping var */
char *valptr; /* Pointer into value */
}
}
}
+
+ if (report)
+ {
+ for (i = 0; i < attr->num_values; i ++)
+ print_test_error("GOT: %s=%d", attr->name, attr->values[i].integer);
+ }
+ break;
+
+ case IPP_TAG_RANGE :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ char op, /* Comparison operator */
+ *nextptr; /* Next pointer */
+ int intvalue; /* Integer value */
+
+
+ valptr = value;
+ if (!strncmp(valptr, "no-value,", 9))
+ valptr += 9;
+
+ while (isspace(*valptr & 255) || isdigit(*valptr & 255) ||
+ *valptr == '-' || *valptr == ',' || *valptr == '<' ||
+ *valptr == '=' || *valptr == '>')
+ {
+ op = '=';
+ while (*valptr && !isdigit(*valptr & 255) && *valptr != '-')
+ {
+ if (*valptr == '<' || *valptr == '>' || *valptr == '=')
+ op = *valptr;
+ valptr ++;
+ }
+
+ if (!*valptr)
+ break;
+
+ intvalue = strtol(valptr, &nextptr, 0);
+ if (nextptr == valptr)
+ break;
+ valptr = nextptr;
+
+ switch (op)
+ {
+ case '=' :
+ if (attr->values[i].range.lower == intvalue ||
+ attr->values[i].range.upper == intvalue)
+ return (1);
+ break;
+ case '<' :
+ if (attr->values[i].range.upper < intvalue)
+ return (1);
+ break;
+ case '>' :
+ if (attr->values[i].range.upper > intvalue)
+ return (1);
+ break;
+ }
+ }
+ }
+
+ if (report)
+ {
+ for (i = 0; i < attr->num_values; i ++)
+ print_test_error("GOT: %s=%d-%d", attr->name,
+ attr->values[i].range.lower,
+ attr->values[i].range.upper);
+ }
break;
case IPP_TAG_BOOLEAN :
if (!strcmp(value, "true") == attr->values[i].boolean)
return (1);
}
+
+ if (report)
+ {
+ for (i = 0; i < attr->num_values; i ++)
+ print_test_error("GOT: %s=%s", attr->name,
+ attr->values[i].boolean ? "true" : "false");
+ }
break;
case IPP_TAG_NOVALUE :
for (i = 0; i < attr->num_values; i ++)
{
if (regexec(&re, attr->values[i].string.text, 0, NULL, 0))
- break;
+ {
+ if (report)
+ print_test_error("GOT: %s=\"%s\"", attr->name,
+ attr->values[i].string.text);
+ else
+ break;
+ }
}
regfree(&re);
if (!strcmp(value, attr->values[i].string.text))
return (1);
}
+
+ if (report)
+ {
+ for (i = 0; i < attr->num_values; i ++)
+ print_test_error("GOT: %s=\"%s\"", attr->name,
+ attr->values[i].string.text);
+ }
}
break;