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 #include <cups/cups-private.h>
29 #endif /* !O_BINARY */
36 typedef enum _cups_transfer_e
/**** How to send request data ****/
38 _CUPS_TRANSFER_AUTO
, /* Chunk for files, length for static */
39 _CUPS_TRANSFER_CHUNKED
, /* Chunk always */
40 _CUPS_TRANSFER_LENGTH
/* Length always */
43 typedef enum _cups_output_e
/**** Output mode ****/
45 _CUPS_OUTPUT_QUIET
, /* No output */
46 _CUPS_OUTPUT_TEST
, /* Traditional CUPS test output */
47 _CUPS_OUTPUT_PLIST
, /* XML plist test output */
48 _CUPS_OUTPUT_IPPSERVER
, /* ippserver attribute file output */
49 _CUPS_OUTPUT_LIST
, /* Tabular list output */
50 _CUPS_OUTPUT_CSV
/* Comma-separated values output */
53 typedef enum _cups_with_e
/**** WITH flags ****/
55 _CUPS_WITH_LITERAL
= 0, /* Match string is a literal value */
56 _CUPS_WITH_ALL
= 1, /* Must match all values */
57 _CUPS_WITH_REGEX
= 2, /* Match string is a regular expression */
58 _CUPS_WITH_HOSTNAME
= 4, /* Match string is a URI hostname */
59 _CUPS_WITH_RESOURCE
= 8, /* Match string is a URI resource */
60 _CUPS_WITH_SCHEME
= 16 /* Match string is a URI scheme */
63 typedef struct _cups_expect_s
/**** Expected attribute info ****/
65 int optional
, /* Optional attribute? */
66 not_expect
, /* Don't expect attribute? */
67 expect_all
; /* Expect all attributes to match/not match */
68 char *name
, /* Attribute name */
69 *of_type
, /* Type name */
70 *same_count_as
, /* Parallel attribute name */
71 *if_defined
, /* Only required if variable defined */
72 *if_not_defined
, /* Only required if variable is not defined */
73 *with_value
, /* Attribute must include this value */
74 *with_value_from
, /* Attribute must have one of the values in this attribute */
75 *define_match
, /* Variable to define on match */
76 *define_no_match
, /* Variable to define on no-match */
77 *define_value
; /* Variable to define with value */
78 int repeat_limit
, /* Maximum number of times to repeat */
79 repeat_match
, /* Repeat test on match */
80 repeat_no_match
, /* Repeat test on no match */
81 with_flags
, /* WITH flags */
82 count
; /* Expected count if > 0 */
83 ipp_tag_t in_group
; /* IN-GROUP value */
86 typedef struct _cups_status_s
/**** Status info ****/
88 ipp_status_t status
; /* Expected status code */
89 char *if_defined
, /* Only if variable is defined */
90 *if_not_defined
, /* Only if variable is not defined */
91 *define_match
, /* Variable to define on match */
92 *define_no_match
, /* Variable to define on no-match */
93 *define_value
; /* Variable to define with value */
94 int repeat_limit
, /* Maximum number of times to repeat */
95 repeat_match
, /* Repeat the test when it does not match */
96 repeat_no_match
; /* Repeat the test when it matches */
99 typedef struct _cups_testdata_s
/**** Test Data ****/
102 http_encryption_t encryption
; /* Encryption for connection */
103 int family
; /* Address family */
104 _cups_output_t output
; /* Output mode */
105 int stop_after_include_error
;
106 /* Stop after include errors? */
107 double timeout
; /* Timeout for connection */
108 int validate_headers
, /* Validate HTTP headers in response? */
109 verbosity
; /* Show all attributes? */
112 int def_ignore_errors
; /* Default IGNORE-ERRORS value */
113 _cups_transfer_t def_transfer
; /* Default TRANSFER value */
114 int def_version
; /* Default IPP version */
117 http_t
*http
; /* HTTP connection to printer/server */
118 cups_file_t
*outfile
; /* Output file */
119 int show_header
, /* Show the test header? */
120 xml_header
; /* 1 if XML plist header was written */
121 int pass
, /* Have we passed all tests? */
122 test_count
, /* Number of tests (total) */
123 pass_count
, /* Number of tests that passed */
124 fail_count
, /* Number of tests that failed */
125 skip_count
; /* Number of tests that were skipped */
128 cups_array_t
*errors
; /* Errors array */
129 int prev_pass
, /* Result of previous test */
130 skip_previous
; /* Skip on previous test failure? */
131 char compression
[16]; /* COMPRESSION value */
132 useconds_t delay
; /* Initial delay */
133 int num_displayed
; /* Number of displayed attributes */
134 char *displayed
[200]; /* Displayed attributes */
135 int num_expects
; /* Number of expected attributes */
136 _cups_expect_t expects
[200], /* Expected attributes */
137 *expect
, /* Current expected attribute */
138 *last_expect
; /* Last EXPECT (for predicates) */
139 char file
[1024], /* Data filename */
140 file_id
[1024]; /* File identifier */
141 int ignore_errors
; /* Ignore test failures? */
142 char name
[1024]; /* Test name */
143 useconds_t repeat_interval
; /* Repeat interval (delay) */
144 int request_id
; /* Current request ID */
145 char resource
[512]; /* Resource for request */
146 int skip_test
, /* Skip this test? */
147 num_statuses
; /* Number of valid status codes */
148 _cups_status_t statuses
[100], /* Valid status codes */
149 *last_status
; /* Last STATUS (for predicates) */
150 char test_id
[1024]; /* Test identifier */
151 _cups_transfer_t transfer
; /* To chunk or not to chunk */
152 int version
; /* IPP version number to use */
160 static int Cancel
= 0; /* Cancel test? */
167 static void add_stringf(cups_array_t
*a
, const char *s
, ...) _CUPS_FORMAT(2, 3);
168 static int compare_uris(const char *a
, const char *b
);
169 static void copy_hex_string(char *buffer
, unsigned char *data
, int datalen
, size_t bufsize
);
170 static int do_test(_ipp_file_t
*f
, _ipp_vars_t
*vars
, _cups_testdata_t
*data
);
171 static int do_tests(const char *testfile
, _ipp_vars_t
*vars
, _cups_testdata_t
*data
);
172 static int error_cb(_ipp_file_t
*f
, _cups_testdata_t
*data
, const char *error
);
173 static int expect_matches(_cups_expect_t
*expect
, ipp_tag_t value_tag
);
174 static char *get_filename(const char *testfile
, char *dst
, const char *src
, size_t dstsize
);
175 static const char *get_string(ipp_attribute_t
*attr
, int element
, int flags
, char *buffer
, size_t bufsize
);
176 static void init_data(_cups_testdata_t
*data
);
177 static char *iso_date(const ipp_uchar_t
*date
);
178 static void pause_message(const char *message
);
179 static void print_attr(cups_file_t
*outfile
, int output
, ipp_attribute_t
*attr
, ipp_tag_t
*group
);
180 static void print_csv(_cups_testdata_t
*data
, ipp_t
*ipp
, ipp_attribute_t
*attr
, int num_displayed
, char **displayed
, size_t *widths
);
181 static void print_fatal_error(_cups_testdata_t
*data
, const char *s
, ...) _CUPS_FORMAT(2, 3);
182 static void print_ippserver_attr(_cups_testdata_t
*data
, ipp_attribute_t
*attr
, int indent
);
183 static void print_ippserver_string(_cups_testdata_t
*data
, const char *s
, size_t len
);
184 static void print_line(_cups_testdata_t
*data
, ipp_t
*ipp
, ipp_attribute_t
*attr
, int num_displayed
, char **displayed
, size_t *widths
);
185 static void print_xml_header(_cups_testdata_t
*data
);
186 static void print_xml_string(cups_file_t
*outfile
, const char *element
, const char *s
);
187 static void print_xml_trailer(_cups_testdata_t
*data
, int success
, const char *message
);
189 static void sigterm_handler(int sig
);
191 static int timeout_cb(http_t
*http
, void *user_data
);
192 static int token_cb(_ipp_file_t
*f
, _ipp_vars_t
*vars
, _cups_testdata_t
*data
, const char *token
);
193 static void usage(void) _CUPS_NORETURN
;
194 static const char *with_flags_string(int flags
);
195 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
);
196 static int with_value_from(cups_array_t
*errors
, ipp_attribute_t
*fromattr
, ipp_attribute_t
*attr
, char *matchbuf
, size_t matchlen
);
200 * 'main()' - Parse options and do tests.
203 int /* O - Exit status */
204 main(int argc
, /* I - Number of command-line args */
205 char *argv
[]) /* I - Command-line arguments */
207 int i
; /* Looping var */
208 int status
; /* Status of tests... */
209 char *opt
, /* Current option */
210 name
[1024], /* Name/value buffer */
211 *value
, /* Pointer to value */
212 filename
[1024], /* Real filename */
213 testname
[1024]; /* Real test filename */
214 const char *ext
, /* Extension on filename */
215 *testfile
; /* Test file to use */
216 int interval
, /* Test interval in microseconds */
217 repeat
; /* Repeat count */
218 _cups_testdata_t data
; /* Test data */
219 _ipp_vars_t vars
; /* Variables */
220 _cups_globals_t
*cg
= _cupsGlobals();
226 * Catch SIGINT and SIGTERM...
229 signal(SIGINT
, sigterm_handler
);
230 signal(SIGTERM
, sigterm_handler
);
234 * Initialize the locale and variables...
237 _cupsSetLocale(argv
);
241 _ippVarsInit(&vars
, NULL
, (_ipp_ferror_cb_t
)error_cb
, (_ipp_ftoken_cb_t
)token_cb
);
246 * ipptool URI testfile
254 for (i
= 1; i
< argc
; i
++)
256 if (!strcmp(argv
[i
], "--help"))
260 else if (!strcmp(argv
[i
], "--ippserver"))
266 _cupsLangPuts(stderr
, _("ipptool: Missing filename for \"--ippserver\"."));
270 if (data
.outfile
!= cupsFileStdout())
273 if ((data
.outfile
= cupsFileOpen(argv
[i
], "w")) == NULL
)
275 _cupsLangPrintf(stderr
, _("%s: Unable to open \"%s\": %s"), "ipptool", argv
[i
], strerror(errno
));
279 data
.output
= _CUPS_OUTPUT_IPPSERVER
;
281 else if (!strcmp(argv
[i
], "--stop-after-include-error"))
283 data
.stop_after_include_error
= 1;
285 else if (!strcmp(argv
[i
], "--version"))
290 else if (argv
[i
][0] == '-')
292 for (opt
= argv
[i
] + 1; *opt
; opt
++)
296 case '4' : /* Connect using IPv4 only */
297 data
.family
= AF_INET
;
301 case '6' : /* Connect using IPv6 only */
302 data
.family
= AF_INET6
;
304 #endif /* AF_INET6 */
306 case 'C' : /* Enable HTTP chunking */
307 data
.def_transfer
= _CUPS_TRANSFER_CHUNKED
;
310 case 'E' : /* Encrypt with TLS */
312 data
.encryption
= HTTP_ENCRYPT_REQUIRED
;
314 _cupsLangPrintf(stderr
, _("%s: Sorry, no encryption support."),
316 #endif /* HAVE_SSL */
319 case 'I' : /* Ignore errors */
320 data
.def_ignore_errors
= 1;
323 case 'L' : /* Disable HTTP chunking */
324 data
.def_transfer
= _CUPS_TRANSFER_LENGTH
;
327 case 'P' : /* Output to plist file */
332 _cupsLangPrintf(stderr
, _("%s: Missing filename for \"-P\"."), "ipptool");
336 if (data
.outfile
!= cupsFileStdout())
339 if ((data
.outfile
= cupsFileOpen(argv
[i
], "w")) == NULL
)
341 _cupsLangPrintf(stderr
, _("%s: Unable to open \"%s\": %s"), "ipptool", argv
[i
], strerror(errno
));
345 data
.output
= _CUPS_OUTPUT_PLIST
;
347 if (interval
|| repeat
)
349 _cupsLangPuts(stderr
, _("ipptool: \"-i\" and \"-n\" are incompatible with \"-P\" and \"-X\"."));
354 case 'S' : /* Encrypt with SSL */
356 data
.encryption
= HTTP_ENCRYPT_ALWAYS
;
358 _cupsLangPrintf(stderr
, _("%s: Sorry, no encryption support."),
360 #endif /* HAVE_SSL */
363 case 'T' : /* Set timeout */
368 _cupsLangPrintf(stderr
,
369 _("%s: Missing timeout for \"-T\"."),
374 data
.timeout
= _cupsStrScand(argv
[i
], NULL
, localeconv());
377 case 'V' : /* Set IPP version */
382 _cupsLangPrintf(stderr
,
383 _("%s: Missing version for \"-V\"."),
388 if (!strcmp(argv
[i
], "1.0"))
390 data
.def_version
= 10;
392 else if (!strcmp(argv
[i
], "1.1"))
394 data
.def_version
= 11;
396 else if (!strcmp(argv
[i
], "2.0"))
398 data
.def_version
= 20;
400 else if (!strcmp(argv
[i
], "2.1"))
402 data
.def_version
= 21;
404 else if (!strcmp(argv
[i
], "2.2"))
406 data
.def_version
= 22;
410 _cupsLangPrintf(stderr
, _("%s: Bad version %s for \"-V\"."), "ipptool", argv
[i
]);
415 case 'X' : /* Produce XML output */
416 data
.output
= _CUPS_OUTPUT_PLIST
;
418 if (interval
|| repeat
)
420 _cupsLangPuts(stderr
, _("ipptool: \"-i\" and \"-n\" are incompatible with \"-P\" and \"-X\"."));
425 case 'c' : /* CSV output */
426 data
.output
= _CUPS_OUTPUT_CSV
;
429 case 'd' : /* Define a variable */
434 _cupsLangPuts(stderr
,
435 _("ipptool: Missing name=value for \"-d\"."));
439 strlcpy(name
, argv
[i
], sizeof(name
));
440 if ((value
= strchr(name
, '=')) != NULL
)
443 value
= name
+ strlen(name
);
445 _ippVarsSet(&vars
, name
, value
);
448 case 'f' : /* Set the default test filename */
453 _cupsLangPuts(stderr
,
454 _("ipptool: Missing filename for \"-f\"."));
458 if (access(argv
[i
], 0))
464 snprintf(filename
, sizeof(filename
), "%s.gz", argv
[i
]);
465 if (access(filename
, 0) && filename
[0] != '/'
467 && (!isalpha(filename
[0] & 255) || filename
[1] != ':')
471 snprintf(filename
, sizeof(filename
), "%s/ipptool/%s", cg
->cups_datadir
, argv
[i
]);
472 if (access(filename
, 0))
474 snprintf(filename
, sizeof(filename
), "%s/ipptool/%s.gz", cg
->cups_datadir
, argv
[i
]);
475 if (access(filename
, 0))
476 strlcpy(filename
, argv
[i
], sizeof(filename
));
481 strlcpy(filename
, argv
[i
], sizeof(filename
));
483 _ippVarsSet(&vars
, "filename", filename
);
485 if ((ext
= strrchr(filename
, '.')) != NULL
)
488 * Guess the MIME media type based on the extension...
491 if (!_cups_strcasecmp(ext
, ".gif"))
492 _ippVarsSet(&vars
, "filetype", "image/gif");
493 else if (!_cups_strcasecmp(ext
, ".htm") ||
494 !_cups_strcasecmp(ext
, ".htm.gz") ||
495 !_cups_strcasecmp(ext
, ".html") ||
496 !_cups_strcasecmp(ext
, ".html.gz"))
497 _ippVarsSet(&vars
, "filetype", "text/html");
498 else if (!_cups_strcasecmp(ext
, ".jpg") ||
499 !_cups_strcasecmp(ext
, ".jpeg"))
500 _ippVarsSet(&vars
, "filetype", "image/jpeg");
501 else if (!_cups_strcasecmp(ext
, ".pcl") ||
502 !_cups_strcasecmp(ext
, ".pcl.gz"))
503 _ippVarsSet(&vars
, "filetype", "application/vnd.hp-PCL");
504 else if (!_cups_strcasecmp(ext
, ".pdf"))
505 _ippVarsSet(&vars
, "filetype", "application/pdf");
506 else if (!_cups_strcasecmp(ext
, ".png"))
507 _ippVarsSet(&vars
, "filetype", "image/png");
508 else if (!_cups_strcasecmp(ext
, ".ps") ||
509 !_cups_strcasecmp(ext
, ".ps.gz"))
510 _ippVarsSet(&vars
, "filetype", "application/postscript");
511 else if (!_cups_strcasecmp(ext
, ".pwg") ||
512 !_cups_strcasecmp(ext
, ".pwg.gz") ||
513 !_cups_strcasecmp(ext
, ".ras") ||
514 !_cups_strcasecmp(ext
, ".ras.gz"))
515 _ippVarsSet(&vars
, "filetype", "image/pwg-raster");
516 else if (!_cups_strcasecmp(ext
, ".tif") ||
517 !_cups_strcasecmp(ext
, ".tiff"))
518 _ippVarsSet(&vars
, "filetype", "image/tiff");
519 else if (!_cups_strcasecmp(ext
, ".txt") ||
520 !_cups_strcasecmp(ext
, ".txt.gz"))
521 _ippVarsSet(&vars
, "filetype", "text/plain");
522 else if (!_cups_strcasecmp(ext
, ".urf") ||
523 !_cups_strcasecmp(ext
, ".urf.gz"))
524 _ippVarsSet(&vars
, "filetype", "image/urf");
525 else if (!_cups_strcasecmp(ext
, ".xps"))
526 _ippVarsSet(&vars
, "filetype", "application/openxps");
528 _ippVarsSet(&vars
, "filetype", "application/octet-stream");
533 * Use the "auto-type" MIME media type...
536 _ippVarsSet(&vars
, "filetype", "application/octet-stream");
540 case 'h' : /* Validate response headers */
541 data
.validate_headers
= 1;
544 case 'i' : /* Test every N seconds */
549 _cupsLangPuts(stderr
, _("ipptool: Missing seconds for \"-i\"."));
554 interval
= (int)(_cupsStrScand(argv
[i
], NULL
, localeconv()) * 1000000.0);
557 _cupsLangPuts(stderr
, _("ipptool: Invalid seconds for \"-i\"."));
562 if ((data
.output
== _CUPS_OUTPUT_PLIST
|| data
.output
== _CUPS_OUTPUT_IPPSERVER
) && interval
)
564 _cupsLangPuts(stderr
, _("ipptool: \"-i\" and \"-n\" are incompatible with \"--ippserver\", \"-P\", and \"-X\"."));
569 case 'l' : /* List as a table */
570 data
.output
= _CUPS_OUTPUT_LIST
;
573 case 'n' : /* Repeat count */
578 _cupsLangPuts(stderr
, _("ipptool: Missing count for \"-n\"."));
582 repeat
= atoi(argv
[i
]);
584 if ((data
.output
== _CUPS_OUTPUT_PLIST
|| data
.output
== _CUPS_OUTPUT_IPPSERVER
) && repeat
)
586 _cupsLangPuts(stderr
, _("ipptool: \"-i\" and \"-n\" are incompatible with \"--ippserver\", \"-P\", and \"-X\"."));
591 case 'q' : /* Be quiet */
592 data
.output
= _CUPS_OUTPUT_QUIET
;
595 case 't' : /* CUPS test output */
596 data
.output
= _CUPS_OUTPUT_TEST
;
599 case 'v' : /* Be verbose */
604 _cupsLangPrintf(stderr
, _("%s: Unknown option \"-%c\"."), "ipptool", *opt
);
609 else if (!strncmp(argv
[i
], "ipp://", 6) || !strncmp(argv
[i
], "http://", 7)
611 || !strncmp(argv
[i
], "ipps://", 7) || !strncmp(argv
[i
], "https://", 8)
612 #endif /* HAVE_SSL */
621 _cupsLangPuts(stderr
, _("ipptool: May only specify a single URI."));
626 if (!strncmp(argv
[i
], "ipps://", 7) || !strncmp(argv
[i
], "https://", 8))
627 data
.encryption
= HTTP_ENCRYPT_ALWAYS
;
628 #endif /* HAVE_SSL */
630 if (!_ippVarsSet(&vars
, "uri", argv
[i
]))
632 _cupsLangPrintf(stderr
, _("ipptool: Bad URI \"%s\"."), argv
[i
]);
636 if (vars
.username
[0] && vars
.password
)
637 cupsSetPasswordCB2(_ippVarsPasswordCB
, &vars
);
647 _cupsLangPuts(stderr
, _("ipptool: URI required before test file."));
648 _cupsLangPuts(stderr
, argv
[i
]);
652 if (access(argv
[i
], 0) && argv
[i
][0] != '/'
654 && (!isalpha(argv
[i
][0] & 255) || argv
[i
][1] != ':')
658 snprintf(testname
, sizeof(testname
), "%s/ipptool/%s", cg
->cups_datadir
, argv
[i
]);
659 if (access(testname
, 0))
667 if (!do_tests(testfile
, &vars
, &data
))
672 if (!vars
.uri
|| !testfile
)
676 * Loop if the interval is set...
679 if (data
.output
== _CUPS_OUTPUT_PLIST
)
680 print_xml_trailer(&data
, !status
, NULL
);
681 else if (interval
> 0 && repeat
> 0)
685 usleep((useconds_t
)interval
);
686 do_tests(testfile
, &vars
, &data
);
690 else if (interval
> 0)
694 usleep((useconds_t
)interval
);
695 do_tests(testfile
, &vars
, &data
);
699 if ((data
.output
== _CUPS_OUTPUT_TEST
|| (data
.output
== _CUPS_OUTPUT_PLIST
&& data
.outfile
)) && data
.test_count
> 1)
702 * Show a summary report if there were multiple tests...
705 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
);
708 cupsFileClose(data
.outfile
);
719 * 'add_stringf()' - Add a formatted string to an array.
723 add_stringf(cups_array_t
*a
, /* I - Array */
724 const char *s
, /* I - Printf-style format string */
725 ...) /* I - Additional args as needed */
727 char buffer
[10240]; /* Format buffer */
728 va_list ap
; /* Argument pointer */
732 * Don't bother is the array is NULL...
739 * Format the message...
743 vsnprintf(buffer
, sizeof(buffer
), s
, ap
);
747 * Add it to the array...
750 cupsArrayAdd(a
, buffer
);
755 * 'compare_uris()' - Compare two URIs...
758 static int /* O - Result of comparison */
759 compare_uris(const char *a
, /* I - First URI */
760 const char *b
) /* I - Second URI */
762 char ascheme
[32], /* Components of first URI */
767 char bscheme
[32], /* Components of second URI */
772 char *ptr
; /* Pointer into string */
773 int result
; /* Result of comparison */
777 * Separate the URIs into their components...
780 if (httpSeparateURI(HTTP_URI_CODING_ALL
, a
, ascheme
, sizeof(ascheme
), auserpass
, sizeof(auserpass
), ahost
, sizeof(ahost
), &aport
, aresource
, sizeof(aresource
)) < HTTP_URI_STATUS_OK
)
783 if (httpSeparateURI(HTTP_URI_CODING_ALL
, b
, bscheme
, sizeof(bscheme
), buserpass
, sizeof(buserpass
), bhost
, sizeof(bhost
), &bport
, bresource
, sizeof(bresource
)) < HTTP_URI_STATUS_OK
)
787 * Strip trailing dots from the host components, if present...
790 if ((ptr
= ahost
+ strlen(ahost
) - 1) > ahost
&& *ptr
== '.')
793 if ((ptr
= bhost
+ strlen(bhost
) - 1) > bhost
&& *ptr
== '.')
797 * Compare each component...
800 if ((result
= _cups_strcasecmp(ascheme
, bscheme
)) != 0)
803 if ((result
= strcmp(auserpass
, buserpass
)) != 0)
806 if ((result
= _cups_strcasecmp(ahost
, bhost
)) != 0)
810 return (aport
- bport
);
812 if (!_cups_strcasecmp(ascheme
, "mailto") || !_cups_strcasecmp(ascheme
, "urn"))
813 return (_cups_strcasecmp(aresource
, bresource
));
815 return (strcmp(aresource
, bresource
));
820 * 'copy_hex_string()' - Copy an octetString to a C string and encode as hex if
825 copy_hex_string(char *buffer
, /* I - String buffer */
826 unsigned char *data
, /* I - octetString data */
827 int datalen
, /* I - octetString length */
828 size_t bufsize
) /* I - Size of string buffer */
830 char *bufptr
, /* Pointer into string buffer */
831 *bufend
= buffer
+ bufsize
- 2;
832 /* End of string buffer */
833 unsigned char *dataptr
, /* Pointer into octetString data */
834 *dataend
= data
+ datalen
;
835 /* End of octetString data */
836 static const char *hexdigits
= "0123456789ABCDEF";
841 * First see if there are any non-ASCII bytes in the octetString...
844 for (dataptr
= data
; dataptr
< dataend
; dataptr
++)
845 if (*dataptr
< 0x20 || *dataptr
>= 0x7f)
851 * Yes, encode as hex...
856 for (bufptr
= buffer
+ 1, dataptr
= data
; bufptr
< bufend
&& dataptr
< dataend
; dataptr
++)
858 *bufptr
++ = hexdigits
[*dataptr
>> 4];
859 *bufptr
++ = hexdigits
[*dataptr
& 15];
870 * No, copy as a string...
873 if ((size_t)datalen
> bufsize
)
874 datalen
= (int)bufsize
- 1;
876 memcpy(buffer
, data
, datalen
);
877 buffer
[datalen
] = '\0';
883 * 'do_test()' - Do a single test from the test file.
886 static int /* O - 1 on success, 0 on failure */
887 do_test(_ipp_file_t
*f
, /* I - IPP data file */
888 _ipp_vars_t
*vars
, /* I - IPP variables */
889 _cups_testdata_t
*data
) /* I - Test data */
892 int i
, /* Looping var */
893 status_ok
, /* Did we get a matching status? */
894 repeat_count
= 0, /* Repeat count */
895 repeat_test
; /* Repeat the test? */
896 _cups_expect_t
*expect
; /* Current expected attribute */
897 ipp_t
*request
, /* IPP request */
898 *response
; /* IPP response */
899 size_t length
; /* Length of IPP request */
900 http_status_t status
; /* HTTP status */
901 cups_array_t
*a
; /* Duplicate attribute array */
902 ipp_tag_t group
; /* Current group */
903 ipp_attribute_t
*attrptr
, /* Attribute pointer */
904 *found
; /* Found attribute */
905 char temp
[1024]; /* Temporary string */
906 cups_file_t
*reqfile
; /* File to send */
907 ssize_t bytes
; /* Bytes read/written */
908 char buffer
[131072]; /* Copy buffer */
909 size_t widths
[200]; /* Width of columns */
910 const char *error
; /* Current error */
917 * Take over control of the attributes in the request...
924 * Submit the IPP request...
929 ippSetVersion(request
, data
->version
/ 10, data
->version
% 10);
930 ippSetRequestId(request
, data
->request_id
);
932 if (data
->output
== _CUPS_OUTPUT_PLIST
)
934 cupsFilePuts(data
->outfile
, "<dict>\n");
935 cupsFilePuts(data
->outfile
, "<key>Name</key>\n");
936 print_xml_string(data
->outfile
, "string", data
->name
);
937 if (data
->file_id
[0])
939 cupsFilePuts(data
->outfile
, "<key>FileId</key>\n");
940 print_xml_string(data
->outfile
, "string", data
->file_id
);
942 if (data
->test_id
[0])
944 cupsFilePuts(data
->outfile
, "<key>TestId</key>\n");
945 print_xml_string(data
->outfile
, "string", data
->test_id
);
947 cupsFilePuts(data
->outfile
, "<key>Version</key>\n");
948 cupsFilePrintf(data
->outfile
, "<string>%d.%d</string>\n", data
->version
/ 10, data
->version
% 10);
949 cupsFilePuts(data
->outfile
, "<key>Operation</key>\n");
950 print_xml_string(data
->outfile
, "string", ippOpString(ippGetOperation(request
)));
951 cupsFilePuts(data
->outfile
, "<key>RequestId</key>\n");
952 cupsFilePrintf(data
->outfile
, "<integer>%d</integer>\n", data
->request_id
);
953 cupsFilePuts(data
->outfile
, "<key>RequestAttributes</key>\n");
954 cupsFilePuts(data
->outfile
, "<array>\n");
955 if (ippFirstAttribute(request
))
957 cupsFilePuts(data
->outfile
, "<dict>\n");
958 for (attrptr
= ippFirstAttribute(request
), group
= ippGetGroupTag(attrptr
); attrptr
; attrptr
= ippNextAttribute(request
))
959 print_attr(data
->outfile
, data
->output
, attrptr
, &group
);
960 cupsFilePuts(data
->outfile
, "</dict>\n");
962 cupsFilePuts(data
->outfile
, "</array>\n");
965 if (data
->output
== _CUPS_OUTPUT_TEST
|| (data
->output
== _CUPS_OUTPUT_PLIST
&& data
->outfile
!= cupsFileStdout()))
969 cupsFilePrintf(cupsFileStdout(), " %s:\n", ippOpString(ippGetOperation(request
)));
971 for (attrptr
= ippFirstAttribute(request
); attrptr
; attrptr
= ippNextAttribute(request
))
972 print_attr(cupsFileStdout(), _CUPS_OUTPUT_TEST
, attrptr
, NULL
);
975 cupsFilePrintf(cupsFileStdout(), " %-68.68s [", data
->name
);
978 if ((data
->skip_previous
&& !data
->prev_pass
) || data
->skip_test
)
986 if (data
->output
== _CUPS_OUTPUT_PLIST
)
988 cupsFilePuts(data
->outfile
, "<key>Successful</key>\n");
989 cupsFilePuts(data
->outfile
, "<true />\n");
990 cupsFilePuts(data
->outfile
, "<key>Skipped</key>\n");
991 cupsFilePuts(data
->outfile
, "<true />\n");
992 cupsFilePuts(data
->outfile
, "<key>StatusCode</key>\n");
993 print_xml_string(data
->outfile
, "string", "skip");
994 cupsFilePuts(data
->outfile
, "<key>ResponseAttributes</key>\n");
995 cupsFilePuts(data
->outfile
, "<dict />\n");
998 if (data
->output
== _CUPS_OUTPUT_TEST
|| (data
->output
== _CUPS_OUTPUT_PLIST
&& data
->outfile
!= cupsFileStdout()))
999 cupsFilePuts(cupsFileStdout(), "SKIP]\n");
1004 vars
->password_tries
= 0;
1008 if (data
->delay
> 0)
1009 usleep(data
->delay
);
1011 data
->delay
= data
->repeat_interval
;
1014 status
= HTTP_STATUS_OK
;
1016 if (data
->transfer
== _CUPS_TRANSFER_CHUNKED
|| (data
->transfer
== _CUPS_TRANSFER_AUTO
&& data
->file
[0]))
1019 * Send request using chunking - a 0 length means "chunk".
1027 * Send request using content length...
1030 length
= ippLength(request
);
1032 if (data
->file
[0] && (reqfile
= cupsFileOpen(data
->file
, "r")) != NULL
)
1035 * Read the file to get the uncompressed file size...
1038 while ((bytes
= cupsFileRead(reqfile
, buffer
, sizeof(buffer
))) > 0)
1039 length
+= (size_t)bytes
;
1041 cupsFileClose(reqfile
);
1046 * Send the request...
1049 data
->prev_pass
= 1;
1053 if (status
!= HTTP_STATUS_ERROR
)
1055 while (!response
&& !Cancel
&& data
->prev_pass
)
1057 status
= cupsSendRequest(data
->http
, request
, data
->resource
, length
);
1060 if (data
->compression
[0])
1061 httpSetField(data
->http
, HTTP_FIELD_CONTENT_ENCODING
, data
->compression
);
1062 #endif /* HAVE_LIBZ */
1064 if (!Cancel
&& status
== HTTP_STATUS_CONTINUE
&& ippGetState(request
) == IPP_DATA
&& data
->file
[0])
1066 if ((reqfile
= cupsFileOpen(data
->file
, "r")) != NULL
)
1068 while (!Cancel
&& (bytes
= cupsFileRead(reqfile
, buffer
, sizeof(buffer
))) > 0)
1070 if ((status
= cupsWriteRequestData(data
->http
, buffer
, (size_t)bytes
)) != HTTP_STATUS_CONTINUE
)
1074 cupsFileClose(reqfile
);
1078 snprintf(buffer
, sizeof(buffer
), "%s: %s", data
->file
, strerror(errno
));
1079 _cupsSetError(IPP_INTERNAL_ERROR
, buffer
, 0);
1081 status
= HTTP_STATUS_ERROR
;
1086 * Get the server's response...
1089 if (!Cancel
&& status
!= HTTP_STATUS_ERROR
)
1091 response
= cupsGetResponse(data
->http
, data
->resource
);
1092 status
= httpGetStatus(data
->http
);
1095 if (!Cancel
&& status
== HTTP_STATUS_ERROR
&& httpError(data
->http
) != EINVAL
&&
1097 httpError(data
->http
) != WSAETIMEDOUT
)
1099 httpError(data
->http
) != ETIMEDOUT
)
1102 if (httpReconnect2(data
->http
, 30000, NULL
))
1103 data
->prev_pass
= 0;
1105 else if (status
== HTTP_STATUS_ERROR
|| status
== HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED
)
1107 data
->prev_pass
= 0;
1110 else if (status
!= HTTP_STATUS_OK
)
1112 httpFlush(data
->http
);
1114 if (status
== HTTP_STATUS_UNAUTHORIZED
)
1122 if (!Cancel
&& status
== HTTP_STATUS_ERROR
&& httpError(data
->http
) != EINVAL
&&
1124 httpError(data
->http
) != WSAETIMEDOUT
)
1126 httpError(data
->http
) != ETIMEDOUT
)
1129 if (httpReconnect2(data
->http
, 30000, NULL
))
1130 data
->prev_pass
= 0;
1132 else if (status
== HTTP_STATUS_ERROR
)
1135 httpReconnect2(data
->http
, 30000, NULL
);
1137 data
->prev_pass
= 0;
1139 else if (status
!= HTTP_STATUS_OK
)
1141 httpFlush(data
->http
);
1142 data
->prev_pass
= 0;
1146 * Check results of request...
1149 cupsArrayClear(data
->errors
);
1151 if (httpGetVersion(data
->http
) != HTTP_1_1
)
1153 int version
= httpGetVersion(data
->http
);
1155 add_stringf(data
->errors
, "Bad HTTP version (%d.%d)", version
/ 100, version
% 100);
1158 if (data
->validate_headers
)
1160 const char *header
; /* HTTP header value */
1162 if ((header
= httpGetField(data
->http
, HTTP_FIELD_CONTENT_TYPE
)) == NULL
|| _cups_strcasecmp(header
, "application/ipp"))
1163 add_stringf(data
->errors
, "Bad HTTP Content-Type in response (%s)", header
&& *header
? header
: "<missing>");
1165 if ((header
= httpGetField(data
->http
, HTTP_FIELD_DATE
)) != NULL
&& *header
&& httpGetDateTime(header
) == 0)
1166 add_stringf(data
->errors
, "Bad HTTP Date in response (%s)", header
);
1172 * No response, log error...
1175 add_stringf(data
->errors
, "IPP request failed with status %s (%s)", ippErrorString(cupsLastError()), cupsLastErrorString());
1180 * Collect common attribute values...
1183 if ((attrptr
= ippFindAttribute(response
, "job-id", IPP_TAG_INTEGER
)) != NULL
)
1185 snprintf(temp
, sizeof(temp
), "%d", ippGetInteger(attrptr
, 0));
1186 _ippVarsSet(vars
, "job-id", temp
);
1189 if ((attrptr
= ippFindAttribute(response
, "job-uri", IPP_TAG_URI
)) != NULL
)
1190 _ippVarsSet(vars
, "job-uri", ippGetString(attrptr
, 0, NULL
));
1192 if ((attrptr
= ippFindAttribute(response
, "notify-subscription-id", IPP_TAG_INTEGER
)) != NULL
)
1194 snprintf(temp
, sizeof(temp
), "%d", ippGetInteger(attrptr
, 0));
1195 _ippVarsSet(vars
, "notify-subscription-id", temp
);
1199 * Check response, validating groups and attributes and logging errors
1203 if (ippGetState(response
) != IPP_DATA
)
1204 add_stringf(data
->errors
, "Missing end-of-attributes-tag in response (RFC 2910 section 3.5.1)");
1208 int major
, minor
; /* IPP version */
1210 major
= ippGetVersion(response
, &minor
);
1212 if (major
!= (data
->version
/ 10) || minor
!= (data
->version
% 10))
1213 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);
1216 if (ippGetRequestId(response
) != data
->request_id
)
1217 add_stringf(data
->errors
, "Bad request ID %d in response - expected %d (RFC 2911 section 3.1.1)", ippGetRequestId(response
), data
->request_id
);
1219 attrptr
= ippFirstAttribute(response
);
1222 add_stringf(data
->errors
, "Missing first attribute \"attributes-charset (charset)\" in group operation-attributes-tag (RFC 2911 section 3.1.4).");
1226 if (!ippGetName(attrptr
) || ippGetValueTag(attrptr
) != IPP_TAG_CHARSET
|| ippGetGroupTag(attrptr
) != IPP_TAG_OPERATION
|| ippGetCount(attrptr
) != 1 ||strcmp(ippGetName(attrptr
), "attributes-charset"))
1227 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
)));
1229 attrptr
= ippNextAttribute(response
);
1231 add_stringf(data
->errors
, "Missing second attribute \"attributes-natural-language (naturalLanguage)\" in group operation-attributes-tag (RFC 2911 section 3.1.4).");
1232 else if (!ippGetName(attrptr
) || ippGetValueTag(attrptr
) != IPP_TAG_LANGUAGE
|| ippGetGroupTag(attrptr
) != IPP_TAG_OPERATION
|| ippGetCount(attrptr
) != 1 || strcmp(ippGetName(attrptr
), "attributes-natural-language"))
1233 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
)));
1236 if ((attrptr
= ippFindAttribute(response
, "status-message", IPP_TAG_ZERO
)) != NULL
)
1238 const char *status_message
= ippGetString(attrptr
, 0, NULL
);
1241 if (ippGetValueTag(attrptr
) != IPP_TAG_TEXT
)
1242 add_stringf(data
->errors
, "status-message (text(255)) has wrong value tag %s (RFC 2911 section 3.1.6.2).", ippTagString(ippGetValueTag(attrptr
)));
1243 if (ippGetGroupTag(attrptr
) != IPP_TAG_OPERATION
)
1244 add_stringf(data
->errors
, "status-message (text(255)) has wrong group tag %s (RFC 2911 section 3.1.6.2).", ippTagString(ippGetGroupTag(attrptr
)));
1245 if (ippGetCount(attrptr
) != 1)
1246 add_stringf(data
->errors
, "status-message (text(255)) has %d values (RFC 2911 section 3.1.6.2).", ippGetCount(attrptr
));
1247 if (status_message
&& strlen(status_message
) > 255)
1248 add_stringf(data
->errors
, "status-message (text(255)) has bad length %d (RFC 2911 section 3.1.6.2).", (int)strlen(status_message
));
1251 if ((attrptr
= ippFindAttribute(response
, "detailed-status-message",
1252 IPP_TAG_ZERO
)) != NULL
)
1254 const char *detailed_status_message
= ippGetString(attrptr
, 0, NULL
);
1257 if (ippGetValueTag(attrptr
) != IPP_TAG_TEXT
)
1258 add_stringf(data
->errors
,
1259 "detailed-status-message (text(MAX)) has wrong "
1260 "value tag %s (RFC 2911 section 3.1.6.3).",
1261 ippTagString(ippGetValueTag(attrptr
)));
1262 if (ippGetGroupTag(attrptr
) != IPP_TAG_OPERATION
)
1263 add_stringf(data
->errors
,
1264 "detailed-status-message (text(MAX)) has wrong "
1265 "group tag %s (RFC 2911 section 3.1.6.3).",
1266 ippTagString(ippGetGroupTag(attrptr
)));
1267 if (ippGetCount(attrptr
) != 1)
1268 add_stringf(data
->errors
,
1269 "detailed-status-message (text(MAX)) has %d values"
1270 " (RFC 2911 section 3.1.6.3).",
1271 ippGetCount(attrptr
));
1272 if (detailed_status_message
&& strlen(detailed_status_message
) > 1023)
1273 add_stringf(data
->errors
,
1274 "detailed-status-message (text(MAX)) has bad "
1275 "length %d (RFC 2911 section 3.1.6.3).",
1276 (int)strlen(detailed_status_message
));
1279 a
= cupsArrayNew((cups_array_func_t
)strcmp
, NULL
);
1281 for (attrptr
= ippFirstAttribute(response
), group
= ippGetGroupTag(attrptr
);
1283 attrptr
= ippNextAttribute(response
))
1285 if (ippGetGroupTag(attrptr
) != group
)
1287 int out_of_order
= 0; /* Are attribute groups out-of-order? */
1290 switch (ippGetGroupTag(attrptr
))
1295 case IPP_TAG_OPERATION
:
1299 case IPP_TAG_UNSUPPORTED_GROUP
:
1300 if (group
!= IPP_TAG_OPERATION
)
1305 case IPP_TAG_PRINTER
:
1306 if (group
!= IPP_TAG_OPERATION
&& group
!= IPP_TAG_UNSUPPORTED_GROUP
)
1310 case IPP_TAG_SUBSCRIPTION
:
1311 if (group
> ippGetGroupTag(attrptr
) && group
!= IPP_TAG_DOCUMENT
)
1316 if (group
> ippGetGroupTag(attrptr
))
1322 add_stringf(data
->errors
, "Attribute groups out of order (%s < %s)",
1323 ippTagString(ippGetGroupTag(attrptr
)),
1324 ippTagString(group
));
1326 if (ippGetGroupTag(attrptr
) != IPP_TAG_ZERO
)
1327 group
= ippGetGroupTag(attrptr
);
1330 if (!ippValidateAttribute(attrptr
))
1331 cupsArrayAdd(data
->errors
, (void *)cupsLastErrorString());
1333 if (ippGetName(attrptr
))
1335 if (cupsArrayFind(a
, (void *)ippGetName(attrptr
)) && data
->output
< _CUPS_OUTPUT_LIST
)
1336 add_stringf(data
->errors
, "Duplicate \"%s\" attribute in %s group",
1337 ippGetName(attrptr
), ippTagString(group
));
1339 cupsArrayAdd(a
, (void *)ippGetName(attrptr
));
1346 * Now check the test-defined expected status-code and attribute
1350 for (i
= 0, status_ok
= 0; i
< data
->num_statuses
; i
++)
1352 if (data
->statuses
[i
].if_defined
&&
1353 !_ippVarsGet(vars
, data
->statuses
[i
].if_defined
))
1356 if (data
->statuses
[i
].if_not_defined
&&
1357 _ippVarsGet(vars
, data
->statuses
[i
].if_not_defined
))
1360 if (ippGetStatusCode(response
) == data
->statuses
[i
].status
)
1364 if (data
->statuses
[i
].repeat_match
&& repeat_count
< data
->statuses
[i
].repeat_limit
)
1367 if (data
->statuses
[i
].define_match
)
1368 _ippVarsSet(vars
, data
->statuses
[i
].define_match
, "1");
1372 if (data
->statuses
[i
].repeat_no_match
&& repeat_count
< data
->statuses
[i
].repeat_limit
)
1375 if (data
->statuses
[i
].define_no_match
)
1377 _ippVarsSet(vars
, data
->statuses
[i
].define_no_match
, "1");
1383 if (!status_ok
&& data
->num_statuses
> 0)
1385 for (i
= 0; i
< data
->num_statuses
; i
++)
1387 if (data
->statuses
[i
].if_defined
&&
1388 !_ippVarsGet(vars
, data
->statuses
[i
].if_defined
))
1391 if (data
->statuses
[i
].if_not_defined
&&
1392 _ippVarsGet(vars
, data
->statuses
[i
].if_not_defined
))
1395 if (!data
->statuses
[i
].repeat_match
|| repeat_count
>= data
->statuses
[i
].repeat_limit
)
1396 add_stringf(data
->errors
, "EXPECTED: STATUS %s (got %s)",
1397 ippErrorString(data
->statuses
[i
].status
),
1398 ippErrorString(cupsLastError()));
1401 if ((attrptr
= ippFindAttribute(response
, "status-message",
1402 IPP_TAG_TEXT
)) != NULL
)
1403 add_stringf(data
->errors
, "status-message=\"%s\"", ippGetString(attrptr
, 0, NULL
));
1406 for (i
= data
->num_expects
, expect
= data
->expects
; i
> 0; i
--, expect
++)
1408 ipp_attribute_t
*group_found
; /* Found parent attribute for group tests */
1410 if (expect
->if_defined
&& !_ippVarsGet(vars
, expect
->if_defined
))
1413 if (expect
->if_not_defined
&&
1414 _ippVarsGet(vars
, expect
->if_not_defined
))
1417 if ((found
= ippFindAttribute(response
, expect
->name
, IPP_TAG_ZERO
)) != NULL
&& expect
->in_group
&& expect
->in_group
!= ippGetGroupTag(found
))
1419 while ((found
= ippFindNextAttribute(response
, expect
->name
, IPP_TAG_ZERO
)) != NULL
)
1420 if (expect
->in_group
== ippGetGroupTag(found
))
1426 group_found
= found
;
1428 if (expect
->in_group
&& strchr(expect
->name
, '/'))
1430 char group_name
[256],/* Parent attribute name */
1431 *group_ptr
; /* Pointer into parent attribute name */
1433 strlcpy(group_name
, expect
->name
, sizeof(group_name
));
1434 if ((group_ptr
= strchr(group_name
, '/')) != NULL
)
1437 group_found
= ippFindAttribute(response
, group_name
, IPP_TAG_ZERO
);
1440 if ((found
&& expect
->not_expect
) ||
1441 (!found
&& !(expect
->not_expect
|| expect
->optional
)) ||
1442 (found
&& !expect_matches(expect
, ippGetValueTag(found
))) ||
1443 (group_found
&& expect
->in_group
&& ippGetGroupTag(group_found
) != expect
->in_group
))
1445 if (expect
->define_no_match
)
1446 _ippVarsSet(vars
, expect
->define_no_match
, "1");
1447 else if (!expect
->define_match
&& !expect
->define_value
)
1449 if (found
&& expect
->not_expect
)
1450 add_stringf(data
->errors
, "NOT EXPECTED: %s", expect
->name
);
1451 else if (!found
&& !(expect
->not_expect
|| expect
->optional
))
1452 add_stringf(data
->errors
, "EXPECTED: %s", expect
->name
);
1455 if (!expect_matches(expect
, ippGetValueTag(found
)))
1456 add_stringf(data
->errors
, "EXPECTED: %s OF-TYPE %s (got %s)",
1457 expect
->name
, expect
->of_type
,
1458 ippTagString(ippGetValueTag(found
)));
1460 if (expect
->in_group
&& ippGetGroupTag(group_found
) != expect
->in_group
)
1461 add_stringf(data
->errors
, "EXPECTED: %s IN-GROUP %s (got %s).",
1462 expect
->name
, ippTagString(expect
->in_group
),
1463 ippTagString(ippGetGroupTag(group_found
)));
1467 if (expect
->repeat_no_match
&& repeat_count
< expect
->repeat_limit
)
1473 ippAttributeString(found
, buffer
, sizeof(buffer
));
1475 if (found
&& expect
->with_value_from
&& !with_value_from(NULL
, ippFindAttribute(response
, expect
->with_value_from
, IPP_TAG_ZERO
), found
, buffer
, sizeof(buffer
)))
1477 if (expect
->define_no_match
)
1478 _ippVarsSet(vars
, expect
->define_no_match
, "1");
1479 else if (!expect
->define_match
&& !expect
->define_value
&& ((!expect
->repeat_match
&& !expect
->repeat_no_match
) || repeat_count
>= expect
->repeat_limit
))
1481 add_stringf(data
->errors
, "EXPECTED: %s WITH-VALUES-FROM %s", expect
->name
, expect
->with_value_from
);
1483 with_value_from(data
->errors
, ippFindAttribute(response
, expect
->with_value_from
, IPP_TAG_ZERO
), found
, buffer
, sizeof(buffer
));
1486 if (expect
->repeat_no_match
&& repeat_count
< expect
->repeat_limit
)
1491 else if (found
&& !with_value(data
, NULL
, expect
->with_value
, expect
->with_flags
, found
, buffer
, sizeof(buffer
)))
1493 if (expect
->define_no_match
)
1494 _ippVarsSet(vars
, expect
->define_no_match
, "1");
1495 else if (!expect
->define_match
&& !expect
->define_value
&&
1496 !expect
->repeat_match
&& (!expect
->repeat_no_match
|| repeat_count
>= expect
->repeat_limit
))
1498 if (expect
->with_flags
& _CUPS_WITH_REGEX
)
1499 add_stringf(data
->errors
, "EXPECTED: %s %s /%s/", expect
->name
, with_flags_string(expect
->with_flags
), expect
->with_value
);
1501 add_stringf(data
->errors
, "EXPECTED: %s %s \"%s\"", expect
->name
, with_flags_string(expect
->with_flags
), expect
->with_value
);
1503 with_value(data
, data
->errors
, expect
->with_value
, expect
->with_flags
, found
, buffer
, sizeof(buffer
));
1506 if (expect
->repeat_no_match
&&
1507 repeat_count
< expect
->repeat_limit
)
1513 if (found
&& expect
->count
> 0 && ippGetCount(found
) != expect
->count
)
1515 if (expect
->define_no_match
)
1516 _ippVarsSet(vars
, expect
->define_no_match
, "1");
1517 else if (!expect
->define_match
&& !expect
->define_value
)
1519 add_stringf(data
->errors
, "EXPECTED: %s COUNT %d (got %d)", expect
->name
,
1520 expect
->count
, ippGetCount(found
));
1523 if (expect
->repeat_no_match
&&
1524 repeat_count
< expect
->repeat_limit
)
1530 if (found
&& expect
->same_count_as
)
1532 attrptr
= ippFindAttribute(response
, expect
->same_count_as
,
1535 if (!attrptr
|| ippGetCount(attrptr
) != ippGetCount(found
))
1537 if (expect
->define_no_match
)
1538 _ippVarsSet(vars
, expect
->define_no_match
, "1");
1539 else if (!expect
->define_match
&& !expect
->define_value
)
1542 add_stringf(data
->errors
,
1543 "EXPECTED: %s (%d values) SAME-COUNT-AS %s "
1544 "(not returned)", expect
->name
,
1545 ippGetCount(found
), expect
->same_count_as
);
1546 else if (ippGetCount(attrptr
) != ippGetCount(found
))
1547 add_stringf(data
->errors
,
1548 "EXPECTED: %s (%d values) SAME-COUNT-AS %s "
1549 "(%d values)", expect
->name
, ippGetCount(found
),
1550 expect
->same_count_as
, ippGetCount(attrptr
));
1553 if (expect
->repeat_no_match
&&
1554 repeat_count
< expect
->repeat_limit
)
1561 if (found
&& expect
->define_match
)
1562 _ippVarsSet(vars
, expect
->define_match
, "1");
1564 if (found
&& expect
->define_value
)
1566 if (!expect
->with_value
)
1568 int last
= ippGetCount(found
) - 1;
1569 /* Last element in attribute */
1571 switch (ippGetValueTag(found
))
1574 case IPP_TAG_INTEGER
:
1575 snprintf(buffer
, sizeof(buffer
), "%d", ippGetInteger(found
, last
));
1578 case IPP_TAG_BOOLEAN
:
1579 if (ippGetBoolean(found
, last
))
1580 strlcpy(buffer
, "true", sizeof(buffer
));
1582 strlcpy(buffer
, "false", sizeof(buffer
));
1585 case IPP_TAG_RESOLUTION
:
1587 int xres
, /* Horizontal resolution */
1588 yres
; /* Vertical resolution */
1589 ipp_res_t units
; /* Resolution units */
1591 xres
= ippGetResolution(found
, last
, &yres
, &units
);
1594 snprintf(buffer
, sizeof(buffer
), "%d%s", xres
, units
== IPP_RES_PER_INCH
? "dpi" : "dpcm");
1596 snprintf(buffer
, sizeof(buffer
), "%dx%d%s", xres
, yres
, units
== IPP_RES_PER_INCH
? "dpi" : "dpcm");
1600 case IPP_TAG_CHARSET
:
1601 case IPP_TAG_KEYWORD
:
1602 case IPP_TAG_LANGUAGE
:
1603 case IPP_TAG_MIMETYPE
:
1605 case IPP_TAG_NAMELANG
:
1607 case IPP_TAG_TEXTLANG
:
1609 case IPP_TAG_URISCHEME
:
1610 strlcpy(buffer
, ippGetString(found
, last
, NULL
), sizeof(buffer
));
1614 ippAttributeString(found
, buffer
, sizeof(buffer
));
1619 _ippVarsSet(vars
, expect
->define_value
, buffer
);
1622 if (found
&& expect
->repeat_match
&&
1623 repeat_count
< expect
->repeat_limit
)
1626 while (expect
->expect_all
&& (found
= ippFindNextAttribute(response
, expect
->name
, IPP_TAG_ZERO
)) != NULL
);
1631 * If we are going to repeat this test, display intermediate results...
1636 if (data
->output
== _CUPS_OUTPUT_TEST
|| (data
->output
== _CUPS_OUTPUT_PLIST
&& data
->outfile
!= cupsFileStdout()))
1638 cupsFilePrintf(cupsFileStdout(), "%04d]\n", repeat_count
);
1640 if (data
->num_displayed
> 0)
1642 for (attrptr
= ippFirstAttribute(response
); attrptr
; attrptr
= ippNextAttribute(response
))
1644 const char *attrname
= ippGetName(attrptr
);
1647 for (i
= 0; i
< data
->num_displayed
; i
++)
1649 if (!strcmp(data
->displayed
[i
], attrname
))
1651 print_attr(cupsFileStdout(), _CUPS_OUTPUT_TEST
, attrptr
, NULL
);
1660 if (data
->output
== _CUPS_OUTPUT_TEST
|| (data
->output
== _CUPS_OUTPUT_PLIST
&& data
->outfile
!= cupsFileStdout()))
1662 cupsFilePrintf(cupsFileStdout(), " %-68.68s [", data
->name
);
1665 ippDelete(response
);
1669 while (repeat_test
);
1675 if (cupsArrayCount(data
->errors
) > 0)
1676 data
->prev_pass
= data
->pass
= 0;
1678 if (data
->prev_pass
)
1679 data
->pass_count
++;
1681 data
->fail_count
++;
1683 if (data
->output
== _CUPS_OUTPUT_PLIST
)
1685 cupsFilePuts(data
->outfile
, "<key>Successful</key>\n");
1686 cupsFilePuts(data
->outfile
, data
->prev_pass
? "<true />\n" : "<false />\n");
1687 cupsFilePuts(data
->outfile
, "<key>StatusCode</key>\n");
1688 print_xml_string(data
->outfile
, "string", ippErrorString(cupsLastError()));
1689 cupsFilePuts(data
->outfile
, "<key>ResponseAttributes</key>\n");
1690 cupsFilePuts(data
->outfile
, "<array>\n");
1691 cupsFilePuts(data
->outfile
, "<dict>\n");
1692 for (attrptr
= ippFirstAttribute(response
), group
= ippGetGroupTag(attrptr
);
1694 attrptr
= ippNextAttribute(response
))
1695 print_attr(data
->outfile
, data
->output
, attrptr
, &group
);
1696 cupsFilePuts(data
->outfile
, "</dict>\n");
1697 cupsFilePuts(data
->outfile
, "</array>\n");
1699 else if (data
->output
== _CUPS_OUTPUT_IPPSERVER
&& response
)
1701 for (attrptr
= ippFirstAttribute(response
); attrptr
; attrptr
= ippNextAttribute(response
))
1703 if (!ippGetName(attrptr
) || ippGetGroupTag(attrptr
) != IPP_TAG_PRINTER
)
1706 print_ippserver_attr(data
, attrptr
, 0);
1710 if (data
->output
== _CUPS_OUTPUT_TEST
|| (data
->output
== _CUPS_OUTPUT_PLIST
&& data
->outfile
!= cupsFileStdout()))
1712 cupsFilePuts(cupsFileStdout(), data
->prev_pass
? "PASS]\n" : "FAIL]\n");
1714 if (!data
->prev_pass
|| (data
->verbosity
&& response
))
1716 cupsFilePrintf(cupsFileStdout(), " RECEIVED: %lu bytes in response\n", (unsigned long)ippLength(response
));
1717 cupsFilePrintf(cupsFileStdout(), " status-code = %s (%s)\n", ippErrorString(cupsLastError()), cupsLastErrorString());
1719 if (data
->verbosity
&& response
)
1721 for (attrptr
= ippFirstAttribute(response
); attrptr
; attrptr
= ippNextAttribute(response
))
1722 print_attr(cupsFileStdout(), _CUPS_OUTPUT_TEST
, attrptr
, NULL
);
1726 else if (!data
->prev_pass
&& data
->output
!= _CUPS_OUTPUT_QUIET
)
1727 fprintf(stderr
, "%s\n", cupsLastErrorString());
1729 if (data
->prev_pass
&& data
->output
>= _CUPS_OUTPUT_LIST
&& !data
->verbosity
&& data
->num_displayed
> 0)
1731 size_t width
; /* Length of value */
1733 for (i
= 0; i
< data
->num_displayed
; i
++)
1735 widths
[i
] = strlen(data
->displayed
[i
]);
1737 for (attrptr
= ippFindAttribute(response
, data
->displayed
[i
], IPP_TAG_ZERO
);
1739 attrptr
= ippFindNextAttribute(response
, data
->displayed
[i
], IPP_TAG_ZERO
))
1741 width
= ippAttributeString(attrptr
, NULL
, 0);
1742 if (width
> widths
[i
])
1747 if (data
->output
== _CUPS_OUTPUT_CSV
)
1748 print_csv(data
, NULL
, NULL
, data
->num_displayed
, data
->displayed
, widths
);
1750 print_line(data
, NULL
, NULL
, data
->num_displayed
, data
->displayed
, widths
);
1752 attrptr
= ippFirstAttribute(response
);
1756 while (attrptr
&& ippGetGroupTag(attrptr
) <= IPP_TAG_OPERATION
)
1757 attrptr
= ippNextAttribute(response
);
1761 if (data
->output
== _CUPS_OUTPUT_CSV
)
1762 print_csv(data
, response
, attrptr
, data
->num_displayed
, data
->displayed
, widths
);
1764 print_line(data
, response
, attrptr
, data
->num_displayed
, data
->displayed
, widths
);
1766 while (attrptr
&& ippGetGroupTag(attrptr
) > IPP_TAG_OPERATION
)
1767 attrptr
= ippNextAttribute(response
);
1771 else if (!data
->prev_pass
)
1773 if (data
->output
== _CUPS_OUTPUT_PLIST
)
1775 cupsFilePuts(data
->outfile
, "<key>Errors</key>\n");
1776 cupsFilePuts(data
->outfile
, "<array>\n");
1778 for (error
= (char *)cupsArrayFirst(data
->errors
);
1780 error
= (char *)cupsArrayNext(data
->errors
))
1781 print_xml_string(data
->outfile
, "string", error
);
1783 cupsFilePuts(data
->outfile
, "</array>\n");
1786 if (data
->output
== _CUPS_OUTPUT_TEST
|| (data
->output
== _CUPS_OUTPUT_PLIST
&& data
->outfile
!= cupsFileStdout()))
1788 for (error
= (char *)cupsArrayFirst(data
->errors
);
1790 error
= (char *)cupsArrayNext(data
->errors
))
1791 cupsFilePrintf(cupsFileStdout(), " %s\n", error
);
1795 if (data
->num_displayed
> 0 && !data
->verbosity
&& response
&& (data
->output
== _CUPS_OUTPUT_TEST
|| (data
->output
== _CUPS_OUTPUT_PLIST
&& data
->outfile
!= cupsFileStdout())))
1797 for (attrptr
= ippFirstAttribute(response
); attrptr
; attrptr
= ippNextAttribute(response
))
1799 if (ippGetName(attrptr
))
1801 for (i
= 0; i
< data
->num_displayed
; i
++)
1803 if (!strcmp(data
->displayed
[i
], ippGetName(attrptr
)))
1805 print_attr(data
->outfile
, data
->output
, attrptr
, NULL
);
1815 if (data
->output
== _CUPS_OUTPUT_PLIST
)
1816 cupsFilePuts(data
->outfile
, "</dict>\n");
1818 ippDelete(response
);
1821 for (i
= 0; i
< data
->num_statuses
; i
++)
1823 if (data
->statuses
[i
].if_defined
)
1824 free(data
->statuses
[i
].if_defined
);
1825 if (data
->statuses
[i
].if_not_defined
)
1826 free(data
->statuses
[i
].if_not_defined
);
1827 if (data
->statuses
[i
].define_match
)
1828 free(data
->statuses
[i
].define_match
);
1829 if (data
->statuses
[i
].define_no_match
)
1830 free(data
->statuses
[i
].define_no_match
);
1832 data
->num_statuses
= 0;
1834 for (i
= data
->num_expects
, expect
= data
->expects
; i
> 0; i
--, expect
++)
1837 if (expect
->of_type
)
1838 free(expect
->of_type
);
1839 if (expect
->same_count_as
)
1840 free(expect
->same_count_as
);
1841 if (expect
->if_defined
)
1842 free(expect
->if_defined
);
1843 if (expect
->if_not_defined
)
1844 free(expect
->if_not_defined
);
1845 if (expect
->with_value
)
1846 free(expect
->with_value
);
1847 if (expect
->define_match
)
1848 free(expect
->define_match
);
1849 if (expect
->define_no_match
)
1850 free(expect
->define_no_match
);
1851 if (expect
->define_value
)
1852 free(expect
->define_value
);
1854 data
->num_expects
= 0;
1856 for (i
= 0; i
< data
->num_displayed
; i
++)
1857 free(data
->displayed
[i
]);
1858 data
->num_displayed
= 0;
1860 return (data
->ignore_errors
|| data
->prev_pass
);
1865 * 'do_tests()' - Do tests as specified in the test file.
1868 static int /* O - 1 on success, 0 on failure */
1869 do_tests(const char *testfile
, /* I - Test file to use */
1870 _ipp_vars_t
*vars
, /* I - Variables */
1871 _cups_testdata_t
*data
) /* I - Test data */
1873 http_encryption_t encryption
; /* Encryption mode */
1877 * Connect to the printer/server...
1880 if (!_cups_strcasecmp(vars
->scheme
, "https") || !_cups_strcasecmp(vars
->scheme
, "ipps"))
1881 encryption
= HTTP_ENCRYPTION_ALWAYS
;
1883 encryption
= data
->encryption
;
1885 if ((data
->http
= httpConnect2(vars
->host
, vars
->port
, NULL
, data
->family
, encryption
, 1, 30000, NULL
)) == NULL
)
1887 print_fatal_error(data
, "Unable to connect to \"%s\" on port %d - %s", vars
->host
, vars
->port
, cupsLastErrorString());
1892 httpSetDefaultField(data
->http
, HTTP_FIELD_ACCEPT_ENCODING
, "deflate, gzip, identity");
1894 httpSetDefaultField(data
->http
, HTTP_FIELD_ACCEPT_ENCODING
, "identity");
1895 #endif /* HAVE_LIBZ */
1897 if (data
->timeout
> 0.0)
1898 httpSetTimeout(data
->http
, data
->timeout
, timeout_cb
, NULL
);
1904 _ippFileParse(vars
, testfile
, (void *)data
);
1907 * Close connection and return...
1910 httpClose(data
->http
);
1913 return (data
->pass
);
1918 * 'error_cb()' - Print/add an error message.
1921 static int /* O - 1 to continue, 0 to stop */
1922 error_cb(_ipp_file_t
*f
, /* I - IPP file data */
1923 _cups_testdata_t
*data
, /* I - Test data */
1924 const char *error
) /* I - Error message */
1928 print_fatal_error(data
, "%s", error
);
1935 * 'expect_matches()' - Return true if the tag matches the specification.
1938 static int /* O - 1 if matches, 0 otherwise */
1940 _cups_expect_t
*expect
, /* I - Expected attribute */
1941 ipp_tag_t value_tag
) /* I - Value tag for attribute */
1943 int match
; /* Match? */
1944 char *of_type
, /* Type name to match */
1945 *next
, /* Next name to match */
1946 sep
; /* Separator character */
1950 * If we don't expect a particular type, return immediately...
1953 if (!expect
->of_type
)
1957 * Parse the "of_type" value since the string can contain multiple attribute
1958 * types separated by "," or "|"...
1961 for (of_type
= expect
->of_type
, match
= 0; !match
&& *of_type
; of_type
= next
)
1964 * Find the next separator, and set it (temporarily) to nul if present.
1967 for (next
= of_type
; *next
&& *next
!= '|' && *next
!= ','; next
++);
1969 if ((sep
= *next
) != '\0')
1973 * Support some meta-types to make it easier to write the test file.
1976 if (!strcmp(of_type
, "text"))
1977 match
= value_tag
== IPP_TAG_TEXTLANG
|| value_tag
== IPP_TAG_TEXT
;
1978 else if (!strcmp(of_type
, "name"))
1979 match
= value_tag
== IPP_TAG_NAMELANG
|| value_tag
== IPP_TAG_NAME
;
1980 else if (!strcmp(of_type
, "collection"))
1981 match
= value_tag
== IPP_TAG_BEGIN_COLLECTION
;
1983 match
= value_tag
== ippTagValue(of_type
);
1986 * Restore the separator if we have one...
1998 * 'get_filename()' - Get a filename based on the current test file.
2001 static char * /* O - Filename */
2002 get_filename(const char *testfile
, /* I - Current test file */
2003 char *dst
, /* I - Destination filename */
2004 const char *src
, /* I - Source filename */
2005 size_t dstsize
) /* I - Size of destination buffer */
2007 char *dstptr
; /* Pointer into destination */
2008 _cups_globals_t
*cg
= _cupsGlobals();
2012 if (*src
== '<' && src
[strlen(src
) - 1] == '>')
2015 * Map <filename> to CUPS_DATADIR/ipptool/filename...
2018 snprintf(dst
, dstsize
, "%s/ipptool/%s", cg
->cups_datadir
, src
+ 1);
2019 dstptr
= dst
+ strlen(dst
) - 1;
2023 else if (!access(src
, R_OK
) || *src
== '/'
2025 || (isalpha(*src
& 255) && src
[1] == ':')
2030 * Use the path as-is...
2033 strlcpy(dst
, src
, dstsize
);
2038 * Make path relative to testfile...
2041 strlcpy(dst
, testfile
, dstsize
);
2042 if ((dstptr
= strrchr(dst
, '/')) != NULL
)
2045 dstptr
= dst
; /* Should never happen */
2047 strlcpy(dstptr
, src
, dstsize
- (size_t)(dstptr
- dst
));
2055 * 'get_string()' - Get a pointer to a string value or the portion of interest.
2058 static const char * /* O - Pointer to string */
2059 get_string(ipp_attribute_t
*attr
, /* I - IPP attribute */
2060 int element
, /* I - Element to fetch */
2061 int flags
, /* I - Value ("with") flags */
2062 char *buffer
, /* I - Temporary buffer */
2063 size_t bufsize
) /* I - Size of temporary buffer */
2065 const char *value
; /* Value */
2066 char *ptr
, /* Pointer into value */
2067 scheme
[256], /* URI scheme */
2068 userpass
[256], /* Username/password */
2069 hostname
[256], /* Hostname */
2070 resource
[1024]; /* Resource */
2071 int port
; /* Port number */
2074 value
= ippGetString(attr
, element
, NULL
);
2076 if (flags
& _CUPS_WITH_HOSTNAME
)
2078 if (httpSeparateURI(HTTP_URI_CODING_ALL
, value
, scheme
, sizeof(scheme
), userpass
, sizeof(userpass
), buffer
, (int)bufsize
, &port
, resource
, sizeof(resource
)) < HTTP_URI_STATUS_OK
)
2081 ptr
= buffer
+ strlen(buffer
) - 1;
2082 if (ptr
>= buffer
&& *ptr
== '.')
2083 *ptr
= '\0'; /* Drop trailing "." */
2087 else if (flags
& _CUPS_WITH_RESOURCE
)
2089 if (httpSeparateURI(HTTP_URI_CODING_ALL
, value
, scheme
, sizeof(scheme
), userpass
, sizeof(userpass
), hostname
, sizeof(hostname
), &port
, buffer
, (int)bufsize
) < HTTP_URI_STATUS_OK
)
2094 else if (flags
& _CUPS_WITH_SCHEME
)
2096 if (httpSeparateURI(HTTP_URI_CODING_ALL
, value
, buffer
, (int)bufsize
, userpass
, sizeof(userpass
), hostname
, sizeof(hostname
), &port
, resource
, sizeof(resource
)) < HTTP_URI_STATUS_OK
)
2101 else if (ippGetValueTag(attr
) == IPP_TAG_URI
&& (!strncmp(value
, "ipp://", 6) || !strncmp(value
, "http://", 7) || !strncmp(value
, "ipps://", 7) || !strncmp(value
, "https://", 8)))
2103 http_uri_status_t status
= httpSeparateURI(HTTP_URI_CODING_ALL
, value
, scheme
, sizeof(scheme
), userpass
, sizeof(userpass
), hostname
, sizeof(hostname
), &port
, resource
, sizeof(resource
));
2105 if (status
< HTTP_URI_STATUS_OK
)
2116 * Normalize URI with no trailing dot...
2119 if ((ptr
= hostname
+ strlen(hostname
) - 1) >= hostname
&& *ptr
== '.')
2122 httpAssembleURI(HTTP_URI_CODING_ALL
, buffer
, (int)bufsize
, scheme
, userpass
, hostname
, port
, resource
);
2133 * 'init_data()' - Initialize test data.
2137 init_data(_cups_testdata_t
*data
) /* I - Data */
2139 memset(data
, 0, sizeof(_cups_testdata_t
));
2141 data
->output
= _CUPS_OUTPUT_LIST
;
2142 data
->outfile
= cupsFileStdout();
2143 data
->family
= AF_UNSPEC
;
2144 data
->def_transfer
= _CUPS_TRANSFER_AUTO
;
2145 data
->def_version
= 11;
2146 data
->errors
= cupsArrayNew3(NULL
, NULL
, NULL
, 0, (cups_acopy_func_t
)strdup
, (cups_afree_func_t
)free
);
2148 data
->prev_pass
= 1;
2149 data
->request_id
= (CUPS_RAND() % 1000) * 137 + 1;
2150 data
->show_header
= 1;
2155 * 'iso_date()' - Return an ISO 8601 date/time string for the given IPP dateTime
2159 static char * /* O - ISO 8601 date/time string */
2160 iso_date(const ipp_uchar_t
*date
) /* I - IPP (RFC 1903) date/time value */
2162 time_t utctime
; /* UTC time since 1970 */
2163 struct tm
*utcdate
; /* UTC date/time */
2164 static char buffer
[255]; /* String buffer */
2167 utctime
= ippDateToTime(date
);
2168 utcdate
= gmtime(&utctime
);
2170 snprintf(buffer
, sizeof(buffer
), "%04d-%02d-%02dT%02d:%02d:%02dZ",
2171 utcdate
->tm_year
+ 1900, utcdate
->tm_mon
+ 1, utcdate
->tm_mday
,
2172 utcdate
->tm_hour
, utcdate
->tm_min
, utcdate
->tm_sec
);
2179 * 'pause_message()' - Display the message and pause until the user presses a key.
2183 pause_message(const char *message
) /* I - Message */
2186 HANDLE tty
; /* Console handle */
2187 DWORD mode
; /* Console mode */
2188 char key
; /* Key press */
2189 DWORD bytes
; /* Bytes read for key press */
2193 * Disable input echo and set raw input...
2196 if ((tty
= GetStdHandle(STD_INPUT_HANDLE
)) == INVALID_HANDLE_VALUE
)
2199 if (!GetConsoleMode(tty
, &mode
))
2202 if (!SetConsoleMode(tty
, 0))
2206 int tty
; /* /dev/tty - never read from stdin */
2207 struct termios original
, /* Original input mode */
2208 noecho
; /* No echo input mode */
2209 char key
; /* Current key press */
2213 * Disable input echo and set raw input...
2216 if ((tty
= open("/dev/tty", O_RDONLY
)) < 0)
2219 if (tcgetattr(tty
, &original
))
2226 noecho
.c_lflag
&= (tcflag_t
)~(ICANON
| ECHO
| ECHOE
| ISIG
);
2228 if (tcsetattr(tty
, TCSAFLUSH
, &noecho
))
2236 * Display the prompt...
2239 cupsFilePrintf(cupsFileStdout(), "%s\n---- PRESS ANY KEY ----", message
);
2246 ReadFile(tty
, &key
, 1, &bytes
, NULL
);
2252 SetConsoleMode(tty
, mode
);
2265 tcsetattr(tty
, TCSAFLUSH
, &original
);
2270 * Erase the "press any key" prompt...
2273 cupsFilePuts(cupsFileStdout(), "\r \r");
2278 * 'print_attr()' - Print an attribute on the screen.
2282 print_attr(cups_file_t
*outfile
, /* I - Output file */
2283 int output
, /* I - Output format */
2284 ipp_attribute_t
*attr
, /* I - Attribute to print */
2285 ipp_tag_t
*group
) /* IO - Current group */
2287 int i
, /* Looping var */
2288 count
; /* Number of values */
2289 ipp_attribute_t
*colattr
; /* Collection attribute */
2292 if (output
== _CUPS_OUTPUT_PLIST
)
2294 if (!ippGetName(attr
) || (group
&& *group
!= ippGetGroupTag(attr
)))
2296 if (ippGetGroupTag(attr
) != IPP_TAG_ZERO
)
2298 cupsFilePuts(outfile
, "</dict>\n");
2299 cupsFilePuts(outfile
, "<dict>\n");
2303 *group
= ippGetGroupTag(attr
);
2306 if (!ippGetName(attr
))
2309 print_xml_string(outfile
, "key", ippGetName(attr
));
2310 if ((count
= ippGetCount(attr
)) > 1)
2311 cupsFilePuts(outfile
, "<array>\n");
2313 switch (ippGetValueTag(attr
))
2315 case IPP_TAG_INTEGER
:
2317 for (i
= 0; i
< count
; i
++)
2318 cupsFilePrintf(outfile
, "<integer>%d</integer>\n", ippGetInteger(attr
, i
));
2321 case IPP_TAG_BOOLEAN
:
2322 for (i
= 0; i
< count
; i
++)
2323 cupsFilePuts(outfile
, ippGetBoolean(attr
, i
) ? "<true />\n" : "<false />\n");
2326 case IPP_TAG_RANGE
:
2327 for (i
= 0; i
< count
; i
++)
2329 int lower
, upper
; /* Lower and upper ranges */
2331 lower
= ippGetRange(attr
, i
, &upper
);
2332 cupsFilePrintf(outfile
, "<dict><key>lower</key><integer>%d</integer><key>upper</key><integer>%d</integer></dict>\n", lower
, upper
);
2336 case IPP_TAG_RESOLUTION
:
2337 for (i
= 0; i
< count
; i
++)
2339 int xres
, yres
; /* Resolution values */
2340 ipp_res_t units
; /* Resolution units */
2342 xres
= ippGetResolution(attr
, i
, &yres
, &units
);
2343 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");
2348 for (i
= 0; i
< count
; i
++)
2349 cupsFilePrintf(outfile
, "<date>%s</date>\n", iso_date(ippGetDate(attr
, i
)));
2352 case IPP_TAG_STRING
:
2353 for (i
= 0; i
< count
; i
++)
2355 int datalen
; /* Length of data */
2356 void *data
= ippGetOctetString(attr
, i
, &datalen
);
2358 char buffer
[IPP_MAX_LENGTH
* 5 / 4 + 1];
2359 /* Base64 output buffer */
2361 cupsFilePrintf(outfile
, "<data>%s</data>\n", httpEncode64_2(buffer
, sizeof(buffer
), data
, datalen
));
2367 case IPP_TAG_KEYWORD
:
2369 case IPP_TAG_URISCHEME
:
2370 case IPP_TAG_CHARSET
:
2371 case IPP_TAG_LANGUAGE
:
2372 case IPP_TAG_MIMETYPE
:
2373 for (i
= 0; i
< count
; i
++)
2374 print_xml_string(outfile
, "string", ippGetString(attr
, i
, NULL
));
2377 case IPP_TAG_TEXTLANG
:
2378 case IPP_TAG_NAMELANG
:
2379 for (i
= 0; i
< count
; i
++)
2381 const char *s
, /* String */
2382 *lang
; /* Language */
2384 s
= ippGetString(attr
, i
, &lang
);
2385 cupsFilePuts(outfile
, "<dict><key>language</key><string>");
2386 print_xml_string(outfile
, NULL
, lang
);
2387 cupsFilePuts(outfile
, "</string><key>string</key><string>");
2388 print_xml_string(outfile
, NULL
, s
);
2389 cupsFilePuts(outfile
, "</string></dict>\n");
2393 case IPP_TAG_BEGIN_COLLECTION
:
2394 for (i
= 0; i
< count
; i
++)
2396 ipp_t
*col
= ippGetCollection(attr
, i
);
2397 /* Collection value */
2399 cupsFilePuts(outfile
, "<dict>\n");
2400 for (colattr
= ippFirstAttribute(col
); colattr
; colattr
= ippNextAttribute(col
))
2401 print_attr(outfile
, output
, colattr
, NULL
);
2402 cupsFilePuts(outfile
, "</dict>\n");
2407 cupsFilePrintf(outfile
, "<string><<%s>></string>\n", ippTagString(ippGetValueTag(attr
)));
2412 cupsFilePuts(outfile
, "</array>\n");
2416 char buffer
[131072]; /* Value buffer */
2418 if (output
== _CUPS_OUTPUT_TEST
)
2420 if (!ippGetName(attr
))
2422 cupsFilePuts(outfile
, " -- separator --\n");
2426 cupsFilePrintf(outfile
, " %s (%s%s) = ", ippGetName(attr
), ippGetCount(attr
) > 1 ? "1setOf " : "", ippTagString(ippGetValueTag(attr
)));
2429 ippAttributeString(attr
, buffer
, sizeof(buffer
));
2430 cupsFilePrintf(outfile
, "%s\n", buffer
);
2436 * 'print_csv()' - Print a line of CSV text.
2441 _cups_testdata_t
*data
, /* I - Test data */
2442 ipp_t
*ipp
, /* I - Response message */
2443 ipp_attribute_t
*attr
, /* I - First attribute for line */
2444 int num_displayed
, /* I - Number of attributes to display */
2445 char **displayed
, /* I - Attributes to display */
2446 size_t *widths
) /* I - Column widths */
2448 int i
; /* Looping var */
2449 size_t maxlength
; /* Max length of all columns */
2450 char *buffer
, /* String buffer */
2451 *bufptr
; /* Pointer into buffer */
2452 ipp_attribute_t
*current
; /* Current attribute */
2456 * Get the maximum string length we have to show and allocate...
2459 for (i
= 1, maxlength
= widths
[0]; i
< num_displayed
; i
++)
2460 if (widths
[i
] > maxlength
)
2461 maxlength
= widths
[i
];
2465 if ((buffer
= malloc(maxlength
)) == NULL
)
2469 * Loop through the attributes to display...
2474 for (i
= 0; i
< num_displayed
; i
++)
2477 cupsFilePutChar(data
->outfile
, ',');
2481 for (current
= attr
; current
; current
= ippNextAttribute(ipp
))
2483 if (!ippGetName(current
))
2485 else if (!strcmp(ippGetName(current
), displayed
[i
]))
2487 ippAttributeString(current
, buffer
, maxlength
);
2492 if (strchr(buffer
, ',') != NULL
|| strchr(buffer
, '\"') != NULL
||
2493 strchr(buffer
, '\\') != NULL
)
2495 cupsFilePutChar(cupsFileStdout(), '\"');
2496 for (bufptr
= buffer
; *bufptr
; bufptr
++)
2498 if (*bufptr
== '\\' || *bufptr
== '\"')
2499 cupsFilePutChar(cupsFileStdout(), '\\');
2500 cupsFilePutChar(cupsFileStdout(), *bufptr
);
2502 cupsFilePutChar(cupsFileStdout(), '\"');
2505 cupsFilePuts(data
->outfile
, buffer
);
2507 cupsFilePutChar(cupsFileStdout(), '\n');
2511 for (i
= 0; i
< num_displayed
; i
++)
2514 cupsFilePutChar(cupsFileStdout(), ',');
2516 cupsFilePuts(data
->outfile
, displayed
[i
]);
2518 cupsFilePutChar(cupsFileStdout(), '\n');
2526 * 'print_fatal_error()' - Print a fatal error message.
2531 _cups_testdata_t
*data
, /* I - Test data */
2532 const char *s
, /* I - Printf-style format string */
2533 ...) /* I - Additional arguments as needed */
2535 char buffer
[10240]; /* Format buffer */
2536 va_list ap
; /* Pointer to arguments */
2540 * Format the error message...
2544 vsnprintf(buffer
, sizeof(buffer
), s
, ap
);
2551 if (data
->output
== _CUPS_OUTPUT_PLIST
)
2553 print_xml_header(data
);
2554 print_xml_trailer(data
, 0, buffer
);
2557 _cupsLangPrintf(stderr
, "ipptool: %s", buffer
);
2562 * 'print_ippserver_attr()' - Print a attribute suitable for use by ippserver.
2566 print_ippserver_attr(
2567 _cups_testdata_t
*data
, /* I - Test data */
2568 ipp_attribute_t
*attr
, /* I - Attribute to print */
2569 int indent
) /* I - Indentation level */
2571 int i
, /* Looping var */
2572 count
= ippGetCount(attr
);
2573 /* Number of values */
2574 ipp_attribute_t
*colattr
; /* Collection attribute */
2578 cupsFilePrintf(data
->outfile
, "ATTR %s %s", ippTagString(ippGetValueTag(attr
)), ippGetName(attr
));
2580 cupsFilePrintf(data
->outfile
, "%*sMEMBER %s %s", indent
, "", ippTagString(ippGetValueTag(attr
)), ippGetName(attr
));
2582 switch (ippGetValueTag(attr
))
2584 case IPP_TAG_INTEGER
:
2586 for (i
= 0; i
< count
; i
++)
2587 cupsFilePrintf(data
->outfile
, "%s%d", i
? "," : " ", ippGetInteger(attr
, i
));
2590 case IPP_TAG_BOOLEAN
:
2591 cupsFilePuts(data
->outfile
, ippGetBoolean(attr
, 0) ? " true" : " false");
2593 for (i
= 1; i
< count
; i
++)
2594 cupsFilePuts(data
->outfile
, ippGetBoolean(attr
, 1) ? ",true" : ",false");
2597 case IPP_TAG_RANGE
:
2598 for (i
= 0; i
< count
; i
++)
2600 int upper
, lower
= ippGetRange(attr
, i
, &upper
);
2602 cupsFilePrintf(data
->outfile
, "%s%d-%d", i
? "," : " ", lower
, upper
);
2606 case IPP_TAG_RESOLUTION
:
2607 for (i
= 0; i
< count
; i
++)
2610 int yres
, xres
= ippGetResolution(attr
, i
, &yres
, &units
);
2612 cupsFilePrintf(data
->outfile
, "%s%dx%d%s", i
? "," : " ", xres
, yres
, units
== IPP_RES_PER_INCH
? "dpi" : "dpcm");
2617 for (i
= 0; i
< count
; i
++)
2618 cupsFilePrintf(data
->outfile
, "%s%s", i
? "," : " ", iso_date(ippGetDate(attr
, i
)));
2621 case IPP_TAG_STRING
:
2622 for (i
= 0; i
< count
; i
++)
2625 const char *s
= (const char *)ippGetOctetString(attr
, i
, &len
);
2627 cupsFilePuts(data
->outfile
, i
? "," : " ");
2628 print_ippserver_string(data
, s
, (size_t)len
);
2633 case IPP_TAG_TEXTLANG
:
2635 case IPP_TAG_NAMELANG
:
2636 case IPP_TAG_KEYWORD
:
2638 case IPP_TAG_URISCHEME
:
2639 case IPP_TAG_CHARSET
:
2640 case IPP_TAG_LANGUAGE
:
2641 case IPP_TAG_MIMETYPE
:
2642 for (i
= 0; i
< count
; i
++)
2644 const char *s
= ippGetString(attr
, i
, NULL
);
2646 cupsFilePuts(data
->outfile
, i
? "," : " ");
2647 print_ippserver_string(data
, s
, strlen(s
));
2651 case IPP_TAG_BEGIN_COLLECTION
:
2652 for (i
= 0; i
< count
; i
++)
2654 ipp_t
*col
= ippGetCollection(attr
, i
);
2656 cupsFilePuts(data
->outfile
, i
? ",{\n" : " {\n");
2657 for (colattr
= ippFirstAttribute(col
); colattr
; colattr
= ippNextAttribute(col
))
2658 print_ippserver_attr(data
, colattr
, indent
+ 4);
2659 cupsFilePrintf(data
->outfile
, "%*s}", indent
, "");
2664 /* Out-of-band value */
2668 cupsFilePuts(data
->outfile
, "\n");
2673 * 'print_ippserver_string()' - Print a string suitable for use by ippserver.
2677 print_ippserver_string(
2678 _cups_testdata_t
*data
, /* I - Test data */
2679 const char *s
, /* I - String to print */
2680 size_t len
) /* I - Length of string */
2682 cupsFilePutChar(data
->outfile
, '\"');
2686 cupsFilePutChar(data
->outfile
, '\\');
2687 cupsFilePutChar(data
->outfile
, *s
);
2692 cupsFilePutChar(data
->outfile
, '\"');
2697 * 'print_line()' - Print a line of formatted or CSV text.
2702 _cups_testdata_t
*data
, /* I - Test data */
2703 ipp_t
*ipp
, /* I - Response message */
2704 ipp_attribute_t
*attr
, /* I - First attribute for line */
2705 int num_displayed
, /* I - Number of attributes to display */
2706 char **displayed
, /* I - Attributes to display */
2707 size_t *widths
) /* I - Column widths */
2709 int i
; /* Looping var */
2710 size_t maxlength
; /* Max length of all columns */
2711 char *buffer
; /* String buffer */
2712 ipp_attribute_t
*current
; /* Current attribute */
2716 * Get the maximum string length we have to show and allocate...
2719 for (i
= 1, maxlength
= widths
[0]; i
< num_displayed
; i
++)
2720 if (widths
[i
] > maxlength
)
2721 maxlength
= widths
[i
];
2725 if ((buffer
= malloc(maxlength
)) == NULL
)
2729 * Loop through the attributes to display...
2734 for (i
= 0; i
< num_displayed
; i
++)
2737 cupsFilePutChar(cupsFileStdout(), ' ');
2741 for (current
= attr
; current
; current
= ippNextAttribute(ipp
))
2743 if (!ippGetName(current
))
2745 else if (!strcmp(ippGetName(current
), displayed
[i
]))
2747 ippAttributeString(current
, buffer
, maxlength
);
2752 cupsFilePrintf(data
->outfile
, "%*s", (int)-widths
[i
], buffer
);
2754 cupsFilePutChar(cupsFileStdout(), '\n');
2758 for (i
= 0; i
< num_displayed
; i
++)
2761 cupsFilePutChar(cupsFileStdout(), ' ');
2763 cupsFilePrintf(data
->outfile
, "%*s", (int)-widths
[i
], displayed
[i
]);
2765 cupsFilePutChar(cupsFileStdout(), '\n');
2767 for (i
= 0; i
< num_displayed
; i
++)
2770 cupsFilePutChar(cupsFileStdout(), ' ');
2772 memset(buffer
, '-', widths
[i
]);
2773 buffer
[widths
[i
]] = '\0';
2774 cupsFilePuts(data
->outfile
, buffer
);
2776 cupsFilePutChar(cupsFileStdout(), '\n');
2784 * 'print_xml_header()' - Print a standard XML plist header.
2788 print_xml_header(_cups_testdata_t
*data
)/* I - Test data */
2790 if (!data
->xml_header
)
2792 cupsFilePuts(data
->outfile
, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
2793 cupsFilePuts(data
->outfile
, "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n");
2794 cupsFilePuts(data
->outfile
, "<plist version=\"1.0\">\n");
2795 cupsFilePuts(data
->outfile
, "<dict>\n");
2796 cupsFilePuts(data
->outfile
, "<key>ipptoolVersion</key>\n");
2797 cupsFilePuts(data
->outfile
, "<string>" CUPS_SVERSION
"</string>\n");
2798 cupsFilePuts(data
->outfile
, "<key>Transfer</key>\n");
2799 cupsFilePrintf(data
->outfile
, "<string>%s</string>\n", data
->transfer
== _CUPS_TRANSFER_AUTO
? "auto" : data
->transfer
== _CUPS_TRANSFER_CHUNKED
? "chunked" : "length");
2800 cupsFilePuts(data
->outfile
, "<key>Tests</key>\n");
2801 cupsFilePuts(data
->outfile
, "<array>\n");
2803 data
->xml_header
= 1;
2809 * 'print_xml_string()' - Print an XML string with escaping.
2813 print_xml_string(cups_file_t
*outfile
, /* I - Test data */
2814 const char *element
, /* I - Element name or NULL */
2815 const char *s
) /* I - String to print */
2818 cupsFilePrintf(outfile
, "<%s>", element
);
2823 cupsFilePuts(outfile
, "&");
2825 cupsFilePuts(outfile
, "<");
2827 cupsFilePuts(outfile
, ">");
2828 else if ((*s
& 0xe0) == 0xc0)
2831 * Validate UTF-8 two-byte sequence...
2834 if ((s
[1] & 0xc0) != 0x80)
2836 cupsFilePutChar(outfile
, '?');
2841 cupsFilePutChar(outfile
, *s
++);
2842 cupsFilePutChar(outfile
, *s
);
2845 else if ((*s
& 0xf0) == 0xe0)
2848 * Validate UTF-8 three-byte sequence...
2851 if ((s
[1] & 0xc0) != 0x80 || (s
[2] & 0xc0) != 0x80)
2853 cupsFilePutChar(outfile
, '?');
2858 cupsFilePutChar(outfile
, *s
++);
2859 cupsFilePutChar(outfile
, *s
++);
2860 cupsFilePutChar(outfile
, *s
);
2863 else if ((*s
& 0xf8) == 0xf0)
2866 * Validate UTF-8 four-byte sequence...
2869 if ((s
[1] & 0xc0) != 0x80 || (s
[2] & 0xc0) != 0x80 ||
2870 (s
[3] & 0xc0) != 0x80)
2872 cupsFilePutChar(outfile
, '?');
2877 cupsFilePutChar(outfile
, *s
++);
2878 cupsFilePutChar(outfile
, *s
++);
2879 cupsFilePutChar(outfile
, *s
++);
2880 cupsFilePutChar(outfile
, *s
);
2883 else if ((*s
& 0x80) || (*s
< ' ' && !isspace(*s
& 255)))
2886 * Invalid control character...
2889 cupsFilePutChar(outfile
, '?');
2892 cupsFilePutChar(outfile
, *s
);
2898 cupsFilePrintf(outfile
, "</%s>\n", element
);
2903 * 'print_xml_trailer()' - Print the XML trailer with success/fail value.
2908 _cups_testdata_t
*data
, /* I - Test data */
2909 int success
, /* I - 1 on success, 0 on failure */
2910 const char *message
) /* I - Error message or NULL */
2912 if (data
->xml_header
)
2914 cupsFilePuts(data
->outfile
, "</array>\n");
2915 cupsFilePuts(data
->outfile
, "<key>Successful</key>\n");
2916 cupsFilePuts(data
->outfile
, success
? "<true />\n" : "<false />\n");
2919 cupsFilePuts(data
->outfile
, "<key>ErrorMessage</key>\n");
2920 print_xml_string(data
->outfile
, "string", message
);
2922 cupsFilePuts(data
->outfile
, "</dict>\n");
2923 cupsFilePuts(data
->outfile
, "</plist>\n");
2925 data
->xml_header
= 0;
2932 * 'sigterm_handler()' - Handle SIGINT and SIGTERM.
2936 sigterm_handler(int sig
) /* I - Signal number (unused) */
2942 signal(SIGINT
, SIG_DFL
);
2943 signal(SIGTERM
, SIG_DFL
);
2945 #endif /* !_WIN32 */
2949 * 'timeout_cb()' - Handle HTTP timeouts.
2952 static int /* O - 1 to continue, 0 to cancel */
2953 timeout_cb(http_t
*http
, /* I - Connection to server */
2954 void *user_data
) /* I - User data (unused) */
2956 int buffered
= 0; /* Bytes buffered but not yet sent */
2962 * If the socket still have data waiting to be sent to the printer (as can
2963 * happen if the printer runs out of paper), continue to wait until the output
2964 * buffer is empty...
2967 #ifdef SO_NWRITE /* macOS and some versions of Linux */
2968 socklen_t len
= sizeof(buffered
); /* Size of return value */
2970 if (getsockopt(httpGetFd(http
), SOL_SOCKET
, SO_NWRITE
, &buffered
, &len
))
2973 #elif defined(SIOCOUTQ) /* Others except Windows */
2974 if (ioctl(httpGetFd(http
), SIOCOUTQ
, &buffered
))
2977 #else /* Windows (not possible) */
2979 #endif /* SO_NWRITE */
2981 return (buffered
> 0);
2986 * 'token_cb()' - Parse test file-specific tokens and run tests.
2989 static int /* O - 1 to continue, 0 to stop */
2990 token_cb(_ipp_file_t
*f
, /* I - IPP file data */
2991 _ipp_vars_t
*vars
, /* I - IPP variables */
2992 _cups_testdata_t
*data
, /* I - Test data */
2993 const char *token
) /* I - Current token */
2995 char name
[1024], /* Name string */
2996 temp
[1024], /* Temporary string */
2997 value
[1024], /* Value string */
2998 *ptr
; /* Pointer into value */
3004 * Initialize state as needed (nothing for now...)
3012 * Parse until we see a close brace...
3015 if (_cups_strcasecmp(token
, "COUNT") &&
3016 _cups_strcasecmp(token
, "DEFINE-MATCH") &&
3017 _cups_strcasecmp(token
, "DEFINE-NO-MATCH") &&
3018 _cups_strcasecmp(token
, "DEFINE-VALUE") &&
3019 _cups_strcasecmp(token
, "IF-DEFINED") &&
3020 _cups_strcasecmp(token
, "IF-NOT-DEFINED") &&
3021 _cups_strcasecmp(token
, "IN-GROUP") &&
3022 _cups_strcasecmp(token
, "OF-TYPE") &&
3023 _cups_strcasecmp(token
, "REPEAT-LIMIT") &&
3024 _cups_strcasecmp(token
, "REPEAT-MATCH") &&
3025 _cups_strcasecmp(token
, "REPEAT-NO-MATCH") &&
3026 _cups_strcasecmp(token
, "SAME-COUNT-AS") &&
3027 _cups_strcasecmp(token
, "WITH-ALL-VALUES") &&
3028 _cups_strcasecmp(token
, "WITH-ALL-HOSTNAMES") &&
3029 _cups_strcasecmp(token
, "WITH-ALL-RESOURCES") &&
3030 _cups_strcasecmp(token
, "WITH-ALL-SCHEMES") &&
3031 _cups_strcasecmp(token
, "WITH-HOSTNAME") &&
3032 _cups_strcasecmp(token
, "WITH-RESOURCE") &&
3033 _cups_strcasecmp(token
, "WITH-SCHEME") &&
3034 _cups_strcasecmp(token
, "WITH-VALUE") &&
3035 _cups_strcasecmp(token
, "WITH-VALUE-FROM"))
3036 data
->last_expect
= NULL
;
3038 if (_cups_strcasecmp(token
, "DEFINE-MATCH") &&
3039 _cups_strcasecmp(token
, "DEFINE-NO-MATCH") &&
3040 _cups_strcasecmp(token
, "IF-DEFINED") &&
3041 _cups_strcasecmp(token
, "IF-NOT-DEFINED") &&
3042 _cups_strcasecmp(token
, "REPEAT-LIMIT") &&
3043 _cups_strcasecmp(token
, "REPEAT-MATCH") &&
3044 _cups_strcasecmp(token
, "REPEAT-NO-MATCH"))
3045 data
->last_status
= NULL
;
3047 if (!strcmp(token
, "}"))
3049 return (do_test(f
, vars
, data
));
3051 else if (!strcmp(token
, "COMPRESSION"))
3055 * COMPRESSION deflate
3059 if (_ippFileReadToken(f
, temp
, sizeof(temp
)))
3061 _ippVarsExpand(vars
, data
->compression
, temp
, sizeof(data
->compression
));
3063 if (strcmp(data
->compression
, "none") && strcmp(data
->compression
, "deflate") &&
3064 strcmp(data
->compression
, "gzip"))
3066 if (strcmp(data
->compression
, "none"))
3067 #endif /* HAVE_LIBZ */
3069 print_fatal_error(data
, "Unsupported COMPRESSION value \"%s\" on line %d of \"%s\".", data
->compression
, f
->linenum
, f
->filename
);
3073 if (!strcmp(data
->compression
, "none"))
3074 data
->compression
[0] = '\0';
3078 print_fatal_error(data
, "Missing COMPRESSION value on line %d of \"%s\".", f
->linenum
, f
->filename
);
3082 else if (!strcmp(token
, "DEFINE"))
3088 if (_ippFileReadToken(f
, name
, sizeof(name
)) && _ippFileReadToken(f
, temp
, sizeof(temp
)))
3090 _ippVarsExpand(vars
, value
, temp
, sizeof(value
));
3091 _ippVarsSet(vars
, name
, value
);
3095 print_fatal_error(data
, "Missing DEFINE name and/or value on line %d of \"%s\".", f
->linenum
, f
->filename
);
3099 else if (!strcmp(token
, "IGNORE-ERRORS"))
3106 if (_ippFileReadToken(f
, temp
, sizeof(temp
)) && (!_cups_strcasecmp(temp
, "yes") || !_cups_strcasecmp(temp
, "no")))
3108 data
->ignore_errors
= !_cups_strcasecmp(temp
, "yes");
3112 print_fatal_error(data
, "Missing IGNORE-ERRORS value on line %d of \"%s\".", f
->linenum
, f
->filename
);
3116 else if (!_cups_strcasecmp(token
, "NAME"))
3122 _ippFileReadToken(f
, temp
, sizeof(temp
));
3123 _ippVarsExpand(vars
, data
->name
, temp
, sizeof(data
->name
));
3125 else if (!_cups_strcasecmp(token
, "PAUSE"))
3128 * Pause with a message...
3131 if (_ippFileReadToken(f
, temp
, sizeof(temp
)))
3133 pause_message(temp
);
3137 print_fatal_error(data
, "Missing PAUSE message on line %d of \"%s\".", f
->linenum
, f
->filename
);
3141 else if (!strcmp(token
, "REQUEST-ID"))
3148 if (_ippFileReadToken(f
, temp
, sizeof(temp
)))
3150 if (isdigit(temp
[0] & 255))
3152 data
->request_id
= atoi(temp
);
3154 else if (!_cups_strcasecmp(temp
, "random"))
3156 data
->request_id
= (CUPS_RAND() % 1000) * 137 + 1;
3160 print_fatal_error(data
, "Bad REQUEST-ID value \"%s\" on line %d of \"%s\".", temp
, f
->linenum
, f
->filename
);
3166 print_fatal_error(data
, "Missing REQUEST-ID value on line %d of \"%s\".", f
->linenum
, f
->filename
);
3170 else if (!strcmp(token
, "SKIP-IF-DEFINED"))
3173 * SKIP-IF-DEFINED variable
3176 if (_ippFileReadToken(f
, name
, sizeof(name
)))
3178 if (_ippVarsGet(vars
, name
))
3179 data
->skip_test
= 1;
3183 print_fatal_error(data
, "Missing SKIP-IF-DEFINED value on line %d of \"%s\".", f
->linenum
, f
->filename
);
3187 else if (!strcmp(token
, "SKIP-IF-MISSING"))
3190 * SKIP-IF-MISSING filename
3193 if (_ippFileReadToken(f
, temp
, sizeof(temp
)))
3195 char filename
[1024]; /* Filename */
3197 _ippVarsExpand(vars
, value
, temp
, sizeof(value
));
3198 get_filename(f
->filename
, filename
, temp
, sizeof(filename
));
3200 if (access(filename
, R_OK
))
3201 data
->skip_test
= 1;
3205 print_fatal_error(data
, "Missing SKIP-IF-MISSING filename on line %d of \"%s\".", f
->linenum
, f
->filename
);
3209 else if (!strcmp(token
, "SKIP-IF-NOT-DEFINED"))
3212 * SKIP-IF-NOT-DEFINED variable
3215 if (_ippFileReadToken(f
, name
, sizeof(name
)))
3217 if (!_ippVarsGet(vars
, name
))
3218 data
->skip_test
= 1;
3222 print_fatal_error(data
, "Missing SKIP-IF-NOT-DEFINED value on line %d of \"%s\".", f
->linenum
, f
->filename
);
3226 else if (!strcmp(token
, "SKIP-PREVIOUS-ERROR"))
3229 * SKIP-PREVIOUS-ERROR yes
3230 * SKIP-PREVIOUS-ERROR no
3233 if (_ippFileReadToken(f
, temp
, sizeof(temp
)) && (!_cups_strcasecmp(temp
, "yes") || !_cups_strcasecmp(temp
, "no")))
3235 data
->skip_previous
= !_cups_strcasecmp(temp
, "yes");
3239 print_fatal_error(data
, "Missing SKIP-PREVIOUS-ERROR value on line %d of \"%s\".", f
->linenum
, f
->filename
);
3243 else if (!strcmp(token
, "TEST-ID"))
3249 if (_ippFileReadToken(f
, temp
, sizeof(temp
)))
3251 _ippVarsExpand(vars
, data
->test_id
, temp
, sizeof(data
->test_id
));
3255 print_fatal_error(data
, "Missing TEST-ID value on line %d of \"%s\".", f
->linenum
, f
->filename
);
3259 else if (!strcmp(token
, "TRANSFER"))
3267 if (_ippFileReadToken(f
, temp
, sizeof(temp
)))
3269 if (!strcmp(temp
, "auto"))
3271 data
->transfer
= _CUPS_TRANSFER_AUTO
;
3273 else if (!strcmp(temp
, "chunked"))
3275 data
->transfer
= _CUPS_TRANSFER_CHUNKED
;
3277 else if (!strcmp(temp
, "length"))
3279 data
->transfer
= _CUPS_TRANSFER_LENGTH
;
3283 print_fatal_error(data
, "Bad TRANSFER value \"%s\" on line %d of \"%s\".", temp
, f
->linenum
, f
->filename
);
3289 print_fatal_error(data
, "Missing TRANSFER value on line %d of \"%s\".", f
->linenum
, f
->filename
);
3293 else if (!_cups_strcasecmp(token
, "VERSION"))
3295 if (_ippFileReadToken(f
, temp
, sizeof(temp
)))
3297 if (!strcmp(temp
, "0.0"))
3301 else if (!strcmp(temp
, "1.0"))
3305 else if (!strcmp(temp
, "1.1"))
3309 else if (!strcmp(temp
, "2.0"))
3313 else if (!strcmp(temp
, "2.1"))
3317 else if (!strcmp(temp
, "2.2"))
3323 print_fatal_error(data
, "Bad VERSION \"%s\" on line %d of \"%s\".", temp
, f
->linenum
, f
->filename
);
3329 print_fatal_error(data
, "Missing VERSION number on line %d of \"%s\".", f
->linenum
, f
->filename
);
3333 else if (!_cups_strcasecmp(token
, "RESOURCE"))
3339 if (!_ippFileReadToken(f
, data
->resource
, sizeof(data
->resource
)))
3341 print_fatal_error(data
, "Missing RESOURCE path on line %d of \"%s\".", f
->linenum
, f
->filename
);
3345 else if (!_cups_strcasecmp(token
, "OPERATION"))
3351 ipp_op_t op
; /* Operation code */
3353 if (!_ippFileReadToken(f
, temp
, sizeof(temp
)))
3355 print_fatal_error(data
, "Missing OPERATION code on line %d of \"%s\".", f
->linenum
, f
->filename
);
3359 _ippVarsExpand(vars
, value
, temp
, sizeof(value
));
3361 if ((op
= ippOpValue(value
)) == (ipp_op_t
)-1 && (op
= (ipp_op_t
)strtol(value
, NULL
, 0)) == 0)
3363 print_fatal_error(data
, "Bad OPERATION code \"%s\" on line %d of \"%s\".", temp
, f
->linenum
, f
->filename
);
3367 ippSetOperation(f
->attrs
, op
);
3369 else if (!_cups_strcasecmp(token
, "GROUP"))
3372 * Attribute group...
3375 ipp_tag_t group_tag
; /* Group tag */
3377 if (!_ippFileReadToken(f
, temp
, sizeof(temp
)))
3379 print_fatal_error(data
, "Missing GROUP tag on line %d of \"%s\".", f
->linenum
, f
->filename
);
3383 if ((group_tag
= ippTagValue(temp
)) == IPP_TAG_ZERO
|| group_tag
>= IPP_TAG_UNSUPPORTED_VALUE
)
3385 print_fatal_error(data
, "Bad GROUP tag \"%s\" on line %d of \"%s\".", temp
, f
->linenum
, f
->filename
);
3389 if (group_tag
== f
->group_tag
)
3390 ippAddSeparator(f
->attrs
);
3392 f
->group_tag
= group_tag
;
3394 else if (!_cups_strcasecmp(token
, "DELAY"))
3397 * Delay before operation...
3400 double dval
; /* Delay value */
3402 if (!_ippFileReadToken(f
, temp
, sizeof(temp
)))
3404 print_fatal_error(data
, "Missing DELAY value on line %d of \"%s\".", f
->linenum
, f
->filename
);
3408 _ippVarsExpand(vars
, value
, temp
, sizeof(value
));
3410 if ((dval
= _cupsStrScand(value
, &ptr
, localeconv())) < 0.0 || (*ptr
&& *ptr
!= ','))
3412 print_fatal_error(data
, "Bad DELAY value \"%s\" on line %d of \"%s\".", value
, f
->linenum
, f
->filename
);
3416 data
->delay
= (useconds_t
)(1000000.0 * dval
);
3420 if ((dval
= _cupsStrScand(ptr
+ 1, &ptr
, localeconv())) <= 0.0 || *ptr
)
3422 print_fatal_error(data
, "Bad DELAY value \"%s\" on line %d of \"%s\".", value
, f
->linenum
, f
->filename
);
3426 data
->repeat_interval
= (useconds_t
)(1000000.0 * dval
);
3429 data
->repeat_interval
= data
->delay
;
3431 else if (!_cups_strcasecmp(token
, "FILE"))
3437 if (!_ippFileReadToken(f
, temp
, sizeof(temp
)))
3439 print_fatal_error(data
, "Missing FILE filename on line %d of \"%s\".", f
->linenum
, f
->filename
);
3443 _ippVarsExpand(vars
, value
, temp
, sizeof(value
));
3444 get_filename(f
->filename
, data
->file
, value
, sizeof(data
->file
));
3446 if (access(data
->file
, R_OK
))
3448 print_fatal_error(data
, "Filename \"%s\" (mapped to \"%s\") on line %d of \"%s\" cannot be read.", value
, data
->file
, f
->linenum
, f
->filename
);
3452 else if (!_cups_strcasecmp(token
, "STATUS"))
3458 if (data
->num_statuses
>= (int)(sizeof(data
->statuses
) / sizeof(data
->statuses
[0])))
3460 print_fatal_error(data
, "Too many STATUS's on line %d of \"%s\".", f
->linenum
, f
->filename
);
3464 if (!_ippFileReadToken(f
, temp
, sizeof(temp
)))
3466 print_fatal_error(data
, "Missing STATUS code on line %d of \"%s\".", f
->linenum
, f
->filename
);
3470 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)
3472 print_fatal_error(data
, "Bad STATUS code \"%s\" on line %d of \"%s\".", temp
, f
->linenum
, f
->filename
);
3476 data
->last_status
= data
->statuses
+ data
->num_statuses
;
3477 data
->num_statuses
++;
3479 data
->last_status
->define_match
= NULL
;
3480 data
->last_status
->define_no_match
= NULL
;
3481 data
->last_status
->if_defined
= NULL
;
3482 data
->last_status
->if_not_defined
= NULL
;
3483 data
->last_status
->repeat_limit
= 1000;
3484 data
->last_status
->repeat_match
= 0;
3485 data
->last_status
->repeat_no_match
= 0;
3487 else if (!_cups_strcasecmp(token
, "EXPECT") || !_cups_strcasecmp(token
, "EXPECT-ALL"))
3490 * Expected attributes...
3493 int expect_all
= !_cups_strcasecmp(token
, "EXPECT-ALL");
3495 if (data
->num_expects
>= (int)(sizeof(data
->expects
) / sizeof(data
->expects
[0])))
3497 print_fatal_error(data
, "Too many EXPECT's on line %d of \"%s\".", f
->linenum
, f
->filename
);
3501 if (!_ippFileReadToken(f
, name
, sizeof(name
)))
3503 print_fatal_error(data
, "Missing EXPECT name on line %d of \"%s\".", f
->linenum
, f
->filename
);
3507 data
->last_expect
= data
->expects
+ data
->num_expects
;
3508 data
->num_expects
++;
3510 memset(data
->last_expect
, 0, sizeof(_cups_expect_t
));
3511 data
->last_expect
->repeat_limit
= 1000;
3512 data
->last_expect
->expect_all
= expect_all
;
3516 data
->last_expect
->not_expect
= 1;
3517 data
->last_expect
->name
= strdup(name
+ 1);
3519 else if (name
[0] == '?')
3521 data
->last_expect
->optional
= 1;
3522 data
->last_expect
->name
= strdup(name
+ 1);
3525 data
->last_expect
->name
= strdup(name
);
3527 else if (!_cups_strcasecmp(token
, "COUNT"))
3529 int count
; /* Count value */
3531 if (!_ippFileReadToken(f
, temp
, sizeof(temp
)))
3533 print_fatal_error(data
, "Missing COUNT number on line %d of \"%s\".", f
->linenum
, f
->filename
);
3537 if ((count
= atoi(temp
)) <= 0)
3539 print_fatal_error(data
, "Bad COUNT \"%s\" on line %d of \"%s\".", temp
, f
->linenum
, f
->filename
);
3543 if (data
->last_expect
)
3545 data
->last_expect
->count
= count
;
3549 print_fatal_error(data
, "COUNT without a preceding EXPECT on line %d of \"%s\".", f
->linenum
, f
->filename
);
3553 else if (!_cups_strcasecmp(token
, "DEFINE-MATCH"))
3555 if (!_ippFileReadToken(f
, temp
, sizeof(temp
)))
3557 print_fatal_error(data
, "Missing DEFINE-MATCH variable on line %d of \"%s\".", f
->linenum
, f
->filename
);
3561 if (data
->last_expect
)
3563 data
->last_expect
->define_match
= strdup(temp
);
3565 else if (data
->last_status
)
3567 data
->last_status
->define_match
= strdup(temp
);
3571 print_fatal_error(data
, "DEFINE-MATCH without a preceding EXPECT or STATUS on line %d of \"%s\".", f
->linenum
, f
->filename
);
3575 else if (!_cups_strcasecmp(token
, "DEFINE-NO-MATCH"))
3577 if (!_ippFileReadToken(f
, temp
, sizeof(temp
)))
3579 print_fatal_error(data
, "Missing DEFINE-NO-MATCH variable on line %d of \"%s\".", f
->linenum
, f
->filename
);
3583 if (data
->last_expect
)
3585 data
->last_expect
->define_no_match
= strdup(temp
);
3587 else if (data
->last_status
)
3589 data
->last_status
->define_no_match
= strdup(temp
);
3593 print_fatal_error(data
, "DEFINE-NO-MATCH without a preceding EXPECT or STATUS on line %d of \"%s\".", f
->linenum
, f
->filename
);
3597 else if (!_cups_strcasecmp(token
, "DEFINE-VALUE"))
3599 if (!_ippFileReadToken(f
, temp
, sizeof(temp
)))
3601 print_fatal_error(data
, "Missing DEFINE-VALUE variable on line %d of \"%s\".", f
->linenum
, f
->filename
);
3605 if (data
->last_expect
)
3607 data
->last_expect
->define_value
= strdup(temp
);
3611 print_fatal_error(data
, "DEFINE-VALUE without a preceding EXPECT on line %d of \"%s\".", f
->linenum
, f
->filename
);
3615 else if (!_cups_strcasecmp(token
, "OF-TYPE"))
3617 if (!_ippFileReadToken(f
, temp
, sizeof(temp
)))
3619 print_fatal_error(data
, "Missing OF-TYPE value tag(s) on line %d of \"%s\".", f
->linenum
, f
->filename
);
3623 if (data
->last_expect
)
3625 data
->last_expect
->of_type
= strdup(temp
);
3629 print_fatal_error(data
, "OF-TYPE without a preceding EXPECT on line %d of \"%s\".", f
->linenum
, f
->filename
);
3633 else if (!_cups_strcasecmp(token
, "IN-GROUP"))
3635 ipp_tag_t in_group
; /* IN-GROUP value */
3637 if (!_ippFileReadToken(f
, temp
, sizeof(temp
)))
3639 print_fatal_error(data
, "Missing IN-GROUP group tag on line %d of \"%s\".", f
->linenum
, f
->filename
);
3643 if ((in_group
= ippTagValue(temp
)) == IPP_TAG_ZERO
|| in_group
>= IPP_TAG_UNSUPPORTED_VALUE
)
3645 print_fatal_error(data
, "Bad IN-GROUP group tag \"%s\" on line %d of \"%s\".", temp
, f
->linenum
, f
->filename
);
3648 else if (data
->last_expect
)
3650 data
->last_expect
->in_group
= in_group
;
3654 print_fatal_error(data
, "IN-GROUP without a preceding EXPECT on line %d of \"%s\".", f
->linenum
, f
->filename
);
3658 else if (!_cups_strcasecmp(token
, "REPEAT-LIMIT"))
3660 if (!_ippFileReadToken(f
, temp
, sizeof(temp
)))
3662 print_fatal_error(data
, "Missing REPEAT-LIMIT value on line %d of \"%s\".", f
->linenum
, f
->filename
);
3665 else if (atoi(temp
) <= 0)
3667 print_fatal_error(data
, "Bad REPEAT-LIMIT value on line %d of \"%s\".", f
->linenum
, f
->filename
);
3671 if (data
->last_status
)
3673 data
->last_status
->repeat_limit
= atoi(temp
);
3675 else if (data
->last_expect
)
3677 data
->last_expect
->repeat_limit
= atoi(temp
);
3681 print_fatal_error(data
, "REPEAT-LIMIT without a preceding EXPECT or STATUS on line %d of \"%s\".", f
->linenum
, f
->filename
);
3685 else if (!_cups_strcasecmp(token
, "REPEAT-MATCH"))
3687 if (data
->last_status
)
3689 data
->last_status
->repeat_match
= 1;
3691 else if (data
->last_expect
)
3693 data
->last_expect
->repeat_match
= 1;
3697 print_fatal_error(data
, "REPEAT-MATCH without a preceding EXPECT or STATUS on line %d of \"%s\".", f
->linenum
, f
->filename
);
3701 else if (!_cups_strcasecmp(token
, "REPEAT-NO-MATCH"))
3703 if (data
->last_status
)
3705 data
->last_status
->repeat_no_match
= 1;
3707 else if (data
->last_expect
)
3709 data
->last_expect
->repeat_no_match
= 1;
3713 print_fatal_error(data
, "REPEAT-NO-MATCH without a preceding EXPECT or STATUS on line %d of \"%s\".", f
->linenum
, f
->filename
);
3717 else if (!_cups_strcasecmp(token
, "SAME-COUNT-AS"))
3719 if (!_ippFileReadToken(f
, temp
, sizeof(temp
)))
3721 print_fatal_error(data
, "Missing SAME-COUNT-AS name on line %d of \"%s\".", f
->linenum
, f
->filename
);
3725 if (data
->last_expect
)
3727 data
->last_expect
->same_count_as
= strdup(temp
);
3731 print_fatal_error(data
, "SAME-COUNT-AS without a preceding EXPECT on line %d of \"%s\".", f
->linenum
, f
->filename
);
3735 else if (!_cups_strcasecmp(token
, "IF-DEFINED"))
3737 if (!_ippFileReadToken(f
, temp
, sizeof(temp
)))
3739 print_fatal_error(data
, "Missing IF-DEFINED name on line %d of \"%s\".", f
->linenum
, f
->filename
);
3743 if (data
->last_expect
)
3745 data
->last_expect
->if_defined
= strdup(temp
);
3747 else if (data
->last_status
)
3749 data
->last_status
->if_defined
= strdup(temp
);
3753 print_fatal_error(data
, "IF-DEFINED without a preceding EXPECT or STATUS on line %d of \"%s\".", f
->linenum
, f
->filename
);
3757 else if (!_cups_strcasecmp(token
, "IF-NOT-DEFINED"))
3759 if (!_ippFileReadToken(f
, temp
, sizeof(temp
)))
3761 print_fatal_error(data
, "Missing IF-NOT-DEFINED name on line %d of \"%s\".", f
->linenum
, f
->filename
);
3765 if (data
->last_expect
)
3767 data
->last_expect
->if_not_defined
= strdup(temp
);
3769 else if (data
->last_status
)
3771 data
->last_status
->if_not_defined
= strdup(temp
);
3775 print_fatal_error(data
, "IF-NOT-DEFINED without a preceding EXPECT or STATUS on line %d of \"%s\".", f
->linenum
, f
->filename
);
3779 else if (!_cups_strcasecmp(token
, "WITH-ALL-VALUES") ||
3780 !_cups_strcasecmp(token
, "WITH-ALL-HOSTNAMES") ||
3781 !_cups_strcasecmp(token
, "WITH-ALL-RESOURCES") ||
3782 !_cups_strcasecmp(token
, "WITH-ALL-SCHEMES") ||
3783 !_cups_strcasecmp(token
, "WITH-HOSTNAME") ||
3784 !_cups_strcasecmp(token
, "WITH-RESOURCE") ||
3785 !_cups_strcasecmp(token
, "WITH-SCHEME") ||
3786 !_cups_strcasecmp(token
, "WITH-VALUE"))
3788 off_t lastpos
; /* Last file position */
3789 int lastline
; /* Last line number */
3791 if (data
->last_expect
)
3793 if (!_cups_strcasecmp(token
, "WITH-ALL-HOSTNAMES") || !_cups_strcasecmp(token
, "WITH-HOSTNAME"))
3794 data
->last_expect
->with_flags
= _CUPS_WITH_HOSTNAME
;
3795 else if (!_cups_strcasecmp(token
, "WITH-ALL-RESOURCES") || !_cups_strcasecmp(token
, "WITH-RESOURCE"))
3796 data
->last_expect
->with_flags
= _CUPS_WITH_RESOURCE
;
3797 else if (!_cups_strcasecmp(token
, "WITH-ALL-SCHEMES") || !_cups_strcasecmp(token
, "WITH-SCHEME"))
3798 data
->last_expect
->with_flags
= _CUPS_WITH_SCHEME
;
3800 if (!_cups_strncasecmp(token
, "WITH-ALL-", 9))
3801 data
->last_expect
->with_flags
|= _CUPS_WITH_ALL
;
3804 if (!_ippFileReadToken(f
, temp
, sizeof(temp
)))
3806 print_fatal_error(data
, "Missing %s value on line %d of \"%s\".", token
, f
->linenum
, f
->filename
);
3811 * Read additional comma-delimited values - needed since legacy test files
3812 * will have unquoted WITH-VALUE values with commas...
3815 ptr
= temp
+ strlen(temp
);
3819 lastpos
= cupsFileTell(f
->fp
);
3820 lastline
= f
->linenum
;
3823 if (!_ippFileReadToken(f
, ptr
, (sizeof(temp
) - (size_t)(ptr
- temp
))))
3826 if (!strcmp(ptr
, ","))
3834 if (!_ippFileReadToken(f
, ptr
, (sizeof(temp
) - (size_t)(ptr
- temp
))))
3840 * Not another value, stop here...
3843 cupsFileSeek(f
->fp
, lastpos
);
3844 f
->linenum
= lastline
;
3850 if (data
->last_expect
)
3853 * Expand any variables in the value and then save it.
3856 _ippVarsExpand(vars
, value
, temp
, sizeof(value
));
3858 ptr
= value
+ strlen(value
) - 1;
3860 if (value
[0] == '/' && ptr
> value
&& *ptr
== '/')
3863 * WITH-VALUE is a POSIX extended regular expression.
3866 data
->last_expect
->with_value
= calloc(1, (size_t)(ptr
- value
));
3867 data
->last_expect
->with_flags
|= _CUPS_WITH_REGEX
;
3869 if (data
->last_expect
->with_value
)
3870 memcpy(data
->last_expect
->with_value
, value
+ 1, (size_t)(ptr
- value
- 1));
3875 * WITH-VALUE is a literal value...
3878 for (ptr
= value
; *ptr
; ptr
++)
3880 if (*ptr
== '\\' && ptr
[1])
3883 * Remove \ from \foo...
3886 _cups_strcpy(ptr
, ptr
+ 1);
3890 data
->last_expect
->with_value
= strdup(value
);
3891 data
->last_expect
->with_flags
|= _CUPS_WITH_LITERAL
;
3896 print_fatal_error(data
, "%s without a preceding EXPECT on line %d of \"%s\".", token
, f
->linenum
, f
->filename
);
3900 else if (!_cups_strcasecmp(token
, "WITH-VALUE-FROM"))
3902 if (!_ippFileReadToken(f
, temp
, sizeof(temp
)))
3904 print_fatal_error(data
, "Missing %s value on line %d of \"%s\".", token
, f
->linenum
, f
->filename
);
3908 if (data
->last_expect
)
3911 * Expand any variables in the value and then save it.
3914 _ippVarsExpand(vars
, value
, temp
, sizeof(value
));
3916 data
->last_expect
->with_value_from
= strdup(value
);
3917 data
->last_expect
->with_flags
= _CUPS_WITH_LITERAL
;
3921 print_fatal_error(data
, "%s without a preceding EXPECT on line %d of \"%s\".", token
, f
->linenum
, f
->filename
);
3925 else if (!_cups_strcasecmp(token
, "DISPLAY"))
3928 * Display attributes...
3931 if (data
->num_displayed
>= (int)(sizeof(data
->displayed
) / sizeof(data
->displayed
[0])))
3933 print_fatal_error(data
, "Too many DISPLAY's on line %d of \"%s\".", f
->linenum
, f
->filename
);
3937 if (!_ippFileReadToken(f
, temp
, sizeof(temp
)))
3939 print_fatal_error(data
, "Missing DISPLAY name on line %d of \"%s\".", f
->linenum
, f
->filename
);
3943 data
->displayed
[data
->num_displayed
] = strdup(temp
);
3944 data
->num_displayed
++;
3948 print_fatal_error(data
, "Unexpected token %s seen on line %d of \"%s\".", token
, f
->linenum
, f
->filename
);
3955 * Scan for the start of a test (open brace)...
3958 if (!strcmp(token
, "{"))
3964 if (data
->show_header
)
3966 if (data
->output
== _CUPS_OUTPUT_PLIST
)
3967 print_xml_header(data
);
3969 if (data
->output
== _CUPS_OUTPUT_TEST
|| (data
->output
== _CUPS_OUTPUT_PLIST
&& data
->outfile
!= cupsFileStdout()))
3970 cupsFilePrintf(cupsFileStdout(), "\"%s\":\n", f
->filename
);
3972 data
->show_header
= 0;
3975 data
->compression
[0] = '\0';
3977 data
->num_expects
= 0;
3978 data
->last_expect
= NULL
;
3979 data
->file
[0] = '\0';
3980 data
->ignore_errors
= data
->def_ignore_errors
;
3981 strlcpy(data
->name
, f
->filename
, sizeof(data
->name
));
3982 if ((ptr
= strrchr(data
->name
, '.')) != NULL
)
3984 data
->repeat_interval
= 5000000;
3985 data
->request_id
++;
3986 strlcpy(data
->resource
, vars
->resource
, sizeof(data
->resource
));
3987 data
->skip_previous
= 0;
3988 data
->skip_test
= 0;
3989 data
->num_statuses
= 0;
3990 data
->last_status
= NULL
;
3991 data
->test_id
[0] = '\0';
3992 data
->transfer
= data
->def_transfer
;
3993 data
->version
= data
->def_version
;
3995 f
->attrs
= ippNew();
3996 f
->group_tag
= IPP_TAG_ZERO
;
3998 else if (!strcmp(token
, "DEFINE"))
4004 if (_ippFileReadToken(f
, name
, sizeof(name
)) && _ippFileReadToken(f
, temp
, sizeof(temp
)))
4006 _ippVarsExpand(vars
, value
, temp
, sizeof(value
));
4007 _ippVarsSet(vars
, name
, value
);
4011 print_fatal_error(data
, "Missing DEFINE name and/or value on line %d of \"%s\".", f
->linenum
, f
->filename
);
4015 else if (!strcmp(token
, "DEFINE-DEFAULT"))
4018 * DEFINE-DEFAULT name value
4021 if (_ippFileReadToken(f
, name
, sizeof(name
)) && _ippFileReadToken(f
, temp
, sizeof(temp
)))
4023 if (!_ippVarsGet(vars
, name
))
4025 _ippVarsExpand(vars
, value
, temp
, sizeof(value
));
4026 _ippVarsSet(vars
, name
, value
);
4031 print_fatal_error(data
, "Missing DEFINE-DEFAULT name and/or value on line %d of \"%s\".", f
->linenum
, f
->filename
);
4035 else if (!strcmp(token
, "FILE-ID"))
4041 if (_ippFileReadToken(f
, temp
, sizeof(temp
)))
4043 _ippVarsExpand(vars
, data
->file_id
, temp
, sizeof(data
->file_id
));
4047 print_fatal_error(data
, "Missing FILE-ID value on line %d of \"%s\".", f
->linenum
, f
->filename
);
4051 else if (!strcmp(token
, "IGNORE-ERRORS"))
4058 if (_ippFileReadToken(f
, temp
, sizeof(temp
)) && (!_cups_strcasecmp(temp
, "yes") || !_cups_strcasecmp(temp
, "no")))
4060 data
->def_ignore_errors
= !_cups_strcasecmp(temp
, "yes");
4064 print_fatal_error(data
, "Missing IGNORE-ERRORS value on line %d of \"%s\".", f
->linenum
, f
->filename
);
4068 else if (!strcmp(token
, "INCLUDE"))
4071 * INCLUDE "filename"
4072 * INCLUDE <filename>
4075 if (_ippFileReadToken(f
, temp
, sizeof(temp
)))
4078 * Map the filename to and then run the tests...
4081 _cups_testdata_t inc_data
; /* Data for included file */
4082 char filename
[1024]; /* Mapped filename */
4084 memcpy(&inc_data
, data
, sizeof(inc_data
));
4085 inc_data
.http
= NULL
;
4087 inc_data
.prev_pass
= 1;
4088 inc_data
.show_header
= 1;
4090 if (!do_tests(get_filename(f
->filename
, filename
, temp
, sizeof(filename
)), vars
, &inc_data
) && data
->stop_after_include_error
)
4092 data
->pass
= data
->prev_pass
= 0;
4098 print_fatal_error(data
, "Missing INCLUDE filename on line %d of \"%s\".", f
->linenum
, f
->filename
);
4102 data
->show_header
= 1;
4104 else if (!strcmp(token
, "INCLUDE-IF-DEFINED"))
4107 * INCLUDE-IF-DEFINED name "filename"
4108 * INCLUDE-IF-DEFINED name <filename>
4111 if (_ippFileReadToken(f
, name
, sizeof(name
)) && _ippFileReadToken(f
, temp
, sizeof(temp
)))
4114 * Map the filename to and then run the tests...
4117 _cups_testdata_t inc_data
; /* Data for included file */
4118 char filename
[1024]; /* Mapped filename */
4120 memcpy(&inc_data
, data
, sizeof(inc_data
));
4121 inc_data
.http
= NULL
;
4123 inc_data
.prev_pass
= 1;
4124 inc_data
.show_header
= 1;
4126 if (!do_tests(get_filename(f
->filename
, filename
, temp
, sizeof(filename
)), vars
, &inc_data
) && data
->stop_after_include_error
)
4128 data
->pass
= data
->prev_pass
= 0;
4134 print_fatal_error(data
, "Missing INCLUDE-IF-DEFINED name or filename on line %d of \"%s\".", f
->linenum
, f
->filename
);
4138 data
->show_header
= 1;
4140 else if (!strcmp(token
, "INCLUDE-IF-NOT-DEFINED"))
4143 * INCLUDE-IF-NOT-DEFINED name "filename"
4144 * INCLUDE-IF-NOT-DEFINED name <filename>
4147 if (_ippFileReadToken(f
, name
, sizeof(name
)) && _ippFileReadToken(f
, temp
, sizeof(temp
)))
4150 * Map the filename to and then run the tests...
4153 _cups_testdata_t inc_data
; /* Data for included file */
4154 char filename
[1024]; /* Mapped filename */
4156 memcpy(&inc_data
, data
, sizeof(inc_data
));
4157 inc_data
.http
= NULL
;
4159 inc_data
.prev_pass
= 1;
4160 inc_data
.show_header
= 1;
4162 if (!do_tests(get_filename(f
->filename
, filename
, temp
, sizeof(filename
)), vars
, &inc_data
) && data
->stop_after_include_error
)
4164 data
->pass
= data
->prev_pass
= 0;
4170 print_fatal_error(data
, "Missing INCLUDE-IF-NOT-DEFINED name or filename on line %d of \"%s\".", f
->linenum
, f
->filename
);
4174 data
->show_header
= 1;
4176 else if (!strcmp(token
, "SKIP-IF-DEFINED"))
4179 * SKIP-IF-DEFINED variable
4182 if (_ippFileReadToken(f
, name
, sizeof(name
)))
4184 if (_ippVarsGet(vars
, name
))
4185 data
->skip_test
= 1;
4189 print_fatal_error(data
, "Missing SKIP-IF-DEFINED variable on line %d of \"%s\".", f
->linenum
, f
->filename
);
4193 else if (!strcmp(token
, "SKIP-IF-NOT-DEFINED"))
4196 * SKIP-IF-NOT-DEFINED variable
4199 if (_ippFileReadToken(f
, name
, sizeof(name
)))
4201 if (!_ippVarsGet(vars
, name
))
4202 data
->skip_test
= 1;
4206 print_fatal_error(data
, "Missing SKIP-IF-NOT-DEFINED variable on line %d of \"%s\".", f
->linenum
, f
->filename
);
4210 else if (!strcmp(token
, "STOP-AFTER-INCLUDE-ERROR"))
4213 * STOP-AFTER-INCLUDE-ERROR yes
4214 * STOP-AFTER-INCLUDE-ERROR no
4217 if (_ippFileReadToken(f
, temp
, sizeof(temp
)) && (!_cups_strcasecmp(temp
, "yes") || !_cups_strcasecmp(temp
, "no")))
4219 data
->stop_after_include_error
= !_cups_strcasecmp(temp
, "yes");
4223 print_fatal_error(data
, "Missing STOP-AFTER-INCLUDE-ERROR value on line %d of \"%s\".", f
->linenum
, f
->filename
);
4227 else if (!strcmp(token
, "TRANSFER"))
4235 if (_ippFileReadToken(f
, temp
, sizeof(temp
)))
4237 if (!strcmp(temp
, "auto"))
4238 data
->def_transfer
= _CUPS_TRANSFER_AUTO
;
4239 else if (!strcmp(temp
, "chunked"))
4240 data
->def_transfer
= _CUPS_TRANSFER_CHUNKED
;
4241 else if (!strcmp(temp
, "length"))
4242 data
->def_transfer
= _CUPS_TRANSFER_LENGTH
;
4245 print_fatal_error(data
, "Bad TRANSFER value \"%s\" on line %d of \"%s\".", temp
, f
->linenum
, f
->filename
);
4251 print_fatal_error(data
, "Missing TRANSFER value on line %d of \"%s\".", f
->linenum
, f
->filename
);
4255 else if (!strcmp(token
, "VERSION"))
4257 if (_ippFileReadToken(f
, temp
, sizeof(temp
)))
4259 if (!strcmp(temp
, "1.0"))
4260 data
->def_version
= 10;
4261 else if (!strcmp(temp
, "1.1"))
4262 data
->def_version
= 11;
4263 else if (!strcmp(temp
, "2.0"))
4264 data
->def_version
= 20;
4265 else if (!strcmp(temp
, "2.1"))
4266 data
->def_version
= 21;
4267 else if (!strcmp(temp
, "2.2"))
4268 data
->def_version
= 22;
4271 print_fatal_error(data
, "Bad VERSION \"%s\" on line %d of \"%s\".", temp
, f
->linenum
, f
->filename
);
4277 print_fatal_error(data
, "Missing VERSION number on line %d of \"%s\".", f
->linenum
, f
->filename
);
4283 print_fatal_error(data
, "Unexpected token %s seen on line %d of \"%s\".", token
, f
->linenum
, f
->filename
);
4293 * 'usage()' - Show program usage.
4299 _cupsLangPuts(stderr
, _("Usage: ipptool [options] URI filename [ ... filenameN ]"));
4300 _cupsLangPuts(stderr
, _("Options:"));
4301 _cupsLangPuts(stderr
, _(" --help Show help."));
4302 _cupsLangPuts(stderr
, _(" --ippserver filename Produce ippserver attribute file."));
4303 _cupsLangPuts(stderr
, _(" --stop-after-include-error\n"
4304 " Stop tests after a failed INCLUDE."));
4305 _cupsLangPuts(stderr
, _(" --version Show version."));
4306 _cupsLangPuts(stderr
, _(" -4 Connect using IPv4."));
4307 _cupsLangPuts(stderr
, _(" -6 Connect using IPv6."));
4308 _cupsLangPuts(stderr
, _(" -C Send requests using "
4309 "chunking (default)."));
4310 _cupsLangPuts(stderr
, _(" -E Test with encryption using HTTP Upgrade to TLS."));
4311 _cupsLangPuts(stderr
, _(" -I Ignore errors."));
4312 _cupsLangPuts(stderr
, _(" -L Send requests using content-length."));
4313 _cupsLangPuts(stderr
, _(" -P filename.plist Produce XML plist to a file and test report to standard output."));
4314 _cupsLangPuts(stderr
, _(" -S Test with encryption using HTTPS."));
4315 _cupsLangPuts(stderr
, _(" -T seconds Set the receive/send timeout in seconds."));
4316 _cupsLangPuts(stderr
, _(" -V version Set default IPP version."));
4317 _cupsLangPuts(stderr
, _(" -X Produce XML plist instead of plain text."));
4318 _cupsLangPuts(stderr
, _(" -c Produce CSV output."));
4319 _cupsLangPuts(stderr
, _(" -d name=value Set named variable to value."));
4320 _cupsLangPuts(stderr
, _(" -f filename Set default request filename."));
4321 _cupsLangPuts(stderr
, _(" -h Validate HTTP response headers."));
4322 _cupsLangPuts(stderr
, _(" -i seconds Repeat the last file with the given time interval."));
4323 _cupsLangPuts(stderr
, _(" -l Produce plain text output."));
4324 _cupsLangPuts(stderr
, _(" -n count Repeat the last file the given number of times."));
4325 _cupsLangPuts(stderr
, _(" -q Run silently."));
4326 _cupsLangPuts(stderr
, _(" -t Produce a test report."));
4327 _cupsLangPuts(stderr
, _(" -v Be verbose."));
4334 * 'with_flags_string()' - Return the "WITH-xxx" predicate that corresponds to
4338 static const char * /* O - WITH-xxx string */
4339 with_flags_string(int flags
) /* I - WITH flags */
4341 if (flags
& _CUPS_WITH_ALL
)
4343 if (flags
& _CUPS_WITH_HOSTNAME
)
4344 return ("WITH-ALL-HOSTNAMES");
4345 else if (flags
& _CUPS_WITH_RESOURCE
)
4346 return ("WITH-ALL-RESOURCES");
4347 else if (flags
& _CUPS_WITH_SCHEME
)
4348 return ("WITH-ALL-SCHEMES");
4350 return ("WITH-ALL-VALUES");
4352 else if (flags
& _CUPS_WITH_HOSTNAME
)
4353 return ("WITH-HOSTNAME");
4354 else if (flags
& _CUPS_WITH_RESOURCE
)
4355 return ("WITH-RESOURCE");
4356 else if (flags
& _CUPS_WITH_SCHEME
)
4357 return ("WITH-SCHEME");
4359 return ("WITH-VALUE");
4364 * 'with_value()' - Test a WITH-VALUE predicate.
4367 static int /* O - 1 on match, 0 on non-match */
4368 with_value(_cups_testdata_t
*data
, /* I - Test data */
4369 cups_array_t
*errors
, /* I - Errors array */
4370 char *value
, /* I - Value string */
4371 int flags
, /* I - Flags for match */
4372 ipp_attribute_t
*attr
, /* I - Attribute to compare */
4373 char *matchbuf
, /* I - Buffer to hold matching value */
4374 size_t matchlen
) /* I - Length of match buffer */
4376 int i
, /* Looping var */
4377 count
, /* Number of values */
4379 char temp
[1024], /* Temporary value string */
4380 *valptr
; /* Pointer into value */
4381 const char *name
; /* Attribute name */
4385 match
= (flags
& _CUPS_WITH_ALL
) ? 1 : 0;
4388 * NULL matches everything.
4391 if (!value
|| !*value
)
4395 * Compare the value string to the attribute value.
4398 name
= ippGetName(attr
);
4399 count
= ippGetCount(attr
);
4401 switch (ippGetValueTag(attr
))
4403 case IPP_TAG_INTEGER
:
4405 for (i
= 0; i
< count
; i
++)
4407 char op
, /* Comparison operator */
4408 *nextptr
; /* Next pointer */
4409 int intvalue
, /* Integer value */
4410 attrvalue
= ippGetInteger(attr
, i
),
4411 /* Attribute value */
4412 valmatch
= 0; /* Does the current value match? */
4416 while (isspace(*valptr
& 255) || isdigit(*valptr
& 255) ||
4417 *valptr
== '-' || *valptr
== ',' || *valptr
== '<' ||
4418 *valptr
== '=' || *valptr
== '>')
4421 while (*valptr
&& !isdigit(*valptr
& 255) && *valptr
!= '-')
4423 if (*valptr
== '<' || *valptr
== '>' || *valptr
== '=')
4431 intvalue
= (int)strtol(valptr
, &nextptr
, 0);
4432 if (nextptr
== valptr
)
4436 if ((op
== '=' && attrvalue
== intvalue
) ||
4437 (op
== '<' && attrvalue
< intvalue
) ||
4438 (op
== '>' && attrvalue
> intvalue
))
4441 snprintf(matchbuf
, matchlen
, "%d", attrvalue
);
4448 if (flags
& _CUPS_WITH_ALL
)
4463 if (!match
&& errors
)
4465 for (i
= 0; i
< count
; i
++)
4466 add_stringf(data
->errors
, "GOT: %s=%d", name
, ippGetInteger(attr
, i
));
4470 case IPP_TAG_RANGE
:
4471 for (i
= 0; i
< count
; i
++)
4473 char op
, /* Comparison operator */
4474 *nextptr
; /* Next pointer */
4475 int intvalue
, /* Integer value */
4476 lower
, /* Lower range */
4477 upper
, /* Upper range */
4478 valmatch
= 0; /* Does the current value match? */
4480 lower
= ippGetRange(attr
, i
, &upper
);
4483 while (isspace(*valptr
& 255) || isdigit(*valptr
& 255) ||
4484 *valptr
== '-' || *valptr
== ',' || *valptr
== '<' ||
4485 *valptr
== '=' || *valptr
== '>')
4488 while (*valptr
&& !isdigit(*valptr
& 255) && *valptr
!= '-')
4490 if (*valptr
== '<' || *valptr
== '>' || *valptr
== '=')
4498 intvalue
= (int)strtol(valptr
, &nextptr
, 0);
4499 if (nextptr
== valptr
)
4503 if ((op
== '=' && (lower
== intvalue
|| upper
== intvalue
)) ||
4504 (op
== '<' && upper
< intvalue
) ||
4505 (op
== '>' && upper
> intvalue
))
4508 snprintf(matchbuf
, matchlen
, "%d-%d", lower
, upper
);
4515 if (flags
& _CUPS_WITH_ALL
)
4530 if (!match
&& errors
)
4532 for (i
= 0; i
< count
; i
++)
4534 int lower
, upper
; /* Range values */
4536 lower
= ippGetRange(attr
, i
, &upper
);
4537 add_stringf(data
->errors
, "GOT: %s=%d-%d", name
, lower
, upper
);
4542 case IPP_TAG_BOOLEAN
:
4543 for (i
= 0; i
< count
; i
++)
4545 if ((!strcmp(value
, "true")) == ippGetBoolean(attr
, i
))
4548 strlcpy(matchbuf
, value
, matchlen
);
4550 if (!(flags
& _CUPS_WITH_ALL
))
4556 else if (flags
& _CUPS_WITH_ALL
)
4563 if (!match
&& errors
)
4565 for (i
= 0; i
< count
; i
++)
4566 add_stringf(data
->errors
, "GOT: %s=%s", name
, ippGetBoolean(attr
, i
) ? "true" : "false");
4570 case IPP_TAG_RESOLUTION
:
4571 for (i
= 0; i
< count
; i
++)
4573 int xres
, yres
; /* Resolution values */
4574 ipp_res_t units
; /* Resolution units */
4576 xres
= ippGetResolution(attr
, i
, &yres
, &units
);
4578 snprintf(temp
, sizeof(temp
), "%d%s", xres
, units
== IPP_RES_PER_INCH
? "dpi" : "dpcm");
4580 snprintf(temp
, sizeof(temp
), "%dx%d%s", xres
, yres
, units
== IPP_RES_PER_INCH
? "dpi" : "dpcm");
4582 if (!strcmp(value
, temp
))
4585 strlcpy(matchbuf
, value
, matchlen
);
4587 if (!(flags
& _CUPS_WITH_ALL
))
4593 else if (flags
& _CUPS_WITH_ALL
)
4600 if (!match
&& errors
)
4602 for (i
= 0; i
< count
; i
++)
4604 int xres
, yres
; /* Resolution values */
4605 ipp_res_t units
; /* Resolution units */
4607 xres
= ippGetResolution(attr
, i
, &yres
, &units
);
4609 snprintf(temp
, sizeof(temp
), "%d%s", xres
, units
== IPP_RES_PER_INCH
? "dpi" : "dpcm");
4611 snprintf(temp
, sizeof(temp
), "%dx%d%s", xres
, yres
, units
== IPP_RES_PER_INCH
? "dpi" : "dpcm");
4613 if (strcmp(value
, temp
))
4614 add_stringf(data
->errors
, "GOT: %s=%s", name
, temp
);
4619 case IPP_TAG_NOVALUE
:
4620 case IPP_TAG_UNKNOWN
:
4623 case IPP_TAG_CHARSET
:
4624 case IPP_TAG_KEYWORD
:
4625 case IPP_TAG_LANGUAGE
:
4626 case IPP_TAG_MIMETYPE
:
4628 case IPP_TAG_NAMELANG
:
4630 case IPP_TAG_TEXTLANG
:
4632 case IPP_TAG_URISCHEME
:
4633 if (flags
& _CUPS_WITH_REGEX
)
4636 * Value is an extended, case-sensitive POSIX regular expression...
4639 regex_t re
; /* Regular expression */
4641 if ((i
= regcomp(&re
, value
, REG_EXTENDED
| REG_NOSUB
)) != 0)
4643 regerror(i
, &re
, temp
, sizeof(temp
));
4645 print_fatal_error(data
, "Unable to compile WITH-VALUE regular expression \"%s\" - %s", value
, temp
);
4650 * See if ALL of the values match the given regular expression.
4653 for (i
= 0; i
< count
; i
++)
4655 if (!regexec(&re
, get_string(attr
, i
, flags
, temp
, sizeof(temp
)),
4659 strlcpy(matchbuf
, get_string(attr
, i
, flags
, temp
, sizeof(temp
)), matchlen
);
4661 if (!(flags
& _CUPS_WITH_ALL
))
4667 else if (flags
& _CUPS_WITH_ALL
)
4676 else if (ippGetValueTag(attr
) == IPP_TAG_URI
&& !(flags
& (_CUPS_WITH_SCHEME
| _CUPS_WITH_HOSTNAME
| _CUPS_WITH_RESOURCE
)))
4679 * Value is a literal URI string, see if the value(s) match...
4682 for (i
= 0; i
< count
; i
++)
4684 if (!compare_uris(value
, get_string(attr
, i
, flags
, temp
, sizeof(temp
))))
4687 strlcpy(matchbuf
, get_string(attr
, i
, flags
, temp
, sizeof(temp
)), matchlen
);
4689 if (!(flags
& _CUPS_WITH_ALL
))
4695 else if (flags
& _CUPS_WITH_ALL
)
4705 * Value is a literal string, see if the value(s) match...
4708 for (i
= 0; i
< count
; i
++)
4712 switch (ippGetValueTag(attr
))
4716 * Some URI components are case-sensitive, some not...
4719 if (flags
& (_CUPS_WITH_SCHEME
| _CUPS_WITH_HOSTNAME
))
4720 result
= _cups_strcasecmp(value
, get_string(attr
, i
, flags
, temp
, sizeof(temp
)));
4722 result
= strcmp(value
, get_string(attr
, i
, flags
, temp
, sizeof(temp
)));
4725 case IPP_TAG_MIMETYPE
:
4727 case IPP_TAG_NAMELANG
:
4729 case IPP_TAG_TEXTLANG
:
4731 * mimeMediaType, nameWithoutLanguage, nameWithLanguage,
4732 * textWithoutLanguage, and textWithLanguage are defined to
4733 * be case-insensitive strings...
4736 result
= _cups_strcasecmp(value
, get_string(attr
, i
, flags
, temp
, sizeof(temp
)));
4741 * Other string syntaxes are defined as lowercased so we use
4742 * case-sensitive comparisons to catch problems...
4745 result
= strcmp(value
, get_string(attr
, i
, flags
, temp
, sizeof(temp
)));
4752 strlcpy(matchbuf
, get_string(attr
, i
, flags
, temp
, sizeof(temp
)), matchlen
);
4754 if (!(flags
& _CUPS_WITH_ALL
))
4760 else if (flags
& _CUPS_WITH_ALL
)
4768 if (!match
&& errors
)
4770 for (i
= 0; i
< count
; i
++)
4771 add_stringf(data
->errors
, "GOT: %s=\"%s\"", name
, ippGetString(attr
, i
, NULL
));
4775 case IPP_TAG_STRING
:
4777 unsigned char withdata
[1023], /* WITH-VALUE data */
4778 *adata
; /* Pointer to octetString data */
4779 int withlen
, /* Length of WITH-VALUE data */
4780 adatalen
; /* Length of octetString */
4785 * Grab hex-encoded value...
4788 if ((withlen
= (int)strlen(value
)) & 1 || withlen
> (int)(2 * (sizeof(withdata
) + 1)))
4790 print_fatal_error(data
, "Bad WITH-VALUE hex value.");
4794 withlen
= withlen
/ 2 - 1;
4796 for (valptr
= value
+ 1, adata
= withdata
; *valptr
; valptr
+= 2)
4798 int ch
; /* Current character/byte */
4800 if (isdigit(valptr
[0]))
4801 ch
= (valptr
[0] - '0') << 4;
4802 else if (isalpha(valptr
[0]))
4803 ch
= (tolower(valptr
[0]) - 'a' + 10) << 4;
4807 if (isdigit(valptr
[1]))
4808 ch
|= valptr
[1] - '0';
4809 else if (isalpha(valptr
[1]))
4810 ch
|= tolower(valptr
[1]) - 'a' + 10;
4814 *adata
++ = (unsigned char)ch
;
4819 print_fatal_error(data
, "Bad WITH-VALUE hex value.");
4826 * Copy literal string value...
4829 withlen
= (int)strlen(value
);
4831 memcpy(withdata
, value
, withlen
);
4834 for (i
= 0; i
< count
; i
++)
4836 adata
= ippGetOctetString(attr
, i
, &adatalen
);
4838 if (withlen
== adatalen
&& !memcmp(withdata
, adata
, (size_t)withlen
))
4841 copy_hex_string(matchbuf
, adata
, adatalen
, matchlen
);
4843 if (!(flags
& _CUPS_WITH_ALL
))
4849 else if (flags
& _CUPS_WITH_ALL
)
4856 if (!match
&& errors
)
4858 for (i
= 0; i
< count
; i
++)
4860 adata
= ippGetOctetString(attr
, i
, &adatalen
);
4861 copy_hex_string(temp
, adata
, adatalen
, sizeof(temp
));
4862 add_stringf(data
->errors
, "GOT: %s=\"%s\"", name
, temp
);
4877 * 'with_value_from()' - Test a WITH-VALUE-FROM predicate.
4880 static int /* O - 1 on match, 0 on non-match */
4882 cups_array_t
*errors
, /* I - Errors array */
4883 ipp_attribute_t
*fromattr
, /* I - "From" attribute */
4884 ipp_attribute_t
*attr
, /* I - Attribute to compare */
4885 char *matchbuf
, /* I - Buffer to hold matching value */
4886 size_t matchlen
) /* I - Length of match buffer */
4888 int i
, j
, /* Looping vars */
4889 count
= ippGetCount(attr
), /* Number of attribute values */
4890 match
= 1; /* Match? */
4896 * Compare the from value(s) to the attribute value(s)...
4899 switch (ippGetValueTag(attr
))
4901 case IPP_TAG_INTEGER
:
4902 if (ippGetValueTag(fromattr
) != IPP_TAG_INTEGER
&& ippGetValueTag(fromattr
) != IPP_TAG_RANGE
)
4903 goto wrong_value_tag
;
4905 for (i
= 0; i
< count
; i
++)
4907 int value
= ippGetInteger(attr
, i
);
4908 /* Current integer value */
4910 if (ippContainsInteger(fromattr
, value
))
4913 snprintf(matchbuf
, matchlen
, "%d", value
);
4917 add_stringf(errors
, "GOT: %s=%d", ippGetName(attr
), value
);
4924 if (ippGetValueTag(fromattr
) != IPP_TAG_ENUM
)
4925 goto wrong_value_tag
;
4927 for (i
= 0; i
< count
; i
++)
4929 int value
= ippGetInteger(attr
, i
);
4930 /* Current integer value */
4932 if (ippContainsInteger(fromattr
, value
))
4935 snprintf(matchbuf
, matchlen
, "%d", value
);
4939 add_stringf(errors
, "GOT: %s=%d", ippGetName(attr
), value
);
4945 case IPP_TAG_RESOLUTION
:
4946 if (ippGetValueTag(fromattr
) != IPP_TAG_RESOLUTION
)
4947 goto wrong_value_tag
;
4949 for (i
= 0; i
< count
; i
++)
4953 int fromcount
= ippGetCount(fromattr
);
4954 int fromxres
, fromyres
;
4955 ipp_res_t fromunits
;
4957 xres
= ippGetResolution(attr
, i
, &yres
, &units
);
4959 for (j
= 0; j
< fromcount
; j
++)
4961 fromxres
= ippGetResolution(fromattr
, j
, &fromyres
, &fromunits
);
4962 if (fromxres
== xres
&& fromyres
== yres
&& fromunits
== units
)
4971 snprintf(matchbuf
, matchlen
, "%d%s", xres
, units
== IPP_RES_PER_INCH
? "dpi" : "dpcm");
4973 snprintf(matchbuf
, matchlen
, "%dx%d%s", xres
, yres
, units
== IPP_RES_PER_INCH
? "dpi" : "dpcm");
4979 add_stringf(errors
, "GOT: %s=%d%s", ippGetName(attr
), xres
, units
== IPP_RES_PER_INCH
? "dpi" : "dpcm");
4981 add_stringf(errors
, "GOT: %s=%dx%d%s", ippGetName(attr
), xres
, yres
, units
== IPP_RES_PER_INCH
? "dpi" : "dpcm");
4988 case IPP_TAG_NOVALUE
:
4989 case IPP_TAG_UNKNOWN
:
4992 case IPP_TAG_CHARSET
:
4993 case IPP_TAG_KEYWORD
:
4994 case IPP_TAG_LANGUAGE
:
4995 case IPP_TAG_MIMETYPE
:
4997 case IPP_TAG_NAMELANG
:
4999 case IPP_TAG_TEXTLANG
:
5000 case IPP_TAG_URISCHEME
:
5001 for (i
= 0; i
< count
; i
++)
5003 const char *value
= ippGetString(attr
, i
, NULL
);
5004 /* Current string value */
5006 if (ippContainsString(fromattr
, value
))
5009 strlcpy(matchbuf
, value
, matchlen
);
5013 add_stringf(errors
, "GOT: %s='%s'", ippGetName(attr
), value
);
5020 for (i
= 0; i
< count
; i
++)
5022 const char *value
= ippGetString(attr
, i
, NULL
);
5023 /* Current string value */
5024 int fromcount
= ippGetCount(fromattr
);
5026 for (j
= 0; j
< fromcount
; j
++)
5028 if (!compare_uris(value
, ippGetString(fromattr
, j
, NULL
)))
5031 strlcpy(matchbuf
, value
, matchlen
);
5038 add_stringf(errors
, "GOT: %s='%s'", ippGetName(attr
), value
);
5051 /* value tag mismatch between fromattr and attr */
5054 add_stringf(errors
, "GOT: %s OF-TYPE %s", ippGetName(attr
), ippTagString(ippGetValueTag(attr
)));