2 * ipptool command for CUPS.
4 * Copyright © 2007-2018 by Apple Inc.
5 * Copyright © 1997-2007 by Easy Software Products.
7 * Licensed under Apache License v2.0. See the file "LICENSE" for more
12 * Include necessary headers...
15 #define _IPP_PRIVATE_STRUCTURES 0 /* Disable private IPP stuff */
16 #include <cups/cups-private.h>
17 #include <cups/file-private.h>
31 #endif /* !O_BINARY */
38 typedef enum _cups_transfer_e
/**** How to send request data ****/
40 _CUPS_TRANSFER_AUTO
, /* Chunk for files, length for static */
41 _CUPS_TRANSFER_CHUNKED
, /* Chunk always */
42 _CUPS_TRANSFER_LENGTH
/* Length always */
45 typedef enum _cups_output_e
/**** Output mode ****/
47 _CUPS_OUTPUT_QUIET
, /* No output */
48 _CUPS_OUTPUT_TEST
, /* Traditional CUPS test output */
49 _CUPS_OUTPUT_PLIST
, /* XML plist test output */
50 _CUPS_OUTPUT_IPPSERVER
, /* ippserver attribute file output */
51 _CUPS_OUTPUT_LIST
, /* Tabular list output */
52 _CUPS_OUTPUT_CSV
/* Comma-separated values output */
55 typedef enum _cups_with_e
/**** WITH flags ****/
57 _CUPS_WITH_LITERAL
= 0, /* Match string is a literal value */
58 _CUPS_WITH_ALL
= 1, /* Must match all values */
59 _CUPS_WITH_REGEX
= 2, /* Match string is a regular expression */
60 _CUPS_WITH_HOSTNAME
= 4, /* Match string is a URI hostname */
61 _CUPS_WITH_RESOURCE
= 8, /* Match string is a URI resource */
62 _CUPS_WITH_SCHEME
= 16 /* Match string is a URI scheme */
65 typedef struct _cups_expect_s
/**** Expected attribute info ****/
67 int optional
, /* Optional attribute? */
68 not_expect
, /* Don't expect attribute? */
69 expect_all
; /* Expect all attributes to match/not match */
70 char *name
, /* Attribute name */
71 *of_type
, /* Type name */
72 *same_count_as
, /* Parallel attribute name */
73 *if_defined
, /* Only required if variable defined */
74 *if_not_defined
, /* Only required if variable is not defined */
75 *with_value
, /* Attribute must include this value */
76 *with_value_from
, /* Attribute must have one of the values in this attribute */
77 *define_match
, /* Variable to define on match */
78 *define_no_match
, /* Variable to define on no-match */
79 *define_value
; /* Variable to define with value */
80 int repeat_limit
, /* Maximum number of times to repeat */
81 repeat_match
, /* Repeat test on match */
82 repeat_no_match
, /* Repeat test on no match */
83 with_flags
, /* WITH flags */
84 count
; /* Expected count if > 0 */
85 ipp_tag_t in_group
; /* IN-GROUP value */
88 typedef struct _cups_status_s
/**** Status info ****/
90 ipp_status_t status
; /* Expected status code */
91 char *if_defined
, /* Only if variable is defined */
92 *if_not_defined
, /* Only if variable is not defined */
93 *define_match
, /* Variable to define on match */
94 *define_no_match
, /* Variable to define on no-match */
95 *define_value
; /* Variable to define with value */
96 int repeat_limit
, /* Maximum number of times to repeat */
97 repeat_match
, /* Repeat the test when it does not match */
98 repeat_no_match
; /* Repeat the test when it matches */
101 typedef struct _cups_testdata_s
/**** Test Data ****/
104 http_encryption_t encryption
; /* Encryption for connection */
105 int family
; /* Address family */
106 _cups_output_t output
; /* Output mode */
107 int stop_after_include_error
;
108 /* Stop after include errors? */
109 double timeout
; /* Timeout for connection */
110 int validate_headers
, /* Validate HTTP headers in response? */
111 verbosity
; /* Show all attributes? */
114 int def_ignore_errors
; /* Default IGNORE-ERRORS value */
115 _cups_transfer_t def_transfer
; /* Default TRANSFER value */
116 int def_version
; /* Default IPP version */
119 http_t
*http
; /* HTTP connection to printer/server */
120 cups_file_t
*outfile
; /* Output file */
121 int show_header
, /* Show the test header? */
122 xml_header
; /* 1 if XML plist header was written */
123 int pass
, /* Have we passed all tests? */
124 test_count
, /* Number of tests (total) */
125 pass_count
, /* Number of tests that passed */
126 fail_count
, /* Number of tests that failed */
127 skip_count
; /* Number of tests that were skipped */
130 cups_array_t
*errors
; /* Errors array */
131 int prev_pass
, /* Result of previous test */
132 skip_previous
; /* Skip on previous test failure? */
133 char compression
[16]; /* COMPRESSION value */
134 useconds_t delay
; /* Initial delay */
135 int num_displayed
; /* Number of displayed attributes */
136 char *displayed
[200]; /* Displayed attributes */
137 int num_expects
; /* Number of expected attributes */
138 _cups_expect_t expects
[200], /* Expected attributes */
139 *expect
, /* Current expected attribute */
140 *last_expect
; /* Last EXPECT (for predicates) */
141 char file
[1024], /* Data filename */
142 file_id
[1024]; /* File identifier */
143 int ignore_errors
; /* Ignore test failures? */
144 char name
[1024]; /* Test name */
145 useconds_t repeat_interval
; /* Repeat interval (delay) */
146 int request_id
; /* Current request ID */
147 char resource
[512]; /* Resource for request */
148 int skip_test
, /* Skip this test? */
149 num_statuses
; /* Number of valid status codes */
150 _cups_status_t statuses
[100], /* Valid status codes */
151 *last_status
; /* Last STATUS (for predicates) */
152 char test_id
[1024]; /* Test identifier */
153 _cups_transfer_t transfer
; /* To chunk or not to chunk */
154 int version
; /* IPP version number to use */
162 static int Cancel
= 0; /* Cancel test? */
169 static void add_stringf(cups_array_t
*a
, const char *s
, ...) __attribute__ ((__format__ (__printf__
, 2, 3)));
170 static int compare_uris(const char *a
, const char *b
);
171 static int do_test(_ipp_file_t
*f
, _ipp_vars_t
*vars
, _cups_testdata_t
*data
);
172 static int do_tests(const char *testfile
, _ipp_vars_t
*vars
, _cups_testdata_t
*data
);
173 static int error_cb(_ipp_file_t
*f
, _cups_testdata_t
*data
, const char *error
);
174 static int expect_matches(_cups_expect_t
*expect
, ipp_tag_t value_tag
);
175 static char *get_filename(const char *testfile
, char *dst
, const char *src
, size_t dstsize
);
176 static const char *get_string(ipp_attribute_t
*attr
, int element
, int flags
, char *buffer
, size_t bufsize
);
177 static void init_data(_cups_testdata_t
*data
);
178 static char *iso_date(const ipp_uchar_t
*date
);
179 static void pause_message(const char *message
);
180 static void print_attr(cups_file_t
*outfile
, int output
, ipp_attribute_t
*attr
, ipp_tag_t
*group
);
181 static void print_csv(_cups_testdata_t
*data
, ipp_t
*ipp
, ipp_attribute_t
*attr
, int num_displayed
, char **displayed
, size_t *widths
);
182 static void print_fatal_error(_cups_testdata_t
*data
, const char *s
, ...) __attribute__ ((__format__ (__printf__
, 2, 3)));
183 static void print_ippserver_attr(_cups_testdata_t
*data
, ipp_attribute_t
*attr
, int indent
);
184 static void print_ippserver_string(_cups_testdata_t
*data
, const char *s
, size_t len
);
185 static void print_line(_cups_testdata_t
*data
, ipp_t
*ipp
, ipp_attribute_t
*attr
, int num_displayed
, char **displayed
, size_t *widths
);
186 static void print_xml_header(_cups_testdata_t
*data
);
187 static void print_xml_string(cups_file_t
*outfile
, const char *element
, const char *s
);
188 static void print_xml_trailer(_cups_testdata_t
*data
, int success
, const char *message
);
190 static void sigterm_handler(int sig
);
192 static int timeout_cb(http_t
*http
, void *user_data
);
193 static int token_cb(_ipp_file_t
*f
, _ipp_vars_t
*vars
, _cups_testdata_t
*data
, const char *token
);
194 static void usage(void) __attribute__((noreturn
));
195 static const char *with_flags_string(int flags
);
196 static int with_value(_cups_testdata_t
*data
, cups_array_t
*errors
, char *value
, int flags
, ipp_attribute_t
*attr
, char *matchbuf
, size_t matchlen
);
197 static int with_value_from(cups_array_t
*errors
, ipp_attribute_t
*fromattr
, ipp_attribute_t
*attr
, char *matchbuf
, size_t matchlen
);
201 * 'main()' - Parse options and do tests.
204 int /* O - Exit status */
205 main(int argc
, /* I - Number of command-line args */
206 char *argv
[]) /* I - Command-line arguments */
208 int i
; /* Looping var */
209 int status
; /* Status of tests... */
210 char *opt
, /* Current option */
211 name
[1024], /* Name/value buffer */
212 *value
, /* Pointer to value */
213 filename
[1024], /* Real filename */
214 testname
[1024]; /* Real test filename */
215 const char *ext
, /* Extension on filename */
216 *testfile
; /* Test file to use */
217 int interval
, /* Test interval in microseconds */
218 repeat
; /* Repeat count */
219 _cups_testdata_t data
; /* Test data */
220 _ipp_vars_t vars
; /* Variables */
221 _cups_globals_t
*cg
= _cupsGlobals();
227 * Catch SIGINT and SIGTERM...
230 signal(SIGINT
, sigterm_handler
);
231 signal(SIGTERM
, sigterm_handler
);
235 * Initialize the locale and variables...
238 _cupsSetLocale(argv
);
247 * ipptool URI testfile
255 for (i
= 1; i
< argc
; i
++)
257 if (!strcmp(argv
[i
], "--help"))
261 else if (!strcmp(argv
[i
], "--ippserver"))
267 _cupsLangPuts(stderr
, _("ipptool: Missing filename for \"--ippserver\"."));
271 if (data
.outfile
!= cupsFileStdout())
274 if ((data
.outfile
= cupsFileOpen(argv
[i
], "w")) == NULL
)
276 _cupsLangPrintf(stderr
, _("%s: Unable to open \"%s\": %s"), "ipptool", argv
[i
], strerror(errno
));
280 data
.output
= _CUPS_OUTPUT_IPPSERVER
;
282 else if (!strcmp(argv
[i
], "--stop-after-include-error"))
284 data
.stop_after_include_error
= 1;
286 else if (!strcmp(argv
[i
], "--version"))
291 else if (argv
[i
][0] == '-')
293 for (opt
= argv
[i
] + 1; *opt
; opt
++)
297 case '4' : /* Connect using IPv4 only */
298 data
.family
= AF_INET
;
302 case '6' : /* Connect using IPv6 only */
303 data
.family
= AF_INET6
;
305 #endif /* AF_INET6 */
307 case 'C' : /* Enable HTTP chunking */
308 data
.def_transfer
= _CUPS_TRANSFER_CHUNKED
;
311 case 'E' : /* Encrypt with TLS */
313 data
.encryption
= HTTP_ENCRYPT_REQUIRED
;
315 _cupsLangPrintf(stderr
, _("%s: Sorry, no encryption support."),
317 #endif /* HAVE_SSL */
320 case 'I' : /* Ignore errors */
321 data
.def_ignore_errors
= 1;
324 case 'L' : /* Disable HTTP chunking */
325 data
.def_transfer
= _CUPS_TRANSFER_LENGTH
;
328 case 'P' : /* Output to plist file */
333 _cupsLangPrintf(stderr
, _("%s: Missing filename for \"-P\"."), "ipptool");
337 if (data
.outfile
!= cupsFileStdout())
340 if ((data
.outfile
= cupsFileOpen(argv
[i
], "w")) == NULL
)
342 _cupsLangPrintf(stderr
, _("%s: Unable to open \"%s\": %s"), "ipptool", argv
[i
], strerror(errno
));
346 data
.output
= _CUPS_OUTPUT_PLIST
;
348 if (interval
|| repeat
)
350 _cupsLangPuts(stderr
, _("ipptool: \"-i\" and \"-n\" are incompatible with \"-P\" and \"-X\"."));
355 case 'S' : /* Encrypt with SSL */
357 data
.encryption
= HTTP_ENCRYPT_ALWAYS
;
359 _cupsLangPrintf(stderr
, _("%s: Sorry, no encryption support."),
361 #endif /* HAVE_SSL */
364 case 'T' : /* Set timeout */
369 _cupsLangPrintf(stderr
,
370 _("%s: Missing timeout for \"-T\"."),
375 data
.timeout
= _cupsStrScand(argv
[i
], NULL
, localeconv());
378 case 'V' : /* Set IPP version */
383 _cupsLangPrintf(stderr
,
384 _("%s: Missing version for \"-V\"."),
389 if (!strcmp(argv
[i
], "1.0"))
391 data
.def_version
= 10;
393 else if (!strcmp(argv
[i
], "1.1"))
395 data
.def_version
= 11;
397 else if (!strcmp(argv
[i
], "2.0"))
399 data
.def_version
= 20;
401 else if (!strcmp(argv
[i
], "2.1"))
403 data
.def_version
= 21;
405 else if (!strcmp(argv
[i
], "2.2"))
407 data
.def_version
= 22;
411 _cupsLangPrintf(stderr
, _("%s: Bad version %s for \"-V\"."), "ipptool", argv
[i
]);
416 case 'X' : /* Produce XML output */
417 data
.output
= _CUPS_OUTPUT_PLIST
;
419 if (interval
|| repeat
)
421 _cupsLangPuts(stderr
, _("ipptool: \"-i\" and \"-n\" are incompatible with \"-P\" and \"-X\"."));
426 case 'c' : /* CSV output */
427 data
.output
= _CUPS_OUTPUT_CSV
;
430 case 'd' : /* Define a variable */
435 _cupsLangPuts(stderr
,
436 _("ipptool: Missing name=value for \"-d\"."));
440 strlcpy(name
, argv
[i
], sizeof(name
));
441 if ((value
= strchr(name
, '=')) != NULL
)
444 value
= name
+ strlen(name
);
446 _ippVarsSet(&vars
, name
, value
);
449 case 'f' : /* Set the default test filename */
454 _cupsLangPuts(stderr
,
455 _("ipptool: Missing filename for \"-f\"."));
459 if (access(argv
[i
], 0))
465 snprintf(filename
, sizeof(filename
), "%s.gz", argv
[i
]);
466 if (access(filename
, 0) && filename
[0] != '/'
468 && (!isalpha(filename
[0] & 255) || filename
[1] != ':')
472 snprintf(filename
, sizeof(filename
), "%s/ipptool/%s", cg
->cups_datadir
, argv
[i
]);
473 if (access(filename
, 0))
475 snprintf(filename
, sizeof(filename
), "%s/ipptool/%s.gz", cg
->cups_datadir
, argv
[i
]);
476 if (access(filename
, 0))
477 strlcpy(filename
, argv
[i
], sizeof(filename
));
482 strlcpy(filename
, argv
[i
], sizeof(filename
));
484 _ippVarsSet(&vars
, "filename", filename
);
486 if ((ext
= strrchr(filename
, '.')) != NULL
)
489 * Guess the MIME media type based on the extension...
492 if (!_cups_strcasecmp(ext
, ".gif"))
493 _ippVarsSet(&vars
, "filetype", "image/gif");
494 else if (!_cups_strcasecmp(ext
, ".htm") ||
495 !_cups_strcasecmp(ext
, ".htm.gz") ||
496 !_cups_strcasecmp(ext
, ".html") ||
497 !_cups_strcasecmp(ext
, ".html.gz"))
498 _ippVarsSet(&vars
, "filetype", "text/html");
499 else if (!_cups_strcasecmp(ext
, ".jpg") ||
500 !_cups_strcasecmp(ext
, ".jpeg"))
501 _ippVarsSet(&vars
, "filetype", "image/jpeg");
502 else if (!_cups_strcasecmp(ext
, ".pcl") ||
503 !_cups_strcasecmp(ext
, ".pcl.gz"))
504 _ippVarsSet(&vars
, "filetype", "application/vnd.hp-PCL");
505 else if (!_cups_strcasecmp(ext
, ".pdf"))
506 _ippVarsSet(&vars
, "filetype", "application/pdf");
507 else if (!_cups_strcasecmp(ext
, ".png"))
508 _ippVarsSet(&vars
, "filetype", "image/png");
509 else if (!_cups_strcasecmp(ext
, ".ps") ||
510 !_cups_strcasecmp(ext
, ".ps.gz"))
511 _ippVarsSet(&vars
, "filetype", "application/postscript");
512 else if (!_cups_strcasecmp(ext
, ".pwg") ||
513 !_cups_strcasecmp(ext
, ".pwg.gz") ||
514 !_cups_strcasecmp(ext
, ".ras") ||
515 !_cups_strcasecmp(ext
, ".ras.gz"))
516 _ippVarsSet(&vars
, "filetype", "image/pwg-raster");
517 else if (!_cups_strcasecmp(ext
, ".tif") ||
518 !_cups_strcasecmp(ext
, ".tiff"))
519 _ippVarsSet(&vars
, "filetype", "image/tiff");
520 else if (!_cups_strcasecmp(ext
, ".txt") ||
521 !_cups_strcasecmp(ext
, ".txt.gz"))
522 _ippVarsSet(&vars
, "filetype", "text/plain");
523 else if (!_cups_strcasecmp(ext
, ".urf") ||
524 !_cups_strcasecmp(ext
, ".urf.gz"))
525 _ippVarsSet(&vars
, "filetype", "image/urf");
526 else if (!_cups_strcasecmp(ext
, ".xps"))
527 _ippVarsSet(&vars
, "filetype", "application/openxps");
529 _ippVarsSet(&vars
, "filetype", "application/octet-stream");
534 * Use the "auto-type" MIME media type...
537 _ippVarsSet(&vars
, "filetype", "application/octet-stream");
541 case 'h' : /* Validate response headers */
542 data
.validate_headers
= 1;
545 case 'i' : /* Test every N seconds */
550 _cupsLangPuts(stderr
, _("ipptool: Missing seconds for \"-i\"."));
555 interval
= (int)(_cupsStrScand(argv
[i
], NULL
, localeconv()) * 1000000.0);
558 _cupsLangPuts(stderr
, _("ipptool: Invalid seconds for \"-i\"."));
563 if ((data
.output
== _CUPS_OUTPUT_PLIST
|| data
.output
== _CUPS_OUTPUT_IPPSERVER
) && interval
)
565 _cupsLangPuts(stderr
, _("ipptool: \"-i\" and \"-n\" are incompatible with \"--ippserver\", \"-P\", and \"-X\"."));
570 case 'l' : /* List as a table */
571 data
.output
= _CUPS_OUTPUT_LIST
;
574 case 'n' : /* Repeat count */
579 _cupsLangPuts(stderr
, _("ipptool: Missing count for \"-n\"."));
583 repeat
= atoi(argv
[i
]);
585 if ((data
.output
== _CUPS_OUTPUT_PLIST
|| data
.output
== _CUPS_OUTPUT_IPPSERVER
) && repeat
)
587 _cupsLangPuts(stderr
, _("ipptool: \"-i\" and \"-n\" are incompatible with \"--ippserver\", \"-P\", and \"-X\"."));
592 case 'q' : /* Be quiet */
593 data
.output
= _CUPS_OUTPUT_QUIET
;
596 case 't' : /* CUPS test output */
597 data
.output
= _CUPS_OUTPUT_TEST
;
600 case 'v' : /* Be verbose */
605 _cupsLangPrintf(stderr
, _("%s: Unknown option \"-%c\"."), "ipptool", *opt
);
610 else if (!strncmp(argv
[i
], "ipp://", 6) || !strncmp(argv
[i
], "http://", 7)
612 || !strncmp(argv
[i
], "ipps://", 7) || !strncmp(argv
[i
], "https://", 8)
613 #endif /* HAVE_SSL */
622 _cupsLangPuts(stderr
, _("ipptool: May only specify a single URI."));
627 if (!strncmp(argv
[i
], "ipps://", 7) || !strncmp(argv
[i
], "https://", 8))
628 data
.encryption
= HTTP_ENCRYPT_ALWAYS
;
629 #endif /* HAVE_SSL */
631 if (!_ippVarsSet(&vars
, "uri", argv
[i
]))
633 _cupsLangPrintf(stderr
, _("ipptool: Bad URI \"%s\"."), argv
[i
]);
637 if (vars
.username
[0] && vars
.password
)
638 cupsSetPasswordCB2(_ippVarsPasswordCB
, &vars
);
648 _cupsLangPuts(stderr
, _("ipptool: URI required before test file."));
649 _cupsLangPuts(stderr
, argv
[i
]);
653 if (access(argv
[i
], 0) && argv
[i
][0] != '/'
655 && (!isalpha(argv
[i
][0] & 255) || argv
[i
][1] != ':')
659 snprintf(testname
, sizeof(testname
), "%s/ipptool/%s", cg
->cups_datadir
, argv
[i
]);
660 if (access(testname
, 0))
668 if (!do_tests(testfile
, &vars
, &data
))
673 if (!vars
.uri
|| !testfile
)
677 * Loop if the interval is set...
680 if (data
.output
== _CUPS_OUTPUT_PLIST
)
681 print_xml_trailer(&data
, !status
, NULL
);
682 else if (interval
> 0 && repeat
> 0)
686 usleep((useconds_t
)interval
);
687 do_tests(testfile
, &vars
, &data
);
691 else if (interval
> 0)
695 usleep((useconds_t
)interval
);
696 do_tests(testfile
, &vars
, &data
);
700 if ((data
.output
== _CUPS_OUTPUT_TEST
|| (data
.output
== _CUPS_OUTPUT_PLIST
&& data
.outfile
)) && data
.test_count
> 1)
703 * Show a summary report if there were multiple tests...
706 cupsFilePrintf(cupsFileStdout(), "\nSummary: %d tests, %d passed, %d failed, %d skipped\nScore: %d%%\n", data
.test_count
, data
.pass_count
, data
.fail_count
, data
.skip_count
, 100 * (data
.pass_count
+ data
.skip_count
) / data
.test_count
);
709 cupsFileClose(data
.outfile
);
720 * 'add_stringf()' - Add a formatted string to an array.
724 add_stringf(cups_array_t
*a
, /* I - Array */
725 const char *s
, /* I - Printf-style format string */
726 ...) /* I - Additional args as needed */
728 char buffer
[10240]; /* Format buffer */
729 va_list ap
; /* Argument pointer */
733 * Don't bother is the array is NULL...
740 * Format the message...
744 vsnprintf(buffer
, sizeof(buffer
), s
, ap
);
748 * Add it to the array...
751 cupsArrayAdd(a
, buffer
);
756 * 'compare_uris()' - Compare two URIs...
759 static int /* O - Result of comparison */
760 compare_uris(const char *a
, /* I - First URI */
761 const char *b
) /* I - Second URI */
763 char ascheme
[32], /* Components of first URI */
768 char bscheme
[32], /* Components of second URI */
773 char *ptr
; /* Pointer into string */
774 int result
; /* Result of comparison */
778 * Separate the URIs into their components...
781 if (httpSeparateURI(HTTP_URI_CODING_ALL
, a
, ascheme
, sizeof(ascheme
), auserpass
, sizeof(auserpass
), ahost
, sizeof(ahost
), &aport
, aresource
, sizeof(aresource
)) < HTTP_URI_STATUS_OK
)
784 if (httpSeparateURI(HTTP_URI_CODING_ALL
, b
, bscheme
, sizeof(bscheme
), buserpass
, sizeof(buserpass
), bhost
, sizeof(bhost
), &bport
, bresource
, sizeof(bresource
)) < HTTP_URI_STATUS_OK
)
788 * Strip trailing dots from the host components, if present...
791 if ((ptr
= ahost
+ strlen(ahost
) - 1) > ahost
&& *ptr
== '.')
794 if ((ptr
= bhost
+ strlen(bhost
) - 1) > bhost
&& *ptr
== '.')
798 * Compare each component...
801 if ((result
= _cups_strcasecmp(ascheme
, bscheme
)) != 0)
804 if ((result
= strcmp(auserpass
, buserpass
)) != 0)
807 if ((result
= _cups_strcasecmp(ahost
, bhost
)) != 0)
811 return (aport
- bport
);
813 if (!_cups_strcasecmp(ascheme
, "mailto") || !_cups_strcasecmp(ascheme
, "urn"))
814 return (_cups_strcasecmp(aresource
, bresource
));
816 return (strcmp(aresource
, bresource
));
821 * 'do_test()' - Do a single test from the test file.
824 static int /* O - 1 on success, 0 on failure */
825 do_test(_ipp_file_t
*f
, /* I - IPP data file */
826 _ipp_vars_t
*vars
, /* I - IPP variables */
827 _cups_testdata_t
*data
) /* I - Test data */
830 int i
, /* Looping var */
831 status_ok
, /* Did we get a matching status? */
832 repeat_count
= 0, /* Repeat count */
833 repeat_test
; /* Repeat the test? */
834 _cups_expect_t
*expect
; /* Current expected attribute */
835 ipp_t
*request
, /* IPP request */
836 *response
; /* IPP response */
837 size_t length
; /* Length of IPP request */
838 http_status_t status
; /* HTTP status */
839 cups_array_t
*a
; /* Duplicate attribute array */
840 ipp_tag_t group
; /* Current group */
841 ipp_attribute_t
*attrptr
, /* Attribute pointer */
842 *found
; /* Found attribute */
843 char temp
[1024]; /* Temporary string */
844 cups_file_t
*reqfile
; /* File to send */
845 ssize_t bytes
; /* Bytes read/written */
846 char buffer
[131072]; /* Copy buffer */
847 size_t widths
[200]; /* Width of columns */
848 const char *error
; /* Current error */
855 * Take over control of the attributes in the request...
862 * Submit the IPP request...
867 ippSetVersion(request
, data
->version
/ 10, data
->version
% 10);
868 ippSetRequestId(request
, data
->request_id
);
870 if (data
->output
== _CUPS_OUTPUT_PLIST
)
872 cupsFilePuts(data
->outfile
, "<dict>\n");
873 cupsFilePuts(data
->outfile
, "<key>Name</key>\n");
874 print_xml_string(data
->outfile
, "string", data
->name
);
875 if (data
->file_id
[0])
877 cupsFilePuts(data
->outfile
, "<key>FileId</key>\n");
878 print_xml_string(data
->outfile
, "string", data
->file_id
);
880 if (data
->test_id
[0])
882 cupsFilePuts(data
->outfile
, "<key>TestId</key>\n");
883 print_xml_string(data
->outfile
, "string", data
->test_id
);
885 cupsFilePuts(data
->outfile
, "<key>Version</key>\n");
886 cupsFilePrintf(data
->outfile
, "<string>%d.%d</string>\n", data
->version
/ 10, data
->version
% 10);
887 cupsFilePuts(data
->outfile
, "<key>Operation</key>\n");
888 print_xml_string(data
->outfile
, "string", ippOpString(ippGetOperation(request
)));
889 cupsFilePuts(data
->outfile
, "<key>RequestId</key>\n");
890 cupsFilePrintf(data
->outfile
, "<integer>%d</integer>\n", data
->request_id
);
891 cupsFilePuts(data
->outfile
, "<key>RequestAttributes</key>\n");
892 cupsFilePuts(data
->outfile
, "<array>\n");
893 if (ippFirstAttribute(request
))
895 cupsFilePuts(data
->outfile
, "<dict>\n");
896 for (attrptr
= ippFirstAttribute(request
), group
= ippGetGroupTag(attrptr
); attrptr
; attrptr
= ippNextAttribute(request
))
897 print_attr(data
->outfile
, data
->output
, attrptr
, &group
);
898 cupsFilePuts(data
->outfile
, "</dict>\n");
900 cupsFilePuts(data
->outfile
, "</array>\n");
903 if (data
->output
== _CUPS_OUTPUT_TEST
|| (data
->output
== _CUPS_OUTPUT_PLIST
&& data
->outfile
!= cupsFileStdout()))
907 cupsFilePrintf(cupsFileStdout(), " %s:\n", ippOpString(ippGetOperation(request
)));
909 for (attrptr
= ippFirstAttribute(request
); attrptr
; attrptr
= ippNextAttribute(request
))
910 print_attr(cupsFileStdout(), _CUPS_OUTPUT_TEST
, attrptr
, NULL
);
913 cupsFilePrintf(cupsFileStdout(), " %-68.68s [", data
->name
);
916 if ((data
->skip_previous
&& !data
->prev_pass
) || data
->skip_test
)
924 if (data
->output
== _CUPS_OUTPUT_PLIST
)
926 cupsFilePuts(data
->outfile
, "<key>Successful</key>\n");
927 cupsFilePuts(data
->outfile
, "<true />\n");
928 cupsFilePuts(data
->outfile
, "<key>Skipped</key>\n");
929 cupsFilePuts(data
->outfile
, "<true />\n");
930 cupsFilePuts(data
->outfile
, "<key>StatusCode</key>\n");
931 print_xml_string(data
->outfile
, "string", "skip");
932 cupsFilePuts(data
->outfile
, "<key>ResponseAttributes</key>\n");
933 cupsFilePuts(data
->outfile
, "<dict />\n");
936 if (data
->output
== _CUPS_OUTPUT_TEST
|| (data
->output
== _CUPS_OUTPUT_PLIST
&& data
->outfile
!= cupsFileStdout()))
937 cupsFilePuts(cupsFileStdout(), "SKIP]\n");
942 vars
->password_tries
= 0;
949 data
->delay
= data
->repeat_interval
;
952 status
= HTTP_STATUS_OK
;
954 if (data
->transfer
== _CUPS_TRANSFER_CHUNKED
|| (data
->transfer
== _CUPS_TRANSFER_AUTO
&& data
->file
[0]))
957 * Send request using chunking - a 0 length means "chunk".
965 * Send request using content length...
968 length
= ippLength(request
);
970 if (data
->file
[0] && (reqfile
= cupsFileOpen(data
->file
, "r")) != NULL
)
973 * Read the file to get the uncompressed file size...
976 while ((bytes
= cupsFileRead(reqfile
, buffer
, sizeof(buffer
))) > 0)
977 length
+= (size_t)bytes
;
979 cupsFileClose(reqfile
);
984 * Send the request...
991 if (status
!= HTTP_STATUS_ERROR
)
993 while (!response
&& !Cancel
&& data
->prev_pass
)
995 status
= cupsSendRequest(data
->http
, request
, data
->resource
, length
);
998 if (data
->compression
[0])
999 httpSetField(data
->http
, HTTP_FIELD_CONTENT_ENCODING
, data
->compression
);
1000 #endif /* HAVE_LIBZ */
1002 if (!Cancel
&& status
== HTTP_STATUS_CONTINUE
&& ippGetState(request
) == IPP_DATA
&& data
->file
[0])
1004 if ((reqfile
= cupsFileOpen(data
->file
, "r")) != NULL
)
1006 while (!Cancel
&& (bytes
= cupsFileRead(reqfile
, buffer
, sizeof(buffer
))) > 0)
1008 if ((status
= cupsWriteRequestData(data
->http
, buffer
, (size_t)bytes
)) != HTTP_STATUS_CONTINUE
)
1012 cupsFileClose(reqfile
);
1016 snprintf(buffer
, sizeof(buffer
), "%s: %s", data
->file
, strerror(errno
));
1017 _cupsSetError(IPP_INTERNAL_ERROR
, buffer
, 0);
1019 status
= HTTP_STATUS_ERROR
;
1024 * Get the server's response...
1027 if (!Cancel
&& status
!= HTTP_STATUS_ERROR
)
1029 response
= cupsGetResponse(data
->http
, data
->resource
);
1030 status
= httpGetStatus(data
->http
);
1033 if (!Cancel
&& status
== HTTP_STATUS_ERROR
&& httpError(data
->http
) != EINVAL
&&
1035 httpError(data
->http
) != WSAETIMEDOUT
)
1037 httpError(data
->http
) != ETIMEDOUT
)
1040 if (httpReconnect2(data
->http
, 30000, NULL
))
1041 data
->prev_pass
= 0;
1043 else if (status
== HTTP_STATUS_ERROR
|| status
== HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED
)
1045 data
->prev_pass
= 0;
1048 else if (status
!= HTTP_STATUS_OK
)
1050 httpFlush(data
->http
);
1052 if (status
== HTTP_STATUS_UNAUTHORIZED
)
1060 if (!Cancel
&& status
== HTTP_STATUS_ERROR
&& httpError(data
->http
) != EINVAL
&&
1062 httpError(data
->http
) != WSAETIMEDOUT
)
1064 httpError(data
->http
) != ETIMEDOUT
)
1067 if (httpReconnect2(data
->http
, 30000, NULL
))
1068 data
->prev_pass
= 0;
1070 else if (status
== HTTP_STATUS_ERROR
)
1073 httpReconnect2(data
->http
, 30000, NULL
);
1075 data
->prev_pass
= 0;
1077 else if (status
!= HTTP_STATUS_OK
)
1079 httpFlush(data
->http
);
1080 data
->prev_pass
= 0;
1084 * Check results of request...
1087 cupsArrayClear(data
->errors
);
1089 if (httpGetVersion(data
->http
) != HTTP_1_1
)
1091 int version
= httpGetVersion(data
->http
);
1093 add_stringf(data
->errors
, "Bad HTTP version (%d.%d)", version
/ 100, version
% 100);
1096 if (data
->validate_headers
)
1098 const char *header
; /* HTTP header value */
1100 if ((header
= httpGetField(data
->http
, HTTP_FIELD_CONTENT_TYPE
)) == NULL
|| _cups_strcasecmp(header
, "application/ipp"))
1101 add_stringf(data
->errors
, "Bad HTTP Content-Type in response (%s)", header
&& *header
? header
: "<missing>");
1103 if ((header
= httpGetField(data
->http
, HTTP_FIELD_DATE
)) != NULL
&& *header
&& httpGetDateTime(header
) == 0)
1104 add_stringf(data
->errors
, "Bad HTTP Date in response (%s)", header
);
1110 * No response, log error...
1113 add_stringf(data
->errors
, "IPP request failed with status %s (%s)", ippErrorString(cupsLastError()), cupsLastErrorString());
1118 * Collect common attribute values...
1121 if ((attrptr
= ippFindAttribute(response
, "job-id", IPP_TAG_INTEGER
)) != NULL
)
1123 snprintf(temp
, sizeof(temp
), "%d", ippGetInteger(attrptr
, 0));
1124 _ippVarsSet(vars
, "job-id", temp
);
1127 if ((attrptr
= ippFindAttribute(response
, "job-uri", IPP_TAG_URI
)) != NULL
)
1128 _ippVarsSet(vars
, "job-uri", ippGetString(attrptr
, 0, NULL
));
1130 if ((attrptr
= ippFindAttribute(response
, "notify-subscription-id", IPP_TAG_INTEGER
)) != NULL
)
1132 snprintf(temp
, sizeof(temp
), "%d", ippGetInteger(attrptr
, 0));
1133 _ippVarsSet(vars
, "notify-subscription-id", temp
);
1137 * Check response, validating groups and attributes and logging errors
1141 if (ippGetState(response
) != IPP_DATA
)
1142 add_stringf(data
->errors
, "Missing end-of-attributes-tag in response (RFC 2910 section 3.5.1)");
1146 int major
, minor
; /* IPP version */
1148 major
= ippGetVersion(response
, &minor
);
1150 if (major
!= (data
->version
/ 10) || minor
!= (data
->version
% 10))
1151 add_stringf(data
->errors
, "Bad version %d.%d in response - expected %d.%d (RFC 2911 section 3.1.8).", major
, minor
, data
->version
/ 10, data
->version
% 10);
1154 if (ippGetRequestId(response
) != data
->request_id
)
1155 add_stringf(data
->errors
, "Bad request ID %d in response - expected %d (RFC 2911 section 3.1.1)", ippGetRequestId(response
), data
->request_id
);
1157 attrptr
= ippFirstAttribute(response
);
1160 add_stringf(data
->errors
, "Missing first attribute \"attributes-charset (charset)\" in group operation-attributes-tag (RFC 2911 section 3.1.4).");
1164 if (!ippGetName(attrptr
) || ippGetValueTag(attrptr
) != IPP_TAG_CHARSET
|| ippGetGroupTag(attrptr
) != IPP_TAG_OPERATION
|| ippGetCount(attrptr
) != 1 ||strcmp(ippGetName(attrptr
), "attributes-charset"))
1165 add_stringf(data
->errors
, "Bad first attribute \"%s (%s%s)\" in group %s, expected \"attributes-charset (charset)\" in group operation-attributes-tag (RFC 2911 section 3.1.4).", ippGetName(attrptr
) ? ippGetName(attrptr
) : "(null)", ippGetCount(attrptr
) > 1 ? "1setOf " : "", ippTagString(ippGetValueTag(attrptr
)), ippTagString(ippGetGroupTag(attrptr
)));
1167 attrptr
= ippNextAttribute(response
);
1169 add_stringf(data
->errors
, "Missing second attribute \"attributes-natural-language (naturalLanguage)\" in group operation-attributes-tag (RFC 2911 section 3.1.4).");
1170 else if (!ippGetName(attrptr
) || ippGetValueTag(attrptr
) != IPP_TAG_LANGUAGE
|| ippGetGroupTag(attrptr
) != IPP_TAG_OPERATION
|| ippGetCount(attrptr
) != 1 || strcmp(ippGetName(attrptr
), "attributes-natural-language"))
1171 add_stringf(data
->errors
, "Bad first attribute \"%s (%s%s)\" in group %s, expected \"attributes-natural-language (naturalLanguage)\" in group operation-attributes-tag (RFC 2911 section 3.1.4).", ippGetName(attrptr
) ? ippGetName(attrptr
) : "(null)", ippGetCount(attrptr
) > 1 ? "1setOf " : "", ippTagString(ippGetValueTag(attrptr
)), ippTagString(ippGetGroupTag(attrptr
)));
1174 if ((attrptr
= ippFindAttribute(response
, "status-message", IPP_TAG_ZERO
)) != NULL
)
1176 const char *status_message
= ippGetString(attrptr
, 0, NULL
);
1179 if (ippGetValueTag(attrptr
) != IPP_TAG_TEXT
)
1180 add_stringf(data
->errors
, "status-message (text(255)) has wrong value tag %s (RFC 2911 section 3.1.6.2).", ippTagString(ippGetValueTag(attrptr
)));
1181 if (ippGetGroupTag(attrptr
) != IPP_TAG_OPERATION
)
1182 add_stringf(data
->errors
, "status-message (text(255)) has wrong group tag %s (RFC 2911 section 3.1.6.2).", ippTagString(ippGetGroupTag(attrptr
)));
1183 if (ippGetCount(attrptr
) != 1)
1184 add_stringf(data
->errors
, "status-message (text(255)) has %d values (RFC 2911 section 3.1.6.2).", ippGetCount(attrptr
));
1185 if (status_message
&& strlen(status_message
) > 255)
1186 add_stringf(data
->errors
, "status-message (text(255)) has bad length %d (RFC 2911 section 3.1.6.2).", (int)strlen(status_message
));
1189 if ((attrptr
= ippFindAttribute(response
, "detailed-status-message",
1190 IPP_TAG_ZERO
)) != NULL
)
1192 const char *detailed_status_message
= ippGetString(attrptr
, 0, NULL
);
1195 if (ippGetValueTag(attrptr
) != IPP_TAG_TEXT
)
1196 add_stringf(data
->errors
,
1197 "detailed-status-message (text(MAX)) has wrong "
1198 "value tag %s (RFC 2911 section 3.1.6.3).",
1199 ippTagString(ippGetValueTag(attrptr
)));
1200 if (ippGetGroupTag(attrptr
) != IPP_TAG_OPERATION
)
1201 add_stringf(data
->errors
,
1202 "detailed-status-message (text(MAX)) has wrong "
1203 "group tag %s (RFC 2911 section 3.1.6.3).",
1204 ippTagString(ippGetGroupTag(attrptr
)));
1205 if (ippGetCount(attrptr
) != 1)
1206 add_stringf(data
->errors
,
1207 "detailed-status-message (text(MAX)) has %d values"
1208 " (RFC 2911 section 3.1.6.3).",
1209 ippGetCount(attrptr
));
1210 if (detailed_status_message
&& strlen(detailed_status_message
) > 1023)
1211 add_stringf(data
->errors
,
1212 "detailed-status-message (text(MAX)) has bad "
1213 "length %d (RFC 2911 section 3.1.6.3).",
1214 (int)strlen(detailed_status_message
));
1217 a
= cupsArrayNew((cups_array_func_t
)strcmp
, NULL
);
1219 for (attrptr
= ippFirstAttribute(response
), group
= ippGetGroupTag(attrptr
);
1221 attrptr
= ippNextAttribute(response
))
1223 if (ippGetGroupTag(attrptr
) != group
)
1225 int out_of_order
= 0; /* Are attribute groups out-of-order? */
1228 switch (ippGetGroupTag(attrptr
))
1233 case IPP_TAG_OPERATION
:
1237 case IPP_TAG_UNSUPPORTED_GROUP
:
1238 if (group
!= IPP_TAG_OPERATION
)
1243 case IPP_TAG_PRINTER
:
1244 if (group
!= IPP_TAG_OPERATION
&& group
!= IPP_TAG_UNSUPPORTED_GROUP
)
1248 case IPP_TAG_SUBSCRIPTION
:
1249 if (group
> ippGetGroupTag(attrptr
) && group
!= IPP_TAG_DOCUMENT
)
1254 if (group
> ippGetGroupTag(attrptr
))
1260 add_stringf(data
->errors
, "Attribute groups out of order (%s < %s)",
1261 ippTagString(ippGetGroupTag(attrptr
)),
1262 ippTagString(group
));
1264 if (ippGetGroupTag(attrptr
) != IPP_TAG_ZERO
)
1265 group
= ippGetGroupTag(attrptr
);
1268 if (!ippValidateAttribute(attrptr
))
1269 cupsArrayAdd(data
->errors
, (void *)cupsLastErrorString());
1271 if (ippGetName(attrptr
))
1273 if (cupsArrayFind(a
, (void *)ippGetName(attrptr
)))
1274 add_stringf(data
->errors
, "Duplicate \"%s\" attribute in %s group",
1275 ippGetName(attrptr
), ippTagString(group
));
1277 cupsArrayAdd(a
, (void *)ippGetName(attrptr
));
1284 * Now check the test-defined expected status-code and attribute
1288 for (i
= 0, status_ok
= 0; i
< data
->num_statuses
; i
++)
1290 if (data
->statuses
[i
].if_defined
&&
1291 !_ippVarsGet(vars
, data
->statuses
[i
].if_defined
))
1294 if (data
->statuses
[i
].if_not_defined
&&
1295 _ippVarsGet(vars
, data
->statuses
[i
].if_not_defined
))
1298 if (ippGetStatusCode(response
) == data
->statuses
[i
].status
)
1302 if (data
->statuses
[i
].repeat_match
&& repeat_count
< data
->statuses
[i
].repeat_limit
)
1305 if (data
->statuses
[i
].define_match
)
1306 _ippVarsSet(vars
, data
->statuses
[i
].define_match
, "1");
1310 if (data
->statuses
[i
].repeat_no_match
&& repeat_count
< data
->statuses
[i
].repeat_limit
)
1313 if (data
->statuses
[i
].define_no_match
)
1315 _ippVarsSet(vars
, data
->statuses
[i
].define_no_match
, "1");
1321 if (!status_ok
&& data
->num_statuses
> 0)
1323 for (i
= 0; i
< data
->num_statuses
; i
++)
1325 if (data
->statuses
[i
].if_defined
&&
1326 !_ippVarsGet(vars
, data
->statuses
[i
].if_defined
))
1329 if (data
->statuses
[i
].if_not_defined
&&
1330 _ippVarsGet(vars
, data
->statuses
[i
].if_not_defined
))
1333 if (!data
->statuses
[i
].repeat_match
|| repeat_count
>= data
->statuses
[i
].repeat_limit
)
1334 add_stringf(data
->errors
, "EXPECTED: STATUS %s (got %s)",
1335 ippErrorString(data
->statuses
[i
].status
),
1336 ippErrorString(cupsLastError()));
1339 if ((attrptr
= ippFindAttribute(response
, "status-message",
1340 IPP_TAG_TEXT
)) != NULL
)
1341 add_stringf(data
->errors
, "status-message=\"%s\"", ippGetString(attrptr
, 0, NULL
));
1344 for (i
= data
->num_expects
, expect
= data
->expects
; i
> 0; i
--, expect
++)
1346 if (expect
->if_defined
&& !_ippVarsGet(vars
, expect
->if_defined
))
1349 if (expect
->if_not_defined
&&
1350 _ippVarsGet(vars
, expect
->if_not_defined
))
1353 found
= ippFindAttribute(response
, expect
->name
, IPP_TAG_ZERO
);
1357 if ((found
&& expect
->not_expect
) ||
1358 (!found
&& !(expect
->not_expect
|| expect
->optional
)) ||
1359 (found
&& !expect_matches(expect
, ippGetValueTag(found
))) ||
1360 (found
&& expect
->in_group
&&
1361 ippGetGroupTag(found
) != expect
->in_group
))
1363 if (expect
->define_no_match
)
1364 _ippVarsSet(vars
, expect
->define_no_match
, "1");
1365 else if (!expect
->define_match
&& !expect
->define_value
)
1367 if (found
&& expect
->not_expect
)
1368 add_stringf(data
->errors
, "NOT EXPECTED: %s", expect
->name
);
1369 else if (!found
&& !(expect
->not_expect
|| expect
->optional
))
1370 add_stringf(data
->errors
, "EXPECTED: %s", expect
->name
);
1373 if (!expect_matches(expect
, ippGetValueTag(found
)))
1374 add_stringf(data
->errors
, "EXPECTED: %s OF-TYPE %s (got %s)",
1375 expect
->name
, expect
->of_type
,
1376 ippTagString(ippGetValueTag(found
)));
1378 if (expect
->in_group
&& ippGetGroupTag(found
) != expect
->in_group
)
1379 add_stringf(data
->errors
, "EXPECTED: %s IN-GROUP %s (got %s).",
1380 expect
->name
, ippTagString(expect
->in_group
),
1381 ippTagString(ippGetGroupTag(found
)));
1385 if (expect
->repeat_no_match
&& repeat_count
< expect
->repeat_limit
)
1391 ippAttributeString(found
, buffer
, sizeof(buffer
));
1393 if (found
&& expect
->with_value_from
&& !with_value_from(NULL
, ippFindAttribute(response
, expect
->with_value_from
, IPP_TAG_ZERO
), found
, buffer
, sizeof(buffer
)))
1395 if (expect
->define_no_match
)
1396 _ippVarsSet(vars
, expect
->define_no_match
, "1");
1397 else if (!expect
->define_match
&& !expect
->define_value
&& ((!expect
->repeat_match
&& !expect
->repeat_no_match
) || repeat_count
>= expect
->repeat_limit
))
1399 add_stringf(data
->errors
, "EXPECTED: %s WITH-VALUES-FROM %s", expect
->name
, expect
->with_value_from
);
1401 with_value_from(data
->errors
, ippFindAttribute(response
, expect
->with_value_from
, IPP_TAG_ZERO
), found
, buffer
, sizeof(buffer
));
1404 if (expect
->repeat_no_match
&& repeat_count
< expect
->repeat_limit
)
1409 else if (found
&& !with_value(data
, NULL
, expect
->with_value
, expect
->with_flags
, found
, buffer
, sizeof(buffer
)))
1411 if (expect
->define_no_match
)
1412 _ippVarsSet(vars
, expect
->define_no_match
, "1");
1413 else if (!expect
->define_match
&& !expect
->define_value
&&
1414 !expect
->repeat_match
&& (!expect
->repeat_no_match
|| repeat_count
>= expect
->repeat_limit
))
1416 if (expect
->with_flags
& _CUPS_WITH_REGEX
)
1417 add_stringf(data
->errors
, "EXPECTED: %s %s /%s/", expect
->name
, with_flags_string(expect
->with_flags
), expect
->with_value
);
1419 add_stringf(data
->errors
, "EXPECTED: %s %s \"%s\"", expect
->name
, with_flags_string(expect
->with_flags
), expect
->with_value
);
1421 with_value(data
, data
->errors
, expect
->with_value
, expect
->with_flags
, found
, buffer
, sizeof(buffer
));
1424 if (expect
->repeat_no_match
&&
1425 repeat_count
< expect
->repeat_limit
)
1431 if (found
&& expect
->count
> 0 && ippGetCount(found
) != expect
->count
)
1433 if (expect
->define_no_match
)
1434 _ippVarsSet(vars
, expect
->define_no_match
, "1");
1435 else if (!expect
->define_match
&& !expect
->define_value
)
1437 add_stringf(data
->errors
, "EXPECTED: %s COUNT %d (got %d)", expect
->name
,
1438 expect
->count
, ippGetCount(found
));
1441 if (expect
->repeat_no_match
&&
1442 repeat_count
< expect
->repeat_limit
)
1448 if (found
&& expect
->same_count_as
)
1450 attrptr
= ippFindAttribute(response
, expect
->same_count_as
,
1453 if (!attrptr
|| ippGetCount(attrptr
) != ippGetCount(found
))
1455 if (expect
->define_no_match
)
1456 _ippVarsSet(vars
, expect
->define_no_match
, "1");
1457 else if (!expect
->define_match
&& !expect
->define_value
)
1460 add_stringf(data
->errors
,
1461 "EXPECTED: %s (%d values) SAME-COUNT-AS %s "
1462 "(not returned)", expect
->name
,
1463 ippGetCount(found
), expect
->same_count_as
);
1464 else if (ippGetCount(attrptr
) != ippGetCount(found
))
1465 add_stringf(data
->errors
,
1466 "EXPECTED: %s (%d values) SAME-COUNT-AS %s "
1467 "(%d values)", expect
->name
, ippGetCount(found
),
1468 expect
->same_count_as
, ippGetCount(attrptr
));
1471 if (expect
->repeat_no_match
&&
1472 repeat_count
< expect
->repeat_limit
)
1479 if (found
&& expect
->define_match
)
1480 _ippVarsSet(vars
, expect
->define_match
, "1");
1482 if (found
&& expect
->define_value
)
1484 if (!expect
->with_value
)
1486 int last
= ippGetCount(found
) - 1;
1487 /* Last element in attribute */
1489 switch (ippGetValueTag(found
))
1492 case IPP_TAG_INTEGER
:
1493 snprintf(buffer
, sizeof(buffer
), "%d", ippGetInteger(found
, last
));
1496 case IPP_TAG_BOOLEAN
:
1497 if (ippGetBoolean(found
, last
))
1498 strlcpy(buffer
, "true", sizeof(buffer
));
1500 strlcpy(buffer
, "false", sizeof(buffer
));
1503 case IPP_TAG_RESOLUTION
:
1505 int xres
, /* Horizontal resolution */
1506 yres
; /* Vertical resolution */
1507 ipp_res_t units
; /* Resolution units */
1509 xres
= ippGetResolution(found
, last
, &yres
, &units
);
1512 snprintf(buffer
, sizeof(buffer
), "%d%s", xres
, units
== IPP_RES_PER_INCH
? "dpi" : "dpcm");
1514 snprintf(buffer
, sizeof(buffer
), "%dx%d%s", xres
, yres
, units
== IPP_RES_PER_INCH
? "dpi" : "dpcm");
1518 case IPP_TAG_CHARSET
:
1519 case IPP_TAG_KEYWORD
:
1520 case IPP_TAG_LANGUAGE
:
1521 case IPP_TAG_MIMETYPE
:
1523 case IPP_TAG_NAMELANG
:
1525 case IPP_TAG_TEXTLANG
:
1527 case IPP_TAG_URISCHEME
:
1528 strlcpy(buffer
, ippGetString(found
, last
, NULL
), sizeof(buffer
));
1532 ippAttributeString(found
, buffer
, sizeof(buffer
));
1537 _ippVarsSet(vars
, expect
->define_value
, buffer
);
1540 if (found
&& expect
->repeat_match
&&
1541 repeat_count
< expect
->repeat_limit
)
1544 while (expect
->expect_all
&& (found
= ippFindNextAttribute(response
, expect
->name
, IPP_TAG_ZERO
)) != NULL
);
1549 * If we are going to repeat this test, display intermediate results...
1554 if (data
->output
== _CUPS_OUTPUT_TEST
|| (data
->output
== _CUPS_OUTPUT_PLIST
&& data
->outfile
!= cupsFileStdout()))
1556 cupsFilePrintf(cupsFileStdout(), "%04d]\n", repeat_count
);
1558 if (data
->num_displayed
> 0)
1560 for (attrptr
= ippFirstAttribute(response
); attrptr
; attrptr
= ippNextAttribute(response
))
1562 const char *attrname
= ippGetName(attrptr
);
1565 for (i
= 0; i
< data
->num_displayed
; i
++)
1567 if (!strcmp(data
->displayed
[i
], attrname
))
1569 print_attr(cupsFileStdout(), _CUPS_OUTPUT_TEST
, attrptr
, NULL
);
1578 if (data
->output
== _CUPS_OUTPUT_TEST
|| (data
->output
== _CUPS_OUTPUT_PLIST
&& data
->outfile
!= cupsFileStdout()))
1580 cupsFilePrintf(cupsFileStdout(), " %-68.68s [", data
->name
);
1583 ippDelete(response
);
1587 while (repeat_test
);
1593 if (cupsArrayCount(data
->errors
) > 0)
1594 data
->prev_pass
= data
->pass
= 0;
1596 if (data
->prev_pass
)
1597 data
->pass_count
++;
1599 data
->fail_count
++;
1601 if (data
->output
== _CUPS_OUTPUT_PLIST
)
1603 cupsFilePuts(data
->outfile
, "<key>Successful</key>\n");
1604 cupsFilePuts(data
->outfile
, data
->prev_pass
? "<true />\n" : "<false />\n");
1605 cupsFilePuts(data
->outfile
, "<key>StatusCode</key>\n");
1606 print_xml_string(data
->outfile
, "string", ippErrorString(cupsLastError()));
1607 cupsFilePuts(data
->outfile
, "<key>ResponseAttributes</key>\n");
1608 cupsFilePuts(data
->outfile
, "<array>\n");
1609 cupsFilePuts(data
->outfile
, "<dict>\n");
1610 for (attrptr
= ippFirstAttribute(response
), group
= ippGetGroupTag(attrptr
);
1612 attrptr
= ippNextAttribute(response
))
1613 print_attr(data
->outfile
, data
->output
, attrptr
, &group
);
1614 cupsFilePuts(data
->outfile
, "</dict>\n");
1615 cupsFilePuts(data
->outfile
, "</array>\n");
1617 else if (data
->output
== _CUPS_OUTPUT_IPPSERVER
&& response
)
1619 for (attrptr
= ippFirstAttribute(response
); attrptr
; attrptr
= ippNextAttribute(response
))
1621 if (!ippGetName(attrptr
) || ippGetGroupTag(attrptr
) != IPP_TAG_PRINTER
)
1624 print_ippserver_attr(data
, attrptr
, 0);
1628 if (data
->output
== _CUPS_OUTPUT_TEST
|| (data
->output
== _CUPS_OUTPUT_PLIST
&& data
->outfile
!= cupsFileStdout()))
1630 cupsFilePuts(cupsFileStdout(), data
->prev_pass
? "PASS]\n" : "FAIL]\n");
1632 if (!data
->prev_pass
|| (data
->verbosity
&& response
))
1634 cupsFilePrintf(cupsFileStdout(), " RECEIVED: %lu bytes in response\n", (unsigned long)ippLength(response
));
1635 cupsFilePrintf(cupsFileStdout(), " status-code = %s (%s)\n", ippErrorString(cupsLastError()), cupsLastErrorString());
1637 if (data
->verbosity
&& response
)
1639 for (attrptr
= ippFirstAttribute(response
); attrptr
; attrptr
= ippNextAttribute(response
))
1640 print_attr(cupsFileStdout(), _CUPS_OUTPUT_TEST
, attrptr
, NULL
);
1644 else if (!data
->prev_pass
&& data
->output
!= _CUPS_OUTPUT_QUIET
)
1645 fprintf(stderr
, "%s\n", cupsLastErrorString());
1647 if (data
->prev_pass
&& data
->output
>= _CUPS_OUTPUT_LIST
&& !data
->verbosity
&& data
->num_displayed
> 0)
1649 size_t width
; /* Length of value */
1651 for (i
= 0; i
< data
->num_displayed
; i
++)
1653 widths
[i
] = strlen(data
->displayed
[i
]);
1655 for (attrptr
= ippFindAttribute(response
, data
->displayed
[i
], IPP_TAG_ZERO
);
1657 attrptr
= ippFindNextAttribute(response
, data
->displayed
[i
], IPP_TAG_ZERO
))
1659 width
= ippAttributeString(attrptr
, NULL
, 0);
1660 if (width
> widths
[i
])
1665 if (data
->output
== _CUPS_OUTPUT_CSV
)
1666 print_csv(data
, NULL
, NULL
, data
->num_displayed
, data
->displayed
, widths
);
1668 print_line(data
, NULL
, NULL
, data
->num_displayed
, data
->displayed
, widths
);
1670 attrptr
= ippFirstAttribute(response
);
1674 while (attrptr
&& ippGetGroupTag(attrptr
) <= IPP_TAG_OPERATION
)
1675 attrptr
= ippNextAttribute(response
);
1679 if (data
->output
== _CUPS_OUTPUT_CSV
)
1680 print_csv(data
, response
, attrptr
, data
->num_displayed
, data
->displayed
, widths
);
1682 print_line(data
, response
, attrptr
, data
->num_displayed
, data
->displayed
, widths
);
1684 while (attrptr
&& ippGetGroupTag(attrptr
) > IPP_TAG_OPERATION
)
1685 attrptr
= ippNextAttribute(response
);
1689 else if (!data
->prev_pass
)
1691 if (data
->output
== _CUPS_OUTPUT_PLIST
)
1693 cupsFilePuts(data
->outfile
, "<key>Errors</key>\n");
1694 cupsFilePuts(data
->outfile
, "<array>\n");
1696 for (error
= (char *)cupsArrayFirst(data
->errors
);
1698 error
= (char *)cupsArrayNext(data
->errors
))
1699 print_xml_string(data
->outfile
, "string", error
);
1701 cupsFilePuts(data
->outfile
, "</array>\n");
1704 if (data
->output
== _CUPS_OUTPUT_TEST
|| (data
->output
== _CUPS_OUTPUT_PLIST
&& data
->outfile
!= cupsFileStdout()))
1706 for (error
= (char *)cupsArrayFirst(data
->errors
);
1708 error
= (char *)cupsArrayNext(data
->errors
))
1709 cupsFilePrintf(cupsFileStdout(), " %s\n", error
);
1713 if (data
->num_displayed
> 0 && !data
->verbosity
&& response
&& (data
->output
== _CUPS_OUTPUT_TEST
|| (data
->output
== _CUPS_OUTPUT_PLIST
&& data
->outfile
!= cupsFileStdout())))
1715 for (attrptr
= ippFirstAttribute(response
); attrptr
; attrptr
= ippNextAttribute(response
))
1717 if (ippGetName(attrptr
))
1719 for (i
= 0; i
< data
->num_displayed
; i
++)
1721 if (!strcmp(data
->displayed
[i
], ippGetName(attrptr
)))
1723 print_attr(data
->outfile
, data
->output
, attrptr
, NULL
);
1733 if (data
->output
== _CUPS_OUTPUT_PLIST
)
1734 cupsFilePuts(data
->outfile
, "</dict>\n");
1736 ippDelete(response
);
1739 for (i
= 0; i
< data
->num_statuses
; i
++)
1741 if (data
->statuses
[i
].if_defined
)
1742 free(data
->statuses
[i
].if_defined
);
1743 if (data
->statuses
[i
].if_not_defined
)
1744 free(data
->statuses
[i
].if_not_defined
);
1745 if (data
->statuses
[i
].define_match
)
1746 free(data
->statuses
[i
].define_match
);
1747 if (data
->statuses
[i
].define_no_match
)
1748 free(data
->statuses
[i
].define_no_match
);
1750 data
->num_statuses
= 0;
1752 for (i
= data
->num_expects
, expect
= data
->expects
; i
> 0; i
--, expect
++)
1755 if (expect
->of_type
)
1756 free(expect
->of_type
);
1757 if (expect
->same_count_as
)
1758 free(expect
->same_count_as
);
1759 if (expect
->if_defined
)
1760 free(expect
->if_defined
);
1761 if (expect
->if_not_defined
)
1762 free(expect
->if_not_defined
);
1763 if (expect
->with_value
)
1764 free(expect
->with_value
);
1765 if (expect
->define_match
)
1766 free(expect
->define_match
);
1767 if (expect
->define_no_match
)
1768 free(expect
->define_no_match
);
1769 if (expect
->define_value
)
1770 free(expect
->define_value
);
1772 data
->num_expects
= 0;
1774 for (i
= 0; i
< data
->num_displayed
; i
++)
1775 free(data
->displayed
[i
]);
1776 data
->num_displayed
= 0;
1778 return (data
->ignore_errors
|| data
->prev_pass
);
1783 * 'do_tests()' - Do tests as specified in the test file.
1786 static int /* O - 1 on success, 0 on failure */
1787 do_tests(const char *testfile
, /* I - Test file to use */
1788 _ipp_vars_t
*vars
, /* I - Variables */
1789 _cups_testdata_t
*data
) /* I - Test data */
1791 http_encryption_t encryption
; /* Encryption mode */
1795 * Connect to the printer/server...
1798 if (!_cups_strcasecmp(vars
->scheme
, "https") || !_cups_strcasecmp(vars
->scheme
, "ipps"))
1799 encryption
= HTTP_ENCRYPTION_ALWAYS
;
1801 encryption
= data
->encryption
;
1803 if ((data
->http
= httpConnect2(vars
->host
, vars
->port
, NULL
, data
->family
, encryption
, 1, 30000, NULL
)) == NULL
)
1805 print_fatal_error(data
, "Unable to connect to \"%s\" on port %d - %s", vars
->host
, vars
->port
, cupsLastErrorString());
1810 httpSetDefaultField(data
->http
, HTTP_FIELD_ACCEPT_ENCODING
, "deflate, gzip, identity");
1812 httpSetDefaultField(data
->http
, HTTP_FIELD_ACCEPT_ENCODING
, "identity");
1813 #endif /* HAVE_LIBZ */
1815 if (data
->timeout
> 0.0)
1816 httpSetTimeout(data
->http
, data
->timeout
, timeout_cb
, NULL
);
1822 _ippFileParse(vars
, testfile
, (_ipp_ftoken_cb_t
)token_cb
, (_ipp_ferror_cb_t
)error_cb
, (void *)data
);
1825 * Close connection and return...
1828 httpClose(data
->http
);
1831 return (data
->pass
);
1836 * 'error_cb()' - Print/add an error message.
1839 static int /* O - 1 to continue, 0 to stop */
1840 error_cb(_ipp_file_t
*f
, /* I - IPP file data */
1841 _cups_testdata_t
*data
, /* I - Test data */
1842 const char *error
) /* I - Error message */
1846 print_fatal_error(data
, "%s", error
);
1853 * 'expect_matches()' - Return true if the tag matches the specification.
1856 static int /* O - 1 if matches, 0 otherwise */
1858 _cups_expect_t
*expect
, /* I - Expected attribute */
1859 ipp_tag_t value_tag
) /* I - Value tag for attribute */
1861 int match
; /* Match? */
1862 char *of_type
, /* Type name to match */
1863 *next
, /* Next name to match */
1864 sep
; /* Separator character */
1868 * If we don't expect a particular type, return immediately...
1871 if (!expect
->of_type
)
1875 * Parse the "of_type" value since the string can contain multiple attribute
1876 * types separated by "," or "|"...
1879 for (of_type
= expect
->of_type
, match
= 0; !match
&& *of_type
; of_type
= next
)
1882 * Find the next separator, and set it (temporarily) to nul if present.
1885 for (next
= of_type
; *next
&& *next
!= '|' && *next
!= ','; next
++);
1887 if ((sep
= *next
) != '\0')
1891 * Support some meta-types to make it easier to write the test file.
1894 if (!strcmp(of_type
, "text"))
1895 match
= value_tag
== IPP_TAG_TEXTLANG
|| value_tag
== IPP_TAG_TEXT
;
1896 else if (!strcmp(of_type
, "name"))
1897 match
= value_tag
== IPP_TAG_NAMELANG
|| value_tag
== IPP_TAG_NAME
;
1898 else if (!strcmp(of_type
, "collection"))
1899 match
= value_tag
== IPP_TAG_BEGIN_COLLECTION
;
1901 match
= value_tag
== ippTagValue(of_type
);
1904 * Restore the separator if we have one...
1916 * 'get_filename()' - Get a filename based on the current test file.
1919 static char * /* O - Filename */
1920 get_filename(const char *testfile
, /* I - Current test file */
1921 char *dst
, /* I - Destination filename */
1922 const char *src
, /* I - Source filename */
1923 size_t dstsize
) /* I - Size of destination buffer */
1925 char *dstptr
; /* Pointer into destination */
1926 _cups_globals_t
*cg
= _cupsGlobals();
1930 if (*src
== '<' && src
[strlen(src
) - 1] == '>')
1933 * Map <filename> to CUPS_DATADIR/ipptool/filename...
1936 snprintf(dst
, dstsize
, "%s/ipptool/%s", cg
->cups_datadir
, src
+ 1);
1937 dstptr
= dst
+ strlen(dst
) - 1;
1941 else if (!access(src
, R_OK
) || *src
== '/'
1943 || (isalpha(*src
& 255) && src
[1] == ':')
1948 * Use the path as-is...
1951 strlcpy(dst
, src
, dstsize
);
1956 * Make path relative to testfile...
1959 strlcpy(dst
, testfile
, dstsize
);
1960 if ((dstptr
= strrchr(dst
, '/')) != NULL
)
1963 dstptr
= dst
; /* Should never happen */
1965 strlcpy(dstptr
, src
, dstsize
- (size_t)(dstptr
- dst
));
1973 * 'get_string()' - Get a pointer to a string value or the portion of interest.
1976 static const char * /* O - Pointer to string */
1977 get_string(ipp_attribute_t
*attr
, /* I - IPP attribute */
1978 int element
, /* I - Element to fetch */
1979 int flags
, /* I - Value ("with") flags */
1980 char *buffer
, /* I - Temporary buffer */
1981 size_t bufsize
) /* I - Size of temporary buffer */
1983 const char *value
; /* Value */
1984 char *ptr
, /* Pointer into value */
1985 scheme
[256], /* URI scheme */
1986 userpass
[256], /* Username/password */
1987 hostname
[256], /* Hostname */
1988 resource
[1024]; /* Resource */
1989 int port
; /* Port number */
1992 value
= ippGetString(attr
, element
, NULL
);
1994 if (flags
& _CUPS_WITH_HOSTNAME
)
1996 if (httpSeparateURI(HTTP_URI_CODING_ALL
, value
, scheme
, sizeof(scheme
), userpass
, sizeof(userpass
), buffer
, (int)bufsize
, &port
, resource
, sizeof(resource
)) < HTTP_URI_STATUS_OK
)
1999 ptr
= buffer
+ strlen(buffer
) - 1;
2000 if (ptr
>= buffer
&& *ptr
== '.')
2001 *ptr
= '\0'; /* Drop trailing "." */
2005 else if (flags
& _CUPS_WITH_RESOURCE
)
2007 if (httpSeparateURI(HTTP_URI_CODING_ALL
, value
, scheme
, sizeof(scheme
), userpass
, sizeof(userpass
), hostname
, sizeof(hostname
), &port
, buffer
, (int)bufsize
) < HTTP_URI_STATUS_OK
)
2012 else if (flags
& _CUPS_WITH_SCHEME
)
2014 if (httpSeparateURI(HTTP_URI_CODING_ALL
, value
, buffer
, (int)bufsize
, userpass
, sizeof(userpass
), hostname
, sizeof(hostname
), &port
, resource
, sizeof(resource
)) < HTTP_URI_STATUS_OK
)
2019 else if (ippGetValueTag(attr
) == IPP_TAG_URI
&& (!strncmp(value
, "ipp://", 6) || !strncmp(value
, "http://", 7) || !strncmp(value
, "ipps://", 7) || !strncmp(value
, "https://", 8)))
2021 http_uri_status_t status
= httpSeparateURI(HTTP_URI_CODING_ALL
, value
, scheme
, sizeof(scheme
), userpass
, sizeof(userpass
), hostname
, sizeof(hostname
), &port
, resource
, sizeof(resource
));
2023 if (status
< HTTP_URI_STATUS_OK
)
2034 * Normalize URI with no trailing dot...
2037 if ((ptr
= hostname
+ strlen(hostname
) - 1) >= hostname
&& *ptr
== '.')
2040 httpAssembleURI(HTTP_URI_CODING_ALL
, buffer
, (int)bufsize
, scheme
, userpass
, hostname
, port
, resource
);
2051 * 'init_data()' - Initialize test data.
2055 init_data(_cups_testdata_t
*data
) /* I - Data */
2057 memset(data
, 0, sizeof(_cups_testdata_t
));
2059 data
->output
= _CUPS_OUTPUT_LIST
;
2060 data
->outfile
= cupsFileStdout();
2061 data
->family
= AF_UNSPEC
;
2062 data
->def_transfer
= _CUPS_TRANSFER_AUTO
;
2063 data
->def_version
= 11;
2064 data
->errors
= cupsArrayNew3(NULL
, NULL
, NULL
, 0, (cups_acopy_func_t
)strdup
, (cups_afree_func_t
)free
);
2066 data
->prev_pass
= 1;
2067 data
->request_id
= (CUPS_RAND() % 1000) * 137 + 1;
2068 data
->show_header
= 1;
2073 * 'iso_date()' - Return an ISO 8601 date/time string for the given IPP dateTime
2077 static char * /* O - ISO 8601 date/time string */
2078 iso_date(const ipp_uchar_t
*date
) /* I - IPP (RFC 1903) date/time value */
2080 time_t utctime
; /* UTC time since 1970 */
2081 struct tm
*utcdate
; /* UTC date/time */
2082 static char buffer
[255]; /* String buffer */
2085 utctime
= ippDateToTime(date
);
2086 utcdate
= gmtime(&utctime
);
2088 snprintf(buffer
, sizeof(buffer
), "%04d-%02d-%02dT%02d:%02d:%02dZ",
2089 utcdate
->tm_year
+ 1900, utcdate
->tm_mon
+ 1, utcdate
->tm_mday
,
2090 utcdate
->tm_hour
, utcdate
->tm_min
, utcdate
->tm_sec
);
2097 * 'pause_message()' - Display the message and pause until the user presses a key.
2101 pause_message(const char *message
) /* I - Message */
2104 HANDLE tty
; /* Console handle */
2105 DWORD mode
; /* Console mode */
2106 char key
; /* Key press */
2107 DWORD bytes
; /* Bytes read for key press */
2111 * Disable input echo and set raw input...
2114 if ((tty
= GetStdHandle(STD_INPUT_HANDLE
)) == INVALID_HANDLE_VALUE
)
2117 if (!GetConsoleMode(tty
, &mode
))
2120 if (!SetConsoleMode(tty
, 0))
2124 int tty
; /* /dev/tty - never read from stdin */
2125 struct termios original
, /* Original input mode */
2126 noecho
; /* No echo input mode */
2127 char key
; /* Current key press */
2131 * Disable input echo and set raw input...
2134 if ((tty
= open("/dev/tty", O_RDONLY
)) < 0)
2137 if (tcgetattr(tty
, &original
))
2144 noecho
.c_lflag
&= (tcflag_t
)~(ICANON
| ECHO
| ECHOE
| ISIG
);
2146 if (tcsetattr(tty
, TCSAFLUSH
, &noecho
))
2154 * Display the prompt...
2157 cupsFilePrintf(cupsFileStdout(), "%s\n---- PRESS ANY KEY ----", message
);
2164 ReadFile(tty
, &key
, 1, &bytes
, NULL
);
2170 SetConsoleMode(tty
, mode
);
2183 tcsetattr(tty
, TCSAFLUSH
, &original
);
2188 * Erase the "press any key" prompt...
2191 cupsFilePuts(cupsFileStdout(), "\r \r");
2196 * 'print_attr()' - Print an attribute on the screen.
2200 print_attr(cups_file_t
*outfile
, /* I - Output file */
2201 int output
, /* I - Output format */
2202 ipp_attribute_t
*attr
, /* I - Attribute to print */
2203 ipp_tag_t
*group
) /* IO - Current group */
2205 int i
, /* Looping var */
2206 count
; /* Number of values */
2207 ipp_attribute_t
*colattr
; /* Collection attribute */
2210 if (output
== _CUPS_OUTPUT_PLIST
)
2212 if (!ippGetName(attr
) || (group
&& *group
!= ippGetGroupTag(attr
)))
2214 if (ippGetGroupTag(attr
) != IPP_TAG_ZERO
)
2216 cupsFilePuts(outfile
, "</dict>\n");
2217 cupsFilePuts(outfile
, "<dict>\n");
2221 *group
= ippGetGroupTag(attr
);
2224 if (!ippGetName(attr
))
2227 print_xml_string(outfile
, "key", ippGetName(attr
));
2228 if ((count
= ippGetCount(attr
)) > 1)
2229 cupsFilePuts(outfile
, "<array>\n");
2231 switch (ippGetValueTag(attr
))
2233 case IPP_TAG_INTEGER
:
2235 for (i
= 0; i
< count
; i
++)
2236 cupsFilePrintf(outfile
, "<integer>%d</integer>\n", ippGetInteger(attr
, i
));
2239 case IPP_TAG_BOOLEAN
:
2240 for (i
= 0; i
< count
; i
++)
2241 cupsFilePuts(outfile
, ippGetBoolean(attr
, i
) ? "<true />\n" : "<false />\n");
2244 case IPP_TAG_RANGE
:
2245 for (i
= 0; i
< count
; i
++)
2247 int lower
, upper
; /* Lower and upper ranges */
2249 lower
= ippGetRange(attr
, i
, &upper
);
2250 cupsFilePrintf(outfile
, "<dict><key>lower</key><integer>%d</integer><key>upper</key><integer>%d</integer></dict>\n", lower
, upper
);
2254 case IPP_TAG_RESOLUTION
:
2255 for (i
= 0; i
< count
; i
++)
2257 int xres
, yres
; /* Resolution values */
2258 ipp_res_t units
; /* Resolution units */
2260 xres
= ippGetResolution(attr
, i
, &yres
, &units
);
2261 cupsFilePrintf(outfile
, "<dict><key>xres</key><integer>%d</integer><key>yres</key><integer>%d</integer><key>units</key><string>%s</string></dict>\n", xres
, yres
, units
== IPP_RES_PER_INCH
? "dpi" : "dpcm");
2266 for (i
= 0; i
< count
; i
++)
2267 cupsFilePrintf(outfile
, "<date>%s</date>\n", iso_date(ippGetDate(attr
, i
)));
2270 case IPP_TAG_STRING
:
2271 for (i
= 0; i
< count
; i
++)
2273 int datalen
; /* Length of data */
2274 void *data
= ippGetOctetString(attr
, i
, &datalen
);
2276 char buffer
[IPP_MAX_LENGTH
* 5 / 4 + 1];
2277 /* Base64 output buffer */
2279 cupsFilePrintf(outfile
, "<data>%s</data>\n", httpEncode64_2(buffer
, sizeof(buffer
), data
, datalen
));
2285 case IPP_TAG_KEYWORD
:
2287 case IPP_TAG_URISCHEME
:
2288 case IPP_TAG_CHARSET
:
2289 case IPP_TAG_LANGUAGE
:
2290 case IPP_TAG_MIMETYPE
:
2291 for (i
= 0; i
< count
; i
++)
2292 print_xml_string(outfile
, "string", ippGetString(attr
, i
, NULL
));
2295 case IPP_TAG_TEXTLANG
:
2296 case IPP_TAG_NAMELANG
:
2297 for (i
= 0; i
< count
; i
++)
2299 const char *s
, /* String */
2300 *lang
; /* Language */
2302 s
= ippGetString(attr
, i
, &lang
);
2303 cupsFilePuts(outfile
, "<dict><key>language</key><string>");
2304 print_xml_string(outfile
, NULL
, lang
);
2305 cupsFilePuts(outfile
, "</string><key>string</key><string>");
2306 print_xml_string(outfile
, NULL
, s
);
2307 cupsFilePuts(outfile
, "</string></dict>\n");
2311 case IPP_TAG_BEGIN_COLLECTION
:
2312 for (i
= 0; i
< count
; i
++)
2314 ipp_t
*col
= ippGetCollection(attr
, i
);
2315 /* Collection value */
2317 cupsFilePuts(outfile
, "<dict>\n");
2318 for (colattr
= ippFirstAttribute(col
); colattr
; colattr
= ippNextAttribute(col
))
2319 print_attr(outfile
, output
, colattr
, NULL
);
2320 cupsFilePuts(outfile
, "</dict>\n");
2325 cupsFilePrintf(outfile
, "<string><<%s>></string>\n", ippTagString(ippGetValueTag(attr
)));
2330 cupsFilePuts(outfile
, "</array>\n");
2334 char buffer
[131072]; /* Value buffer */
2336 if (output
== _CUPS_OUTPUT_TEST
)
2338 if (!ippGetName(attr
))
2340 cupsFilePuts(outfile
, " -- separator --\n");
2344 cupsFilePrintf(outfile
, " %s (%s%s) = ", ippGetName(attr
), ippGetCount(attr
) > 1 ? "1setOf " : "", ippTagString(ippGetValueTag(attr
)));
2347 ippAttributeString(attr
, buffer
, sizeof(buffer
));
2348 cupsFilePrintf(outfile
, "%s\n", buffer
);
2354 * 'print_csv()' - Print a line of CSV text.
2359 _cups_testdata_t
*data
, /* I - Test data */
2360 ipp_t
*ipp
, /* I - Response message */
2361 ipp_attribute_t
*attr
, /* I - First attribute for line */
2362 int num_displayed
, /* I - Number of attributes to display */
2363 char **displayed
, /* I - Attributes to display */
2364 size_t *widths
) /* I - Column widths */
2366 int i
; /* Looping var */
2367 size_t maxlength
; /* Max length of all columns */
2368 char *buffer
, /* String buffer */
2369 *bufptr
; /* Pointer into buffer */
2370 ipp_attribute_t
*current
; /* Current attribute */
2374 * Get the maximum string length we have to show and allocate...
2377 for (i
= 1, maxlength
= widths
[0]; i
< num_displayed
; i
++)
2378 if (widths
[i
] > maxlength
)
2379 maxlength
= widths
[i
];
2383 if ((buffer
= malloc(maxlength
)) == NULL
)
2387 * Loop through the attributes to display...
2392 for (i
= 0; i
< num_displayed
; i
++)
2395 cupsFilePutChar(data
->outfile
, ',');
2399 for (current
= attr
; current
; current
= ippNextAttribute(ipp
))
2401 if (!ippGetName(current
))
2403 else if (!strcmp(ippGetName(current
), displayed
[i
]))
2405 ippAttributeString(current
, buffer
, maxlength
);
2410 if (strchr(buffer
, ',') != NULL
|| strchr(buffer
, '\"') != NULL
||
2411 strchr(buffer
, '\\') != NULL
)
2413 cupsFilePutChar(cupsFileStdout(), '\"');
2414 for (bufptr
= buffer
; *bufptr
; bufptr
++)
2416 if (*bufptr
== '\\' || *bufptr
== '\"')
2417 cupsFilePutChar(cupsFileStdout(), '\\');
2418 cupsFilePutChar(cupsFileStdout(), *bufptr
);
2420 cupsFilePutChar(cupsFileStdout(), '\"');
2423 cupsFilePuts(data
->outfile
, buffer
);
2425 cupsFilePutChar(cupsFileStdout(), '\n');
2429 for (i
= 0; i
< num_displayed
; i
++)
2432 cupsFilePutChar(cupsFileStdout(), ',');
2434 cupsFilePuts(data
->outfile
, displayed
[i
]);
2436 cupsFilePutChar(cupsFileStdout(), '\n');
2444 * 'print_fatal_error()' - Print a fatal error message.
2449 _cups_testdata_t
*data
, /* I - Test data */
2450 const char *s
, /* I - Printf-style format string */
2451 ...) /* I - Additional arguments as needed */
2453 char buffer
[10240]; /* Format buffer */
2454 va_list ap
; /* Pointer to arguments */
2458 * Format the error message...
2462 vsnprintf(buffer
, sizeof(buffer
), s
, ap
);
2469 if (data
->output
== _CUPS_OUTPUT_PLIST
)
2471 print_xml_header(data
);
2472 print_xml_trailer(data
, 0, buffer
);
2475 _cupsLangPrintf(stderr
, "ipptool: %s", buffer
);
2480 * 'print_ippserver_attr()' - Print a attribute suitable for use by ippserver.
2484 print_ippserver_attr(
2485 _cups_testdata_t
*data
, /* I - Test data */
2486 ipp_attribute_t
*attr
, /* I - Attribute to print */
2487 int indent
) /* I - Indentation level */
2489 int i
, /* Looping var */
2490 count
= ippGetCount(attr
);
2491 /* Number of values */
2492 ipp_attribute_t
*colattr
; /* Collection attribute */
2496 cupsFilePrintf(data
->outfile
, "ATTR %s %s", ippTagString(ippGetValueTag(attr
)), ippGetName(attr
));
2498 cupsFilePrintf(data
->outfile
, "%*sMEMBER %s %s", indent
, "", ippTagString(ippGetValueTag(attr
)), ippGetName(attr
));
2500 switch (ippGetValueTag(attr
))
2502 case IPP_TAG_INTEGER
:
2504 for (i
= 0; i
< count
; i
++)
2505 cupsFilePrintf(data
->outfile
, "%s%d", i
? "," : " ", ippGetInteger(attr
, i
));
2508 case IPP_TAG_BOOLEAN
:
2509 cupsFilePuts(data
->outfile
, ippGetBoolean(attr
, 0) ? " true" : " false");
2511 for (i
= 1; i
< count
; i
++)
2512 cupsFilePuts(data
->outfile
, ippGetBoolean(attr
, 1) ? ",true" : ",false");
2515 case IPP_TAG_RANGE
:
2516 for (i
= 0; i
< count
; i
++)
2518 int upper
, lower
= ippGetRange(attr
, i
, &upper
);
2520 cupsFilePrintf(data
->outfile
, "%s%d-%d", i
? "," : " ", lower
, upper
);
2524 case IPP_TAG_RESOLUTION
:
2525 for (i
= 0; i
< count
; i
++)
2528 int yres
, xres
= ippGetResolution(attr
, i
, &yres
, &units
);
2530 cupsFilePrintf(data
->outfile
, "%s%dx%d%s", i
? "," : " ", xres
, yres
, units
== IPP_RES_PER_INCH
? "dpi" : "dpcm");
2535 for (i
= 0; i
< count
; i
++)
2536 cupsFilePrintf(data
->outfile
, "%s%s", i
? "," : " ", iso_date(ippGetDate(attr
, i
)));
2539 case IPP_TAG_STRING
:
2540 for (i
= 0; i
< count
; i
++)
2543 const char *s
= (const char *)ippGetOctetString(attr
, i
, &len
);
2545 cupsFilePuts(data
->outfile
, i
? "," : " ");
2546 print_ippserver_string(data
, s
, (size_t)len
);
2551 case IPP_TAG_TEXTLANG
:
2553 case IPP_TAG_NAMELANG
:
2554 case IPP_TAG_KEYWORD
:
2556 case IPP_TAG_URISCHEME
:
2557 case IPP_TAG_CHARSET
:
2558 case IPP_TAG_LANGUAGE
:
2559 case IPP_TAG_MIMETYPE
:
2560 for (i
= 0; i
< count
; i
++)
2562 const char *s
= ippGetString(attr
, i
, NULL
);
2564 cupsFilePuts(data
->outfile
, i
? "," : " ");
2565 print_ippserver_string(data
, s
, strlen(s
));
2569 case IPP_TAG_BEGIN_COLLECTION
:
2570 for (i
= 0; i
< count
; i
++)
2572 ipp_t
*col
= ippGetCollection(attr
, i
);
2574 cupsFilePuts(data
->outfile
, i
? ",{\n" : " {\n");
2575 for (colattr
= ippFirstAttribute(col
); colattr
; colattr
= ippNextAttribute(col
))
2576 print_ippserver_attr(data
, colattr
, indent
+ 4);
2577 cupsFilePrintf(data
->outfile
, "%*s}", indent
, "");
2582 cupsFilePuts(data
->outfile
, " \"\"");
2586 cupsFilePuts(data
->outfile
, "\n");
2591 * 'print_ippserver_string()' - Print a string suitable for use by ippserver.
2595 print_ippserver_string(
2596 _cups_testdata_t
*data
, /* I - Test data */
2597 const char *s
, /* I - String to print */
2598 size_t len
) /* I - Length of string */
2600 cupsFilePutChar(data
->outfile
, '\"');
2604 cupsFilePutChar(data
->outfile
, '\\');
2605 cupsFilePutChar(data
->outfile
, *s
);
2610 cupsFilePutChar(data
->outfile
, '\"');
2615 * 'print_line()' - Print a line of formatted or CSV text.
2620 _cups_testdata_t
*data
, /* I - Test data */
2621 ipp_t
*ipp
, /* I - Response message */
2622 ipp_attribute_t
*attr
, /* I - First attribute for line */
2623 int num_displayed
, /* I - Number of attributes to display */
2624 char **displayed
, /* I - Attributes to display */
2625 size_t *widths
) /* I - Column widths */
2627 int i
; /* Looping var */
2628 size_t maxlength
; /* Max length of all columns */
2629 char *buffer
; /* String buffer */
2630 ipp_attribute_t
*current
; /* Current attribute */
2634 * Get the maximum string length we have to show and allocate...
2637 for (i
= 1, maxlength
= widths
[0]; i
< num_displayed
; i
++)
2638 if (widths
[i
] > maxlength
)
2639 maxlength
= widths
[i
];
2643 if ((buffer
= malloc(maxlength
)) == NULL
)
2647 * Loop through the attributes to display...
2652 for (i
= 0; i
< num_displayed
; i
++)
2655 cupsFilePutChar(cupsFileStdout(), ' ');
2659 for (current
= attr
; current
; current
= ippNextAttribute(ipp
))
2661 if (!ippGetName(current
))
2663 else if (!strcmp(ippGetName(current
), displayed
[i
]))
2665 ippAttributeString(current
, buffer
, maxlength
);
2670 cupsFilePrintf(data
->outfile
, "%*s", (int)-widths
[i
], buffer
);
2672 cupsFilePutChar(cupsFileStdout(), '\n');
2676 for (i
= 0; i
< num_displayed
; i
++)
2679 cupsFilePutChar(cupsFileStdout(), ' ');
2681 cupsFilePrintf(data
->outfile
, "%*s", (int)-widths
[i
], displayed
[i
]);
2683 cupsFilePutChar(cupsFileStdout(), '\n');
2685 for (i
= 0; i
< num_displayed
; i
++)
2688 cupsFilePutChar(cupsFileStdout(), ' ');
2690 memset(buffer
, '-', widths
[i
]);
2691 buffer
[widths
[i
]] = '\0';
2692 cupsFilePuts(data
->outfile
, buffer
);
2694 cupsFilePutChar(cupsFileStdout(), '\n');
2702 * 'print_xml_header()' - Print a standard XML plist header.
2706 print_xml_header(_cups_testdata_t
*data
)/* I - Test data */
2708 if (!data
->xml_header
)
2710 cupsFilePuts(data
->outfile
, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
2711 cupsFilePuts(data
->outfile
, "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n");
2712 cupsFilePuts(data
->outfile
, "<plist version=\"1.0\">\n");
2713 cupsFilePuts(data
->outfile
, "<dict>\n");
2714 cupsFilePuts(data
->outfile
, "<key>ipptoolVersion</key>\n");
2715 cupsFilePuts(data
->outfile
, "<string>" CUPS_SVERSION
"</string>\n");
2716 cupsFilePuts(data
->outfile
, "<key>Transfer</key>\n");
2717 cupsFilePrintf(data
->outfile
, "<string>%s</string>\n", data
->transfer
== _CUPS_TRANSFER_AUTO
? "auto" : data
->transfer
== _CUPS_TRANSFER_CHUNKED
? "chunked" : "length");
2718 cupsFilePuts(data
->outfile
, "<key>Tests</key>\n");
2719 cupsFilePuts(data
->outfile
, "<array>\n");
2721 data
->xml_header
= 1;
2727 * 'print_xml_string()' - Print an XML string with escaping.
2731 print_xml_string(cups_file_t
*outfile
, /* I - Test data */
2732 const char *element
, /* I - Element name or NULL */
2733 const char *s
) /* I - String to print */
2736 cupsFilePrintf(outfile
, "<%s>", element
);
2741 cupsFilePuts(outfile
, "&");
2743 cupsFilePuts(outfile
, "<");
2745 cupsFilePuts(outfile
, ">");
2746 else if ((*s
& 0xe0) == 0xc0)
2749 * Validate UTF-8 two-byte sequence...
2752 if ((s
[1] & 0xc0) != 0x80)
2754 cupsFilePutChar(outfile
, '?');
2759 cupsFilePutChar(outfile
, *s
++);
2760 cupsFilePutChar(outfile
, *s
);
2763 else if ((*s
& 0xf0) == 0xe0)
2766 * Validate UTF-8 three-byte sequence...
2769 if ((s
[1] & 0xc0) != 0x80 || (s
[2] & 0xc0) != 0x80)
2771 cupsFilePutChar(outfile
, '?');
2776 cupsFilePutChar(outfile
, *s
++);
2777 cupsFilePutChar(outfile
, *s
++);
2778 cupsFilePutChar(outfile
, *s
);
2781 else if ((*s
& 0xf8) == 0xf0)
2784 * Validate UTF-8 four-byte sequence...
2787 if ((s
[1] & 0xc0) != 0x80 || (s
[2] & 0xc0) != 0x80 ||
2788 (s
[3] & 0xc0) != 0x80)
2790 cupsFilePutChar(outfile
, '?');
2795 cupsFilePutChar(outfile
, *s
++);
2796 cupsFilePutChar(outfile
, *s
++);
2797 cupsFilePutChar(outfile
, *s
++);
2798 cupsFilePutChar(outfile
, *s
);
2801 else if ((*s
& 0x80) || (*s
< ' ' && !isspace(*s
& 255)))
2804 * Invalid control character...
2807 cupsFilePutChar(outfile
, '?');
2810 cupsFilePutChar(outfile
, *s
);
2816 cupsFilePrintf(outfile
, "</%s>\n", element
);
2821 * 'print_xml_trailer()' - Print the XML trailer with success/fail value.
2826 _cups_testdata_t
*data
, /* I - Test data */
2827 int success
, /* I - 1 on success, 0 on failure */
2828 const char *message
) /* I - Error message or NULL */
2830 if (data
->xml_header
)
2832 cupsFilePuts(data
->outfile
, "</array>\n");
2833 cupsFilePuts(data
->outfile
, "<key>Successful</key>\n");
2834 cupsFilePuts(data
->outfile
, success
? "<true />\n" : "<false />\n");
2837 cupsFilePuts(data
->outfile
, "<key>ErrorMessage</key>\n");
2838 print_xml_string(data
->outfile
, "string", message
);
2840 cupsFilePuts(data
->outfile
, "</dict>\n");
2841 cupsFilePuts(data
->outfile
, "</plist>\n");
2843 data
->xml_header
= 0;
2850 * 'sigterm_handler()' - Handle SIGINT and SIGTERM.
2854 sigterm_handler(int sig
) /* I - Signal number (unused) */
2860 signal(SIGINT
, SIG_DFL
);
2861 signal(SIGTERM
, SIG_DFL
);
2867 * 'timeout_cb()' - Handle HTTP timeouts.
2870 static int /* O - 1 to continue, 0 to cancel */
2871 timeout_cb(http_t
*http
, /* I - Connection to server */
2872 void *user_data
) /* I - User data (unused) */
2874 int buffered
= 0; /* Bytes buffered but not yet sent */
2880 * If the socket still have data waiting to be sent to the printer (as can
2881 * happen if the printer runs out of paper), continue to wait until the output
2882 * buffer is empty...
2885 #ifdef SO_NWRITE /* macOS and some versions of Linux */
2886 socklen_t len
= sizeof(buffered
); /* Size of return value */
2888 if (getsockopt(httpGetFd(http
), SOL_SOCKET
, SO_NWRITE
, &buffered
, &len
))
2891 #elif defined(SIOCOUTQ) /* Others except Windows */
2892 if (ioctl(httpGetFd(http
), SIOCOUTQ
, &buffered
))
2895 #else /* Windows (not possible) */
2897 #endif /* SO_NWRITE */
2899 return (buffered
> 0);
2904 * 'token_cb()' - Parse test file-specific tokens and run tests.
2907 static int /* O - 1 to continue, 0 to stop */
2908 token_cb(_ipp_file_t
*f
, /* I - IPP file data */
2909 _ipp_vars_t
*vars
, /* I - IPP variables */
2910 _cups_testdata_t
*data
, /* I - Test data */
2911 const char *token
) /* I - Current token */
2913 char name
[1024], /* Name string */
2914 temp
[1024], /* Temporary string */
2915 value
[1024], /* Value string */
2916 *ptr
; /* Pointer into value */
2922 * Initialize state as needed (nothing for now...)
2930 * Parse until we see a close brace...
2933 if (_cups_strcasecmp(token
, "COUNT") &&
2934 _cups_strcasecmp(token
, "DEFINE-MATCH") &&
2935 _cups_strcasecmp(token
, "DEFINE-NO-MATCH") &&
2936 _cups_strcasecmp(token
, "DEFINE-VALUE") &&
2937 _cups_strcasecmp(token
, "IF-DEFINED") &&
2938 _cups_strcasecmp(token
, "IF-NOT-DEFINED") &&
2939 _cups_strcasecmp(token
, "IN-GROUP") &&
2940 _cups_strcasecmp(token
, "OF-TYPE") &&
2941 _cups_strcasecmp(token
, "REPEAT-LIMIT") &&
2942 _cups_strcasecmp(token
, "REPEAT-MATCH") &&
2943 _cups_strcasecmp(token
, "REPEAT-NO-MATCH") &&
2944 _cups_strcasecmp(token
, "SAME-COUNT-AS") &&
2945 _cups_strcasecmp(token
, "WITH-ALL-VALUES") &&
2946 _cups_strcasecmp(token
, "WITH-ALL-HOSTNAMES") &&
2947 _cups_strcasecmp(token
, "WITH-ALL-RESOURCES") &&
2948 _cups_strcasecmp(token
, "WITH-ALL-SCHEMES") &&
2949 _cups_strcasecmp(token
, "WITH-HOSTNAME") &&
2950 _cups_strcasecmp(token
, "WITH-RESOURCE") &&
2951 _cups_strcasecmp(token
, "WITH-SCHEME") &&
2952 _cups_strcasecmp(token
, "WITH-VALUE") &&
2953 _cups_strcasecmp(token
, "WITH-VALUE-FROM"))
2954 data
->last_expect
= NULL
;
2956 if (_cups_strcasecmp(token
, "DEFINE-MATCH") &&
2957 _cups_strcasecmp(token
, "DEFINE-NO-MATCH") &&
2958 _cups_strcasecmp(token
, "IF-DEFINED") &&
2959 _cups_strcasecmp(token
, "IF-NOT-DEFINED") &&
2960 _cups_strcasecmp(token
, "REPEAT-LIMIT") &&
2961 _cups_strcasecmp(token
, "REPEAT-MATCH") &&
2962 _cups_strcasecmp(token
, "REPEAT-NO-MATCH"))
2963 data
->last_status
= NULL
;
2965 if (!strcmp(token
, "}"))
2967 return (do_test(f
, vars
, data
));
2969 else if (!strcmp(token
, "COMPRESSION"))
2973 * COMPRESSION deflate
2977 if (_ippFileReadToken(f
, temp
, sizeof(temp
)))
2979 _ippVarsExpand(vars
, data
->compression
, temp
, sizeof(data
->compression
));
2981 if (strcmp(data
->compression
, "none") && strcmp(data
->compression
, "deflate") &&
2982 strcmp(data
->compression
, "gzip"))
2984 if (strcmp(data
->compression
, "none"))
2985 #endif /* HAVE_LIBZ */
2987 print_fatal_error(data
, "Unsupported COMPRESSION value \"%s\" on line %d of \"%s\".", data
->compression
, f
->linenum
, f
->filename
);
2991 if (!strcmp(data
->compression
, "none"))
2992 data
->compression
[0] = '\0';
2996 print_fatal_error(data
, "Missing COMPRESSION value on line %d of \"%s\".", f
->linenum
, f
->filename
);
3000 else if (!strcmp(token
, "DEFINE"))
3006 if (_ippFileReadToken(f
, name
, sizeof(name
)) && _ippFileReadToken(f
, temp
, sizeof(temp
)))
3008 _ippVarsExpand(vars
, value
, temp
, sizeof(value
));
3009 _ippVarsSet(vars
, name
, value
);
3013 print_fatal_error(data
, "Missing DEFINE name and/or value on line %d of \"%s\".", f
->linenum
, f
->filename
);
3017 else if (!strcmp(token
, "IGNORE-ERRORS"))
3024 if (_ippFileReadToken(f
, temp
, sizeof(temp
)) && (!_cups_strcasecmp(temp
, "yes") || !_cups_strcasecmp(temp
, "no")))
3026 data
->ignore_errors
= !_cups_strcasecmp(temp
, "yes");
3030 print_fatal_error(data
, "Missing IGNORE-ERRORS value on line %d of \"%s\".", f
->linenum
, f
->filename
);
3034 else if (!_cups_strcasecmp(token
, "NAME"))
3040 _ippFileReadToken(f
, temp
, sizeof(temp
));
3041 _ippVarsExpand(vars
, data
->name
, temp
, sizeof(data
->name
));
3043 else if (!_cups_strcasecmp(token
, "PAUSE"))
3046 * Pause with a message...
3049 if (_ippFileReadToken(f
, temp
, sizeof(temp
)))
3051 pause_message(temp
);
3055 print_fatal_error(data
, "Missing PAUSE message on line %d of \"%s\".", f
->linenum
, f
->filename
);
3059 else if (!strcmp(token
, "REQUEST-ID"))
3066 if (_ippFileReadToken(f
, temp
, sizeof(temp
)))
3068 if (isdigit(temp
[0] & 255))
3070 data
->request_id
= atoi(temp
);
3072 else if (!_cups_strcasecmp(temp
, "random"))
3074 data
->request_id
= (CUPS_RAND() % 1000) * 137 + 1;
3078 print_fatal_error(data
, "Bad REQUEST-ID value \"%s\" on line %d of \"%s\".", temp
, f
->linenum
, f
->filename
);
3084 print_fatal_error(data
, "Missing REQUEST-ID value on line %d of \"%s\".", f
->linenum
, f
->filename
);
3088 else if (!strcmp(token
, "SKIP-IF-DEFINED"))
3091 * SKIP-IF-DEFINED variable
3094 if (_ippFileReadToken(f
, name
, sizeof(name
)))
3096 if (_ippVarsGet(vars
, name
))
3097 data
->skip_test
= 1;
3101 print_fatal_error(data
, "Missing SKIP-IF-DEFINED value on line %d of \"%s\".", f
->linenum
, f
->filename
);
3105 else if (!strcmp(token
, "SKIP-IF-MISSING"))
3108 * SKIP-IF-MISSING filename
3111 if (_ippFileReadToken(f
, temp
, sizeof(temp
)))
3113 char filename
[1024]; /* Filename */
3115 _ippVarsExpand(vars
, value
, temp
, sizeof(value
));
3116 get_filename(f
->filename
, filename
, temp
, sizeof(filename
));
3118 if (access(filename
, R_OK
))
3119 data
->skip_test
= 1;
3123 print_fatal_error(data
, "Missing SKIP-IF-MISSING filename on line %d of \"%s\".", f
->linenum
, f
->filename
);
3127 else if (!strcmp(token
, "SKIP-IF-NOT-DEFINED"))
3130 * SKIP-IF-NOT-DEFINED variable
3133 if (_ippFileReadToken(f
, name
, sizeof(name
)))
3135 if (!_ippVarsGet(vars
, name
))
3136 data
->skip_test
= 1;
3140 print_fatal_error(data
, "Missing SKIP-IF-NOT-DEFINED value on line %d of \"%s\".", f
->linenum
, f
->filename
);
3144 else if (!strcmp(token
, "SKIP-PREVIOUS-ERROR"))
3147 * SKIP-PREVIOUS-ERROR yes
3148 * SKIP-PREVIOUS-ERROR no
3151 if (_ippFileReadToken(f
, temp
, sizeof(temp
)) && (!_cups_strcasecmp(temp
, "yes") || !_cups_strcasecmp(temp
, "no")))
3153 data
->skip_previous
= !_cups_strcasecmp(temp
, "yes");
3157 print_fatal_error(data
, "Missing SKIP-PREVIOUS-ERROR value on line %d of \"%s\".", f
->linenum
, f
->filename
);
3161 else if (!strcmp(token
, "TEST-ID"))
3167 if (_ippFileReadToken(f
, temp
, sizeof(temp
)))
3169 _ippVarsExpand(vars
, data
->test_id
, temp
, sizeof(data
->test_id
));
3173 print_fatal_error(data
, "Missing TEST-ID value on line %d of \"%s\".", f
->linenum
, f
->filename
);
3177 else if (!strcmp(token
, "TRANSFER"))
3185 if (_ippFileReadToken(f
, temp
, sizeof(temp
)))
3187 if (!strcmp(temp
, "auto"))
3189 data
->transfer
= _CUPS_TRANSFER_AUTO
;
3191 else if (!strcmp(temp
, "chunked"))
3193 data
->transfer
= _CUPS_TRANSFER_CHUNKED
;
3195 else if (!strcmp(temp
, "length"))
3197 data
->transfer
= _CUPS_TRANSFER_LENGTH
;
3201 print_fatal_error(data
, "Bad TRANSFER value \"%s\" on line %d of \"%s\".", temp
, f
->linenum
, f
->filename
);
3207 print_fatal_error(data
, "Missing TRANSFER value on line %d of \"%s\".", f
->linenum
, f
->filename
);
3211 else if (!_cups_strcasecmp(token
, "VERSION"))
3213 if (_ippFileReadToken(f
, temp
, sizeof(temp
)))
3215 if (!strcmp(temp
, "0.0"))
3219 else if (!strcmp(temp
, "1.0"))
3223 else if (!strcmp(temp
, "1.1"))
3227 else if (!strcmp(temp
, "2.0"))
3231 else if (!strcmp(temp
, "2.1"))
3235 else if (!strcmp(temp
, "2.2"))
3241 print_fatal_error(data
, "Bad VERSION \"%s\" on line %d of \"%s\".", temp
, f
->linenum
, f
->filename
);
3247 print_fatal_error(data
, "Missing VERSION number on line %d of \"%s\".", f
->linenum
, f
->filename
);
3251 else if (!_cups_strcasecmp(token
, "RESOURCE"))
3257 if (!_ippFileReadToken(f
, data
->resource
, sizeof(data
->resource
)))
3259 print_fatal_error(data
, "Missing RESOURCE path on line %d of \"%s\".", f
->linenum
, f
->filename
);
3263 else if (!_cups_strcasecmp(token
, "OPERATION"))
3269 ipp_op_t op
; /* Operation code */
3271 if (!_ippFileReadToken(f
, temp
, sizeof(temp
)))
3273 print_fatal_error(data
, "Missing OPERATION code on line %d of \"%s\".", f
->linenum
, f
->filename
);
3277 _ippVarsExpand(vars
, value
, temp
, sizeof(value
));
3279 if ((op
= ippOpValue(value
)) == (ipp_op_t
)-1 && (op
= (ipp_op_t
)strtol(value
, NULL
, 0)) == 0)
3281 print_fatal_error(data
, "Bad OPERATION code \"%s\" on line %d of \"%s\".", temp
, f
->linenum
, f
->filename
);
3285 ippSetOperation(f
->attrs
, op
);
3287 else if (!_cups_strcasecmp(token
, "GROUP"))
3290 * Attribute group...
3293 ipp_tag_t group_tag
; /* Group tag */
3295 if (!_ippFileReadToken(f
, temp
, sizeof(temp
)))
3297 print_fatal_error(data
, "Missing GROUP tag on line %d of \"%s\".", f
->linenum
, f
->filename
);
3301 if ((group_tag
= ippTagValue(temp
)) == IPP_TAG_ZERO
|| group_tag
>= IPP_TAG_UNSUPPORTED_VALUE
)
3303 print_fatal_error(data
, "Bad GROUP tag \"%s\" on line %d of \"%s\".", temp
, f
->linenum
, f
->filename
);
3307 if (group_tag
== f
->group_tag
)
3308 ippAddSeparator(f
->attrs
);
3310 f
->group_tag
= group_tag
;
3312 else if (!_cups_strcasecmp(token
, "DELAY"))
3315 * Delay before operation...
3318 double dval
; /* Delay value */
3320 if (!_ippFileReadToken(f
, temp
, sizeof(temp
)))
3322 print_fatal_error(data
, "Missing DELAY value on line %d of \"%s\".", f
->linenum
, f
->filename
);
3326 _ippVarsExpand(vars
, value
, temp
, sizeof(value
));
3328 if ((dval
= _cupsStrScand(value
, &ptr
, localeconv())) < 0.0 || (*ptr
&& *ptr
!= ','))
3330 print_fatal_error(data
, "Bad DELAY value \"%s\" on line %d of \"%s\".", value
, f
->linenum
, f
->filename
);
3334 data
->delay
= (useconds_t
)(1000000.0 * dval
);
3338 if ((dval
= _cupsStrScand(ptr
+ 1, &ptr
, localeconv())) <= 0.0 || *ptr
)
3340 print_fatal_error(data
, "Bad DELAY value \"%s\" on line %d of \"%s\".", value
, f
->linenum
, f
->filename
);
3344 data
->repeat_interval
= (useconds_t
)(1000000.0 * dval
);
3347 data
->repeat_interval
= data
->delay
;
3349 else if (!_cups_strcasecmp(token
, "FILE"))
3355 if (!_ippFileReadToken(f
, temp
, sizeof(temp
)))
3357 print_fatal_error(data
, "Missing FILE filename on line %d of \"%s\".", f
->linenum
, f
->filename
);
3361 _ippVarsExpand(vars
, value
, temp
, sizeof(value
));
3362 get_filename(f
->filename
, data
->file
, value
, sizeof(data
->file
));
3364 if (access(data
->file
, R_OK
))
3366 print_fatal_error(data
, "Filename \"%s\" (mapped to \"%s\") on line %d of \"%s\" cannot be read.", value
, data
->file
, f
->linenum
, f
->filename
);
3370 else if (!_cups_strcasecmp(token
, "STATUS"))
3376 if (data
->num_statuses
>= (int)(sizeof(data
->statuses
) / sizeof(data
->statuses
[0])))
3378 print_fatal_error(data
, "Too many STATUS's on line %d of \"%s\".", f
->linenum
, f
->filename
);
3382 if (!_ippFileReadToken(f
, temp
, sizeof(temp
)))
3384 print_fatal_error(data
, "Missing STATUS code on line %d of \"%s\".", f
->linenum
, f
->filename
);
3388 if ((data
->statuses
[data
->num_statuses
].status
= ippErrorValue(temp
)) == (ipp_status_t
)-1 && (data
->statuses
[data
->num_statuses
].status
= (ipp_status_t
)strtol(temp
, NULL
, 0)) == 0)
3390 print_fatal_error(data
, "Bad STATUS code \"%s\" on line %d of \"%s\".", temp
, f
->linenum
, f
->filename
);
3394 data
->last_status
= data
->statuses
+ data
->num_statuses
;
3395 data
->num_statuses
++;
3397 data
->last_status
->define_match
= NULL
;
3398 data
->last_status
->define_no_match
= NULL
;
3399 data
->last_status
->if_defined
= NULL
;
3400 data
->last_status
->if_not_defined
= NULL
;
3401 data
->last_status
->repeat_limit
= 1000;
3402 data
->last_status
->repeat_match
= 0;
3403 data
->last_status
->repeat_no_match
= 0;
3405 else if (!_cups_strcasecmp(token
, "EXPECT") || !_cups_strcasecmp(token
, "EXPECT-ALL"))
3408 * Expected attributes...
3411 int expect_all
= !_cups_strcasecmp(token
, "EXPECT-ALL");
3413 if (data
->num_expects
>= (int)(sizeof(data
->expects
) / sizeof(data
->expects
[0])))
3415 print_fatal_error(data
, "Too many EXPECT's on line %d of \"%s\".", f
->linenum
, f
->filename
);
3419 if (!_ippFileReadToken(f
, name
, sizeof(name
)))
3421 print_fatal_error(data
, "Missing EXPECT name on line %d of \"%s\".", f
->linenum
, f
->filename
);
3425 data
->last_expect
= data
->expects
+ data
->num_expects
;
3426 data
->num_expects
++;
3428 memset(data
->last_expect
, 0, sizeof(_cups_expect_t
));
3429 data
->last_expect
->repeat_limit
= 1000;
3430 data
->last_expect
->expect_all
= expect_all
;
3434 data
->last_expect
->not_expect
= 1;
3435 data
->last_expect
->name
= strdup(name
+ 1);
3437 else if (name
[0] == '?')
3439 data
->last_expect
->optional
= 1;
3440 data
->last_expect
->name
= strdup(name
+ 1);
3443 data
->last_expect
->name
= strdup(name
);
3445 else if (!_cups_strcasecmp(token
, "COUNT"))
3447 int count
; /* Count value */
3449 if (!_ippFileReadToken(f
, temp
, sizeof(temp
)))
3451 print_fatal_error(data
, "Missing COUNT number on line %d of \"%s\".", f
->linenum
, f
->filename
);
3455 if ((count
= atoi(temp
)) <= 0)
3457 print_fatal_error(data
, "Bad COUNT \"%s\" on line %d of \"%s\".", temp
, f
->linenum
, f
->filename
);
3461 if (data
->last_expect
)
3463 data
->last_expect
->count
= count
;
3467 print_fatal_error(data
, "COUNT without a preceding EXPECT on line %d of \"%s\".", f
->linenum
, f
->filename
);
3471 else if (!_cups_strcasecmp(token
, "DEFINE-MATCH"))
3473 if (!_ippFileReadToken(f
, temp
, sizeof(temp
)))
3475 print_fatal_error(data
, "Missing DEFINE-MATCH variable on line %d of \"%s\".", f
->linenum
, f
->filename
);
3479 if (data
->last_expect
)
3481 data
->last_expect
->define_match
= strdup(temp
);
3483 else if (data
->last_status
)
3485 data
->last_status
->define_match
= strdup(temp
);
3489 print_fatal_error(data
, "DEFINE-MATCH without a preceding EXPECT or STATUS on line %d of \"%s\".", f
->linenum
, f
->filename
);
3493 else if (!_cups_strcasecmp(token
, "DEFINE-NO-MATCH"))
3495 if (!_ippFileReadToken(f
, temp
, sizeof(temp
)))
3497 print_fatal_error(data
, "Missing DEFINE-NO-MATCH variable on line %d of \"%s\".", f
->linenum
, f
->filename
);
3501 if (data
->last_expect
)
3503 data
->last_expect
->define_no_match
= strdup(temp
);
3505 else if (data
->last_status
)
3507 data
->last_status
->define_no_match
= strdup(temp
);
3511 print_fatal_error(data
, "DEFINE-NO-MATCH without a preceding EXPECT or STATUS on line %d of \"%s\".", f
->linenum
, f
->filename
);
3515 else if (!_cups_strcasecmp(token
, "DEFINE-VALUE"))
3517 if (!_ippFileReadToken(f
, temp
, sizeof(temp
)))
3519 print_fatal_error(data
, "Missing DEFINE-VALUE variable on line %d of \"%s\".", f
->linenum
, f
->filename
);
3523 if (data
->last_expect
)
3525 data
->last_expect
->define_value
= strdup(temp
);
3529 print_fatal_error(data
, "DEFINE-VALUE without a preceding EXPECT on line %d of \"%s\".", f
->linenum
, f
->filename
);
3533 else if (!_cups_strcasecmp(token
, "OF-TYPE"))
3535 if (!_ippFileReadToken(f
, temp
, sizeof(temp
)))
3537 print_fatal_error(data
, "Missing OF-TYPE value tag(s) on line %d of \"%s\".", f
->linenum
, f
->filename
);
3541 if (data
->last_expect
)
3543 data
->last_expect
->of_type
= strdup(temp
);
3547 print_fatal_error(data
, "OF-TYPE without a preceding EXPECT on line %d of \"%s\".", f
->linenum
, f
->filename
);
3551 else if (!_cups_strcasecmp(token
, "IN-GROUP"))
3553 ipp_tag_t in_group
; /* IN-GROUP value */
3555 if (!_ippFileReadToken(f
, temp
, sizeof(temp
)))
3557 print_fatal_error(data
, "Missing IN-GROUP group tag on line %d of \"%s\".", f
->linenum
, f
->filename
);
3561 if ((in_group
= ippTagValue(temp
)) == IPP_TAG_ZERO
|| in_group
>= IPP_TAG_UNSUPPORTED_VALUE
)
3563 print_fatal_error(data
, "Bad IN-GROUP group tag \"%s\" on line %d of \"%s\".", temp
, f
->linenum
, f
->filename
);
3566 else if (data
->last_expect
)
3568 data
->last_expect
->in_group
= in_group
;
3572 print_fatal_error(data
, "IN-GROUP without a preceding EXPECT on line %d of \"%s\".", f
->linenum
, f
->filename
);
3576 else if (!_cups_strcasecmp(token
, "REPEAT-LIMIT"))
3578 if (!_ippFileReadToken(f
, temp
, sizeof(temp
)))
3580 print_fatal_error(data
, "Missing REPEAT-LIMIT value on line %d of \"%s\".", f
->linenum
, f
->filename
);
3583 else if (atoi(temp
) <= 0)
3585 print_fatal_error(data
, "Bad REPEAT-LIMIT value on line %d of \"%s\".", f
->linenum
, f
->filename
);
3589 if (data
->last_status
)
3591 data
->last_status
->repeat_limit
= atoi(temp
);
3593 else if (data
->last_expect
)
3595 data
->last_expect
->repeat_limit
= atoi(temp
);
3599 print_fatal_error(data
, "REPEAT-LIMIT without a preceding EXPECT or STATUS on line %d of \"%s\".", f
->linenum
, f
->filename
);
3603 else if (!_cups_strcasecmp(token
, "REPEAT-MATCH"))
3605 if (data
->last_status
)
3607 data
->last_status
->repeat_match
= 1;
3609 else if (data
->last_expect
)
3611 data
->last_expect
->repeat_match
= 1;
3615 print_fatal_error(data
, "REPEAT-MATCH without a preceding EXPECT or STATUS on line %d of \"%s\".", f
->linenum
, f
->filename
);
3619 else if (!_cups_strcasecmp(token
, "REPEAT-NO-MATCH"))
3621 if (data
->last_status
)
3623 data
->last_status
->repeat_no_match
= 1;
3625 else if (data
->last_expect
)
3627 data
->last_expect
->repeat_no_match
= 1;
3631 print_fatal_error(data
, "REPEAT-NO-MATCH without a preceding EXPECT or STATUS on line %d of \"%s\".", f
->linenum
, f
->filename
);
3635 else if (!_cups_strcasecmp(token
, "SAME-COUNT-AS"))
3637 if (!_ippFileReadToken(f
, temp
, sizeof(temp
)))
3639 print_fatal_error(data
, "Missing SAME-COUNT-AS name on line %d of \"%s\".", f
->linenum
, f
->filename
);
3643 if (data
->last_expect
)
3645 data
->last_expect
->same_count_as
= strdup(temp
);
3649 print_fatal_error(data
, "SAME-COUNT-AS without a preceding EXPECT on line %d of \"%s\".", f
->linenum
, f
->filename
);
3653 else if (!_cups_strcasecmp(token
, "IF-DEFINED"))
3655 if (!_ippFileReadToken(f
, temp
, sizeof(temp
)))
3657 print_fatal_error(data
, "Missing IF-DEFINED name on line %d of \"%s\".", f
->linenum
, f
->filename
);
3661 if (data
->last_expect
)
3663 data
->last_expect
->if_defined
= strdup(temp
);
3665 else if (data
->last_status
)
3667 data
->last_status
->if_defined
= strdup(temp
);
3671 print_fatal_error(data
, "IF-DEFINED without a preceding EXPECT or STATUS on line %d of \"%s\".", f
->linenum
, f
->filename
);
3675 else if (!_cups_strcasecmp(token
, "IF-NOT-DEFINED"))
3677 if (!_ippFileReadToken(f
, temp
, sizeof(temp
)))
3679 print_fatal_error(data
, "Missing IF-NOT-DEFINED name on line %d of \"%s\".", f
->linenum
, f
->filename
);
3683 if (data
->last_expect
)
3685 data
->last_expect
->if_not_defined
= strdup(temp
);
3687 else if (data
->last_status
)
3689 data
->last_status
->if_not_defined
= strdup(temp
);
3693 print_fatal_error(data
, "IF-NOT-DEFINED without a preceding EXPECT or STATUS on line %d of \"%s\".", f
->linenum
, f
->filename
);
3697 else if (!_cups_strcasecmp(token
, "WITH-ALL-VALUES") ||
3698 !_cups_strcasecmp(token
, "WITH-ALL-HOSTNAMES") ||
3699 !_cups_strcasecmp(token
, "WITH-ALL-RESOURCES") ||
3700 !_cups_strcasecmp(token
, "WITH-ALL-SCHEMES") ||
3701 !_cups_strcasecmp(token
, "WITH-HOSTNAME") ||
3702 !_cups_strcasecmp(token
, "WITH-RESOURCE") ||
3703 !_cups_strcasecmp(token
, "WITH-SCHEME") ||
3704 !_cups_strcasecmp(token
, "WITH-VALUE"))
3706 off_t lastpos
; /* Last file position */
3708 if (data
->last_expect
)
3710 if (!_cups_strcasecmp(token
, "WITH-ALL-HOSTNAMES") || !_cups_strcasecmp(token
, "WITH-HOSTNAME"))
3711 data
->last_expect
->with_flags
= _CUPS_WITH_HOSTNAME
;
3712 else if (!_cups_strcasecmp(token
, "WITH-ALL-RESOURCES") || !_cups_strcasecmp(token
, "WITH-RESOURCE"))
3713 data
->last_expect
->with_flags
= _CUPS_WITH_RESOURCE
;
3714 else if (!_cups_strcasecmp(token
, "WITH-ALL-SCHEMES") || !_cups_strcasecmp(token
, "WITH-SCHEME"))
3715 data
->last_expect
->with_flags
= _CUPS_WITH_SCHEME
;
3717 if (!_cups_strncasecmp(token
, "WITH-ALL-", 9))
3718 data
->last_expect
->with_flags
|= _CUPS_WITH_ALL
;
3721 if (!_ippFileReadToken(f
, temp
, sizeof(temp
)))
3723 print_fatal_error(data
, "Missing %s value on line %d of \"%s\".", token
, f
->linenum
, f
->filename
);
3728 * Read additional comma-delimited values - needed since legacy test files
3729 * will have unquoted WITH-VALUE values with commas...
3732 ptr
= temp
+ strlen(temp
);
3736 lastpos
= cupsFileTell(f
->fp
);
3739 if (!_ippFileReadToken(f
, ptr
, (sizeof(temp
) - (size_t)(ptr
- temp
))))
3742 if (!strcmp(ptr
, ","))
3750 if (!_ippFileReadToken(f
, ptr
, (sizeof(temp
) - (size_t)(ptr
- temp
))))
3756 * Not another value, stop here...
3759 cupsFileSeek(f
->fp
, lastpos
);
3765 if (data
->last_expect
)
3768 * Expand any variables in the value and then save it.
3771 _ippVarsExpand(vars
, value
, temp
, sizeof(value
));
3773 ptr
= value
+ strlen(value
) - 1;
3775 if (value
[0] == '/' && ptr
> value
&& *ptr
== '/')
3778 * WITH-VALUE is a POSIX extended regular expression.
3781 data
->last_expect
->with_value
= calloc(1, (size_t)(ptr
- value
));
3782 data
->last_expect
->with_flags
|= _CUPS_WITH_REGEX
;
3784 if (data
->last_expect
->with_value
)
3785 memcpy(data
->last_expect
->with_value
, value
+ 1, (size_t)(ptr
- value
- 1));
3790 * WITH-VALUE is a literal value...
3793 for (ptr
= value
; *ptr
; ptr
++)
3795 if (*ptr
== '\\' && ptr
[1])
3798 * Remove \ from \foo...
3801 _cups_strcpy(ptr
, ptr
+ 1);
3805 data
->last_expect
->with_value
= strdup(value
);
3806 data
->last_expect
->with_flags
|= _CUPS_WITH_LITERAL
;
3811 print_fatal_error(data
, "%s without a preceding EXPECT on line %d of \"%s\".", token
, f
->linenum
, f
->filename
);
3815 else if (!_cups_strcasecmp(token
, "WITH-VALUE-FROM"))
3817 if (!_ippFileReadToken(f
, temp
, sizeof(temp
)))
3819 print_fatal_error(data
, "Missing %s value on line %d of \"%s\".", token
, f
->linenum
, f
->filename
);
3823 if (data
->last_expect
)
3826 * Expand any variables in the value and then save it.
3829 _ippVarsExpand(vars
, value
, temp
, sizeof(value
));
3831 data
->last_expect
->with_value_from
= strdup(value
);
3832 data
->last_expect
->with_flags
= _CUPS_WITH_LITERAL
;
3836 print_fatal_error(data
, "%s without a preceding EXPECT on line %d of \"%s\".", token
, f
->linenum
, f
->filename
);
3840 else if (!_cups_strcasecmp(token
, "DISPLAY"))
3843 * Display attributes...
3846 if (data
->num_displayed
>= (int)(sizeof(data
->displayed
) / sizeof(data
->displayed
[0])))
3848 print_fatal_error(data
, "Too many DISPLAY's on line %d of \"%s\".", f
->linenum
, f
->filename
);
3852 if (!_ippFileReadToken(f
, temp
, sizeof(temp
)))
3854 print_fatal_error(data
, "Missing DISPLAY name on line %d of \"%s\".", f
->linenum
, f
->filename
);
3858 data
->displayed
[data
->num_displayed
] = strdup(temp
);
3859 data
->num_displayed
++;
3863 print_fatal_error(data
, "Unexpected token %s seen on line %d of \"%s\".", token
, f
->linenum
, f
->filename
);
3870 * Scan for the start of a test (open brace)...
3873 if (!strcmp(token
, "{"))
3879 if (data
->show_header
)
3881 if (data
->output
== _CUPS_OUTPUT_PLIST
)
3882 print_xml_header(data
);
3884 if (data
->output
== _CUPS_OUTPUT_TEST
|| (data
->output
== _CUPS_OUTPUT_PLIST
&& data
->outfile
!= cupsFileStdout()))
3885 cupsFilePrintf(cupsFileStdout(), "\"%s\":\n", f
->filename
);
3887 data
->show_header
= 0;
3890 data
->compression
[0] = '\0';
3892 data
->num_expects
= 0;
3893 data
->last_expect
= NULL
;
3894 data
->file
[0] = '\0';
3895 data
->ignore_errors
= data
->def_ignore_errors
;
3896 strlcpy(data
->name
, f
->filename
, sizeof(data
->name
));
3897 if ((ptr
= strrchr(data
->name
, '.')) != NULL
)
3899 data
->repeat_interval
= 5000000;
3900 data
->request_id
++;
3901 strlcpy(data
->resource
, vars
->resource
, sizeof(data
->resource
));
3902 data
->skip_previous
= 0;
3903 data
->skip_test
= 0;
3904 data
->num_statuses
= 0;
3905 data
->last_status
= NULL
;
3906 data
->test_id
[0] = '\0';
3907 data
->transfer
= data
->def_transfer
;
3908 data
->version
= data
->def_version
;
3910 f
->attrs
= ippNew();
3911 f
->group_tag
= IPP_TAG_ZERO
;
3913 else if (!strcmp(token
, "DEFINE"))
3919 if (_ippFileReadToken(f
, name
, sizeof(name
)) && _ippFileReadToken(f
, temp
, sizeof(temp
)))
3921 _ippVarsExpand(vars
, value
, temp
, sizeof(value
));
3922 _ippVarsSet(vars
, name
, value
);
3926 print_fatal_error(data
, "Missing DEFINE name and/or value on line %d of \"%s\".", f
->linenum
, f
->filename
);
3930 else if (!strcmp(token
, "DEFINE-DEFAULT"))
3933 * DEFINE-DEFAULT name value
3936 if (_ippFileReadToken(f
, name
, sizeof(name
)) && _ippFileReadToken(f
, temp
, sizeof(temp
)))
3938 if (!_ippVarsGet(vars
, name
))
3940 _ippVarsExpand(vars
, value
, temp
, sizeof(value
));
3941 _ippVarsSet(vars
, name
, value
);
3946 print_fatal_error(data
, "Missing DEFINE-DEFAULT name and/or value on line %d of \"%s\".", f
->linenum
, f
->filename
);
3950 else if (!strcmp(token
, "FILE-ID"))
3956 if (_ippFileReadToken(f
, temp
, sizeof(temp
)))
3958 _ippVarsExpand(vars
, data
->file_id
, temp
, sizeof(data
->file_id
));
3962 print_fatal_error(data
, "Missing FILE-ID value on line %d of \"%s\".", f
->linenum
, f
->filename
);
3966 else if (!strcmp(token
, "IGNORE-ERRORS"))
3973 if (_ippFileReadToken(f
, temp
, sizeof(temp
)) && (!_cups_strcasecmp(temp
, "yes") || !_cups_strcasecmp(temp
, "no")))
3975 data
->def_ignore_errors
= !_cups_strcasecmp(temp
, "yes");
3979 print_fatal_error(data
, "Missing IGNORE-ERRORS value on line %d of \"%s\".", f
->linenum
, f
->filename
);
3983 else if (!strcmp(token
, "INCLUDE"))
3986 * INCLUDE "filename"
3987 * INCLUDE <filename>
3990 if (_ippFileReadToken(f
, temp
, sizeof(temp
)))
3993 * Map the filename to and then run the tests...
3996 _cups_testdata_t inc_data
; /* Data for included file */
3997 char filename
[1024]; /* Mapped filename */
3999 memcpy(&inc_data
, data
, sizeof(inc_data
));
4000 inc_data
.http
= NULL
;
4002 inc_data
.prev_pass
= 1;
4003 inc_data
.show_header
= 1;
4005 if (!do_tests(get_filename(f
->filename
, filename
, temp
, sizeof(filename
)), vars
, &inc_data
) && data
->stop_after_include_error
)
4007 data
->pass
= data
->prev_pass
= 0;
4013 print_fatal_error(data
, "Missing INCLUDE filename on line %d of \"%s\".", f
->linenum
, f
->filename
);
4017 data
->show_header
= 1;
4019 else if (!strcmp(token
, "INCLUDE-IF-DEFINED"))
4022 * INCLUDE-IF-DEFINED name "filename"
4023 * INCLUDE-IF-DEFINED name <filename>
4026 if (_ippFileReadToken(f
, name
, sizeof(name
)) && _ippFileReadToken(f
, temp
, sizeof(temp
)))
4029 * Map the filename to and then run the tests...
4032 _cups_testdata_t inc_data
; /* Data for included file */
4033 char filename
[1024]; /* Mapped filename */
4035 memcpy(&inc_data
, data
, sizeof(inc_data
));
4036 inc_data
.http
= NULL
;
4038 inc_data
.prev_pass
= 1;
4039 inc_data
.show_header
= 1;
4041 if (!do_tests(get_filename(f
->filename
, filename
, temp
, sizeof(filename
)), vars
, &inc_data
) && data
->stop_after_include_error
)
4043 data
->pass
= data
->prev_pass
= 0;
4049 print_fatal_error(data
, "Missing INCLUDE-IF-DEFINED name or filename on line %d of \"%s\".", f
->linenum
, f
->filename
);
4053 data
->show_header
= 1;
4055 else if (!strcmp(token
, "INCLUDE-IF-NOT-DEFINED"))
4058 * INCLUDE-IF-NOT-DEFINED name "filename"
4059 * INCLUDE-IF-NOT-DEFINED name <filename>
4062 if (_ippFileReadToken(f
, name
, sizeof(name
)) && _ippFileReadToken(f
, temp
, sizeof(temp
)))
4065 * Map the filename to and then run the tests...
4068 _cups_testdata_t inc_data
; /* Data for included file */
4069 char filename
[1024]; /* Mapped filename */
4071 memcpy(&inc_data
, data
, sizeof(inc_data
));
4072 inc_data
.http
= NULL
;
4074 inc_data
.prev_pass
= 1;
4075 inc_data
.show_header
= 1;
4077 if (!do_tests(get_filename(f
->filename
, filename
, temp
, sizeof(filename
)), vars
, &inc_data
) && data
->stop_after_include_error
)
4079 data
->pass
= data
->prev_pass
= 0;
4085 print_fatal_error(data
, "Missing INCLUDE-IF-NOT-DEFINED name or filename on line %d of \"%s\".", f
->linenum
, f
->filename
);
4089 data
->show_header
= 1;
4091 else if (!strcmp(token
, "SKIP-IF-DEFINED"))
4094 * SKIP-IF-DEFINED variable
4097 if (_ippFileReadToken(f
, name
, sizeof(name
)))
4099 if (_ippVarsGet(vars
, name
))
4100 data
->skip_test
= 1;
4104 print_fatal_error(data
, "Missing SKIP-IF-DEFINED variable on line %d of \"%s\".", f
->linenum
, f
->filename
);
4108 else if (!strcmp(token
, "SKIP-IF-NOT-DEFINED"))
4111 * SKIP-IF-NOT-DEFINED variable
4114 if (_ippFileReadToken(f
, name
, sizeof(name
)))
4116 if (!_ippVarsGet(vars
, name
))
4117 data
->skip_test
= 1;
4121 print_fatal_error(data
, "Missing SKIP-IF-NOT-DEFINED variable on line %d of \"%s\".", f
->linenum
, f
->filename
);
4125 else if (!strcmp(token
, "STOP-AFTER-INCLUDE-ERROR"))
4128 * STOP-AFTER-INCLUDE-ERROR yes
4129 * STOP-AFTER-INCLUDE-ERROR no
4132 if (_ippFileReadToken(f
, temp
, sizeof(temp
)) && (!_cups_strcasecmp(temp
, "yes") || !_cups_strcasecmp(temp
, "no")))
4134 data
->stop_after_include_error
= !_cups_strcasecmp(temp
, "yes");
4138 print_fatal_error(data
, "Missing STOP-AFTER-INCLUDE-ERROR value on line %d of \"%s\".", f
->linenum
, f
->filename
);
4142 else if (!strcmp(token
, "TRANSFER"))
4150 if (_ippFileReadToken(f
, temp
, sizeof(temp
)))
4152 if (!strcmp(temp
, "auto"))
4153 data
->def_transfer
= _CUPS_TRANSFER_AUTO
;
4154 else if (!strcmp(temp
, "chunked"))
4155 data
->def_transfer
= _CUPS_TRANSFER_CHUNKED
;
4156 else if (!strcmp(temp
, "length"))
4157 data
->def_transfer
= _CUPS_TRANSFER_LENGTH
;
4160 print_fatal_error(data
, "Bad TRANSFER value \"%s\" on line %d of \"%s\".", temp
, f
->linenum
, f
->filename
);
4166 print_fatal_error(data
, "Missing TRANSFER value on line %d of \"%s\".", f
->linenum
, f
->filename
);
4170 else if (!strcmp(token
, "VERSION"))
4172 if (_ippFileReadToken(f
, temp
, sizeof(temp
)))
4174 if (!strcmp(temp
, "1.0"))
4175 data
->def_version
= 10;
4176 else if (!strcmp(temp
, "1.1"))
4177 data
->def_version
= 11;
4178 else if (!strcmp(temp
, "2.0"))
4179 data
->def_version
= 20;
4180 else if (!strcmp(temp
, "2.1"))
4181 data
->def_version
= 21;
4182 else if (!strcmp(temp
, "2.2"))
4183 data
->def_version
= 22;
4186 print_fatal_error(data
, "Bad VERSION \"%s\" on line %d of \"%s\".", temp
, f
->linenum
, f
->filename
);
4192 print_fatal_error(data
, "Missing VERSION number on line %d of \"%s\".", f
->linenum
, f
->filename
);
4198 print_fatal_error(data
, "Unexpected token %s seen on line %d of \"%s\".", token
, f
->linenum
, f
->filename
);
4208 * 'usage()' - Show program usage.
4214 _cupsLangPuts(stderr
, _("Usage: ipptool [options] URI filename [ ... filenameN ]"));
4215 _cupsLangPuts(stderr
, _("Options:"));
4216 _cupsLangPuts(stderr
, _(" --help Show help."));
4217 _cupsLangPuts(stderr
, _(" --ippserver filename Produce ippserver attribute file."));
4218 _cupsLangPuts(stderr
, _(" --stop-after-include-error\n"
4219 " Stop tests after a failed INCLUDE."));
4220 _cupsLangPuts(stderr
, _(" --version Show version."));
4221 _cupsLangPuts(stderr
, _(" -4 Connect using IPv4."));
4222 _cupsLangPuts(stderr
, _(" -6 Connect using IPv6."));
4223 _cupsLangPuts(stderr
, _(" -C Send requests using "
4224 "chunking (default)."));
4225 _cupsLangPuts(stderr
, _(" -E Test with encryption using HTTP Upgrade to TLS."));
4226 _cupsLangPuts(stderr
, _(" -I Ignore errors."));
4227 _cupsLangPuts(stderr
, _(" -L Send requests using content-length."));
4228 _cupsLangPuts(stderr
, _(" -P filename.plist Produce XML plist to a file and test report to standard output."));
4229 _cupsLangPuts(stderr
, _(" -S Test with encryption using HTTPS."));
4230 _cupsLangPuts(stderr
, _(" -T seconds Set the receive/send timeout in seconds."));
4231 _cupsLangPuts(stderr
, _(" -V version Set default IPP version."));
4232 _cupsLangPuts(stderr
, _(" -X Produce XML plist instead of plain text."));
4233 _cupsLangPuts(stderr
, _(" -c Produce CSV output."));
4234 _cupsLangPuts(stderr
, _(" -d name=value Set named variable to value."));
4235 _cupsLangPuts(stderr
, _(" -f filename Set default request filename."));
4236 _cupsLangPuts(stderr
, _(" -h Validate HTTP response headers."));
4237 _cupsLangPuts(stderr
, _(" -i seconds Repeat the last file with the given time interval."));
4238 _cupsLangPuts(stderr
, _(" -l Produce plain text output."));
4239 _cupsLangPuts(stderr
, _(" -n count Repeat the last file the given number of times."));
4240 _cupsLangPuts(stderr
, _(" -q Run silently."));
4241 _cupsLangPuts(stderr
, _(" -t Produce a test report."));
4242 _cupsLangPuts(stderr
, _(" -v Be verbose."));
4249 * 'with_flags_string()' - Return the "WITH-xxx" predicate that corresponds to
4253 static const char * /* O - WITH-xxx string */
4254 with_flags_string(int flags
) /* I - WITH flags */
4256 if (flags
& _CUPS_WITH_ALL
)
4258 if (flags
& _CUPS_WITH_HOSTNAME
)
4259 return ("WITH-ALL-HOSTNAMES");
4260 else if (flags
& _CUPS_WITH_RESOURCE
)
4261 return ("WITH-ALL-RESOURCES");
4262 else if (flags
& _CUPS_WITH_SCHEME
)
4263 return ("WITH-ALL-SCHEMES");
4265 return ("WITH-ALL-VALUES");
4267 else if (flags
& _CUPS_WITH_HOSTNAME
)
4268 return ("WITH-HOSTNAME");
4269 else if (flags
& _CUPS_WITH_RESOURCE
)
4270 return ("WITH-RESOURCE");
4271 else if (flags
& _CUPS_WITH_SCHEME
)
4272 return ("WITH-SCHEME");
4274 return ("WITH-VALUE");
4279 * 'with_value()' - Test a WITH-VALUE predicate.
4282 static int /* O - 1 on match, 0 on non-match */
4283 with_value(_cups_testdata_t
*data
, /* I - Test data */
4284 cups_array_t
*errors
, /* I - Errors array */
4285 char *value
, /* I - Value string */
4286 int flags
, /* I - Flags for match */
4287 ipp_attribute_t
*attr
, /* I - Attribute to compare */
4288 char *matchbuf
, /* I - Buffer to hold matching value */
4289 size_t matchlen
) /* I - Length of match buffer */
4291 int i
, /* Looping var */
4292 count
, /* Number of values */
4294 char temp
[1024], /* Temporary value string */
4295 *valptr
; /* Pointer into value */
4296 const char *name
; /* Attribute name */
4300 match
= (flags
& _CUPS_WITH_ALL
) ? 1 : 0;
4303 * NULL matches everything.
4306 if (!value
|| !*value
)
4310 * Compare the value string to the attribute value.
4313 name
= ippGetName(attr
);
4314 count
= ippGetCount(attr
);
4316 switch (ippGetValueTag(attr
))
4318 case IPP_TAG_INTEGER
:
4320 for (i
= 0; i
< count
; i
++)
4322 char op
, /* Comparison operator */
4323 *nextptr
; /* Next pointer */
4324 int intvalue
, /* Integer value */
4325 attrvalue
= ippGetInteger(attr
, i
),
4326 /* Attribute value */
4327 valmatch
= 0; /* Does the current value match? */
4331 while (isspace(*valptr
& 255) || isdigit(*valptr
& 255) ||
4332 *valptr
== '-' || *valptr
== ',' || *valptr
== '<' ||
4333 *valptr
== '=' || *valptr
== '>')
4336 while (*valptr
&& !isdigit(*valptr
& 255) && *valptr
!= '-')
4338 if (*valptr
== '<' || *valptr
== '>' || *valptr
== '=')
4346 intvalue
= (int)strtol(valptr
, &nextptr
, 0);
4347 if (nextptr
== valptr
)
4351 if ((op
== '=' && attrvalue
== intvalue
) ||
4352 (op
== '<' && attrvalue
< intvalue
) ||
4353 (op
== '>' && attrvalue
> intvalue
))
4356 snprintf(matchbuf
, matchlen
, "%d", attrvalue
);
4363 if (flags
& _CUPS_WITH_ALL
)
4378 if (!match
&& errors
)
4380 for (i
= 0; i
< count
; i
++)
4381 add_stringf(data
->errors
, "GOT: %s=%d", name
, ippGetInteger(attr
, i
));
4385 case IPP_TAG_RANGE
:
4386 for (i
= 0; i
< count
; i
++)
4388 char op
, /* Comparison operator */
4389 *nextptr
; /* Next pointer */
4390 int intvalue
, /* Integer value */
4391 lower
, /* Lower range */
4392 upper
, /* Upper range */
4393 valmatch
= 0; /* Does the current value match? */
4395 lower
= ippGetRange(attr
, i
, &upper
);
4398 while (isspace(*valptr
& 255) || isdigit(*valptr
& 255) ||
4399 *valptr
== '-' || *valptr
== ',' || *valptr
== '<' ||
4400 *valptr
== '=' || *valptr
== '>')
4403 while (*valptr
&& !isdigit(*valptr
& 255) && *valptr
!= '-')
4405 if (*valptr
== '<' || *valptr
== '>' || *valptr
== '=')
4413 intvalue
= (int)strtol(valptr
, &nextptr
, 0);
4414 if (nextptr
== valptr
)
4418 if ((op
== '=' && (lower
== intvalue
|| upper
== intvalue
)) ||
4419 (op
== '<' && upper
< intvalue
) ||
4420 (op
== '>' && upper
> intvalue
))
4423 snprintf(matchbuf
, matchlen
, "%d-%d", lower
, upper
);
4430 if (flags
& _CUPS_WITH_ALL
)
4445 if (!match
&& errors
)
4447 for (i
= 0; i
< count
; i
++)
4449 int lower
, upper
; /* Range values */
4451 lower
= ippGetRange(attr
, i
, &upper
);
4452 add_stringf(data
->errors
, "GOT: %s=%d-%d", name
, lower
, upper
);
4457 case IPP_TAG_BOOLEAN
:
4458 for (i
= 0; i
< count
; i
++)
4460 if ((!strcmp(value
, "true")) == ippGetBoolean(attr
, i
))
4463 strlcpy(matchbuf
, value
, matchlen
);
4465 if (!(flags
& _CUPS_WITH_ALL
))
4471 else if (flags
& _CUPS_WITH_ALL
)
4478 if (!match
&& errors
)
4480 for (i
= 0; i
< count
; i
++)
4481 add_stringf(data
->errors
, "GOT: %s=%s", name
, ippGetBoolean(attr
, i
) ? "true" : "false");
4485 case IPP_TAG_RESOLUTION
:
4486 for (i
= 0; i
< count
; i
++)
4488 int xres
, yres
; /* Resolution values */
4489 ipp_res_t units
; /* Resolution units */
4491 xres
= ippGetResolution(attr
, i
, &yres
, &units
);
4493 snprintf(temp
, sizeof(temp
), "%d%s", xres
, units
== IPP_RES_PER_INCH
? "dpi" : "dpcm");
4495 snprintf(temp
, sizeof(temp
), "%dx%d%s", xres
, yres
, units
== IPP_RES_PER_INCH
? "dpi" : "dpcm");
4497 if (!strcmp(value
, temp
))
4500 strlcpy(matchbuf
, value
, matchlen
);
4502 if (!(flags
& _CUPS_WITH_ALL
))
4508 else if (flags
& _CUPS_WITH_ALL
)
4515 if (!match
&& errors
)
4517 for (i
= 0; i
< count
; i
++)
4519 int xres
, yres
; /* Resolution values */
4520 ipp_res_t units
; /* Resolution units */
4522 xres
= ippGetResolution(attr
, i
, &yres
, &units
);
4524 snprintf(temp
, sizeof(temp
), "%d%s", xres
, units
== IPP_RES_PER_INCH
? "dpi" : "dpcm");
4526 snprintf(temp
, sizeof(temp
), "%dx%d%s", xres
, yres
, units
== IPP_RES_PER_INCH
? "dpi" : "dpcm");
4528 if (strcmp(value
, temp
))
4529 add_stringf(data
->errors
, "GOT: %s=%s", name
, temp
);
4534 case IPP_TAG_NOVALUE
:
4535 case IPP_TAG_UNKNOWN
:
4538 case IPP_TAG_CHARSET
:
4539 case IPP_TAG_KEYWORD
:
4540 case IPP_TAG_LANGUAGE
:
4541 case IPP_TAG_MIMETYPE
:
4543 case IPP_TAG_NAMELANG
:
4545 case IPP_TAG_TEXTLANG
:
4547 case IPP_TAG_URISCHEME
:
4548 if (flags
& _CUPS_WITH_REGEX
)
4551 * Value is an extended, case-sensitive POSIX regular expression...
4554 regex_t re
; /* Regular expression */
4556 if ((i
= regcomp(&re
, value
, REG_EXTENDED
| REG_NOSUB
)) != 0)
4558 regerror(i
, &re
, temp
, sizeof(temp
));
4560 print_fatal_error(data
, "Unable to compile WITH-VALUE regular expression \"%s\" - %s", value
, temp
);
4565 * See if ALL of the values match the given regular expression.
4568 for (i
= 0; i
< count
; i
++)
4570 if (!regexec(&re
, get_string(attr
, i
, flags
, temp
, sizeof(temp
)),
4574 strlcpy(matchbuf
, get_string(attr
, i
, flags
, temp
, sizeof(temp
)), matchlen
);
4576 if (!(flags
& _CUPS_WITH_ALL
))
4582 else if (flags
& _CUPS_WITH_ALL
)
4591 else if (ippGetValueTag(attr
) == IPP_TAG_URI
&& !(flags
& (_CUPS_WITH_SCHEME
| _CUPS_WITH_HOSTNAME
| _CUPS_WITH_RESOURCE
)))
4594 * Value is a literal URI string, see if the value(s) match...
4597 for (i
= 0; i
< count
; i
++)
4599 if (!compare_uris(value
, get_string(attr
, i
, flags
, temp
, sizeof(temp
))))
4602 strlcpy(matchbuf
, get_string(attr
, i
, flags
, temp
, sizeof(temp
)), matchlen
);
4604 if (!(flags
& _CUPS_WITH_ALL
))
4610 else if (flags
& _CUPS_WITH_ALL
)
4620 * Value is a literal string, see if the value(s) match...
4623 for (i
= 0; i
< count
; i
++)
4627 switch (ippGetValueTag(attr
))
4631 * Some URI components are case-sensitive, some not...
4634 if (flags
& (_CUPS_WITH_SCHEME
| _CUPS_WITH_HOSTNAME
))
4635 result
= _cups_strcasecmp(value
, get_string(attr
, i
, flags
, temp
, sizeof(temp
)));
4637 result
= strcmp(value
, get_string(attr
, i
, flags
, temp
, sizeof(temp
)));
4640 case IPP_TAG_MIMETYPE
:
4642 case IPP_TAG_NAMELANG
:
4644 case IPP_TAG_TEXTLANG
:
4646 * mimeMediaType, nameWithoutLanguage, nameWithLanguage,
4647 * textWithoutLanguage, and textWithLanguage are defined to
4648 * be case-insensitive strings...
4651 result
= _cups_strcasecmp(value
, get_string(attr
, i
, flags
, temp
, sizeof(temp
)));
4656 * Other string syntaxes are defined as lowercased so we use
4657 * case-sensitive comparisons to catch problems...
4660 result
= strcmp(value
, get_string(attr
, i
, flags
, temp
, sizeof(temp
)));
4667 strlcpy(matchbuf
, get_string(attr
, i
, flags
, temp
, sizeof(temp
)), matchlen
);
4669 if (!(flags
& _CUPS_WITH_ALL
))
4675 else if (flags
& _CUPS_WITH_ALL
)
4683 if (!match
&& errors
)
4685 for (i
= 0; i
< count
; i
++)
4686 add_stringf(data
->errors
, "GOT: %s=\"%s\"", name
, ippGetString(attr
, i
, NULL
));
4699 * 'with_value_from()' - Test a WITH-VALUE-FROM predicate.
4702 static int /* O - 1 on match, 0 on non-match */
4704 cups_array_t
*errors
, /* I - Errors array */
4705 ipp_attribute_t
*fromattr
, /* I - "From" attribute */
4706 ipp_attribute_t
*attr
, /* I - Attribute to compare */
4707 char *matchbuf
, /* I - Buffer to hold matching value */
4708 size_t matchlen
) /* I - Length of match buffer */
4710 int i
, j
, /* Looping vars */
4711 count
= ippGetCount(attr
), /* Number of attribute values */
4712 match
= 1; /* Match? */
4718 * Compare the from value(s) to the attribute value(s)...
4721 switch (ippGetValueTag(attr
))
4723 case IPP_TAG_INTEGER
:
4724 if (ippGetValueTag(fromattr
) != IPP_TAG_INTEGER
&& ippGetValueTag(fromattr
) != IPP_TAG_RANGE
)
4725 goto wrong_value_tag
;
4727 for (i
= 0; i
< count
; i
++)
4729 int value
= ippGetInteger(attr
, i
);
4730 /* Current integer value */
4732 if (ippContainsInteger(fromattr
, value
))
4735 snprintf(matchbuf
, matchlen
, "%d", value
);
4739 add_stringf(errors
, "GOT: %s=%d", ippGetName(attr
), value
);
4746 if (ippGetValueTag(fromattr
) != IPP_TAG_ENUM
)
4747 goto wrong_value_tag
;
4749 for (i
= 0; i
< count
; i
++)
4751 int value
= ippGetInteger(attr
, i
);
4752 /* Current integer value */
4754 if (ippContainsInteger(fromattr
, value
))
4757 snprintf(matchbuf
, matchlen
, "%d", value
);
4761 add_stringf(errors
, "GOT: %s=%d", ippGetName(attr
), value
);
4767 case IPP_TAG_RESOLUTION
:
4768 if (ippGetValueTag(fromattr
) != IPP_TAG_RESOLUTION
)
4769 goto wrong_value_tag
;
4771 for (i
= 0; i
< count
; i
++)
4775 int fromcount
= ippGetCount(fromattr
);
4776 int fromxres
, fromyres
;
4777 ipp_res_t fromunits
;
4779 xres
= ippGetResolution(attr
, i
, &yres
, &units
);
4781 for (j
= 0; j
< fromcount
; j
++)
4783 fromxres
= ippGetResolution(fromattr
, j
, &fromyres
, &fromunits
);
4784 if (fromxres
== xres
&& fromyres
== yres
&& fromunits
== units
)
4793 snprintf(matchbuf
, matchlen
, "%d%s", xres
, units
== IPP_RES_PER_INCH
? "dpi" : "dpcm");
4795 snprintf(matchbuf
, matchlen
, "%dx%d%s", xres
, yres
, units
== IPP_RES_PER_INCH
? "dpi" : "dpcm");
4801 add_stringf(errors
, "GOT: %s=%d%s", ippGetName(attr
), xres
, units
== IPP_RES_PER_INCH
? "dpi" : "dpcm");
4803 add_stringf(errors
, "GOT: %s=%dx%d%s", ippGetName(attr
), xres
, yres
, units
== IPP_RES_PER_INCH
? "dpi" : "dpcm");
4810 case IPP_TAG_NOVALUE
:
4811 case IPP_TAG_UNKNOWN
:
4814 case IPP_TAG_CHARSET
:
4815 case IPP_TAG_KEYWORD
:
4816 case IPP_TAG_LANGUAGE
:
4817 case IPP_TAG_MIMETYPE
:
4819 case IPP_TAG_NAMELANG
:
4821 case IPP_TAG_TEXTLANG
:
4822 case IPP_TAG_URISCHEME
:
4823 for (i
= 0; i
< count
; i
++)
4825 const char *value
= ippGetString(attr
, i
, NULL
);
4826 /* Current string value */
4828 if (ippContainsString(fromattr
, value
))
4831 strlcpy(matchbuf
, value
, matchlen
);
4835 add_stringf(errors
, "GOT: %s='%s'", ippGetName(attr
), value
);
4842 for (i
= 0; i
< count
; i
++)
4844 const char *value
= ippGetString(attr
, i
, NULL
);
4845 /* Current string value */
4846 int fromcount
= ippGetCount(fromattr
);
4848 for (j
= 0; j
< fromcount
; j
++)
4850 if (!compare_uris(value
, ippGetString(fromattr
, j
, NULL
)))
4853 strlcpy(matchbuf
, value
, matchlen
);
4860 add_stringf(errors
, "GOT: %s='%s'", ippGetName(attr
), value
);
4873 /* value tag mismatch between fromattr and attr */
4876 add_stringf(errors
, "GOT: %s OF-TYPE %s", ippGetName(attr
), ippTagString(ippGetValueTag(attr
)));