--- /dev/null
+CHANGES-IPPTOOL.txt - 2011-09-28
+--------------------------------
+
+This file provides a list of changes to the ipptool binary distribution posted
+on cups.org.
+
+
+2011-09-28
+
+ - Test output now includes a summary and overall score at the end.
+ - The MATCH-VALUE predicate now correctly deals with a failed EXPECT
+ condition.
+ - The IPP/1.1 test suite now looks for legacy media names and uses them
+ if the corresponding PWG standard names are not present.
+ - The IPP/1.1 test suite now tests the Print-Job+Release-Job when the
+ printer supports the job-hold-until attribute, Hold-Job operation, and
+ Release-Job operation.
+
+
+2011-09-21
+
+ - Fixes for HTTP chunking, timeout, and encryption issues reported by
+ various users.
+ - Greatly improved IPP tests with added IPP/2.2 tests.
+ - New test documents - 1-page and 4-page mixed A4/Letter PDF/PS and a
+ couple JPEGs.
+ - New REPEAT directives to programmatically repeat tests as needed.
+
+
+2011-08-16
+
+ - The Windows version no longer requires Visual Studio to be installed.
+ - The Windows version now supports SSL.
+ - Added "ipps" URI support.
+ - Added a new "-T" option.
+ - Added support for fractional seconds for the -i option and DELAY
+ directive.
+ - Added support for authentication.
+ - Added DEFINE-MATCH, DEFINE-NO-MATCH, DEFINE-VALUE, IF-NOT-DEFINED,
+ IGNORE-ERRORS, SKIP-IF-DEFINED, SKIP-IF-NOT-DEFINED,
+ SKIP-PREVIOUS-ERROR directives.
+ - WITH-VALUE now supports variable expansion.
+ - Updated the IPP/1.1 conformance test to skip the "my-jobs different
+ user" test if the printer URI contains a username.
+ - Updated the IPP conformance tests to validate media, media-default,
+ and media-supported values.
+ - No longer error out if a Printer returns a different version number in
+ the response when the request contains the version 0.0.
+
+
+2010-10-16
+
+ - Initial release of standalone binary.
-IPPTOOL.txt - 2011-09-14
+IPPTOOL.txt - 2011-09-28
------------------------
+See the file CHANGES-IPPTOOL.txt for a list of changes to this software.
+
INTRODUCTION
IPP/2.2. For a given printer URI, the following commands perform tests at
each level:
- ipptool -tf filename [options] printer-uri ipp-1.1.test
- ipptool -tf filename [options] -V 2.0 printer-uri ipp-2.0.test
- ipptool -tf filename [options] -V 2.1 printer-uri ipp-2.1.test
- ipptool -tf filename [options] -V 2.2 printer-uri ipp-2.2.test
+ ipptool -tf filename [options] -I printer-uri ipp-1.1.test
+ ipptool -tf filename [options] -I -V 2.0 printer-uri ipp-2.0.test
+ ipptool -tf filename [options] -I -V 2.1 printer-uri ipp-2.1.test
+ ipptool -tf filename [options] -I -V 2.2 printer-uri ipp-2.2.test
The filename must use a format supported by the printer; ipptool will guess
the MIME media type using the extension, otherwise application/octet stream
Print-by-reference (URL) printing can be tested by defining the document-uri
variable to a URL, for example:
- ipptool -tf filename -d document-uri=your-url printer-uri ipp-1.1.test
+ ipptool -tf filename -d document-uri=url -I printer-uri ipp-1.1.test
The standard test files are available on cups.org under the "test"
directory, for example:
http://www.cups.org/test/document-a4.pdf
+ The "document" test files contain 4 pages each. Doing the IPP conformance
+ tests will will produce up to 90 pages on various media, depending on the
+ printer.
+
READING THE DOCUMENTATION
See the CUPS web site at "http://www.cups.org/" for other resources.
+REPORTING BUGS
+
+ If you believe you have discovered a bug in ipptool, please fill out the
+ bug form at:
+
+ http://www.cups.org/str.php
+
+ Be sure to identify the version of CUPS and ipptool (if you downloaded the
+ standalone version) you are using, the printer (if any) and firmware
+ version, and include any files that apply.
+
+ If you downloaded the standalone version of ipptool, please also re-run the
+ test with debug logging enabled. Run the following commands on Windows to
+ enable debug logging:
+
+ set CUPS_DEBUG_LOG=ipptool.log
+ set CUPS_DEBUG_LEVEL=6
+
+ For Linux and Mac OS X use:
+
+ CUPS_DEBUG_LOG=ipptool.log; export CUPS_DEBUG_LOG
+ CUPS_DEBUG_LEVEL=6; export CUPS_DEBUG_LEVEL
+
+ Then when you run the ipptool command a new "ipptool.log" file will be
+ created with detailed information - attach this file to the bug you file
+ as well.
+
+
LEGAL STUFF
CUPS is Copyright 2007-2011 by Apple Inc. CUPS and the CUPS logo are
The MD5 Digest code is Copyright 1999 Aladdin Enterprises.
- This software is based in part on the work of the Independent JPEG Group.
-
CUPS is provided under the terms of version 2 of the GNU General Public
License and GNU Library General Public License. This program is distributed
in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
datalen = *data++;
- if (!datalen || (data + datalen) >= dataend)
+ if (!datalen || (data + datalen) > dataend)
break;
datanext = data + datalen;
if ((value = TXTRecordGetValuePtr(txtLen, txtRecord, "rp",
&valueLen)) != NULL)
+ {
+ if (((char *)value)[0] == '/')
+ {
+ /*
+ * "rp" value (incorrectly) has a leading slash already...
+ */
+
+ memcpy(rp, value, valueLen);
+ rp[valueLen] = '\0';
+ }
+ else
+ {
+ /*
+ * Convert to resource by concatenating with a leading "/"...
+ */
+
+ rp[0] = '/';
+ memcpy(rp + 1, value, valueLen);
+ rp[valueLen + 1] = '\0';
+ }
+ }
+ else
{
/*
- * Convert to resource by concatenating with a leading "/"...
+ * Default "rp" value is blank, mapping to a path of "/"...
*/
rp[0] = '/';
- memcpy(rp + 1, value, valueLen);
- rp[valueLen + 1] = '\0';
+ rp[1] = '\0';
}
- else
- rp[0] = '\0';
/*
* Lookup the FQDN if needed...
return (error);
}
# endif /* HAVE_CDSASSL && HAVE_SECCERTIFICATECOPYDATA */
+#endif /* HAVE_SSL */
/*
}
+#ifdef HAVE_SSL
/*
* 'http_setup_ssl()' - Set up SSL/TLS support on a connection.
*/
return (0);
}
-#endif /* HAVE_SSL */
-#ifdef HAVE_SSL
/*
* 'http_shutdown_ssl()' - Shut down SSL/TLS on a connection.
*/
bufptr += strlen(ptr);
break;
}
+ else if (!strcmp(attr->name, "operations-supported"))
+ {
+ ptr = ippOpString(val->integer);
+
+ if (buffer && bufptr < bufend)
+ strlcpy(bufptr, ptr, bufend - bufptr + 1);
+
+ bufptr += strlen(ptr);
+ break;
+ }
case IPP_TAG_INTEGER :
if (buffer && bufptr < bufend)
* No, build an "unknown-xxxx" operation string...
*/
- sprintf(cg->ipp_unknown, "unknown-%04x", op);
+ sprintf(cg->ipp_unknown, "0x%04x", op);
return (cg->ipp_unknown);
}
int i;
+ if (!strncmp(name, "0x", 2))
+ return ((ipp_op_t)strtol(name + 2, NULL, 16));
+
for (i = 0; i < (sizeof(ipp_std_ops) / sizeof(ipp_std_ops[0])); i ++)
if (!_cups_strcasecmp(name, ipp_std_ops[i]))
return ((ipp_op_t)i);
attr ? attr->values[0].string.text :
ippErrorString(response->request.status.status_code), 0);
}
+ else if (status == HTTP_ERROR)
+ _cupsSetError(IPP_INTERNAL_ERROR, strerror(http->error), 0);
else if (status != HTTP_OK)
_cupsSetHTTPError(status);
.\" 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/".
.\"
-.TH ipptoolfile 5 "CUPS" "13 September 2011" "Apple Inc."
+.TH ipptoolfile 5 "CUPS" "28 September 2011" "Apple Inc."
.SH NAME
ipptoolfile \- ipptool file format
.TP 5
DEFINE-VALUE variable-name
Defines the variable to the value of the attribute when the EXPECT condition
-matches.
+matches. A side-effect of this predicate is that this EXPECT will never fail a test.
.TP 5
IF-DEFINED variable-name
Makes the EXPECT conditions apply only if the specified variable is defined.
ipptool.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/language-private.h
ipptool.o: ../cups/transcode.h ../cups/thread-private.h
ipptool.o: ../cups/file-private.h ../cups/cups-private.h
+xmltotest.o: ../cups/cups.h ../cups/file.h ../cups/versioning.h ../cups/ipp.h
+xmltotest.o: ../cups/http.h ../cups/array.h ../cups/language.h
testfile.txt
OBJS = \
ippserver.o \
- ipptool.o
+ ipptool.o \
+ xmltotest.o
TARGETS = \
ippserver \
ipptool \
$(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ)
+#
+# xmltotest
+#
+
+xmltotest: xmltotest.o ../cups/$(LIBUPSSTATIC)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ xmltotest.o ../cups/$(LIBCUPSSTATIC) \
+ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) \
+ -lmxml
+
+
#
# Dependencies...
#
STATUS successful-ok
+ # Display some useful information to identify the test
+ DISPLAY printer-name
+ DISPLAY printer-make-and-model
+ DISPLAY color-supported
+ DISPLAY pages-per-minute
+ DISPLAY pages-per-minute-color
+ DISPLAY document-format-supported
+ DISPLAY finishings-supported
+ DISPLAY job-sheets-supported
+ DISPLAY media-supported
+ DISPLAY number-up-supported
+ DISPLAY operations-supported
+ DISPLAY print-quality-supported
+ DISPLAY reference-uri-schemes-supported
+ DISPLAY sizes-supported
+
# Job template attributes
EXPECT ?copies-default OF-TYPE integer IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE >0
EXPECT ?copies-supported OF-TYPE rangeOfInteger IN-GROUP printer-attributes-tag
EXPECT document-format-supported WITH-VALUE "application/postscript" DEFINE-MATCH OPTIONAL_POSTSCRIPT
EXPECT document-format-supported WITH-VALUE "image/jpeg" DEFINE-MATCH OPTIONAL_JPEG
EXPECT job-sheets-supported WITH-VALUE "standard" DEFINE-MATCH OPTIONAL_STANDARD_SHEET
- EXPECT media-supported WITH-VALUE "iso_a4_210x297mm" DEFINE-MATCH OPTIONAL_A4_MEDIA
- EXPECT media-supported WITH-VALUE "na_letter_8.5x11in" DEFINE-MATCH OPTIONAL_LETTER_MEDIA
- EXPECT media-supported WITH-VALUE "na_index-4x6_4x6in" DEFINE-MATCH OPTIONAL_4X6_MEDIA
+ EXPECT media-supported WITH-VALUE "/^(a4|iso-a4|iso_a4_210x297mm)$$/" DEFINE-VALUE OPTIONAL_A4_MEDIA
+ EXPECT media-supported WITH-VALUE "/^(letter|na-letter|na_letter_8.5x11in)$$/" DEFINE-VALUE OPTIONAL_LETTER_MEDIA
+ EXPECT media-supported WITH-VALUE "/^(index-4x6|na_index-4x6_4x6in)$$/" DEFINE-VALUE OPTIONAL_4X6_MEDIA
EXPECT number-up-supported WITH-VALUE 2 DEFINE-MATCH OPTIONAL_2UP
EXPECT print-quality WITH-VALUE 3 DEFINE-MATCH OPTIONAL_DRAFT_QUALITY
EXPECT print-quality WITH-VALUE 4 DEFINE-MATCH OPTIONAL_NORMAL_QUALITY
{
SKIP-IF-NOT-DEFINED OPTIONAL_CREATE_JOB
SKIP-IF-NOT-DEFINED OPTIONAL_SEND_DOCUMENT
+ SKIP-PREVIOUS-ERROR yes
NAME "RFC 2911 section 3.3.1: Send-Document Operation"
OPERATION Send-Document
{
SKIP-IF-NOT-DEFINED OPTIONAL_CREATE_JOB
SKIP-IF-NOT-DEFINED OPTIONAL_SEND_DOCUMENT
+ SKIP-PREVIOUS-ERROR yes
NAME "Send-Document missing last-document: Send-Document Operation"
OPERATION Send-Document
{
SKIP-IF-NOT-DEFINED OPTIONAL_CREATE_JOB
SKIP-IF-NOT-DEFINED OPTIONAL_SEND_DOCUMENT
+ SKIP-PREVIOUS-ERROR yes
NAME "RFC 2911 section 3.3.3: Cancel-Job Operation"
OPERATION Cancel-Job
SKIP-IF-NOT-DEFINED OPTIONAL_CREATE_JOB
SKIP-IF-NOT-DEFINED OPTIONAL_SEND_URI
SKIP-IF-NOT-DEFINED document-uri
+ SKIP-PREVIOUS-ERROR yes
NAME "RFC 2911 section 3.3.2: Send-URI Operation"
OPERATION Send-URI
{
SKIP-IF-NOT-DEFINED OPTIONAL_CREATE_JOB
SKIP-IF-NOT-DEFINED OPTIONAL_SEND_URI
+ SKIP-PREVIOUS-ERROR yes
NAME "Send-URI with bad URI: Send-URI Operation (bad URI)"
OPERATION Send-URI
{
SKIP-IF-NOT-DEFINED OPTIONAL_CREATE_JOB
SKIP-IF-NOT-DEFINED OPTIONAL_SEND_URI
+ SKIP-PREVIOUS-ERROR yes
NAME "Send-URI with bad URI: Cancel-Job Operation"
OPERATION Cancel-Job
ATTR keyword compression none
ATTR mimeMediaType document-format application/pdf
GROUP job-attributes-tag
- ATTR keyword media iso_a4_210x297mm
+ ATTR keyword media $OPTIONAL_A4_MEDIA
FILE document-a4.pdf
STATUS successful-ok
ATTR keyword compression none
ATTR mimeMediaType document-format application/pdf
GROUP job-attributes-tag
- ATTR keyword media iso_a4_210x297mm
+ ATTR keyword media $OPTIONAL_A4_MEDIA
ATTR keyword sides two-sided-long-edge
FILE document-a4.pdf
ATTR keyword compression none
ATTR mimeMediaType document-format application/pdf
GROUP job-attributes-tag
- ATTR keyword media na_letter_8.5x11in
+ ATTR keyword media $OPTIONAL_LETTER_MEDIA
FILE document-letter.pdf
STATUS successful-ok
ATTR keyword compression none
ATTR mimeMediaType document-format application/pdf
GROUP job-attributes-tag
- ATTR keyword media na_letter_8.5x11in
+ ATTR keyword media $OPTIONAL_LETTER_MEDIA
ATTR keyword sides two-sided-long-edge
FILE document-letter.pdf
ATTR keyword compression none
ATTR mimeMediaType document-format application/postscript
GROUP job-attributes-tag
- ATTR keyword media iso_a4_210x297mm
+ ATTR keyword media $OPTIONAL_LETTER_MEDIA
FILE document-a4.ps
STATUS successful-ok
ATTR keyword compression none
ATTR mimeMediaType document-format application/postscript
GROUP job-attributes-tag
- ATTR keyword media iso_a4_210x297mm
+ ATTR keyword media $OPTIONAL_A4_MEDIA
ATTR keyword sides two-sided-long-edge
FILE document-a4.ps
ATTR keyword compression none
ATTR mimeMediaType document-format application/postscript
GROUP job-attributes-tag
- ATTR keyword media na_letter_8.5x11in
+ ATTR keyword media $OPTIONAL_LETTER_MEDIA
FILE document-letter.ps
STATUS successful-ok
ATTR keyword compression none
ATTR mimeMediaType document-format application/postscript
GROUP job-attributes-tag
- ATTR keyword media na_letter_8.5x11in
+ ATTR keyword media $OPTIONAL_LETTER_MEDIA
ATTR keyword sides two-sided-long-edge
FILE document-letter.ps
ATTR keyword compression none
ATTR mimeMediaType document-format image/jpeg
GROUP job-attributes-tag
- ATTR keyword media iso_a4_210x297mm
+ ATTR keyword media $OPTIONAL_A4_MEDIA
FILE color.jpg
STATUS successful-ok
ATTR keyword compression none
ATTR mimeMediaType document-format image/jpeg
GROUP job-attributes-tag
- ATTR keyword media na_letter_8.5x11in
+ ATTR keyword media $OPTIONAL_LETTER_MEDIA
FILE color.jpg
STATUS successful-ok
ATTR keyword compression none
ATTR mimeMediaType document-format image/jpeg
GROUP job-attributes-tag
- ATTR keyword media na_index-4x6_4x6in
+ ATTR keyword media $OPTIONAL_4X6_MEDIA
FILE color.jpg
STATUS successful-ok
ATTR keyword compression none
ATTR mimeMediaType document-format image/jpeg
GROUP job-attributes-tag
- ATTR keyword media iso_a4_210x297mm
+ ATTR keyword media $OPTIONAL_A4_MEDIA
FILE gray.jpg
STATUS successful-ok
ATTR keyword compression none
ATTR mimeMediaType document-format image/jpeg
GROUP job-attributes-tag
- ATTR keyword media na_letter_8.5x11in
+ ATTR keyword media $OPTIONAL_LETTER_MEDIA
FILE gray.jpg
STATUS successful-ok
ATTR keyword compression none
ATTR mimeMediaType document-format image/jpeg
GROUP job-attributes-tag
- ATTR keyword media na_index-4x6_4x6in
+ ATTR keyword media $OPTIONAL_4X6_MEDIA
FILE gray.jpg
STATUS successful-ok
ATTR keyword compression none
ATTR mimeMediaType document-format application/pdf
GROUP job-attributes-tag
- ATTR keyword media iso_a4_210x297mm
+ ATTR keyword media $OPTIONAL_A4_MEDIA
ATTR keyword job-sheets standard
FILE document-a4.pdf
ATTR keyword compression none
ATTR mimeMediaType document-format application/pdf
GROUP job-attributes-tag
- ATTR keyword media na_letter_8.5x11in
+ ATTR keyword media $OPTIONAL_LETTER_MEDIA
ATTR keyword job-sheets standard
FILE document-a4.pdf
ATTR keyword compression none
ATTR mimeMediaType document-format application/postscript
GROUP job-attributes-tag
- ATTR keyword media iso_a4_210x297mm
+ ATTR keyword media $OPTIONAL_A4_MEDIA
ATTR keyword job-sheets standard
FILE document-a4.ps
ATTR keyword compression none
ATTR mimeMediaType document-format application/postscript
GROUP job-attributes-tag
- ATTR keyword media na_letter_8.5x11in
+ ATTR keyword media $OPTIONAL_LETTER_MEDIA
ATTR keyword job-sheets standard
FILE document-a4.ps
ATTR keyword compression none
ATTR mimeMediaType document-format application/pdf
GROUP job-attributes-tag
- ATTR keyword media iso_a4_210x297mm
+ ATTR keyword media $OPTIONAL_A4_MEDIA
ATTR integer number-up 2
FILE document-a4.pdf
ATTR keyword compression none
ATTR mimeMediaType document-format application/pdf
GROUP job-attributes-tag
- ATTR keyword media na_letter_8.5x11in
+ ATTR keyword media $OPTIONAL_LETTER_MEDIA
ATTR integer number-up 2
FILE document-letter.pdf
ATTR keyword compression none
ATTR mimeMediaType document-format application/postscript
GROUP job-attributes-tag
- ATTR keyword media iso_a4_210x297mm
+ ATTR keyword media $OPTIONAL_A4_MEDIA
ATTR integer number-up 2
FILE document-a4.ps
ATTR keyword compression none
ATTR mimeMediaType document-format application/postscript
GROUP job-attributes-tag
- ATTR keyword media na_letter_8.5x11in
+ ATTR keyword media $OPTIONAL_LETTER_MEDIA
ATTR integer number-up 2
FILE document-letter.ps
ATTR keyword compression none
ATTR mimeMediaType document-format image/jpeg
GROUP job-attributes-tag
- ATTR keyword media na_index-4x6_4x6in
+ ATTR keyword media $OPTIONAL_4X6_MEDIA
ATTR enum print-quality 3
FILE color.jpeg
ATTR keyword compression none
ATTR mimeMediaType document-format image/jpeg
GROUP job-attributes-tag
- ATTR keyword media na_index-4x6_4x6in
+ ATTR keyword media $OPTIONAL_4X6_MEDIA
ATTR enum print-quality 4
FILE color.jpeg
ATTR keyword compression none
ATTR mimeMediaType document-format image/jpeg
GROUP job-attributes-tag
- ATTR keyword media na_index-4x6_4x6in
+ ATTR keyword media $OPTIONAL_4X6_MEDIA
ATTR enum print-quality 5
FILE color.jpeg
ATTR keyword compression none
ATTR mimeMediaType document-format application/pdf
GROUP job-attributes-tag
- ATTR keyword media iso_a4_210x297mm
+ ATTR keyword media $OPTIONAL_A4_MEDIA
ATTR enum print-quality 3
FILE document-a4.pdf
ATTR keyword compression none
ATTR mimeMediaType document-format application/pdf
GROUP job-attributes-tag
- ATTR keyword media na_letter_8.5x11in
+ ATTR keyword media $OPTIONAL_LETTER_MEDIA
ATTR enum print-quality 3
FILE document-letter.pdf
}
+# Test hold/release in the context of Print-Job w/job-hold-until + Release-Job
+{
+ SKIP-IF-NOT-DEFINED OPTIONAL_HOLD_JOB
+
+ NAME "Print-Job with job-hold-until"
+ OPERATION Print-Job
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+ ATTR name job-name "Test Document w/Hold"
+ ATTR name document-name $filename
+ ATTR keyword compression none
+ ATTR mimeMediaType document-format $filetype
+ GROUP job-attributes-tag
+ ATTR keyword job-hold-until indefinite
+ FILE $filename
+
+ STATUS successful-ok
+ STATUS server-error-job-canceled
+ STATUS server-error-busy REPEAT-MATCH
+
+ EXPECT job-uri OF-TYPE uri COUNT 1 IN-GROUP job-attributes-tag WITH-VALUE "$IPP_URI_SCHEME"
+ EXPECT job-id OF-TYPE integer COUNT 1 IN-GROUP job-attributes-tag
+ WITH-VALUE >0
+ EXPECT job-state OF-TYPE enum COUNT 1 IN-GROUP job-attributes-tag
+ WITH-VALUE 3,4,5,6,7,8,9
+ EXPECT job-state-reasons OF-TYPE keyword IN-GROUP job-attributes-tag
+ EXPECT ?job-state-message OF-TYPE text IN-GROUP job-attributes-tag
+ EXPECT ?number-of-intervening-jobs OF-TYPE integer
+ IN-GROUP job-attributes-tag WITH-VALUE >-1
+}
+
+{
+ SKIP-IF-NOT-DEFINED OPTIONAL_HOLD_JOB
+
+ NAME "Release-Job"
+ OPERATION Release-Job
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR integer job-id $job-id
+ ATTR name requesting-user-name $user
+
+ STATUS successful-ok
+ STATUS client-error-not-possible
+}
+
+
#
# End of "$Id$".
#
#
# Usage:
#
-# ./ipptool -V 2.1 {-d PRINTER_IS_COLOR=1} -f filename -t printer-uri ipp-2.1.test
+# ./ipptool -V 2.1 -f filename -t printer-uri ipp-2.1.test
#
# Do all of the IPP/1.1 and IPP/2.0 tests as an IPP/2.1 client
#
# Usage:
#
-# ./ipptool -V 2.2 {-d PRINTER_IS_COLOR=1} -f filename -t printer-uri ipp-2.2.test
+# ./ipptool -V 2.2 -f filename -t printer-uri ipp-2.2.test
#
# Do all of the IPP/1.1, IPP/2.0, and IPP/2.1 tests as an IPP/2.2 client
IgnoreErrors = 0, /* Ignore errors? */
Verbosity = 0, /* Show all attributes? */
Version = 11, /* Default IPP version */
- XMLHeader = 0; /* 1 if header is written */
+ XMLHeader = 0, /* 1 if header is written */
+ TestCount = 0, /* Number of tests run */
+ PassCount = 0, /* Number of passing tests */
+ FailCount = 0, /* Number of failing tests */
+ SkipCount = 0; /* Number of skipped tests */
char *Password = NULL; /* Password from URI */
const char * const URIStatusStrings[] = /* URI status strings */
{
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,
- int report);
+ int report, char *matchbuf, size_t matchlen);
/*
if (vars.filename)
free(vars.filename);
- if (access(argv[i], 0) && argv[i][0] != '/')
+ if (access(argv[i], 0))
{
- snprintf(filename, sizeof(filename), "%s/ipptool/%s",
- cg->cups_datadir, argv[i]);
- if (access(argv[i], 0))
- vars.filename = strdup(argv[i]);
- else
- vars.filename = strdup(filename);
- }
+ /*
+ * Try filename.gz...
+ */
+
+ snprintf(filename, sizeof(filename), "%s.gz", argv[i]);
+ if (access(filename, 0) && filename[0] != '/')
+ {
+ snprintf(filename, sizeof(filename), "%s/ipptool/%s",
+ cg->cups_datadir, argv[i]);
+ if (access(filename, 0))
+ {
+ snprintf(filename, sizeof(filename), "%s/ipptool/%s.gz",
+ cg->cups_datadir, argv[i]);
+ if (access(filename, 0))
+ vars.filename = strdup(argv[i]);
+ }
+ else
+ vars.filename = strdup(filename);
+ }
+ else
+ vars.filename = strdup(filename);
+ }
else
vars.filename = strdup(argv[i]);
if (!_cups_strcasecmp(ext, ".gif"))
set_variable(&vars, "filetype", "image/gif");
else if (!_cups_strcasecmp(ext, ".htm") ||
- !_cups_strcasecmp(ext, ".html"))
+ !_cups_strcasecmp(ext, ".htm.gz") ||
+ !_cups_strcasecmp(ext, ".html") ||
+ !_cups_strcasecmp(ext, ".html.gz"))
set_variable(&vars, "filetype", "text/html");
else if (!_cups_strcasecmp(ext, ".jpg"))
set_variable(&vars, "filetype", "image/jpeg");
set_variable(&vars, "filetype", "application/pdf");
else if (!_cups_strcasecmp(ext, ".png"))
set_variable(&vars, "filetype", "image/png");
- else if (!_cups_strcasecmp(ext, ".ps"))
+ else if (!_cups_strcasecmp(ext, ".ps") ||
+ !_cups_strcasecmp(ext, ".ps.gz"))
set_variable(&vars, "filetype", "application/postscript");
- else if (!_cups_strcasecmp(ext, ".ras"))
+ else if (!_cups_strcasecmp(ext, ".ras") ||
+ !_cups_strcasecmp(ext, ".ras.gz"))
set_variable(&vars, "filetype", "image/pwg-raster");
- else if (!_cups_strcasecmp(ext, ".txt"))
+ else if (!_cups_strcasecmp(ext, ".txt") ||
+ !_cups_strcasecmp(ext, ".txt.gz"))
set_variable(&vars, "filetype", "text/plain");
else if (!_cups_strcasecmp(ext, ".xps"))
set_variable(&vars, "filetype", "application/openxps");
do_tests(&vars, testfile);
}
}
+ else if (Output == _CUPS_OUTPUT_TEST && TestCount > 1)
+ {
+ /*
+ * 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);
+ }
/*
* Exit...
*response = NULL; /* IPP response */
size_t length; /* Length of IPP request */
http_status_t status; /* HTTP status */
- int fd; /* File to send */
+ cups_file_t *reqfile; /* File to send */
ssize_t bytes; /* Bytes read/written */
char attr[128]; /* Attribute name */
ipp_op_t op; /* Operation */
last_expect = NULL;
last_status = NULL;
filename[0] = '\0';
+ skip_previous = 0;
skip_test = 0;
version = Version;
transfer = Transfer;
* Submit the IPP request...
*/
+ TestCount ++;
+
request->request.op.version[0] = version / 10;
request->request.op.version[1] = version % 10;
request->request.op.operation_id = op;
if ((skip_previous && !prev_pass) || skip_test)
{
+ SkipCount ++;
+
ippDelete(request);
request = NULL;
length = ippLength(request);
- if (filename[0])
+ if (filename[0] && (reqfile = cupsFileOpen(filename, "r")) != NULL)
{
- struct stat fileinfo; /* File information */
+ /*
+ * Read the file to get the uncompressed file size...
+ */
- if (stat(filename, &fileinfo))
- {
- snprintf(buffer, sizeof(buffer), "%s: %s", filename,
- strerror(errno));
- _cupsSetError(IPP_INTERNAL_ERROR, buffer, 0);
+ while ((bytes = cupsFileRead(reqfile, buffer, sizeof(buffer))) > 0)
+ length += bytes;
- status = HTTP_ERROR;
- }
- else
- length += fileinfo.st_size;
+ cupsFileClose(reqfile);
}
}
* Send the request...
*/
- response = NULL;
+ response = NULL;
+ repeat_test = 0;
+ prev_pass = 1;
if (status != HTTP_ERROR)
{
- while (!response && !Cancel)
+ while (!response && !Cancel && prev_pass)
{
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)
+ if ((reqfile = cupsFileOpen(filename, "r")) != NULL)
{
- while (!Cancel && (bytes = read(fd, buffer, sizeof(buffer))) > 0)
+ while (!Cancel &&
+ (bytes = cupsFileRead(reqfile, buffer,
+ sizeof(buffer))) > 0)
if ((status = cupsWriteRequestData(http, buffer,
bytes)) != HTTP_CONTINUE)
break;
+
+ cupsFileClose(reqfile);
}
else
{
#endif /* WIN32 */
{
if (httpReconnect(http))
- {
- print_fatal_error("Unable to connect to %s on port %d - %s",
- vars->hostname, vars->port,
- cupsLastErrorString());
- pass = 0;
- goto test_exit;
- }
+ prev_pass = 0;
+ }
+ else if (status == HTTP_ERROR)
+ {
+ if (!Cancel)
+ httpReconnect(http);
+
+ prev_pass = 0;
}
}
}
* Check results of request...
*/
- repeat_test = 0;
- prev_pass = 1;
-
if (!response)
prev_pass = pass = 0;
else
continue;
}
+ if (found)
+ _ippAttrString(found, buffer, sizeof(buffer));
+
if (found &&
- !with_value(expect->with_value, expect->with_regex, found, 0))
+ !with_value(expect->with_value, expect->with_regex, found, 0,
+ buffer, sizeof(buffer)))
{
if (expect->define_no_match)
set_variable(vars, expect->define_no_match, "1");
- else if (!expect->define_match)
+ else if (!expect->define_match && !expect->define_value)
prev_pass = pass = 0;
if (expect->repeat_no_match)
{
if (expect->define_no_match)
set_variable(vars, expect->define_no_match, "1");
- else if (!expect->define_match)
+ else if (!expect->define_match && !expect->define_value)
prev_pass = pass = 0;
if (expect->repeat_no_match)
{
if (expect->define_no_match)
set_variable(vars, expect->define_no_match, "1");
- else if (!expect->define_match)
+ else if (!expect->define_match && !expect->define_value)
prev_pass = pass = 0;
if (expect->repeat_no_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);
- }
+ set_variable(vars, expect->define_value, buffer);
if (found && expect->repeat_match)
repeat_test = 1;
ippDelete(request);
- request = NULL;
+ request = NULL;
+
+ if (prev_pass)
+ PassCount ++;
+ else
+ FailCount ++;
if (Output == _CUPS_OUTPUT_PLIST)
{
for (i = num_expects, expect = expects; i > 0; i --, expect ++)
{
- if (expect->define_match || expect->define_no_match)
+ if (expect->define_match || expect->define_no_match ||
+ expect->define_value)
continue;
if (expect->if_defined && !get_variable(vars, expect->if_defined))
expect->name, ippTagString(expect->in_group),
ippTagString(found->group_tag));
- if (!with_value(expect->with_value, expect->with_regex, found, 0))
+ if (!with_value(expect->with_value, expect->with_regex, found, 0,
+ buffer, sizeof(buffer)))
{
if (expect->with_regex)
print_test_error("EXPECTED: %s WITH-VALUE /%s/",
print_test_error("EXPECTED: %s WITH-VALUE \"%s\"",
expect->name, expect->with_value);
- with_value(expect->with_value, expect->with_regex, found, 1);
+ with_value(expect->with_value, expect->with_regex, found, 1,
+ buffer, sizeof(buffer));
}
if (expect->count > 0 && found->num_values != expect->count)
print_xml_string("key", attr->name);
if (attr->num_values > 1)
puts("<array>");
- }
- else if (Output == _CUPS_OUTPUT_TEST)
- {
- if (!attr->name)
- {
- puts(" -- separator --");
- return;
- }
- printf(" %s (%s%s) = ", attr->name,
- attr->num_values > 1 ? "1setOf " : "",
- ippTagString(attr->value_tag));
- }
+ switch (attr->value_tag)
+ {
+ case IPP_TAG_INTEGER :
+ case IPP_TAG_ENUM :
+ for (i = 0; i < attr->num_values; i ++)
+ if (Output == _CUPS_OUTPUT_PLIST)
+ printf("<integer>%d</integer>\n", attr->values[i].integer);
+ else
+ printf("%d ", attr->values[i].integer);
+ break;
- switch (attr->value_tag)
- {
- case IPP_TAG_INTEGER :
- case IPP_TAG_ENUM :
- for (i = 0; i < attr->num_values; i ++)
- if (Output == _CUPS_OUTPUT_PLIST)
- printf("<integer>%d</integer>\n", attr->values[i].integer);
- else
- printf("%d ", attr->values[i].integer);
- break;
+ case IPP_TAG_BOOLEAN :
+ for (i = 0; i < attr->num_values; i ++)
+ if (Output == _CUPS_OUTPUT_PLIST)
+ puts(attr->values[i].boolean ? "<true />" : "<false />");
+ else if (attr->values[i].boolean)
+ fputs("true ", stdout);
+ else
+ fputs("false ", stdout);
+ break;
- case IPP_TAG_BOOLEAN :
- for (i = 0; i < attr->num_values; i ++)
- if (Output == _CUPS_OUTPUT_PLIST)
- puts(attr->values[i].boolean ? "<true />" : "<false />");
- else if (attr->values[i].boolean)
- fputs("true ", stdout);
- else
- fputs("false ", stdout);
- break;
+ case IPP_TAG_RANGE :
+ for (i = 0; i < attr->num_values; i ++)
+ if (Output == _CUPS_OUTPUT_PLIST)
+ printf("<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);
+ else
+ printf("%d-%d ", attr->values[i].range.lower,
+ attr->values[i].range.upper);
+ break;
- case IPP_TAG_RANGE :
- for (i = 0; i < attr->num_values; i ++)
- if (Output == _CUPS_OUTPUT_PLIST)
- printf("<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);
- else
- printf("%d-%d ", attr->values[i].range.lower,
- attr->values[i].range.upper);
- break;
+ case IPP_TAG_RESOLUTION :
+ for (i = 0; i < attr->num_values; i ++)
+ if (Output == _CUPS_OUTPUT_PLIST)
+ printf("<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,
+ attr->values[i].resolution.yres,
+ attr->values[i].resolution.units == IPP_RES_PER_INCH ?
+ "dpi" : "dpc");
+ else
+ printf("%dx%d%s ", attr->values[i].resolution.xres,
+ attr->values[i].resolution.yres,
+ attr->values[i].resolution.units == IPP_RES_PER_INCH ?
+ "dpi" : "dpc");
+ break;
- case IPP_TAG_RESOLUTION :
- for (i = 0; i < attr->num_values; i ++)
- if (Output == _CUPS_OUTPUT_PLIST)
- printf("<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,
- attr->values[i].resolution.yres,
- attr->values[i].resolution.units == IPP_RES_PER_INCH ?
- "dpi" : "dpc");
- else
- printf("%dx%d%s ", attr->values[i].resolution.xres,
- attr->values[i].resolution.yres,
- attr->values[i].resolution.units == IPP_RES_PER_INCH ?
- "dpi" : "dpc");
- break;
+ case IPP_TAG_DATE :
+ for (i = 0; i < attr->num_values; i ++)
+ if (Output == _CUPS_OUTPUT_PLIST)
+ printf("<date>%s</date>\n", iso_date(attr->values[i].date));
+ else
+ printf("%s ", iso_date(attr->values[i].date));
+ break;
- case IPP_TAG_DATE :
- for (i = 0; i < attr->num_values; i ++)
- if (Output == _CUPS_OUTPUT_PLIST)
- printf("<date>%s</date>\n", iso_date(attr->values[i].date));
- else
- printf("%s ", iso_date(attr->values[i].date));
- break;
+ case IPP_TAG_STRING :
+ 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_LANGUAGE :
+ for (i = 0; i < attr->num_values; i ++)
+ if (Output == _CUPS_OUTPUT_PLIST)
+ print_xml_string("string", attr->values[i].string.text);
+ else
+ printf("\"%s\" ", attr->values[i].string.text);
+ break;
- case IPP_TAG_STRING :
- 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_LANGUAGE :
- for (i = 0; i < attr->num_values; i ++)
- if (Output == _CUPS_OUTPUT_PLIST)
- print_xml_string("string", attr->values[i].string.text);
- else
- printf("\"%s\" ", attr->values[i].string.text);
- break;
+ case IPP_TAG_TEXTLANG :
+ case IPP_TAG_NAMELANG :
+ for (i = 0; i < attr->num_values; i ++)
+ if (Output == _CUPS_OUTPUT_PLIST)
+ {
+ fputs("<dict><key>language</key><string>", stdout);
+ print_xml_string(NULL, attr->values[i].string.charset);
+ fputs("</string><key>string</key><string>", stdout);
+ print_xml_string(NULL, attr->values[i].string.text);
+ puts("</string></dict>");
+ }
+ else
+ printf("\"%s\"(%s) ", attr->values[i].string.text,
+ attr->values[i].string.charset);
+ break;
- case IPP_TAG_TEXTLANG :
- case IPP_TAG_NAMELANG :
- for (i = 0; i < attr->num_values; i ++)
- if (Output == _CUPS_OUTPUT_PLIST)
+ case IPP_TAG_BEGIN_COLLECTION :
+ for (i = 0; i < attr->num_values; i ++)
{
- fputs("<dict><key>language</key><string>", stdout);
- print_xml_string(NULL, attr->values[i].string.charset);
- fputs("</string><key>string</key><string>", stdout);
- print_xml_string(NULL, attr->values[i].string.text);
- puts("</string></dict>");
+ if (Output == _CUPS_OUTPUT_PLIST)
+ {
+ puts("<dict>");
+ for (colattr = attr->values[i].collection->attrs;
+ colattr;
+ colattr = colattr->next)
+ print_attr(colattr, NULL);
+ puts("</dict>");
+ }
+ else
+ {
+ if (i)
+ putchar(' ');
+
+ print_col(attr->values[i].collection);
+ }
}
- else
- printf("\"%s\"(%s) ", attr->values[i].string.text,
- attr->values[i].string.charset);
- break;
+ break;
- case IPP_TAG_BEGIN_COLLECTION :
- for (i = 0; i < attr->num_values; i ++)
- {
+ default :
if (Output == _CUPS_OUTPUT_PLIST)
- {
- puts("<dict>");
- for (colattr = attr->values[i].collection->attrs;
- colattr;
- colattr = colattr->next)
- print_attr(colattr, NULL);
- puts("</dict>");
- }
+ printf("<string><<%s>></string>\n",
+ ippTagString(attr->value_tag));
else
- {
- if (i)
- putchar(' ');
-
- print_col(attr->values[i].collection);
- }
- }
- break;
-
- default :
- if (Output == _CUPS_OUTPUT_PLIST)
- printf("<string><<%s>></string>\n",
- ippTagString(attr->value_tag));
- else
- fputs(ippTagString(attr->value_tag), stdout);
- break;
- }
+ fputs(ippTagString(attr->value_tag), stdout);
+ break;
+ }
- if (Output == _CUPS_OUTPUT_PLIST)
- {
if (attr->num_values > 1)
puts("</array>");
}
else
- putchar('\n');
+ {
+ char buffer[8192]; /* Value buffer */
+
+ if (Output == _CUPS_OUTPUT_TEST)
+ {
+ if (!attr->name)
+ {
+ puts(" -- separator --");
+ return;
+ }
+
+ printf(" %s (%s%s) = ", attr->name,
+ attr->num_values > 1 ? "1setOf " : "",
+ ippTagString(attr->value_tag));
+ }
+
+ _ippAttrString(attr, buffer, sizeof(buffer));
+ puts(buffer);
+ }
}
(void)sig;
Cancel = 1;
+
+ signal(SIGINT, SIG_DFL);
+ signal(SIGTERM, SIG_DFL);
}
#endif /* !WIN32 */
with_value(char *value, /* I - Value string */
int regex, /* I - Value is a regular expression */
ipp_attribute_t *attr, /* I - Attribute to compare */
- int report) /* I - 1 = report failures */
+ int report, /* I - 1 = report failures */
+ char *matchbuf, /* I - Buffer to hold matching value */
+ size_t matchlen) /* I - Length of match buffer */
{
int i; /* Looping var */
char *valptr; /* Pointer into value */
+ *matchbuf = '\0';
+
/*
* NULL matches everything.
*/
{
case '=' :
if (attr->values[i].integer == intvalue)
+ {
+ snprintf(matchbuf, matchlen, "%d", attr->values[i].integer);
return (1);
+ }
break;
case '<' :
if (attr->values[i].integer < intvalue)
+ {
+ snprintf(matchbuf, matchlen, "%d", attr->values[i].integer);
return (1);
+ }
break;
case '>' :
if (attr->values[i].integer > intvalue)
+ {
+ snprintf(matchbuf, matchlen, "%d", attr->values[i].integer);
return (1);
+ }
break;
}
}
case '=' :
if (attr->values[i].range.lower == intvalue ||
attr->values[i].range.upper == intvalue)
+ {
+ snprintf(matchbuf, matchlen, "%d-%d",
+ attr->values[i].range.lower,
+ attr->values[i].range.upper);
return (1);
+ }
break;
case '<' :
if (attr->values[i].range.upper < intvalue)
+ {
+ snprintf(matchbuf, matchlen, "%d-%d",
+ attr->values[i].range.lower,
+ attr->values[i].range.upper);
return (1);
+ }
break;
case '>' :
- if (attr->values[i].range.upper > intvalue)
+ if (attr->values[i].range.lower > intvalue)
+ {
+ snprintf(matchbuf, matchlen, "%d-%d",
+ attr->values[i].range.lower,
+ attr->values[i].range.upper);
return (1);
+ }
break;
}
}
for (i = 0; i < attr->num_values; i ++)
{
if (!strcmp(value, "true") == attr->values[i].boolean)
+ {
+ strlcpy(matchbuf, value, matchlen);
return (1);
+ }
}
if (report)
break;
case IPP_TAG_NOVALUE :
- return (!strcmp(value, "no-value") || !strncmp(value, "no-value,", 9));
+ if (!strcmp(value, "no-value") || !strncmp(value, "no-value,", 9))
+ {
+ strlcpy(matchbuf, "no-value", matchlen);
+ return (1);
+ }
+ else
+ return (0);
case IPP_TAG_CHARSET :
case IPP_TAG_KEYWORD :
regfree(&re);
+ if (i == attr->num_values)
+ strlcpy(matchbuf, attr->values[0].string.text, matchlen);
+
return (i == attr->num_values);
}
else
for (i = 0; i < attr->num_values; i ++)
{
if (!strcmp(value, attr->values[i].string.text))
+ {
+ strlcpy(matchbuf, attr->values[i].string.text, matchlen);
return (1);
+ }
}
if (report)
--- /dev/null
+/*
+ * "$Id$"
+ *
+ * IANA XML registration to test file generator for CUPS.
+ *
+ * Copyright 2011 by Apple Inc.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
+ * which should have been included with this file. If this file is
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Usage:
+ *
+ * ./xmltotest [--ref standard] {--job|--printer} [XML file/URL] >file.test
+ *
+ * If not specified, loads the XML registrations from:
+ *
+ * http://www.iana.org/assignments/ipp-registrations/ipp-registrations.xml
+ *
+ * "Standard" is of the form "rfcNNNN" or "pwgNNNN.N".
+ *
+ * Contents:
+ *
+ * main() - Process command-line arguments.
+ * compare_reg() - Compare two registrations.
+ * load_xml() - Load the XML registration file or URL.
+ * match_xref() - Compare the xref against the named standard.
+ * new_reg() - Create a new registration record.
+ * usage() - Show usage message.
+ * write_expect() - Write an EXPECT test for an attribute.
+ */
+
+#include <mxml.h>
+#include <cups/cups.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+
+/*
+ * Local types...
+ */
+
+typedef struct _cups_reg_s /**** Registration data ****/
+{
+ char *name, /* Attribute name */
+ *member, /* Member attribute name */
+ *sub_member, /* Sub-member attribute name */
+ *syntax; /* Attribute syntax */
+} _cups_reg_t;
+
+
+/*
+ * Local functions...
+ */
+
+static int compare_reg(_cups_reg_t *a, _cups_reg_t *b);
+static mxml_node_t *load_xml(const char *reg_file);
+static int match_xref(mxml_node_t *xref, const char *standard);
+static _cups_reg_t *new_reg(mxml_node_t *name, mxml_node_t *member,
+ mxml_node_t *sub_member, mxml_node_t *syntax);
+static int usage(void);
+static void write_expect(_cups_reg_t *reg, ipp_tag_t group);
+
+
+/*
+ * 'main()' - Process command-line arguments.
+ */
+
+int
+main(int argc, /* I - Number of command-line args */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i; /* Looping var */
+ const char *reg_file = NULL, /* Registration file/URL to use */
+ *reg_standard = NULL; /* Which standard to extract */
+ mxml_node_t *reg_xml, /* Registration XML data */
+ *reg_2, /* ipp-registrations-2 */
+ *reg_record, /* <record> */
+ *reg_collection, /* <collection> */
+ *reg_name, /* <name> */
+ *reg_member, /* <member_attribute> */
+ *reg_sub_member, /* <sub-member_attribute> */
+ *reg_syntax, /* <syntax> */
+ *reg_xref; /* <xref> */
+ cups_array_t *attrs; /* Attribute registrations */
+ _cups_reg_t *current; /* Current attribute registration */
+ ipp_tag_t group = IPP_TAG_ZERO, /* Which attributes to test */
+ reg_group; /* Group for registration */
+
+
+ /*
+ * Parse command-line...
+ */
+
+ for (i = 1; i < argc; i ++)
+ {
+ if (!strcmp(argv[i], "--job") && group == IPP_TAG_ZERO)
+ group = IPP_TAG_JOB;
+ else if (!strcmp(argv[i], "--ref"))
+ {
+ i ++;
+ if (i >= argc)
+ return (usage());
+
+ reg_standard = argv[i];
+ }
+ else if (!strcmp(argv[i], "--printer") && group == IPP_TAG_ZERO)
+ group = IPP_TAG_PRINTER;
+ else if (argv[i][0] == '-' || reg_file)
+ return (usage());
+ else
+ reg_file = argv[i];
+ }
+
+ if (group == IPP_TAG_ZERO)
+ return (usage());
+
+ /*
+ * Read registrations...
+ */
+
+ if (!reg_file)
+ reg_file = "http://www.iana.org/assignments/ipp-registrations/"
+ "ipp-registrations.xml";
+
+ if ((reg_xml = load_xml(reg_file)) == NULL)
+ return (1);
+
+ /*
+ * Scan registrations for attributes...
+ */
+
+ if ((reg_2 = mxmlFindElement(reg_xml, reg_xml, "registry", "id",
+ "ipp-registrations-2",
+ MXML_DESCEND)) == NULL)
+ {
+ fprintf(stderr, "xmltotest: No IPP attribute registrations in \"%s\".\n",
+ reg_file);
+ return (1);
+ }
+
+ attrs = cupsArrayNew((cups_array_func_t)compare_reg, NULL);
+
+ for (reg_record = mxmlFindElement(reg_2, reg_2, "record", NULL, NULL,
+ MXML_DESCEND);
+ reg_record;
+ reg_record = mxmlFindElement(reg_record, reg_2, "record", NULL, NULL,
+ MXML_NO_DESCEND))
+ {
+ /*
+ * Get the values from the current record...
+ */
+
+ reg_collection = mxmlFindElement(reg_record, reg_record, "collection",
+ NULL, NULL, MXML_DESCEND);
+ reg_name = mxmlFindElement(reg_record, reg_record, "name", NULL, NULL,
+ MXML_DESCEND);
+ reg_member = mxmlFindElement(reg_record, reg_record, "member_attribute",
+ NULL, NULL, MXML_DESCEND);
+ reg_sub_member = mxmlFindElement(reg_record, reg_record,
+ "sub-member_attribute", NULL, NULL,
+ MXML_DESCEND);
+ reg_syntax = mxmlFindElement(reg_record, reg_record, "syntax", NULL,
+ NULL, MXML_DESCEND);
+ reg_xref = mxmlFindElement(reg_record, reg_record, "xref", NULL, NULL,
+ MXML_DESCEND);
+
+ if (!reg_collection || !reg_name || !reg_syntax || !reg_xref)
+ continue;
+
+ /*
+ * Filter based on group and standard...
+ */
+
+ if (!strcmp(reg_collection->child->value.opaque, "Printer Description"))
+ reg_group = IPP_TAG_PRINTER;
+ else if (!strcmp(reg_collection->child->value.opaque, "Job Description"))
+ reg_group = IPP_TAG_JOB;
+ else if (!strcmp(reg_collection->child->value.opaque, "Job Template"))
+ {
+ if (strstr(reg_name->child->value.opaque, "-default") ||
+ strstr(reg_name->child->value.opaque, "-supported"))
+ reg_group = IPP_TAG_PRINTER;
+ else
+ reg_group = IPP_TAG_JOB;
+ }
+ else
+ reg_group = IPP_TAG_ZERO;
+
+ if (reg_group != group)
+ continue;
+
+ if (reg_standard && !match_xref(reg_xref, reg_standard))
+ continue;
+
+ /*
+ * Add the record to the array...
+ */
+
+ if ((current = new_reg(reg_name, reg_member, reg_sub_member,
+ reg_syntax)) != NULL)
+ cupsArrayAdd(attrs, current);
+ }
+
+ /*
+ * Write out a test for all of the selected attributes...
+ */
+
+ puts("{");
+
+ if (group == IPP_TAG_PRINTER)
+ {
+ puts("\tOPERATION Get-Printer-Attributes");
+ puts("\tGROUP operation-attributes-tag");
+ puts("\tATTR charset attributes-charset utf-8");
+ puts("\tATTR naturalLanguage attributes-natural-language en");
+ puts("\tATTR uri printer-uri $uri");
+ puts("\tATTR name requesting-user-name $user");
+ puts("\tATTR keyword requested-attributes all,media-col-database");
+ puts("");
+ puts("\tSTATUS successful-ok");
+ puts("\tSTATUS successful-ok-ignored-or-substituted-attributes");
+ puts("");
+ }
+ else
+ {
+ puts("\tOPERATION Get-Job-Attributes");
+ puts("\tGROUP operation-attributes-tag");
+ puts("\tATTR charset attributes-charset utf-8");
+ puts("\tATTR naturalLanguage attributes-natural-language en");
+ puts("\tATTR uri printer-uri $uri");
+ puts("\tATTR integer job-id $job-id");
+ puts("\tATTR name requesting-user-name $user");
+ puts("");
+ puts("\tSTATUS successful-ok");
+ puts("");
+ }
+
+ for (current = cupsArrayFirst(attrs);
+ current;
+ current = cupsArrayNext(attrs))
+ write_expect(current, group);
+
+ puts("}");
+
+ return (0);
+}
+
+
+/*
+ * 'compare_reg()' - Compare two registrations.
+ */
+
+static int /* O - Result of comparison */
+compare_reg(_cups_reg_t *a, /* I - First registration */
+ _cups_reg_t *b) /* I - Second registration */
+{
+ int retval; /* Return value */
+
+
+ if ((retval = strcmp(a->name, b->name)) != 0)
+ return (retval);
+
+ if (a->member && b->member)
+ retval = strcmp(a->member, b->member);
+ else if (a->member)
+ retval = 1;
+ else if (b->member)
+ retval = -1;
+
+ if (retval)
+ return (retval);
+
+ if (a->sub_member && b->sub_member)
+ retval = strcmp(a->sub_member, b->sub_member);
+ else if (a->sub_member)
+ retval = 1;
+ else if (b->sub_member)
+ retval = -1;
+
+ return (retval);
+}
+
+
+/*
+ * 'load_xml()' - Load the XML registration file or URL.
+ */
+
+static mxml_node_t * /* O - XML file or NULL */
+load_xml(const char *reg_file) /* I - Filename or URL */
+{
+ mxml_node_t *xml; /* XML file */
+ char scheme[256], /* Scheme */
+ userpass[256], /* Username and password */
+ hostname[256], /* Hostname */
+ resource[1024], /* Resource path */
+ filename[1024]; /* Temporary file */
+ int port, /* Port number */
+ fd; /* File descriptor */
+
+
+ if (httpSeparateURI(HTTP_URI_CODING_ALL, reg_file, scheme, sizeof(scheme),
+ userpass, sizeof(userpass), hostname, sizeof(hostname),
+ &port, resource, sizeof(resource)) < HTTP_URI_OK)
+ {
+ fprintf(stderr, "xmltotest: Bad URI or filename \"%s\".\n", reg_file);
+ return (NULL);
+ }
+
+ if (!strcmp(scheme, "file"))
+ {
+ /*
+ * Local file...
+ */
+
+ if ((fd = open(resource, O_RDONLY)) < 0)
+ {
+ fprintf(stderr, "xmltotest: Unable to open \"%s\": %s\n", resource,
+ strerror(errno));
+ return (NULL);
+ }
+
+ filename[0] = '\0';
+ }
+ else if (strcmp(scheme, "http") && strcmp(scheme, "https"))
+ {
+ fprintf(stderr, "xmltotest: Unsupported URI scheme \"%s\".\n", scheme);
+ return (NULL);
+ }
+ else
+ {
+ http_t *http; /* HTTP connection */
+ http_encryption_t encryption; /* Encryption to use */
+ http_status_t status; /* Status of HTTP GET */
+
+ if (!strcmp(scheme, "https") || port == 443)
+ encryption = HTTP_ENCRYPT_ALWAYS;
+ else
+ encryption = HTTP_ENCRYPT_IF_REQUESTED;
+
+ if ((http = httpConnectEncrypt(hostname, port, encryption)) == NULL)
+ {
+ fprintf(stderr, "xmltotest: Unable to connect to \"%s\": %s\n", hostname,
+ cupsLastErrorString());
+ return (NULL);
+ }
+
+ if ((fd = cupsTempFd(filename, sizeof(filename))) < 0)
+ {
+ fprintf(stderr, "xmltotest: Unable to create temporary file: %s\n",
+ strerror(errno));
+ httpClose(http);
+ return (NULL);
+ }
+
+ status = cupsGetFd(http, resource, fd);
+ httpClose(http);
+
+ if (status != HTTP_OK)
+ {
+ fprintf(stderr, "mxmltotest: Unable to get \"%s\": %d\n", reg_file,
+ status);
+ close(fd);
+ unlink(filename);
+ return (NULL);
+ }
+
+ lseek(fd, 0, SEEK_SET);
+ }
+
+ /*
+ * Load the XML file...
+ */
+
+ xml = mxmlLoadFd(NULL, fd, MXML_OPAQUE_CALLBACK);
+
+ close(fd);
+
+ if (filename[0])
+ unlink(filename);
+
+ return (xml);
+}
+
+
+/*
+ * 'match_xref()' - Compare the xref against the named standard.
+ */
+
+static int /* O - 1 if match, 0 if not */
+match_xref(mxml_node_t *xref, /* I - <xref> node */
+ const char *standard) /* I - Name of standard */
+{
+ const char *data; /* "data" attribute */
+ char s[256]; /* String to look for */
+
+
+ if ((data = mxmlElementGetAttr(xref, "data")) == NULL)
+ return (1);
+
+ if (!strcmp(data, standard))
+ return (1);
+
+ if (!strncmp(standard, "pwg", 3))
+ {
+ snprintf(s, sizeof(s), "-%s.pdf", standard + 3);
+ return (strstr(data, s) != NULL);
+ }
+ else
+ return (0);
+}
+
+
+/*
+ * 'new_reg()' - Create a new registration record.
+ */
+
+static _cups_reg_t * /* O - New record */
+new_reg(mxml_node_t *name, /* I - Attribute name */
+ mxml_node_t *member, /* I - Member attribute, if any */
+ mxml_node_t *sub_member, /* I - Sub-member attribute, if any */
+ mxml_node_t *syntax) /* I - Syntax */
+{
+ _cups_reg_t *reg; /* New record */
+
+
+ if ((reg = calloc(1, sizeof(_cups_reg_t))) != NULL)
+ {
+ reg->name = name->child->value.opaque;
+ reg->syntax = syntax->child->value.opaque;
+
+ if (member)
+ reg->member = member->child->value.opaque;
+
+ if (sub_member)
+ reg->sub_member = sub_member->child->value.opaque;
+ }
+
+ return (reg);
+}
+
+
+/*
+ * 'usage()' - Show usage message.
+ */
+
+static int /* O - Exit status */
+usage(void)
+{
+ puts("Usage ./xmltotest [--ref standard] {--job|--printer} [XML file/URL] "
+ ">file.test");
+ return (1);
+}
+
+
+/*
+ * 'write_expect()' - Write an EXPECT test for an attribute.
+ */
+
+static void
+write_expect(_cups_reg_t *reg, /* I - Registration information */
+ ipp_tag_t group) /* I - Attribute group tag */
+{
+ const char *syntax; /* Pointer into syntax string */
+ int single = 1, /* Single valued? */
+ skip = 0; /* Skip characters? */
+
+
+ printf("\tEXPECT ?%s OF-TYPE ", reg->name);
+
+ syntax = reg->syntax;
+
+ while (*syntax)
+ {
+ if (!strncmp(syntax, "1setOf", 6))
+ {
+ single = 0;
+ syntax += 6;
+
+ while (isspace(*syntax & 255))
+ syntax ++;
+
+ if (*syntax == '(')
+ syntax ++;
+ }
+ else if (!strncmp(syntax, "type1", 5) || !strncmp(syntax, "type2", 5) ||
+ !strncmp(syntax, "type3", 5))
+ syntax += 5;
+ else if (*syntax == '(')
+ {
+ skip = 1;
+ syntax ++;
+ }
+ else if (*syntax == ')')
+ {
+ skip = 0;
+ syntax ++;
+ }
+ else if (!skip && (*syntax == '|' || isalpha(*syntax & 255)))
+ putchar(*syntax++);
+ else
+ syntax ++;
+ }
+
+ if (single)
+ printf(" IN-GROUP %s COUNT 1\n", ippTagString(group));
+ else
+ printf(" IN-GROUP %s\n", ippTagString(group));
+}
+
+
+/*
+ * End of "$Id$".
+ */
echo Updating to get snapshot version...
svn up
rev=`svnversion . | sed -e '1,$s/[a-zA-Z]//g'`
- fileversion="1.5svn-r$rev"
- version=snapshots
+ fileversion="`date '+%Y%m%d'`-r$rev"
else
fileversion=$1
- version=$1
fi
if (svn st | grep -qv '^\?'); then
mkdir $pkgdir || exit 1
echo Copying package files
-cp IPPTOOL.txt LICENSE.txt $pkgdir
+cp CHANGES-IPPTOOL.txt IPPTOOL.txt LICENSE.txt $pkgdir
cp doc/help/man-ipptool*.html $pkgdir
+cp test/color.jpg $pkgdir
cp test/create-printer-subscription.test $pkgdir
+cp test/document-*.pdf $pkgdir
+cp test/document-*.ps $pkgdir
cp test/get-completed-jobs.test test/get-jobs.test $pkgdir
cp test/get-printer-attributes.test $pkgdir
+cp test/gray.jpg $pkgdir
cp test/ipp-[12].*.test $pkgdir
cp test/ipptool-static $pkgdir/ipptool
+cp test/onepage-*.pdf $pkgdir
+cp test/onepage-*.ps $pkgdir
cp test/testfile.* $pkgdir
if test `uname` = Darwin; then
fi
if test -x /usr/bin/md5sum; then
- (md5sum $pkgfile | awk '{print $1, "'$fileversion' cups/'$version'/" $2}')
+ (md5sum $pkgfile | awk '{print $1, "'$fileversion' cups/ipptool/" $2}')
elif test -x /sbin/md5; then
- (md5 $pkgfile | awk '{print $4, "'$fileversion' cups/'$version'/" substr($2, 2, length($2) - 2)}')
+ (md5 $pkgfile | awk '{print $4, "'$fileversion' cups/ipptool/" substr($2, 2, length($2) - 2)}')
fi
echo Removing temporary files...