4 * ipptool command for CUPS.
6 * Copyright 2007-2011 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products.
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
15 * This file is subject to the Apple OS-Developed Software exception.
19 * main() - Parse options and do tests.
20 * compare_vars() - Compare two variables.
21 * do_tests() - Do tests as specified in the test file.
22 * expand_variables() - Expand variables in a string.
23 * expect_matches() - Return true if the tag matches the specification.
24 * get_collection() - Get a collection value from the current test file.
25 * get_filename() - Get a filename based on the current test file.
26 * get_token() - Get a token from a file.
27 * get_variable() - Get the value of a variable.
28 * iso_date() - Return an ISO 8601 date/time string for the given IPP
30 * password_cb() - Password callback for authenticated tests.
31 * print_attr() - Print an attribute on the screen.
32 * print_col() - Print a collection attribute on the screen.
33 * print_csv() - Print a line of CSV text.
34 * print_fatal_error() - Print a fatal error message.
35 * print_line() - Print a line of formatted or CSV text.
36 * print_test_error() - Print a test error message.
37 * print_xml_header() - Print a standard XML plist header.
38 * print_xml_string() - Print an XML string with escaping.
39 * print_xml_trailer() - Print the XML trailer with success/fail value.
40 * set_variable() - Set a variable value.
41 * sigterm_handler() - Handle SIGINT and SIGTERM.
42 * timeout_cb() - Handle HTTP timeouts.
43 * usage() - Show program usage.
44 * validate_attr() - Determine whether an attribute is valid.
45 * with_value() - Test a WITH-VALUE predicate.
49 * Include necessary headers...
52 #include <cups/cups-private.h>
53 #include <cups/file-private.h>
61 #endif /* !O_BINARY */
68 typedef enum _cups_transfer_e
/**** How to send request data ****/
70 _CUPS_TRANSFER_AUTO
, /* Chunk for files, length for static */
71 _CUPS_TRANSFER_CHUNKED
, /* Chunk always */
72 _CUPS_TRANSFER_LENGTH
/* Length always */
75 typedef enum _cups_output_e
/**** Output mode ****/
77 _CUPS_OUTPUT_QUIET
, /* No output */
78 _CUPS_OUTPUT_TEST
, /* Traditional CUPS test output */
79 _CUPS_OUTPUT_PLIST
, /* XML plist test output */
80 _CUPS_OUTPUT_LIST
, /* Tabular list output */
81 _CUPS_OUTPUT_CSV
/* Comma-separated values output */
84 typedef struct _cups_expect_s
/**** Expected attribute info ****/
86 int optional
, /* Optional attribute? */
87 not_expect
; /* Don't expect attribute? */
88 char *name
, /* Attribute name */
89 *of_type
, /* Type name */
90 *same_count_as
, /* Parallel attribute name */
91 *if_defined
, /* Only required if variable defined */
92 *if_not_defined
, /* Only required if variable is not defined */
93 *with_value
, /* Attribute must include this value */
94 *define_match
, /* Variable to define on match */
95 *define_no_match
, /* Variable to define on no-match */
96 *define_value
; /* Variable to define with value */
97 int repeat_match
, /* Repeat test on match */
98 repeat_no_match
, /* Repeat test on no match */
99 with_regex
, /* WITH-VALUE is a regular expression */
100 count
; /* Expected count if > 0 */
101 ipp_tag_t in_group
; /* IN-GROUP value */
104 typedef struct _cups_status_s
/**** Status info ****/
106 ipp_status_t status
; /* Expected status code */
107 char *if_defined
, /* Only if variable is defined */
108 *if_not_defined
; /* Only if variable is not defined */
109 int repeat_match
, /* Repeat the test when it does not match */
110 repeat_no_match
; /* Repeat the test when it matches */
113 typedef struct _cups_var_s
/**** Variable ****/
115 char *name
, /* Name of variable */
116 *value
; /* Value of variable */
119 typedef struct _cups_vars_s
/**** Set of variables ****/
121 char *uri
, /* URI for printer */
122 *filename
, /* Filename */
123 scheme
[64], /* Scheme from URI */
124 userpass
[256], /* Username/password from URI */
125 hostname
[256], /* Hostname from URI */
126 resource
[1024]; /* Resource path from URI */
127 int port
; /* Port number from URI */
128 http_encryption_t encryption
; /* Encryption for connection? */
129 double timeout
; /* Timeout for connection */
130 int family
; /* Address family */
131 cups_array_t
*vars
; /* Array of variables */
139 _cups_transfer_t Transfer
= _CUPS_TRANSFER_AUTO
;
140 /* How to transfer requests */
141 _cups_output_t Output
= _CUPS_OUTPUT_LIST
;
143 int Cancel
= 0, /* Cancel test? */
144 IgnoreErrors
= 0, /* Ignore errors? */
145 Verbosity
= 0, /* Show all attributes? */
146 Version
= 11, /* Default IPP version */
147 XMLHeader
= 0, /* 1 if header is written */
148 TestCount
= 0, /* Number of tests run */
149 PassCount
= 0, /* Number of passing tests */
150 FailCount
= 0, /* Number of failing tests */
151 SkipCount
= 0; /* Number of skipped tests */
152 char *Password
= NULL
; /* Password from URI */
153 const char * const URIStatusStrings
[] = /* URI status strings */
156 "Bad arguments to function",
157 "Bad resource in URI",
158 "Bad port number in URI",
159 "Bad hostname/address in URI",
160 "Bad username in URI",
164 "Missing scheme in URI",
165 "Unknown scheme in URI",
166 "Missing resource in URI"
174 static int compare_vars(_cups_var_t
*a
, _cups_var_t
*b
);
175 static int do_tests(_cups_vars_t
*vars
, const char *testfile
);
176 static void expand_variables(_cups_vars_t
*vars
, char *dst
, const char *src
,
177 size_t dstsize
) __attribute__((nonnull(1,2,3)));
178 static int expect_matches(_cups_expect_t
*expect
, ipp_tag_t value_tag
);
179 static ipp_t
*get_collection(_cups_vars_t
*vars
, FILE *fp
, int *linenum
);
180 static char *get_filename(const char *testfile
, char *dst
, const char *src
,
182 static char *get_token(FILE *fp
, char *buf
, int buflen
,
184 static char *get_variable(_cups_vars_t
*vars
, const char *name
);
185 static char *iso_date(ipp_uchar_t
*date
);
186 static const char *password_cb(const char *prompt
);
187 static void print_attr(ipp_attribute_t
*attr
, ipp_tag_t
*group
);
188 static void print_col(ipp_t
*col
);
189 static void print_csv(ipp_attribute_t
*attr
, int num_displayed
,
190 char **displayed
, size_t *widths
);
191 static void print_fatal_error(const char *s
, ...)
192 __attribute__ ((__format__ (__printf__
, 1, 2)));
193 static void print_line(ipp_attribute_t
*attr
, int num_displayed
,
194 char **displayed
, size_t *widths
);
195 static void print_test_error(const char *s
, ...)
196 __attribute__ ((__format__ (__printf__
, 1, 2)));
197 static void print_xml_header(void);
198 static void print_xml_string(const char *element
, const char *s
);
199 static void print_xml_trailer(int success
, const char *message
);
200 static void set_variable(_cups_vars_t
*vars
, const char *name
,
203 static void sigterm_handler(int sig
);
205 static int timeout_cb(http_t
*http
, void *user_data
);
206 static void usage(void) __attribute__((noreturn
));
207 static int validate_attr(ipp_attribute_t
*attr
, int print
);
208 static int with_value(char *value
, int regex
, ipp_attribute_t
*attr
,
209 int report
, char *matchbuf
, size_t matchlen
);
213 * 'main()' - Parse options and do tests.
216 int /* O - Exit status */
217 main(int argc
, /* I - Number of command-line args */
218 char *argv
[]) /* I - Command-line arguments */
220 int i
; /* Looping var */
221 int status
; /* Status of tests... */
222 char *opt
, /* Current option */
223 name
[1024], /* Name/value buffer */
224 *value
, /* Pointer to value */
225 filename
[1024], /* Real filename */
226 testname
[1024], /* Real test filename */
227 uri
[1024]; /* Copy of printer URI */
228 const char *ext
, /* Extension on filename */
229 *testfile
; /* Test file to use */
230 int interval
, /* Test interval in microseconds */
231 repeat
; /* Repeat count */
232 _cups_vars_t vars
; /* Variables */
233 http_uri_status_t uri_status
; /* URI separation status */
234 _cups_globals_t
*cg
= _cupsGlobals();
240 * Catch SIGINT and SIGTERM...
243 signal(SIGINT
, sigterm_handler
);
244 signal(SIGTERM
, sigterm_handler
);
248 * Initialize the locale and variables...
251 _cupsSetLocale(argv
);
253 memset(&vars
, 0, sizeof(vars
));
254 vars
.family
= AF_UNSPEC
;
255 vars
.vars
= cupsArrayNew((cups_array_func_t
)compare_vars
, NULL
);
260 * ipptool URI testfile
268 for (i
= 1; i
< argc
; i
++)
270 if (argv
[i
][0] == '-')
272 for (opt
= argv
[i
] + 1; *opt
; opt
++)
276 case '4' : /* Connect using IPv4 only */
277 vars
.family
= AF_INET
;
281 case '6' : /* Connect using IPv6 only */
282 vars
.family
= AF_INET6
;
284 #endif /* AF_INET6 */
286 case 'C' : /* Enable HTTP chunking */
287 Transfer
= _CUPS_TRANSFER_CHUNKED
;
290 case 'E' : /* Encrypt with TLS */
292 vars
.encryption
= HTTP_ENCRYPT_REQUIRED
;
294 _cupsLangPrintf(stderr
, _("%s: Sorry, no encryption support."),
296 #endif /* HAVE_SSL */
299 case 'I' : /* Ignore errors */
303 case 'L' : /* Disable HTTP chunking */
304 Transfer
= _CUPS_TRANSFER_LENGTH
;
307 case 'S' : /* Encrypt with SSL */
309 vars
.encryption
= HTTP_ENCRYPT_ALWAYS
;
311 _cupsLangPrintf(stderr
, _("%s: Sorry, no encryption support."),
313 #endif /* HAVE_SSL */
316 case 'T' : /* Set timeout */
321 _cupsLangPuts(stderr
,
322 _("ipptool: Missing timeout for \"-T\"."));
326 vars
.timeout
= _cupsStrScand(argv
[i
], NULL
, localeconv());
329 case 'V' : /* Set IPP version */
334 _cupsLangPuts(stderr
,
335 _("ipptool: Missing version for \"-V\"."));
339 if (!strcmp(argv
[i
], "1.0"))
341 else if (!strcmp(argv
[i
], "1.1"))
343 else if (!strcmp(argv
[i
], "2.0"))
345 else if (!strcmp(argv
[i
], "2.1"))
347 else if (!strcmp(argv
[i
], "2.2"))
351 _cupsLangPrintf(stderr
,
352 _("ipptool: Bad version %s for \"-V\"."),
358 case 'X' : /* Produce XML output */
359 Output
= _CUPS_OUTPUT_PLIST
;
361 if (interval
|| repeat
)
363 _cupsLangPuts(stderr
, _("ipptool: \"-i\" and \"-n\" are "
364 "incompatible with -X\"."));
369 case 'c' : /* CSV output */
370 Output
= _CUPS_OUTPUT_CSV
;
373 case 'd' : /* Define a variable */
378 _cupsLangPuts(stderr
,
379 _("ipptool: Missing name=value for \"-d\"."));
383 strlcpy(name
, argv
[i
], sizeof(name
));
384 if ((value
= strchr(name
, '=')) != NULL
)
387 value
= name
+ strlen(name
);
389 set_variable(&vars
, name
, value
);
392 case 'f' : /* Set the default test filename */
397 _cupsLangPuts(stderr
,
398 _("ipptool: Missing filename for \"-f\"."));
405 if (access(argv
[i
], 0))
411 snprintf(filename
, sizeof(filename
), "%s.gz", argv
[i
]);
412 if (access(filename
, 0) && filename
[0] != '/')
414 snprintf(filename
, sizeof(filename
), "%s/ipptool/%s",
415 cg
->cups_datadir
, argv
[i
]);
416 if (access(filename
, 0))
418 snprintf(filename
, sizeof(filename
), "%s/ipptool/%s.gz",
419 cg
->cups_datadir
, argv
[i
]);
420 if (access(filename
, 0))
421 vars
.filename
= strdup(argv
[i
]);
424 vars
.filename
= strdup(filename
);
427 vars
.filename
= strdup(filename
);
430 vars
.filename
= strdup(argv
[i
]);
432 if ((ext
= strrchr(vars
.filename
, '.')) != NULL
)
435 * Guess the MIME media type based on the extension...
438 if (!_cups_strcasecmp(ext
, ".gif"))
439 set_variable(&vars
, "filetype", "image/gif");
440 else if (!_cups_strcasecmp(ext
, ".htm") ||
441 !_cups_strcasecmp(ext
, ".htm.gz") ||
442 !_cups_strcasecmp(ext
, ".html") ||
443 !_cups_strcasecmp(ext
, ".html.gz"))
444 set_variable(&vars
, "filetype", "text/html");
445 else if (!_cups_strcasecmp(ext
, ".jpg"))
446 set_variable(&vars
, "filetype", "image/jpeg");
447 else if (!_cups_strcasecmp(ext
, ".pdf"))
448 set_variable(&vars
, "filetype", "application/pdf");
449 else if (!_cups_strcasecmp(ext
, ".png"))
450 set_variable(&vars
, "filetype", "image/png");
451 else if (!_cups_strcasecmp(ext
, ".ps") ||
452 !_cups_strcasecmp(ext
, ".ps.gz"))
453 set_variable(&vars
, "filetype", "application/postscript");
454 else if (!_cups_strcasecmp(ext
, ".ras") ||
455 !_cups_strcasecmp(ext
, ".ras.gz"))
456 set_variable(&vars
, "filetype", "image/pwg-raster");
457 else if (!_cups_strcasecmp(ext
, ".txt") ||
458 !_cups_strcasecmp(ext
, ".txt.gz"))
459 set_variable(&vars
, "filetype", "text/plain");
460 else if (!_cups_strcasecmp(ext
, ".xps"))
461 set_variable(&vars
, "filetype", "application/openxps");
463 set_variable(&vars
, "filetype", "application/octet-stream");
468 * Use the "auto-type" MIME media type...
471 set_variable(&vars
, "filetype", "application/octet-stream");
475 case 'i' : /* Test every N seconds */
480 _cupsLangPuts(stderr
,
481 _("ipptool: Missing seconds for \"-i\"."));
486 interval
= (int)(_cupsStrScand(argv
[i
], NULL
, localeconv()) *
490 _cupsLangPuts(stderr
,
491 _("ipptool: Invalid seconds for \"-i\"."));
496 if (Output
== _CUPS_OUTPUT_PLIST
&& interval
)
498 _cupsLangPuts(stderr
, _("ipptool: \"-i\" is incompatible with "
504 case 'l' : /* List as a table */
505 Output
= _CUPS_OUTPUT_LIST
;
508 case 'n' : /* Repeat count */
513 _cupsLangPuts(stderr
,
514 _("ipptool: Missing count for \"-n\"."));
518 repeat
= atoi(argv
[i
]);
520 if (Output
== _CUPS_OUTPUT_PLIST
&& repeat
)
522 _cupsLangPuts(stderr
, _("ipptool: \"-n\" is incompatible with "
528 case 'q' : /* Be quiet */
529 Output
= _CUPS_OUTPUT_QUIET
;
532 case 't' : /* CUPS test output */
533 Output
= _CUPS_OUTPUT_TEST
;
536 case 'v' : /* Be verbose */
541 _cupsLangPrintf(stderr
, _("ipptool: Unknown option \"-%c\"."),
548 else if (!strncmp(argv
[i
], "ipp://", 6) || !strncmp(argv
[i
], "http://", 7)
550 || !strncmp(argv
[i
], "ipps://", 7)
551 || !strncmp(argv
[i
], "https://", 8)
552 #endif /* HAVE_SSL */
561 _cupsLangPuts(stderr
, _("ipptool: May only specify a single URI."));
566 if (!strncmp(argv
[i
], "ipps://", 7) || !strncmp(argv
[i
], "https://", 8))
567 vars
.encryption
= HTTP_ENCRYPT_ALWAYS
;
568 #endif /* HAVE_SSL */
571 uri_status
= httpSeparateURI(HTTP_URI_CODING_ALL
, vars
.uri
,
572 vars
.scheme
, sizeof(vars
.scheme
),
573 vars
.userpass
, sizeof(vars
.userpass
),
574 vars
.hostname
, sizeof(vars
.hostname
),
576 vars
.resource
, sizeof(vars
.resource
));
578 if (uri_status
!= HTTP_URI_OK
)
580 _cupsLangPrintf(stderr
, _("ipptool: Bad URI - %s."),
581 URIStatusStrings
[uri_status
- HTTP_URI_OVERFLOW
]);
585 if (vars
.userpass
[0])
587 if ((Password
= strchr(vars
.userpass
, ':')) != NULL
)
590 cupsSetUser(vars
.userpass
);
591 cupsSetPasswordCB(password_cb
);
592 set_variable(&vars
, "uriuser", vars
.userpass
);
595 httpAssembleURI(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), vars
.scheme
, NULL
,
596 vars
.hostname
, vars
.port
, vars
.resource
);
607 _cupsLangPuts(stderr
, _("ipptool: URI required before test file."));
611 if (access(argv
[i
], 0) && argv
[i
][0] != '/')
613 snprintf(testname
, sizeof(testname
), "%s/ipptool/%s", cg
->cups_datadir
,
615 if (access(testname
, 0))
623 if (!do_tests(&vars
, testfile
))
628 if (!vars
.uri
|| !testfile
)
632 * Loop if the interval is set...
635 if (Output
== _CUPS_OUTPUT_PLIST
)
636 print_xml_trailer(!status
, NULL
);
637 else if (interval
> 0 && repeat
> 0)
642 do_tests(&vars
, testfile
);
646 else if (interval
> 0)
651 do_tests(&vars
, testfile
);
654 else if (Output
== _CUPS_OUTPUT_TEST
&& TestCount
> 1)
657 * Show a summary report if there were multiple tests...
660 printf("\nSummary: %d tests, %d passed, %d failed, %d skipped\n"
661 "Score: %d%%\n", TestCount
, PassCount
, FailCount
, SkipCount
,
662 100 * (PassCount
+ SkipCount
) / TestCount
);
674 * 'compare_vars()' - Compare two variables.
677 static int /* O - Result of comparison */
678 compare_vars(_cups_var_t
*a
, /* I - First variable */
679 _cups_var_t
*b
) /* I - Second variable */
681 return (_cups_strcasecmp(a
->name
, b
->name
));
686 * 'do_tests()' - Do tests as specified in the test file.
689 static int /* 1 = success, 0 = failure */
690 do_tests(_cups_vars_t
*vars
, /* I - Variables */
691 const char *testfile
) /* I - Test file to use */
693 int i
, /* Looping var */
694 linenum
, /* Current line number */
695 pass
, /* Did we pass the test? */
696 prev_pass
= 1, /* Did we pass the previous test? */
697 request_id
, /* Current request ID */
698 show_header
= 1, /* Show the test header? */
699 ignore_errors
, /* Ignore test failures? */
700 skip_previous
= 0, /* Skip on previous test failure? */
701 repeat_test
; /* Repeat a test? */
702 http_t
*http
= NULL
; /* HTTP connection to server */
703 FILE *fp
= NULL
; /* Test file */
704 char resource
[512], /* Resource for request */
705 token
[1024], /* Token from file */
706 *tokenptr
, /* Pointer into token */
707 temp
[1024], /* Temporary string */
708 buffer
[8192]; /* Copy buffer */
709 ipp_t
*request
= NULL
, /* IPP request */
710 *response
= NULL
; /* IPP response */
711 size_t length
; /* Length of IPP request */
712 http_status_t status
; /* HTTP status */
713 cups_file_t
*reqfile
; /* File to send */
714 ssize_t bytes
; /* Bytes read/written */
715 char attr
[128]; /* Attribute name */
716 ipp_op_t op
; /* Operation */
717 ipp_tag_t group
; /* Current group */
718 ipp_tag_t value
; /* Current value type */
719 ipp_attribute_t
*attrptr
, /* Attribute pointer */
720 *found
, /* Found attribute */
721 *lastcol
= NULL
; /* Last collection attribute */
722 char name
[1024]; /* Name of test */
723 char filename
[1024]; /* Filename */
724 _cups_transfer_t transfer
; /* To chunk or not to chunk */
725 int version
, /* IPP version number to use */
726 skip_test
; /* Skip this test? */
727 int num_statuses
= 0; /* Number of valid status codes */
728 _cups_status_t statuses
[100], /* Valid status codes */
729 *last_status
; /* Last STATUS (for predicates) */
730 int num_expects
= 0; /* Number of expected attributes */
731 _cups_expect_t expects
[200], /* Expected attributes */
732 *expect
, /* Current expected attribute */
733 *last_expect
; /* Last EXPECT (for predicates) */
734 int num_displayed
= 0; /* Number of displayed attributes */
735 char *displayed
[200]; /* Displayed attributes */
736 size_t widths
[200]; /* Width of columns */
737 cups_array_t
*a
; /* Duplicate attribute array */
741 * Open the test file...
744 if ((fp
= fopen(testfile
, "r")) == NULL
)
746 print_fatal_error("Unable to open test file %s - %s", testfile
,
753 * Connect to the server...
756 if ((http
= _httpCreate(vars
->hostname
, vars
->port
, NULL
, vars
->encryption
,
757 vars
->family
)) == NULL
)
759 print_fatal_error("Unable to connect to %s on port %d - %s", vars
->hostname
,
760 vars
->port
, cupsLastErrorString());
765 if (httpReconnect(http
))
767 print_fatal_error("Unable to connect to %s on port %d - %s", vars
->hostname
,
768 vars
->port
, cupsLastErrorString());
773 if (vars
->timeout
> 0.0)
774 httpSetTimeout(http
, vars
->timeout
, timeout_cb
, NULL
);
780 CUPS_SRAND(time(NULL
));
784 request_id
= (CUPS_RAND() % 1000) * 137 + 1;
786 while (!Cancel
&& get_token(fp
, token
, sizeof(token
), &linenum
) != NULL
)
789 * Expect an open brace...
792 if (!strcmp(token
, "DEFINE"))
798 if (get_token(fp
, attr
, sizeof(attr
), &linenum
) &&
799 get_token(fp
, temp
, sizeof(temp
), &linenum
))
801 expand_variables(vars
, token
, temp
, sizeof(token
));
802 set_variable(vars
, attr
, token
);
806 print_fatal_error("Missing DEFINE name and/or value on line %d.",
814 else if (!strcmp(token
, "DEFINE-DEFAULT"))
817 * DEFINE-DEFAULT name value
820 if (get_token(fp
, attr
, sizeof(attr
), &linenum
) &&
821 get_token(fp
, temp
, sizeof(temp
), &linenum
))
823 expand_variables(vars
, token
, temp
, sizeof(token
));
824 if (!get_variable(vars
, attr
))
825 set_variable(vars
, attr
, token
);
829 print_fatal_error("Missing DEFINE-DEFAULT name and/or value on line "
837 else if (!strcmp(token
, "IGNORE-ERRORS"))
844 if (get_token(fp
, temp
, sizeof(temp
), &linenum
) &&
845 (!_cups_strcasecmp(temp
, "yes") || !_cups_strcasecmp(temp
, "no")))
847 IgnoreErrors
= !_cups_strcasecmp(temp
, "yes");
851 print_fatal_error("Missing IGNORE-ERRORS value on line %d.", linenum
);
858 else if (!strcmp(token
, "INCLUDE"))
865 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
868 * Map the filename to and then run the tests...
871 if (!do_tests(vars
, get_filename(testfile
, filename
, temp
,
882 print_fatal_error("Missing INCLUDE filename on line %d.", linenum
);
890 else if (!strcmp(token
, "INCLUDE-IF-DEFINED"))
893 * INCLUDE-IF-DEFINED name "filename"
894 * INCLUDE-IF-DEFINED name <filename>
897 if (get_token(fp
, attr
, sizeof(attr
), &linenum
) &&
898 get_token(fp
, temp
, sizeof(temp
), &linenum
))
901 * Map the filename to and then run the tests...
904 if (get_variable(vars
, attr
) &&
905 !do_tests(vars
, get_filename(testfile
, filename
, temp
,
916 print_fatal_error("Missing INCLUDE-IF-DEFINED name or filename on line "
925 else if (!strcmp(token
, "INCLUDE-IF-NOT-DEFINED"))
928 * INCLUDE-IF-NOT-DEFINED name "filename"
929 * INCLUDE-IF-NOT-DEFINED name <filename>
932 if (get_token(fp
, attr
, sizeof(attr
), &linenum
) &&
933 get_token(fp
, temp
, sizeof(temp
), &linenum
))
936 * Map the filename to and then run the tests...
939 if (!get_variable(vars
, attr
) &&
940 !do_tests(vars
, get_filename(testfile
, filename
, temp
,
951 print_fatal_error("Missing INCLUDE-IF-NOT-DEFINED name or filename on "
952 "line %d.", linenum
);
960 else if (!strcmp(token
, "SKIP-IF-DEFINED"))
963 * SKIP-IF-DEFINED variable
966 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
968 if (get_variable(vars
, temp
))
973 print_fatal_error("Missing SKIP-IF-DEFINED variable on line %d.",
979 else if (!strcmp(token
, "SKIP-IF-NOT-DEFINED"))
982 * SKIP-IF-NOT-DEFINED variable
985 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
987 if (!get_variable(vars
, temp
))
992 print_fatal_error("Missing SKIP-IF-NOT-DEFINED variable on line %d.",
998 else if (!strcmp(token
, "TRANSFER"))
1006 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
1008 if (!strcmp(temp
, "auto"))
1009 Transfer
= _CUPS_TRANSFER_AUTO
;
1010 else if (!strcmp(temp
, "chunked"))
1011 Transfer
= _CUPS_TRANSFER_CHUNKED
;
1012 else if (!strcmp(temp
, "length"))
1013 Transfer
= _CUPS_TRANSFER_LENGTH
;
1016 print_fatal_error("Bad TRANSFER value \"%s\" on line %d.", temp
,
1024 print_fatal_error("Missing TRANSFER value on line %d.", linenum
);
1031 else if (!strcmp(token
, "VERSION"))
1033 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
1035 if (!strcmp(temp
, "1.0"))
1037 else if (!strcmp(temp
, "1.1"))
1039 else if (!strcmp(temp
, "2.0"))
1041 else if (!strcmp(temp
, "2.1"))
1043 else if (!strcmp(temp
, "2.2"))
1047 print_fatal_error("Bad VERSION \"%s\" on line %d.", temp
, linenum
);
1054 print_fatal_error("Missing VERSION number on line %d.", linenum
);
1061 else if (strcmp(token
, "{"))
1063 print_fatal_error("Unexpected token %s seen on line %d.", token
, linenum
);
1069 * Initialize things...
1074 if (Output
== _CUPS_OUTPUT_PLIST
)
1076 else if (Output
== _CUPS_OUTPUT_TEST
)
1077 printf("\"%s\":\n", testfile
);
1082 strlcpy(resource
, vars
->resource
, sizeof(resource
));
1087 group
= IPP_TAG_ZERO
;
1088 ignore_errors
= IgnoreErrors
;
1095 transfer
= Transfer
;
1097 strlcpy(name
, testfile
, sizeof(name
));
1098 if (strrchr(name
, '.') != NULL
)
1099 *strrchr(name
, '.') = '\0';
1102 * Parse until we see a close brace...
1105 while (get_token(fp
, token
, sizeof(token
), &linenum
) != NULL
)
1107 if (_cups_strcasecmp(token
, "COUNT") &&
1108 _cups_strcasecmp(token
, "DEFINE-MATCH") &&
1109 _cups_strcasecmp(token
, "DEFINE-NO-MATCH") &&
1110 _cups_strcasecmp(token
, "DEFINE-VALUE") &&
1111 _cups_strcasecmp(token
, "IF-DEFINED") &&
1112 _cups_strcasecmp(token
, "IF-NOT-DEFINED") &&
1113 _cups_strcasecmp(token
, "IN-GROUP") &&
1114 _cups_strcasecmp(token
, "OF-TYPE") &&
1115 _cups_strcasecmp(token
, "REPEAT-MATCH") &&
1116 _cups_strcasecmp(token
, "REPEAT-NO-MATCH") &&
1117 _cups_strcasecmp(token
, "SAME-COUNT-AS") &&
1118 _cups_strcasecmp(token
, "WITH-VALUE"))
1121 if (_cups_strcasecmp(token
, "IF-DEFINED") &&
1122 _cups_strcasecmp(token
, "IF-NOT-DEFINED") &&
1123 _cups_strcasecmp(token
, "REPEAT-MATCH") &&
1124 _cups_strcasecmp(token
, "REPEAT-NO-MATCH"))
1127 if (!strcmp(token
, "}"))
1129 else if (!strcmp(token
, "{") && lastcol
)
1132 * Another collection value
1135 ipp_t
*col
= get_collection(vars
, fp
, &linenum
);
1136 /* Collection value */
1140 ipp_attribute_t
*tempcol
; /* Pointer to new buffer */
1144 * Reallocate memory...
1147 if ((tempcol
= realloc(lastcol
, sizeof(ipp_attribute_t
) +
1148 (lastcol
->num_values
+ 1) *
1149 sizeof(_ipp_value_t
))) == NULL
)
1151 print_fatal_error("Unable to allocate memory on line %d.", linenum
);
1156 if (tempcol
!= lastcol
)
1159 * Reset pointers in the list...
1163 request
->prev
->next
= tempcol
;
1165 request
->attrs
= tempcol
;
1167 lastcol
= request
->current
= request
->last
= tempcol
;
1170 lastcol
->values
[lastcol
->num_values
].collection
= col
;
1171 lastcol
->num_values
++;
1179 else if (!strcmp(token
, "DEFINE"))
1185 if (get_token(fp
, attr
, sizeof(attr
), &linenum
) &&
1186 get_token(fp
, temp
, sizeof(temp
), &linenum
))
1188 expand_variables(vars
, token
, temp
, sizeof(token
));
1189 set_variable(vars
, attr
, token
);
1193 print_fatal_error("Missing DEFINE name and/or value on line %d.",
1199 else if (!strcmp(token
, "IGNORE-ERRORS"))
1206 if (get_token(fp
, temp
, sizeof(temp
), &linenum
) &&
1207 (!_cups_strcasecmp(temp
, "yes") || !_cups_strcasecmp(temp
, "no")))
1209 ignore_errors
= !_cups_strcasecmp(temp
, "yes");
1213 print_fatal_error("Missing IGNORE-ERRORS value on line %d.", linenum
);
1220 else if (!_cups_strcasecmp(token
, "NAME"))
1226 get_token(fp
, name
, sizeof(name
), &linenum
);
1228 else if (!strcmp(token
, "REQUEST-ID"))
1235 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
1237 if (isdigit(temp
[0] & 255))
1238 request_id
= atoi(temp
);
1239 else if (!_cups_strcasecmp(temp
, "random"))
1240 request_id
= (CUPS_RAND() % 1000) * 137 + 1;
1243 print_fatal_error("Bad REQUEST-ID value \"%s\" on line %d.", temp
,
1251 print_fatal_error("Missing REQUEST-ID value on line %d.", linenum
);
1256 else if (!strcmp(token
, "SKIP-IF-DEFINED"))
1259 * SKIP-IF-DEFINED variable
1262 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
1264 if (get_variable(vars
, temp
))
1269 print_fatal_error("Missing SKIP-IF-DEFINED value on line %d.",
1275 else if (!strcmp(token
, "SKIP-IF-NOT-DEFINED"))
1278 * SKIP-IF-NOT-DEFINED variable
1281 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
1283 if (!get_variable(vars
, temp
))
1288 print_fatal_error("Missing SKIP-IF-NOT-DEFINED value on line %d.",
1294 else if (!strcmp(token
, "SKIP-PREVIOUS-ERROR"))
1297 * SKIP-PREVIOUS-ERROR yes
1298 * SKIP-PREVIOUS-ERROR no
1301 if (get_token(fp
, temp
, sizeof(temp
), &linenum
) &&
1302 (!_cups_strcasecmp(temp
, "yes") || !_cups_strcasecmp(temp
, "no")))
1304 skip_previous
= !_cups_strcasecmp(temp
, "yes");
1308 print_fatal_error("Missing SKIP-PREVIOUS-ERROR value on line %d.", linenum
);
1315 else if (!strcmp(token
, "TRANSFER"))
1323 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
1325 if (!strcmp(temp
, "auto"))
1326 transfer
= _CUPS_TRANSFER_AUTO
;
1327 else if (!strcmp(temp
, "chunked"))
1328 transfer
= _CUPS_TRANSFER_CHUNKED
;
1329 else if (!strcmp(temp
, "length"))
1330 transfer
= _CUPS_TRANSFER_LENGTH
;
1333 print_fatal_error("Bad TRANSFER value \"%s\" on line %d.", temp
,
1341 print_fatal_error("Missing TRANSFER value on line %d.", linenum
);
1346 else if (!_cups_strcasecmp(token
, "VERSION"))
1348 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
1350 if (!strcmp(temp
, "0.0"))
1352 else if (!strcmp(temp
, "1.0"))
1354 else if (!strcmp(temp
, "1.1"))
1356 else if (!strcmp(temp
, "2.0"))
1358 else if (!strcmp(temp
, "2.1"))
1360 else if (!strcmp(temp
, "2.2"))
1364 print_fatal_error("Bad VERSION \"%s\" on line %d.", temp
, linenum
);
1371 print_fatal_error("Missing VERSION number on line %d.", linenum
);
1376 else if (!_cups_strcasecmp(token
, "RESOURCE"))
1382 if (!get_token(fp
, resource
, sizeof(resource
), &linenum
))
1384 print_fatal_error("Missing RESOURCE path on line %d.", linenum
);
1389 else if (!_cups_strcasecmp(token
, "OPERATION"))
1395 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1397 print_fatal_error("Missing OPERATION code on line %d.", linenum
);
1402 if ((op
= ippOpValue(token
)) == (ipp_op_t
)-1 &&
1403 (op
= strtol(token
, NULL
, 0)) == 0)
1405 print_fatal_error("Bad OPERATION code \"%s\" on line %d.", token
,
1411 else if (!_cups_strcasecmp(token
, "GROUP"))
1414 * Attribute group...
1417 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1419 print_fatal_error("Missing GROUP tag on line %d.", linenum
);
1424 if ((value
= ippTagValue(token
)) < 0)
1426 print_fatal_error("Bad GROUP tag \"%s\" on line %d.", token
, linenum
);
1432 ippAddSeparator(request
);
1436 else if (!_cups_strcasecmp(token
, "DELAY"))
1439 * Delay before operation...
1444 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1446 print_fatal_error("Missing DELAY value on line %d.", linenum
);
1451 if ((delay
= _cupsStrScand(token
, NULL
, localeconv())) <= 0.0)
1453 print_fatal_error("Bad DELAY value \"%s\" on line %d.", token
,
1460 if (Output
== _CUPS_OUTPUT_TEST
)
1461 printf(" [%g second delay]\n", delay
);
1463 usleep((int)(1000000.0 * delay
));
1466 else if (!_cups_strcasecmp(token
, "ATTR"))
1472 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1474 print_fatal_error("Missing ATTR value tag on line %d.", linenum
);
1479 if ((value
= ippTagValue(token
)) == IPP_TAG_ZERO
)
1481 print_fatal_error("Bad ATTR value tag \"%s\" on line %d.", token
,
1487 if (!get_token(fp
, attr
, sizeof(attr
), &linenum
))
1489 print_fatal_error("Missing ATTR name on line %d.", linenum
);
1494 if (!get_token(fp
, temp
, sizeof(temp
), &linenum
))
1496 print_fatal_error("Missing ATTR value on line %d.", linenum
);
1501 expand_variables(vars
, token
, temp
, sizeof(token
));
1506 case IPP_TAG_BOOLEAN
:
1507 if (!_cups_strcasecmp(token
, "true"))
1508 attrptr
= ippAddBoolean(request
, group
, attr
, 1);
1510 attrptr
= ippAddBoolean(request
, group
, attr
, atoi(token
));
1513 case IPP_TAG_INTEGER
:
1515 if (!strchr(token
, ','))
1516 attrptr
= ippAddInteger(request
, group
, value
, attr
,
1517 strtol(token
, &tokenptr
, 0));
1520 int values
[100], /* Values */
1521 num_values
= 1; /* Number of values */
1523 values
[0] = strtol(token
, &tokenptr
, 10);
1524 while (tokenptr
&& *tokenptr
&&
1525 num_values
< (int)(sizeof(values
) / sizeof(values
[0])))
1527 if (*tokenptr
== ',')
1529 else if (!isdigit(*tokenptr
& 255) && *tokenptr
!= '-')
1532 values
[num_values
] = strtol(tokenptr
, &tokenptr
, 0);
1536 attrptr
= ippAddIntegers(request
, group
, value
, attr
, num_values
, values
);
1539 if (!tokenptr
|| *tokenptr
)
1541 print_fatal_error("Bad %s value \"%s\" on line %d.",
1542 ippTagString(value
), token
, linenum
);
1548 case IPP_TAG_RESOLUTION
:
1550 int xres
, /* X resolution */
1551 yres
; /* Y resolution */
1552 char *ptr
; /* Pointer into value */
1554 xres
= yres
= strtol(token
, (char **)&ptr
, 10);
1555 if (ptr
> token
&& xres
> 0)
1558 yres
= strtol(ptr
+ 1, (char **)&ptr
, 10);
1561 if (ptr
<= token
|| xres
<= 0 || yres
<= 0 || !ptr
||
1562 (_cups_strcasecmp(ptr
, "dpi") && _cups_strcasecmp(ptr
, "dpc") &&
1563 _cups_strcasecmp(ptr
, "other")))
1565 print_fatal_error("Bad resolution value \"%s\" on line %d.",
1571 if (!_cups_strcasecmp(ptr
, "dpi"))
1572 attrptr
= ippAddResolution(request
, group
, attr
, IPP_RES_PER_INCH
,
1574 else if (!_cups_strcasecmp(ptr
, "dpc"))
1575 attrptr
= ippAddResolution(request
, group
, attr
, IPP_RES_PER_CM
,
1578 attrptr
= ippAddResolution(request
, group
, attr
, (ipp_res_t
)0,
1583 case IPP_TAG_RANGE
:
1585 int lowers
[4], /* Lower value */
1586 uppers
[4], /* Upper values */
1587 num_vals
; /* Number of values */
1590 num_vals
= sscanf(token
, "%d-%d,%d-%d,%d-%d,%d-%d",
1591 lowers
+ 0, uppers
+ 0,
1592 lowers
+ 1, uppers
+ 1,
1593 lowers
+ 2, uppers
+ 2,
1594 lowers
+ 3, uppers
+ 3);
1596 if ((num_vals
& 1) || num_vals
== 0)
1598 print_fatal_error("Bad rangeOfInteger value \"%s\" on line "
1599 "%d.", token
, linenum
);
1604 attrptr
= ippAddRanges(request
, group
, attr
, num_vals
/ 2, lowers
,
1609 case IPP_TAG_BEGIN_COLLECTION
:
1610 if (!strcmp(token
, "{"))
1612 ipp_t
*col
= get_collection(vars
, fp
, &linenum
);
1613 /* Collection value */
1617 attrptr
= lastcol
= ippAddCollection(request
, group
, attr
, col
);
1628 print_fatal_error("Bad ATTR collection value on line %d.",
1636 print_fatal_error("Unsupported ATTR value tag %s on line %d.",
1637 ippTagString(value
), linenum
);
1641 case IPP_TAG_TEXTLANG
:
1642 case IPP_TAG_NAMELANG
:
1645 case IPP_TAG_KEYWORD
:
1647 case IPP_TAG_URISCHEME
:
1648 case IPP_TAG_CHARSET
:
1649 case IPP_TAG_LANGUAGE
:
1650 case IPP_TAG_MIMETYPE
:
1651 if (!strchr(token
, ','))
1652 attrptr
= ippAddString(request
, group
, value
, attr
, NULL
, token
);
1656 * Multiple string values...
1659 int num_values
; /* Number of values */
1660 char *values
[100], /* Values */
1661 *ptr
; /* Pointer to next value */
1667 for (ptr
= strchr(token
, ','); ptr
; ptr
= strchr(ptr
, ','))
1670 values
[num_values
] = ptr
;
1674 attrptr
= ippAddStrings(request
, group
, value
, attr
, num_values
,
1675 NULL
, (const char **)values
);
1682 print_fatal_error("Unable to add attribute on line %d: %s", linenum
,
1683 cupsLastErrorString());
1688 else if (!_cups_strcasecmp(token
, "FILE"))
1694 if (!get_token(fp
, temp
, sizeof(temp
), &linenum
))
1696 print_fatal_error("Missing FILE filename on line %d.", linenum
);
1701 expand_variables(vars
, token
, temp
, sizeof(token
));
1702 get_filename(testfile
, filename
, token
, sizeof(filename
));
1704 else if (!_cups_strcasecmp(token
, "STATUS"))
1710 if (num_statuses
>= (int)(sizeof(statuses
) / sizeof(statuses
[0])))
1712 print_fatal_error("Too many STATUS's on line %d.", linenum
);
1717 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1719 print_fatal_error("Missing STATUS code on line %d.", linenum
);
1724 if ((statuses
[num_statuses
].status
= ippErrorValue(token
))
1725 == (ipp_status_t
)-1 &&
1726 (statuses
[num_statuses
].status
= strtol(token
, NULL
, 0)) == 0)
1728 print_fatal_error("Bad STATUS code \"%s\" on line %d.", token
,
1734 last_status
= statuses
+ num_statuses
;
1737 last_status
->if_defined
= NULL
;
1738 last_status
->if_not_defined
= NULL
;
1739 last_status
->repeat_match
= 0;
1740 last_status
->repeat_no_match
= 0;
1742 else if (!_cups_strcasecmp(token
, "EXPECT"))
1745 * Expected attributes...
1748 if (num_expects
>= (int)(sizeof(expects
) / sizeof(expects
[0])))
1750 print_fatal_error("Too many EXPECT's on line %d.", linenum
);
1755 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1757 print_fatal_error("Missing EXPECT name on line %d.", linenum
);
1762 last_expect
= expects
+ num_expects
;
1765 memset(last_expect
, 0, sizeof(_cups_expect_t
));
1767 if (token
[0] == '!')
1769 last_expect
->not_expect
= 1;
1770 last_expect
->name
= strdup(token
+ 1);
1772 else if (token
[0] == '?')
1774 last_expect
->optional
= 1;
1775 last_expect
->name
= strdup(token
+ 1);
1778 last_expect
->name
= strdup(token
);
1780 else if (!_cups_strcasecmp(token
, "COUNT"))
1782 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1784 print_fatal_error("Missing COUNT number on line %d.", linenum
);
1789 if ((i
= atoi(token
)) <= 0)
1791 print_fatal_error("Bad COUNT \"%s\" on line %d.", token
, linenum
);
1797 last_expect
->count
= i
;
1800 print_fatal_error("COUNT without a preceding EXPECT on line %d.",
1806 else if (!_cups_strcasecmp(token
, "DEFINE-MATCH"))
1808 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1810 print_fatal_error("Missing DEFINE-MATCH variable on line %d.",
1817 last_expect
->define_match
= strdup(token
);
1820 print_fatal_error("DEFINE-MATCH without a preceding EXPECT on line "
1826 else if (!_cups_strcasecmp(token
, "DEFINE-NO-MATCH"))
1828 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1830 print_fatal_error("Missing DEFINE-NO-MATCH variable on line %d.",
1837 last_expect
->define_no_match
= strdup(token
);
1840 print_fatal_error("DEFINE-NO-MATCH without a preceding EXPECT on "
1841 "line %d.", linenum
);
1846 else if (!_cups_strcasecmp(token
, "DEFINE-VALUE"))
1848 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1850 print_fatal_error("Missing DEFINE-VALUE variable on line %d.",
1857 last_expect
->define_value
= strdup(token
);
1860 print_fatal_error("DEFINE-VALUE without a preceding EXPECT on line "
1866 else if (!_cups_strcasecmp(token
, "OF-TYPE"))
1868 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1870 print_fatal_error("Missing OF-TYPE value tag(s) on line %d.",
1877 last_expect
->of_type
= strdup(token
);
1880 print_fatal_error("OF-TYPE without a preceding EXPECT on line %d.",
1886 else if (!_cups_strcasecmp(token
, "IN-GROUP"))
1888 ipp_tag_t in_group
; /* IN-GROUP value */
1891 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1893 print_fatal_error("Missing IN-GROUP group tag on line %d.", linenum
);
1898 if ((in_group
= ippTagValue(token
)) == (ipp_tag_t
)-1)
1901 else if (last_expect
)
1902 last_expect
->in_group
= in_group
;
1905 print_fatal_error("IN-GROUP without a preceding EXPECT on line %d.",
1911 else if (!_cups_strcasecmp(token
, "REPEAT-MATCH"))
1914 last_status
->repeat_match
= 1;
1915 else if (last_expect
)
1916 last_expect
->repeat_match
= 1;
1919 print_fatal_error("REPEAT-MATCH without a preceding EXPECT or STATUS "
1920 "on line %d.", linenum
);
1925 else if (!_cups_strcasecmp(token
, "REPEAT-NO-MATCH"))
1928 last_status
->repeat_no_match
= 1;
1929 else if (last_expect
)
1930 last_expect
->repeat_no_match
= 1;
1933 print_fatal_error("REPEAT-NO-MATCH without a preceding EXPECT or "
1934 "STATUS on ine %d.", linenum
);
1939 else if (!_cups_strcasecmp(token
, "SAME-COUNT-AS"))
1941 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1943 print_fatal_error("Missing SAME-COUNT-AS name on line %d.", linenum
);
1949 last_expect
->same_count_as
= strdup(token
);
1952 print_fatal_error("SAME-COUNT-AS without a preceding EXPECT on line "
1958 else if (!_cups_strcasecmp(token
, "IF-DEFINED"))
1960 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1962 print_fatal_error("Missing IF-DEFINED name on line %d.", linenum
);
1968 last_expect
->if_defined
= strdup(token
);
1969 else if (last_status
)
1970 last_status
->if_defined
= strdup(token
);
1973 print_fatal_error("IF-DEFINED without a preceding EXPECT or STATUS "
1974 "on line %d.", linenum
);
1979 else if (!_cups_strcasecmp(token
, "IF-NOT-DEFINED"))
1981 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1983 print_fatal_error("Missing IF-NOT-DEFINED name on line %d.", linenum
);
1989 last_expect
->if_not_defined
= strdup(token
);
1990 else if (last_status
)
1991 last_status
->if_not_defined
= strdup(token
);
1994 print_fatal_error("IF-NOT-DEFINED without a preceding EXPECT or STATUS "
1995 "on line %d.", linenum
);
2000 else if (!_cups_strcasecmp(token
, "WITH-VALUE"))
2002 if (!get_token(fp
, temp
, sizeof(temp
), &linenum
))
2004 print_fatal_error("Missing WITH-VALUE value on line %d.", linenum
);
2012 * Expand any variables in the value and then save it.
2015 expand_variables(vars
, token
, temp
, sizeof(token
));
2017 tokenptr
= token
+ strlen(token
) - 1;
2019 if (token
[0] == '/' && tokenptr
> token
&& *tokenptr
== '/')
2022 * WITH-VALUE is a POSIX extended regular expression.
2025 last_expect
->with_value
= calloc(1, tokenptr
- token
);
2026 last_expect
->with_regex
= 1;
2028 if (last_expect
->with_value
)
2029 memcpy(last_expect
->with_value
, token
+ 1, tokenptr
- token
- 1);
2034 * WITH-VALUE is a literal value...
2037 last_expect
->with_value
= strdup(token
);
2042 print_fatal_error("WITH-VALUE without a preceding EXPECT on line %d.",
2048 else if (!_cups_strcasecmp(token
, "DISPLAY"))
2051 * Display attributes...
2054 if (num_displayed
>= (int)(sizeof(displayed
) / sizeof(displayed
[0])))
2056 print_fatal_error("Too many DISPLAY's on line %d", linenum
);
2061 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
2063 print_fatal_error("Missing DISPLAY name on line %d.", linenum
);
2068 displayed
[num_displayed
] = strdup(token
);
2073 print_fatal_error("Unexpected token %s seen on line %d.", token
,
2081 * Submit the IPP request...
2086 request
->request
.op
.version
[0] = version
/ 10;
2087 request
->request
.op
.version
[1] = version
% 10;
2088 request
->request
.op
.operation_id
= op
;
2089 request
->request
.op
.request_id
= request_id
;
2091 if (Output
== _CUPS_OUTPUT_PLIST
)
2094 puts("<key>Name</key>");
2095 print_xml_string("string", name
);
2096 puts("<key>Operation</key>");
2097 print_xml_string("string", ippOpString(op
));
2098 puts("<key>RequestAttributes</key>");
2103 for (attrptr
= request
->attrs
, group
= attrptr
->group_tag
;
2105 attrptr
= attrptr
->next
)
2106 print_attr(attrptr
, &group
);
2111 else if (Output
== _CUPS_OUTPUT_TEST
)
2115 printf(" %s:\n", ippOpString(op
));
2117 for (attrptr
= request
->attrs
; attrptr
; attrptr
= attrptr
->next
)
2118 print_attr(attrptr
, NULL
);
2121 printf(" %-68.68s [", name
);
2125 if ((skip_previous
&& !prev_pass
) || skip_test
)
2132 if (Output
== _CUPS_OUTPUT_PLIST
)
2134 puts("<key>Successful</key>");
2136 puts("<key>StatusCode</key>");
2137 print_xml_string("string", "skip");
2138 puts("<key>ResponseAttributes</key>");
2142 else if (Output
== _CUPS_OUTPUT_TEST
)
2152 if (transfer
== _CUPS_TRANSFER_CHUNKED
||
2153 (transfer
== _CUPS_TRANSFER_AUTO
&& filename
[0]))
2156 * Send request using chunking - a 0 length means "chunk".
2164 * Send request using content length...
2167 length
= ippLength(request
);
2169 if (filename
[0] && (reqfile
= cupsFileOpen(filename
, "r")) != NULL
)
2172 * Read the file to get the uncompressed file size...
2175 while ((bytes
= cupsFileRead(reqfile
, buffer
, sizeof(buffer
))) > 0)
2178 cupsFileClose(reqfile
);
2183 * Send the request...
2190 if (status
!= HTTP_ERROR
)
2192 while (!response
&& !Cancel
&& prev_pass
)
2194 status
= cupsSendRequest(http
, request
, resource
, length
);
2196 if (!Cancel
&& status
== HTTP_CONTINUE
&&
2197 request
->state
== IPP_DATA
&& filename
[0])
2199 if ((reqfile
= cupsFileOpen(filename
, "r")) != NULL
)
2202 (bytes
= cupsFileRead(reqfile
, buffer
,
2203 sizeof(buffer
))) > 0)
2204 if ((status
= cupsWriteRequestData(http
, buffer
,
2205 bytes
)) != HTTP_CONTINUE
)
2208 cupsFileClose(reqfile
);
2212 snprintf(buffer
, sizeof(buffer
), "%s: %s", filename
,
2214 _cupsSetError(IPP_INTERNAL_ERROR
, buffer
, 0);
2216 status
= HTTP_ERROR
;
2221 * Get the server's response...
2224 if (!Cancel
&& status
!= HTTP_ERROR
)
2226 response
= cupsGetResponse(http
, resource
);
2227 status
= httpGetStatus(http
);
2230 if (!Cancel
&& status
== HTTP_ERROR
&&
2232 http
->error
!= WSAETIMEDOUT
)
2234 http
->error
!= ETIMEDOUT
)
2237 if (httpReconnect(http
))
2240 else if (status
== HTTP_ERROR
)
2243 httpReconnect(http
);
2251 * Check results of request...
2255 prev_pass
= pass
= 0;
2258 if (http
->version
!= HTTP_1_1
)
2259 prev_pass
= pass
= 0;
2261 if (response
->state
!= IPP_DATA
)
2262 prev_pass
= pass
= 0;
2264 if (response
->request
.status
.request_id
!= request_id
)
2265 prev_pass
= pass
= 0;
2268 (response
->request
.status
.version
[0] != (version
/ 10) ||
2269 response
->request
.status
.version
[1] != (version
% 10)))
2270 prev_pass
= pass
= 0;
2272 if ((attrptr
= ippFindAttribute(response
, "job-id",
2273 IPP_TAG_INTEGER
)) != NULL
)
2275 snprintf(temp
, sizeof(temp
), "%d", attrptr
->values
[0].integer
);
2276 set_variable(vars
, "job-id", temp
);
2279 if ((attrptr
= ippFindAttribute(response
, "job-uri",
2280 IPP_TAG_URI
)) != NULL
)
2281 set_variable(vars
, "job-uri", attrptr
->values
[0].string
.text
);
2283 if ((attrptr
= ippFindAttribute(response
, "notify-subscription-id",
2284 IPP_TAG_INTEGER
)) != NULL
)
2286 snprintf(temp
, sizeof(temp
), "%d", attrptr
->values
[0].integer
);
2287 set_variable(vars
, "notify-subscription-id", temp
);
2290 attrptr
= response
->attrs
;
2291 if (!attrptr
|| !attrptr
->name
||
2292 attrptr
->value_tag
!= IPP_TAG_CHARSET
||
2293 attrptr
->group_tag
!= IPP_TAG_OPERATION
||
2294 attrptr
->num_values
!= 1 ||
2295 strcmp(attrptr
->name
, "attributes-charset"))
2296 prev_pass
= pass
= 0;
2300 attrptr
= attrptr
->next
;
2301 if (!attrptr
|| !attrptr
->name
||
2302 attrptr
->value_tag
!= IPP_TAG_LANGUAGE
||
2303 attrptr
->group_tag
!= IPP_TAG_OPERATION
||
2304 attrptr
->num_values
!= 1 ||
2305 strcmp(attrptr
->name
, "attributes-natural-language"))
2306 prev_pass
= pass
= 0;
2309 if ((attrptr
= ippFindAttribute(response
, "status-message",
2310 IPP_TAG_ZERO
)) != NULL
&&
2311 (attrptr
->value_tag
!= IPP_TAG_TEXT
||
2312 attrptr
->group_tag
!= IPP_TAG_OPERATION
||
2313 attrptr
->num_values
!= 1 ||
2314 (attrptr
->value_tag
== IPP_TAG_TEXT
&&
2315 strlen(attrptr
->values
[0].string
.text
) > 255)))
2316 prev_pass
= pass
= 0;
2318 if ((attrptr
= ippFindAttribute(response
, "detailed-status-message",
2319 IPP_TAG_ZERO
)) != NULL
&&
2320 (attrptr
->value_tag
!= IPP_TAG_TEXT
||
2321 attrptr
->group_tag
!= IPP_TAG_OPERATION
||
2322 attrptr
->num_values
!= 1 ||
2323 (attrptr
->value_tag
== IPP_TAG_TEXT
&&
2324 strlen(attrptr
->values
[0].string
.text
) > 1023)))
2325 prev_pass
= pass
= 0;
2327 a
= cupsArrayNew((cups_array_func_t
)strcmp
, NULL
);
2329 for (attrptr
= response
->attrs
, group
= attrptr
->group_tag
;
2331 attrptr
= attrptr
->next
)
2333 if (attrptr
->group_tag
!= group
)
2337 switch (attrptr
->group_tag
)
2342 case IPP_TAG_OPERATION
:
2343 prev_pass
= pass
= 0;
2346 case IPP_TAG_UNSUPPORTED_GROUP
:
2347 if (group
!= IPP_TAG_OPERATION
)
2348 prev_pass
= pass
= 0;
2352 case IPP_TAG_PRINTER
:
2353 if (group
!= IPP_TAG_OPERATION
&&
2354 group
!= IPP_TAG_UNSUPPORTED_GROUP
)
2355 prev_pass
= pass
= 0;
2358 case IPP_TAG_SUBSCRIPTION
:
2359 if (group
> attrptr
->group_tag
&&
2360 group
!= IPP_TAG_DOCUMENT
)
2361 prev_pass
= pass
= 0;
2365 if (group
> attrptr
->group_tag
)
2366 prev_pass
= pass
= 0;
2373 if (attrptr
->group_tag
!= IPP_TAG_ZERO
)
2374 group
= attrptr
->group_tag
;
2377 if (!validate_attr(attrptr
, 0))
2379 prev_pass
= pass
= 0;
2385 if (cupsArrayFind(a
, attrptr
->name
))
2387 prev_pass
= pass
= 0;
2391 cupsArrayAdd(a
, attrptr
->name
);
2397 for (i
= 0; i
< num_statuses
; i
++)
2399 if (statuses
[i
].if_defined
&&
2400 !get_variable(vars
, statuses
[i
].if_defined
))
2403 if (statuses
[i
].if_not_defined
&&
2404 get_variable(vars
, statuses
[i
].if_not_defined
))
2407 if (response
->request
.status
.status_code
== statuses
[i
].status
)
2409 if (statuses
[i
].repeat_match
)
2414 else if (statuses
[i
].repeat_no_match
)
2418 if (i
== num_statuses
&& num_statuses
> 0)
2419 prev_pass
= pass
= 0;
2421 for (i
= num_expects
, expect
= expects
; i
> 0; i
--, expect
++)
2423 if (expect
->if_defined
&& !get_variable(vars
, expect
->if_defined
))
2426 if (expect
->if_not_defined
&&
2427 get_variable(vars
, expect
->if_not_defined
))
2430 found
= ippFindAttribute(response
, expect
->name
, IPP_TAG_ZERO
);
2432 if ((found
&& expect
->not_expect
) ||
2433 (!found
&& !(expect
->not_expect
|| expect
->optional
)) ||
2434 (found
&& !expect_matches(expect
, found
->value_tag
)) ||
2435 (found
&& expect
->in_group
&&
2436 found
->group_tag
!= expect
->in_group
))
2438 if (expect
->define_no_match
)
2439 set_variable(vars
, expect
->define_no_match
, "1");
2440 else if (!expect
->define_match
&& !expect
->define_value
)
2441 prev_pass
= pass
= 0;
2443 if (expect
->repeat_no_match
)
2450 ippAttributeString(found
, buffer
, sizeof(buffer
));
2453 !with_value(expect
->with_value
, expect
->with_regex
, found
, 0,
2454 buffer
, sizeof(buffer
)))
2456 if (expect
->define_no_match
)
2457 set_variable(vars
, expect
->define_no_match
, "1");
2458 else if (!expect
->define_match
&& !expect
->define_value
)
2459 prev_pass
= pass
= 0;
2461 if (expect
->repeat_no_match
)
2467 if (found
&& expect
->count
> 0 &&
2468 found
->num_values
!= expect
->count
)
2470 if (expect
->define_no_match
)
2471 set_variable(vars
, expect
->define_no_match
, "1");
2472 else if (!expect
->define_match
&& !expect
->define_value
)
2473 prev_pass
= pass
= 0;
2475 if (expect
->repeat_no_match
)
2481 if (found
&& expect
->same_count_as
)
2483 attrptr
= ippFindAttribute(response
, expect
->same_count_as
,
2486 if (!attrptr
|| attrptr
->num_values
!= found
->num_values
)
2488 if (expect
->define_no_match
)
2489 set_variable(vars
, expect
->define_no_match
, "1");
2490 else if (!expect
->define_match
&& !expect
->define_value
)
2491 prev_pass
= pass
= 0;
2493 if (expect
->repeat_no_match
)
2500 if (found
&& expect
->define_match
)
2501 set_variable(vars
, expect
->define_match
, "1");
2503 if (found
&& expect
->define_value
)
2504 set_variable(vars
, expect
->define_value
, buffer
);
2506 if (found
&& expect
->repeat_match
)
2512 * If we are going to repeat this test, sleep 1 second so we don't flood
2513 * the printer with requests...
2519 while (repeat_test
);
2530 if (Output
== _CUPS_OUTPUT_PLIST
)
2532 puts("<key>Successful</key>");
2533 puts(prev_pass
? "<true />" : "<false />");
2534 puts("<key>StatusCode</key>");
2535 print_xml_string("string", ippErrorString(cupsLastError()));
2536 puts("<key>ResponseAttributes</key>");
2539 for (attrptr
= response
? response
->attrs
: NULL
,
2540 group
= attrptr
? attrptr
->group_tag
: IPP_TAG_ZERO
;
2542 attrptr
= attrptr
->next
)
2543 print_attr(attrptr
, &group
);
2547 else if (Output
== _CUPS_OUTPUT_TEST
)
2549 puts(prev_pass
? "PASS]" : "FAIL]");
2551 if (!prev_pass
|| (Verbosity
&& response
))
2553 printf(" RECEIVED: %lu bytes in response\n",
2554 (unsigned long)ippLength(response
));
2555 printf(" status-code = %s (%s)\n", ippErrorString(cupsLastError()),
2556 cupsLastErrorString());
2560 for (attrptr
= response
->attrs
;
2562 attrptr
= attrptr
->next
)
2563 print_attr(attrptr
, NULL
);
2567 else if (!prev_pass
)
2568 fprintf(stderr
, "%s\n", cupsLastErrorString());
2570 if (prev_pass
&& Output
>= _CUPS_OUTPUT_LIST
&& !Verbosity
&&
2573 size_t width
; /* Length of value */
2575 for (i
= 0; i
< num_displayed
; i
++)
2577 widths
[i
] = strlen(displayed
[i
]);
2579 for (attrptr
= ippFindAttribute(response
, displayed
[i
], IPP_TAG_ZERO
);
2581 attrptr
= ippFindNextAttribute(response
, displayed
[i
],
2584 width
= ippAttributeString(attrptr
, NULL
, 0);
2585 if (width
> widths
[i
])
2590 if (Output
== _CUPS_OUTPUT_CSV
)
2591 print_csv(NULL
, num_displayed
, displayed
, widths
);
2593 print_line(NULL
, num_displayed
, displayed
, widths
);
2595 attrptr
= response
->attrs
;
2599 while (attrptr
&& attrptr
->group_tag
<= IPP_TAG_OPERATION
)
2600 attrptr
= attrptr
->next
;
2604 if (Output
== _CUPS_OUTPUT_CSV
)
2605 print_csv(attrptr
, num_displayed
, displayed
, widths
);
2607 print_line(attrptr
, num_displayed
, displayed
, widths
);
2609 while (attrptr
&& attrptr
->group_tag
> IPP_TAG_OPERATION
)
2610 attrptr
= attrptr
->next
;
2614 else if (!prev_pass
)
2616 if (Output
== _CUPS_OUTPUT_PLIST
)
2618 puts("<key>Errors</key>");
2622 if (http
->version
!= HTTP_1_1
)
2623 print_test_error("Bad HTTP version (%d.%d)", http
->version
/ 100,
2624 http
->version
% 100);
2627 print_test_error("IPP request failed with status %s (%s)",
2628 ippErrorString(cupsLastError()),
2629 cupsLastErrorString());
2632 if (response
->state
!= IPP_DATA
)
2633 print_test_error("Missing end-of-attributes-tag in response "
2634 "(RFC 2910 section 3.5.1)");
2637 (response
->request
.status
.version
[0] != (version
/ 10) ||
2638 response
->request
.status
.version
[1] != (version
% 10)))
2639 print_test_error("Bad version %d.%d in response - expected %d.%d "
2640 "(RFC 2911 section 3.1.8).",
2641 response
->request
.status
.version
[0],
2642 response
->request
.status
.version
[1],
2643 version
/ 10, version
% 10);
2645 if (response
->request
.status
.request_id
!= request_id
)
2646 print_test_error("Bad request ID %d in response - expected %d "
2647 "(RFC 2911 section 3.1.1)",
2648 response
->request
.status
.request_id
, request_id
);
2650 attrptr
= response
->attrs
;
2652 print_test_error("Missing first attribute \"attributes-charset "
2653 "(charset)\" in group operation-attributes-tag "
2654 "(RFC 2911 section 3.1.4).");
2657 if (!attrptr
->name
||
2658 attrptr
->value_tag
!= IPP_TAG_CHARSET
||
2659 attrptr
->group_tag
!= IPP_TAG_OPERATION
||
2660 attrptr
->num_values
!= 1 ||
2661 strcmp(attrptr
->name
, "attributes-charset"))
2662 print_test_error("Bad first attribute \"%s (%s%s)\" in group %s, "
2663 "expected \"attributes-charset (charset)\" in "
2664 "group operation-attributes-tag (RFC 2911 section "
2666 attrptr
->name
? attrptr
->name
: "(null)",
2667 attrptr
->num_values
> 1 ? "1setOf " : "",
2668 ippTagString(attrptr
->value_tag
),
2669 ippTagString(attrptr
->group_tag
));
2671 attrptr
= attrptr
->next
;
2673 print_test_error("Missing second attribute \"attributes-natural-"
2674 "language (naturalLanguage)\" in group "
2675 "operation-attributes-tag (RFC 2911 section "
2677 else if (!attrptr
->name
||
2678 attrptr
->value_tag
!= IPP_TAG_LANGUAGE
||
2679 attrptr
->group_tag
!= IPP_TAG_OPERATION
||
2680 attrptr
->num_values
!= 1 ||
2681 strcmp(attrptr
->name
, "attributes-natural-language"))
2682 print_test_error("Bad first attribute \"%s (%s%s)\" in group %s, "
2683 "expected \"attributes-natural-language "
2684 "(naturalLanguage)\" in group "
2685 "operation-attributes-tag (RFC 2911 section "
2687 attrptr
->name
? attrptr
->name
: "(null)",
2688 attrptr
->num_values
> 1 ? "1setOf " : "",
2689 ippTagString(attrptr
->value_tag
),
2690 ippTagString(attrptr
->group_tag
));
2693 if ((attrptr
= ippFindAttribute(response
, "status-message",
2694 IPP_TAG_ZERO
)) != NULL
)
2696 if (attrptr
->value_tag
!= IPP_TAG_TEXT
)
2697 print_test_error("status-message (text(255)) has wrong value tag "
2698 "%s (RFC 2911 section 3.1.6.2).",
2699 ippTagString(attrptr
->value_tag
));
2700 if (attrptr
->group_tag
!= IPP_TAG_OPERATION
)
2701 print_test_error("status-message (text(255)) has wrong group tag "
2702 "%s (RFC 2911 section 3.1.6.2).",
2703 ippTagString(attrptr
->group_tag
));
2704 if (attrptr
->num_values
!= 1)
2705 print_test_error("status-message (text(255)) has %d values "
2706 "(RFC 2911 section 3.1.6.2).",
2707 attrptr
->num_values
);
2708 if (attrptr
->value_tag
== IPP_TAG_TEXT
&&
2709 strlen(attrptr
->values
[0].string
.text
) > 255)
2710 print_test_error("status-message (text(255)) has bad length %d"
2711 " (RFC 2911 section 3.1.6.2).",
2712 (int)strlen(attrptr
->values
[0].string
.text
));
2715 if ((attrptr
= ippFindAttribute(response
, "detailed-status-message",
2716 IPP_TAG_ZERO
)) != NULL
)
2718 if (attrptr
->value_tag
!= IPP_TAG_TEXT
)
2719 print_test_error("detailed-status-message (text(MAX)) has wrong "
2720 "value tag %s (RFC 2911 section 3.1.6.3).",
2721 ippTagString(attrptr
->value_tag
));
2722 if (attrptr
->group_tag
!= IPP_TAG_OPERATION
)
2723 print_test_error("detailed-status-message (text(MAX)) has wrong "
2724 "group tag %s (RFC 2911 section 3.1.6.3).",
2725 ippTagString(attrptr
->group_tag
));
2726 if (attrptr
->num_values
!= 1)
2727 print_test_error("detailed-status-message (text(MAX)) has %d values"
2728 " (RFC 2911 section 3.1.6.3).",
2729 attrptr
->num_values
);
2730 if (attrptr
->value_tag
== IPP_TAG_TEXT
&&
2731 strlen(attrptr
->values
[0].string
.text
) > 1023)
2732 print_test_error("detailed-status-message (text(MAX)) has bad "
2733 "length %d (RFC 2911 section 3.1.6.3).",
2734 (int)strlen(attrptr
->values
[0].string
.text
));
2737 a
= cupsArrayNew((cups_array_func_t
)strcmp
, NULL
);
2739 for (attrptr
= response
->attrs
, group
= attrptr
->group_tag
;
2741 attrptr
= attrptr
->next
)
2743 if (attrptr
->group_tag
!= group
)
2747 switch (attrptr
->group_tag
)
2752 case IPP_TAG_OPERATION
:
2753 prev_pass
= pass
= 0;
2756 case IPP_TAG_UNSUPPORTED_GROUP
:
2757 if (group
!= IPP_TAG_OPERATION
)
2758 print_test_error("Attribute groups out of order (%s < %s)",
2759 ippTagString(attrptr
->group_tag
),
2760 ippTagString(group
));
2764 case IPP_TAG_PRINTER
:
2765 if (group
!= IPP_TAG_OPERATION
&&
2766 group
!= IPP_TAG_UNSUPPORTED_GROUP
)
2767 print_test_error("Attribute groups out of order (%s < %s)",
2768 ippTagString(attrptr
->group_tag
),
2769 ippTagString(group
));
2772 case IPP_TAG_SUBSCRIPTION
:
2773 if (group
> attrptr
->group_tag
&&
2774 group
!= IPP_TAG_DOCUMENT
)
2775 print_test_error("Attribute groups out of order (%s < %s)",
2776 ippTagString(attrptr
->group_tag
),
2777 ippTagString(group
));
2781 if (group
> attrptr
->group_tag
)
2782 print_test_error("Attribute groups out of order (%s < %s)",
2783 ippTagString(attrptr
->group_tag
),
2784 ippTagString(group
));
2788 if (attrptr
->group_tag
!= IPP_TAG_ZERO
)
2789 group
= attrptr
->group_tag
;
2792 validate_attr(attrptr
, 1);
2796 if (cupsArrayFind(a
, attrptr
->name
))
2797 print_test_error("Duplicate \"%s\" attribute in %s group",
2798 attrptr
->name
, ippTagString(group
));
2800 cupsArrayAdd(a
, attrptr
->name
);
2806 for (i
= 0; i
< num_statuses
; i
++)
2808 if (statuses
[i
].if_defined
&&
2809 !get_variable(vars
, statuses
[i
].if_defined
))
2812 if (statuses
[i
].if_not_defined
&&
2813 get_variable(vars
, statuses
[i
].if_not_defined
))
2816 if (response
->request
.status
.status_code
== statuses
[i
].status
)
2820 if (i
== num_statuses
&& num_statuses
> 0)
2822 for (i
= 0; i
< num_statuses
; i
++)
2824 if (statuses
[i
].if_defined
&&
2825 !get_variable(vars
, statuses
[i
].if_defined
))
2828 if (statuses
[i
].if_not_defined
&&
2829 get_variable(vars
, statuses
[i
].if_not_defined
))
2832 print_test_error("EXPECTED: STATUS %s (got %s)",
2833 ippErrorString(statuses
[i
].status
),
2834 ippErrorString(cupsLastError()));
2837 if ((attrptr
= ippFindAttribute(response
, "status-message",
2838 IPP_TAG_TEXT
)) != NULL
)
2839 print_test_error("status-message=\"%s\"",
2840 attrptr
->values
[0].string
.text
);
2843 for (i
= num_expects
, expect
= expects
; i
> 0; i
--, expect
++)
2845 if (expect
->define_match
|| expect
->define_no_match
||
2846 expect
->define_value
)
2849 if (expect
->if_defined
&& !get_variable(vars
, expect
->if_defined
))
2852 if (expect
->if_not_defined
&&
2853 get_variable(vars
, expect
->if_not_defined
))
2856 found
= ippFindAttribute(response
, expect
->name
, IPP_TAG_ZERO
);
2858 if (found
&& expect
->not_expect
)
2859 print_test_error("NOT EXPECTED: %s", expect
->name
);
2860 else if (!found
&& !(expect
->not_expect
|| expect
->optional
))
2861 print_test_error("EXPECTED: %s", expect
->name
);
2864 if (!expect_matches(expect
, found
->value_tag
))
2865 print_test_error("EXPECTED: %s OF-TYPE %s (got %s)",
2866 expect
->name
, expect
->of_type
,
2867 ippTagString(found
->value_tag
));
2869 if (expect
->in_group
&& found
->group_tag
!= expect
->in_group
)
2870 print_test_error("EXPECTED: %s IN-GROUP %s (got %s).",
2871 expect
->name
, ippTagString(expect
->in_group
),
2872 ippTagString(found
->group_tag
));
2874 if (!with_value(expect
->with_value
, expect
->with_regex
, found
, 0,
2875 buffer
, sizeof(buffer
)))
2877 if (expect
->with_regex
)
2878 print_test_error("EXPECTED: %s WITH-VALUE /%s/",
2879 expect
->name
, expect
->with_value
);
2881 print_test_error("EXPECTED: %s WITH-VALUE \"%s\"",
2882 expect
->name
, expect
->with_value
);
2884 with_value(expect
->with_value
, expect
->with_regex
, found
, 1,
2885 buffer
, sizeof(buffer
));
2888 if (expect
->count
> 0 && found
->num_values
!= expect
->count
)
2890 print_test_error("EXPECTED: %s COUNT %d (got %d)", expect
->name
,
2891 expect
->count
, found
->num_values
);
2894 if (expect
->same_count_as
)
2896 attrptr
= ippFindAttribute(response
, expect
->same_count_as
,
2900 print_test_error("EXPECTED: %s (%d values) SAME-COUNT-AS %s "
2901 "(not returned)", expect
->name
,
2902 found
->num_values
, expect
->same_count_as
);
2903 else if (attrptr
->num_values
!= found
->num_values
)
2904 print_test_error("EXPECTED: %s (%d values) SAME-COUNT-AS %s "
2905 "(%d values)", expect
->name
, found
->num_values
,
2906 expect
->same_count_as
, attrptr
->num_values
);
2912 if (Output
== _CUPS_OUTPUT_PLIST
)
2916 if (num_displayed
> 0 && !Verbosity
&&
2917 (Output
== _CUPS_OUTPUT_TEST
|| Output
== _CUPS_OUTPUT_PLIST
))
2919 for (attrptr
= response
->attrs
;
2921 attrptr
= attrptr
->next
)
2925 for (i
= 0; i
< num_displayed
; i
++)
2927 if (!strcmp(displayed
[i
], attrptr
->name
))
2929 print_attr(attrptr
, NULL
);
2939 if (Output
== _CUPS_OUTPUT_PLIST
)
2944 ippDelete(response
);
2947 for (i
= 0; i
< num_statuses
; i
++)
2949 if (statuses
[i
].if_defined
)
2950 free(statuses
[i
].if_defined
);
2951 if (statuses
[i
].if_not_defined
)
2952 free(statuses
[i
].if_not_defined
);
2956 for (i
= num_expects
, expect
= expects
; i
> 0; i
--, expect
++)
2959 if (expect
->of_type
)
2960 free(expect
->of_type
);
2961 if (expect
->same_count_as
)
2962 free(expect
->same_count_as
);
2963 if (expect
->if_defined
)
2964 free(expect
->if_defined
);
2965 if (expect
->if_not_defined
)
2966 free(expect
->if_not_defined
);
2967 if (expect
->with_value
)
2968 free(expect
->with_value
);
2969 if (expect
->define_match
)
2970 free(expect
->define_match
);
2971 if (expect
->define_no_match
)
2972 free(expect
->define_no_match
);
2973 if (expect
->define_value
)
2974 free(expect
->define_value
);
2978 for (i
= 0; i
< num_displayed
; i
++)
2982 if (!ignore_errors
&& !prev_pass
)
2993 ippDelete(response
);
2995 for (i
= 0; i
< num_statuses
; i
++)
2997 if (statuses
[i
].if_defined
)
2998 free(statuses
[i
].if_defined
);
2999 if (statuses
[i
].if_not_defined
)
3000 free(statuses
[i
].if_not_defined
);
3003 for (i
= num_expects
, expect
= expects
; i
> 0; i
--, expect
++)
3006 if (expect
->of_type
)
3007 free(expect
->of_type
);
3008 if (expect
->same_count_as
)
3009 free(expect
->same_count_as
);
3010 if (expect
->if_defined
)
3011 free(expect
->if_defined
);
3012 if (expect
->if_not_defined
)
3013 free(expect
->if_not_defined
);
3014 if (expect
->with_value
)
3015 free(expect
->with_value
);
3016 if (expect
->define_match
)
3017 free(expect
->define_match
);
3018 if (expect
->define_no_match
)
3019 free(expect
->define_no_match
);
3020 if (expect
->define_value
)
3021 free(expect
->define_value
);
3024 for (i
= 0; i
< num_displayed
; i
++)
3032 * 'expand_variables()' - Expand variables in a string.
3036 expand_variables(_cups_vars_t
*vars
, /* I - Variables */
3037 char *dst
, /* I - Destination string buffer */
3038 const char *src
, /* I - Source string */
3039 size_t dstsize
) /* I - Size of destination buffer */
3041 char *dstptr
, /* Pointer into destination */
3042 *dstend
, /* End of destination */
3043 temp
[256], /* Temporary string */
3044 *tempptr
; /* Pointer into temporary string */
3045 const char *value
; /* Value to substitute */
3049 dstend
= dst
+ dstsize
- 1;
3051 while (*src
&& dstptr
< dstend
)
3056 * Substitute a string/number...
3059 if (!strncmp(src
, "$$", 2))
3064 else if (!strncmp(src
, "$ENV[", 5))
3066 strlcpy(temp
, src
+ 5, sizeof(temp
));
3068 for (tempptr
= temp
; *tempptr
; tempptr
++)
3069 if (*tempptr
== ']')
3075 value
= getenv(temp
);
3076 src
+= tempptr
- temp
+ 5;
3080 strlcpy(temp
, src
+ 1, sizeof(temp
));
3082 for (tempptr
= temp
; *tempptr
; tempptr
++)
3083 if (!isalnum(*tempptr
& 255) && *tempptr
!= '-' && *tempptr
!= '_')
3089 if (!strcmp(temp
, "uri"))
3091 else if (!strcmp(temp
, "filename"))
3092 value
= vars
->filename
;
3093 else if (!strcmp(temp
, "scheme") || !strcmp(temp
, "method"))
3094 value
= vars
->scheme
;
3095 else if (!strcmp(temp
, "username"))
3096 value
= vars
->userpass
;
3097 else if (!strcmp(temp
, "hostname"))
3098 value
= vars
->hostname
;
3099 else if (!strcmp(temp
, "port"))
3101 snprintf(temp
, sizeof(temp
), "%d", vars
->port
);
3104 else if (!strcmp(temp
, "resource"))
3105 value
= vars
->resource
;
3106 else if (!strcmp(temp
, "user"))
3109 value
= get_variable(vars
, temp
);
3111 src
+= tempptr
- temp
+ 1;
3121 strlcpy(dstptr
, value
, dstend
- dstptr
+ 1);
3122 dstptr
+= strlen(dstptr
);
3134 * 'expect_matches()' - Return true if the tag matches the specification.
3137 static int /* O - 1 if matches, 0 otherwise */
3139 _cups_expect_t
*expect
, /* I - Expected attribute */
3140 ipp_tag_t value_tag
) /* I - Value tag for attribute */
3142 int match
; /* Match? */
3143 char *of_type
, /* Type name to match */
3144 *next
, /* Next name to match */
3145 sep
; /* Separator character */
3149 * If we don't expect a particular type, return immediately...
3152 if (!expect
->of_type
)
3156 * Parse the "of_type" value since the string can contain multiple attribute
3157 * types separated by "," or "|"...
3160 for (of_type
= expect
->of_type
, match
= 0; !match
&& *of_type
; of_type
= next
)
3163 * Find the next separator, and set it (temporarily) to nul if present.
3166 for (next
= of_type
; *next
&& *next
!= '|' && *next
!= ','; next
++);
3168 if ((sep
= *next
) != '\0')
3172 * Support some meta-types to make it easier to write the test file.
3175 if (!strcmp(of_type
, "text"))
3176 match
= value_tag
== IPP_TAG_TEXTLANG
|| value_tag
== IPP_TAG_TEXT
;
3177 else if (!strcmp(of_type
, "name"))
3178 match
= value_tag
== IPP_TAG_NAMELANG
|| value_tag
== IPP_TAG_NAME
;
3179 else if (!strcmp(of_type
, "collection"))
3180 match
= value_tag
== IPP_TAG_BEGIN_COLLECTION
;
3182 match
= value_tag
== ippTagValue(of_type
);
3185 * Restore the separator if we have one...
3197 * 'get_collection()' - Get a collection value from the current test file.
3200 static ipp_t
* /* O - Collection value */
3201 get_collection(_cups_vars_t
*vars
, /* I - Variables */
3202 FILE *fp
, /* I - File to read from */
3203 int *linenum
) /* IO - Line number */
3205 char token
[1024], /* Token from file */
3206 temp
[1024], /* Temporary string */
3207 attr
[128]; /* Attribute name */
3208 ipp_tag_t value
; /* Current value type */
3209 ipp_t
*col
= ippNew(); /* Collection value */
3210 ipp_attribute_t
*lastcol
= NULL
; /* Last collection attribute */
3213 while (get_token(fp
, token
, sizeof(token
), linenum
) != NULL
)
3215 if (!strcmp(token
, "}"))
3217 else if (!strcmp(token
, "{") && lastcol
)
3220 * Another collection value
3223 ipp_t
*subcol
= get_collection(vars
, fp
, linenum
);
3224 /* Collection value */
3228 ipp_attribute_t
*tempcol
; /* Pointer to new buffer */
3232 * Reallocate memory...
3235 if ((tempcol
= realloc(lastcol
, sizeof(ipp_attribute_t
) +
3236 (lastcol
->num_values
+ 1) *
3237 sizeof(_ipp_value_t
))) == NULL
)
3239 print_fatal_error("Unable to allocate memory on line %d.", *linenum
);
3243 if (tempcol
!= lastcol
)
3246 * Reset pointers in the list...
3250 col
->prev
->next
= tempcol
;
3252 col
->attrs
= tempcol
;
3254 lastcol
= col
->current
= col
->last
= tempcol
;
3257 lastcol
->values
[lastcol
->num_values
].collection
= subcol
;
3258 lastcol
->num_values
++;
3263 else if (!_cups_strcasecmp(token
, "MEMBER"))
3271 if (!get_token(fp
, token
, sizeof(token
), linenum
))
3273 print_fatal_error("Missing MEMBER value tag on line %d.", *linenum
);
3277 if ((value
= ippTagValue(token
)) == IPP_TAG_ZERO
)
3279 print_fatal_error("Bad MEMBER value tag \"%s\" on line %d.", token
,
3284 if (!get_token(fp
, attr
, sizeof(attr
), linenum
))
3286 print_fatal_error("Missing MEMBER name on line %d.", *linenum
);
3290 if (!get_token(fp
, temp
, sizeof(temp
), linenum
))
3292 print_fatal_error("Missing MEMBER value on line %d.", *linenum
);
3296 expand_variables(vars
, token
, temp
, sizeof(token
));
3300 case IPP_TAG_BOOLEAN
:
3301 if (!_cups_strcasecmp(token
, "true"))
3302 ippAddBoolean(col
, IPP_TAG_ZERO
, attr
, 1);
3304 ippAddBoolean(col
, IPP_TAG_ZERO
, attr
, atoi(token
));
3307 case IPP_TAG_INTEGER
:
3309 ippAddInteger(col
, IPP_TAG_ZERO
, value
, attr
, atoi(token
));
3312 case IPP_TAG_RESOLUTION
:
3314 int xres
, /* X resolution */
3315 yres
; /* Y resolution */
3316 char units
[6]; /* Units */
3318 if (sscanf(token
, "%dx%d%5s", &xres
, &yres
, units
) != 3 ||
3319 (_cups_strcasecmp(units
, "dpi") && _cups_strcasecmp(units
, "dpc") &&
3320 _cups_strcasecmp(units
, "other")))
3322 print_fatal_error("Bad resolution value \"%s\" on line %d.",
3327 if (!_cups_strcasecmp(units
, "dpi"))
3328 ippAddResolution(col
, IPP_TAG_ZERO
, attr
, xres
, yres
,
3330 else if (!_cups_strcasecmp(units
, "dpc"))
3331 ippAddResolution(col
, IPP_TAG_ZERO
, attr
, xres
, yres
,
3334 ippAddResolution(col
, IPP_TAG_ZERO
, attr
, xres
, yres
,
3339 case IPP_TAG_RANGE
:
3341 int lowers
[4], /* Lower value */
3342 uppers
[4], /* Upper values */
3343 num_vals
; /* Number of values */
3346 num_vals
= sscanf(token
, "%d-%d,%d-%d,%d-%d,%d-%d",
3347 lowers
+ 0, uppers
+ 0,
3348 lowers
+ 1, uppers
+ 1,
3349 lowers
+ 2, uppers
+ 2,
3350 lowers
+ 3, uppers
+ 3);
3352 if ((num_vals
& 1) || num_vals
== 0)
3354 print_fatal_error("Bad rangeOfInteger value \"%s\" on line %d.",
3359 ippAddRanges(col
, IPP_TAG_ZERO
, attr
, num_vals
/ 2, lowers
,
3364 case IPP_TAG_BEGIN_COLLECTION
:
3365 if (!strcmp(token
, "{"))
3367 ipp_t
*subcol
= get_collection(vars
, fp
, linenum
);
3368 /* Collection value */
3372 lastcol
= ippAddCollection(col
, IPP_TAG_ZERO
, attr
, subcol
);
3380 print_fatal_error("Bad collection value on line %d.", *linenum
);
3386 if (!strchr(token
, ','))
3387 ippAddString(col
, IPP_TAG_ZERO
, value
, attr
, NULL
, token
);
3391 * Multiple string values...
3394 int num_values
; /* Number of values */
3395 char *values
[100], /* Values */
3396 *ptr
; /* Pointer to next value */
3402 for (ptr
= strchr(token
, ','); ptr
; ptr
= strchr(ptr
, ','))
3405 values
[num_values
] = ptr
;
3409 ippAddStrings(col
, IPP_TAG_ZERO
, value
, attr
, num_values
,
3410 NULL
, (const char **)values
);
3420 * If we get here there was a parse error; free memory and return.
3432 * 'get_filename()' - Get a filename based on the current test file.
3435 static char * /* O - Filename */
3436 get_filename(const char *testfile
, /* I - Current test file */
3437 char *dst
, /* I - Destination filename */
3438 const char *src
, /* I - Source filename */
3439 size_t dstsize
) /* I - Size of destination buffer */
3441 char *dstptr
; /* Pointer into destination */
3442 _cups_globals_t
*cg
= _cupsGlobals();
3446 if (*src
== '<' && src
[strlen(src
) - 1] == '>')
3449 * Map <filename> to CUPS_DATADIR/ipptool/filename...
3452 snprintf(dst
, dstsize
, "%s/ipptool/%s", cg
->cups_datadir
, src
+ 1);
3453 dstptr
= dst
+ strlen(dst
) - 1;
3457 else if (*src
== '/' || !strchr(testfile
, '/'))
3460 * Use the path as-is...
3463 strlcpy(dst
, src
, dstsize
);
3468 * Make path relative to testfile...
3471 strlcpy(dst
, testfile
, dstsize
);
3472 if ((dstptr
= strrchr(dst
, '/')) != NULL
)
3475 dstptr
= dst
; /* Should never happen */
3477 strlcpy(dstptr
, src
, dstsize
- (dstptr
- dst
));
3485 * 'get_token()' - Get a token from a file.
3488 static char * /* O - Token from file or NULL on EOF */
3489 get_token(FILE *fp
, /* I - File to read from */
3490 char *buf
, /* I - Buffer to read into */
3491 int buflen
, /* I - Length of buffer */
3492 int *linenum
) /* IO - Current line number */
3494 int ch
, /* Character from file */
3495 quote
; /* Quoting character */
3496 char *bufptr
, /* Pointer into buffer */
3497 *bufend
; /* End of buffer */
3503 * Skip whitespace...
3506 while (isspace(ch
= getc(fp
)))
3518 else if (ch
== '\'' || ch
== '\"')
3521 * Quoted text or regular expression...
3526 bufend
= buf
+ buflen
- 1;
3528 while ((ch
= getc(fp
)) != EOF
)
3533 * Escape next character...
3536 if (bufptr
< bufend
)
3539 if ((ch
= getc(fp
)) != EOF
&& bufptr
< bufend
)
3542 else if (ch
== quote
)
3544 else if (bufptr
< bufend
)
3558 while ((ch
= getc(fp
)) != EOF
)
3567 * Whitespace delimited text...
3573 bufend
= buf
+ buflen
- 1;
3575 while ((ch
= getc(fp
)) != EOF
)
3576 if (isspace(ch
) || ch
== '#')
3578 else if (bufptr
< bufend
)
3583 else if (ch
== '\n')
3595 * 'get_variable()' - Get the value of a variable.
3598 static char * /* O - Value or NULL */
3599 get_variable(_cups_vars_t
*vars
, /* I - Variables */
3600 const char *name
) /* I - Variable name */
3602 _cups_var_t key
, /* Search key */
3603 *match
; /* Matching variable, if any */
3606 key
.name
= (char *)name
;
3607 match
= cupsArrayFind(vars
->vars
, &key
);
3609 return (match
? match
->value
: NULL
);
3614 * 'iso_date()' - Return an ISO 8601 date/time string for the given IPP dateTime
3618 static char * /* O - ISO 8601 date/time string */
3619 iso_date(ipp_uchar_t
*date
) /* I - IPP (RFC 1903) date/time value */
3621 time_t utctime
; /* UTC time since 1970 */
3622 struct tm
*utcdate
; /* UTC date/time */
3623 static char buffer
[255]; /* String buffer */
3626 utctime
= ippDateToTime(date
);
3627 utcdate
= gmtime(&utctime
);
3629 snprintf(buffer
, sizeof(buffer
), "%04d-%02d-%02dT%02d:%02d:%02dZ",
3630 utcdate
->tm_year
+ 1900, utcdate
->tm_mon
+ 1, utcdate
->tm_mday
,
3631 utcdate
->tm_hour
, utcdate
->tm_min
, utcdate
->tm_sec
);
3638 * 'password_cb()' - Password callback for authenticated tests.
3641 static const char * /* O - Password */
3642 password_cb(const char *prompt
) /* I - Prompt (unused) */
3651 * 'print_attr()' - Print an attribute on the screen.
3655 print_attr(ipp_attribute_t
*attr
, /* I - Attribute to print */
3656 ipp_tag_t
*group
) /* IO - Current group */
3658 int i
; /* Looping var */
3659 ipp_attribute_t
*colattr
; /* Collection attribute */
3662 if (Output
== _CUPS_OUTPUT_PLIST
)
3664 if (!attr
->name
|| (group
&& *group
!= attr
->group_tag
))
3670 *group
= attr
->group_tag
;
3676 print_xml_string("key", attr
->name
);
3677 if (attr
->num_values
> 1)
3680 switch (attr
->value_tag
)
3682 case IPP_TAG_INTEGER
:
3684 for (i
= 0; i
< attr
->num_values
; i
++)
3685 if (Output
== _CUPS_OUTPUT_PLIST
)
3686 printf("<integer>%d</integer>\n", attr
->values
[i
].integer
);
3688 printf("%d ", attr
->values
[i
].integer
);
3691 case IPP_TAG_BOOLEAN
:
3692 for (i
= 0; i
< attr
->num_values
; i
++)
3693 if (Output
== _CUPS_OUTPUT_PLIST
)
3694 puts(attr
->values
[i
].boolean
? "<true />" : "<false />");
3695 else if (attr
->values
[i
].boolean
)
3696 fputs("true ", stdout
);
3698 fputs("false ", stdout
);
3701 case IPP_TAG_RANGE
:
3702 for (i
= 0; i
< attr
->num_values
; i
++)
3703 if (Output
== _CUPS_OUTPUT_PLIST
)
3704 printf("<dict><key>lower</key><integer>%d</integer>"
3705 "<key>upper</key><integer>%d</integer></dict>\n",
3706 attr
->values
[i
].range
.lower
, attr
->values
[i
].range
.upper
);
3708 printf("%d-%d ", attr
->values
[i
].range
.lower
,
3709 attr
->values
[i
].range
.upper
);
3712 case IPP_TAG_RESOLUTION
:
3713 for (i
= 0; i
< attr
->num_values
; i
++)
3714 if (Output
== _CUPS_OUTPUT_PLIST
)
3715 printf("<dict><key>xres</key><integer>%d</integer>"
3716 "<key>yres</key><integer>%d</integer>"
3717 "<key>units</key><string>%s</string></dict>\n",
3718 attr
->values
[i
].resolution
.xres
,
3719 attr
->values
[i
].resolution
.yres
,
3720 attr
->values
[i
].resolution
.units
== IPP_RES_PER_INCH
?
3723 printf("%dx%d%s ", attr
->values
[i
].resolution
.xres
,
3724 attr
->values
[i
].resolution
.yres
,
3725 attr
->values
[i
].resolution
.units
== IPP_RES_PER_INCH
?
3730 for (i
= 0; i
< attr
->num_values
; i
++)
3731 if (Output
== _CUPS_OUTPUT_PLIST
)
3732 printf("<date>%s</date>\n", iso_date(attr
->values
[i
].date
));
3734 printf("%s ", iso_date(attr
->values
[i
].date
));
3737 case IPP_TAG_STRING
:
3740 case IPP_TAG_KEYWORD
:
3741 case IPP_TAG_CHARSET
:
3743 case IPP_TAG_MIMETYPE
:
3744 case IPP_TAG_LANGUAGE
:
3745 for (i
= 0; i
< attr
->num_values
; i
++)
3746 if (Output
== _CUPS_OUTPUT_PLIST
)
3747 print_xml_string("string", attr
->values
[i
].string
.text
);
3749 printf("\"%s\" ", attr
->values
[i
].string
.text
);
3752 case IPP_TAG_TEXTLANG
:
3753 case IPP_TAG_NAMELANG
:
3754 for (i
= 0; i
< attr
->num_values
; i
++)
3755 if (Output
== _CUPS_OUTPUT_PLIST
)
3757 fputs("<dict><key>language</key><string>", stdout
);
3758 print_xml_string(NULL
, attr
->values
[i
].string
.language
);
3759 fputs("</string><key>string</key><string>", stdout
);
3760 print_xml_string(NULL
, attr
->values
[i
].string
.text
);
3761 puts("</string></dict>");
3764 printf("\"%s\"[%s] ", attr
->values
[i
].string
.text
,
3765 attr
->values
[i
].string
.language
);
3768 case IPP_TAG_BEGIN_COLLECTION
:
3769 for (i
= 0; i
< attr
->num_values
; i
++)
3771 if (Output
== _CUPS_OUTPUT_PLIST
)
3774 for (colattr
= attr
->values
[i
].collection
->attrs
;
3776 colattr
= colattr
->next
)
3777 print_attr(colattr
, NULL
);
3785 print_col(attr
->values
[i
].collection
);
3791 if (Output
== _CUPS_OUTPUT_PLIST
)
3792 printf("<string><<%s>></string>\n",
3793 ippTagString(attr
->value_tag
));
3795 fputs(ippTagString(attr
->value_tag
), stdout
);
3799 if (attr
->num_values
> 1)
3804 char buffer
[8192]; /* Value buffer */
3806 if (Output
== _CUPS_OUTPUT_TEST
)
3810 puts(" -- separator --");
3814 printf(" %s (%s%s) = ", attr
->name
,
3815 attr
->num_values
> 1 ? "1setOf " : "",
3816 ippTagString(attr
->value_tag
));
3819 ippAttributeString(attr
, buffer
, sizeof(buffer
));
3826 * 'print_col()' - Print a collection attribute on the screen.
3830 print_col(ipp_t
*col
) /* I - Collection attribute to print */
3832 int i
; /* Looping var */
3833 ipp_attribute_t
*attr
; /* Current attribute in collection */
3836 fputs("{ ", stdout
);
3837 for (attr
= col
->attrs
; attr
; attr
= attr
->next
)
3839 printf("%s (%s%s) = ", attr
->name
, attr
->num_values
> 1 ? "1setOf " : "",
3840 ippTagString(attr
->value_tag
));
3842 switch (attr
->value_tag
)
3844 case IPP_TAG_INTEGER
:
3846 for (i
= 0; i
< attr
->num_values
; i
++)
3847 printf("%d ", attr
->values
[i
].integer
);
3850 case IPP_TAG_BOOLEAN
:
3851 for (i
= 0; i
< attr
->num_values
; i
++)
3852 if (attr
->values
[i
].boolean
)
3858 case IPP_TAG_NOVALUE
:
3862 case IPP_TAG_RANGE
:
3863 for (i
= 0; i
< attr
->num_values
; i
++)
3864 printf("%d-%d ", attr
->values
[i
].range
.lower
,
3865 attr
->values
[i
].range
.upper
);
3868 case IPP_TAG_RESOLUTION
:
3869 for (i
= 0; i
< attr
->num_values
; i
++)
3870 printf("%dx%d%s ", attr
->values
[i
].resolution
.xres
,
3871 attr
->values
[i
].resolution
.yres
,
3872 attr
->values
[i
].resolution
.units
== IPP_RES_PER_INCH
?
3876 case IPP_TAG_STRING
:
3879 case IPP_TAG_KEYWORD
:
3880 case IPP_TAG_CHARSET
:
3882 case IPP_TAG_MIMETYPE
:
3883 case IPP_TAG_LANGUAGE
:
3884 for (i
= 0; i
< attr
->num_values
; i
++)
3885 printf("\"%s\" ", attr
->values
[i
].string
.text
);
3888 case IPP_TAG_TEXTLANG
:
3889 case IPP_TAG_NAMELANG
:
3890 for (i
= 0; i
< attr
->num_values
; i
++)
3891 printf("\"%s\"[%s] ", attr
->values
[i
].string
.text
,
3892 attr
->values
[i
].string
.language
);
3895 case IPP_TAG_BEGIN_COLLECTION
:
3896 for (i
= 0; i
< attr
->num_values
; i
++)
3898 print_col(attr
->values
[i
].collection
);
3904 break; /* anti-compiler-warning-code */
3913 * 'print_csv()' - Print a line of CSV text.
3918 ipp_attribute_t
*attr
, /* I - First attribute for line */
3919 int num_displayed
, /* I - Number of attributes to display */
3920 char **displayed
, /* I - Attributes to display */
3921 size_t *widths
) /* I - Column widths */
3923 int i
; /* Looping var */
3924 size_t maxlength
; /* Max length of all columns */
3925 char *buffer
, /* String buffer */
3926 *bufptr
; /* Pointer into buffer */
3927 ipp_attribute_t
*current
; /* Current attribute */
3931 * Get the maximum string length we have to show and allocate...
3934 for (i
= 1, maxlength
= widths
[0]; i
< num_displayed
; i
++)
3935 if (widths
[i
] > maxlength
)
3936 maxlength
= widths
[i
];
3940 if ((buffer
= malloc(maxlength
)) == NULL
)
3944 * Loop through the attributes to display...
3949 for (i
= 0; i
< num_displayed
; i
++)
3956 for (current
= attr
; current
; current
= current
->next
)
3960 else if (!strcmp(current
->name
, displayed
[i
]))
3962 ippAttributeString(current
, buffer
, maxlength
);
3967 if (strchr(buffer
, ',') != NULL
|| strchr(buffer
, '\"') != NULL
||
3968 strchr(buffer
, '\\') != NULL
)
3971 for (bufptr
= buffer
; *bufptr
; bufptr
++)
3973 if (*bufptr
== '\\' || *bufptr
== '\"')
3980 fputs(buffer
, stdout
);
3986 for (i
= 0; i
< num_displayed
; i
++)
3991 fputs(displayed
[i
], stdout
);
4001 * 'print_fatal_error()' - Print a fatal error message.
4005 print_fatal_error(const char *s
, /* I - Printf-style format string */
4006 ...) /* I - Additional arguments as needed */
4008 char buffer
[10240]; /* Format buffer */
4009 va_list ap
; /* Pointer to arguments */
4013 * Format the error message...
4017 vsnprintf(buffer
, sizeof(buffer
), s
, ap
);
4024 if (Output
== _CUPS_OUTPUT_PLIST
)
4027 print_xml_trailer(0, buffer
);
4030 _cupsLangPrintf(stderr
, "ipptool: %s", buffer
);
4035 * 'print_line()' - Print a line of formatted or CSV text.
4040 ipp_attribute_t
*attr
, /* I - First attribute for line */
4041 int num_displayed
, /* I - Number of attributes to display */
4042 char **displayed
, /* I - Attributes to display */
4043 size_t *widths
) /* I - Column widths */
4045 int i
; /* Looping var */
4046 size_t maxlength
; /* Max length of all columns */
4047 char *buffer
; /* String buffer */
4048 ipp_attribute_t
*current
; /* Current attribute */
4052 * Get the maximum string length we have to show and allocate...
4055 for (i
= 1, maxlength
= widths
[0]; i
< num_displayed
; i
++)
4056 if (widths
[i
] > maxlength
)
4057 maxlength
= widths
[i
];
4061 if ((buffer
= malloc(maxlength
)) == NULL
)
4065 * Loop through the attributes to display...
4070 for (i
= 0; i
< num_displayed
; i
++)
4077 for (current
= attr
; current
; current
= current
->next
)
4081 else if (!strcmp(current
->name
, displayed
[i
]))
4083 ippAttributeString(current
, buffer
, maxlength
);
4088 printf("%*s", (int)-widths
[i
], buffer
);
4094 for (i
= 0; i
< num_displayed
; i
++)
4099 printf("%*s", (int)-widths
[i
], displayed
[i
]);
4103 for (i
= 0; i
< num_displayed
; i
++)
4108 memset(buffer
, '-', widths
[i
]);
4109 buffer
[widths
[i
]] = '\0';
4110 fputs(buffer
, stdout
);
4120 * 'print_test_error()' - Print a test error message.
4124 print_test_error(const char *s
, /* I - Printf-style format string */
4125 ...) /* I - Additional arguments as needed */
4127 char buffer
[10240]; /* Format buffer */
4128 va_list ap
; /* Pointer to arguments */
4132 * Format the error message...
4136 vsnprintf(buffer
, sizeof(buffer
), s
, ap
);
4143 if (Output
== _CUPS_OUTPUT_PLIST
)
4144 print_xml_string("string", buffer
);
4146 printf(" %s\n", buffer
);
4151 * 'print_xml_header()' - Print a standard XML plist header.
4155 print_xml_header(void)
4159 puts("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
4160 puts("<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" "
4161 "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">");
4162 puts("<plist version=\"1.0\">");
4164 puts("<key>Transfer</key>");
4165 printf("<string>%s</string>\n",
4166 Transfer
== _CUPS_TRANSFER_AUTO
? "auto" :
4167 Transfer
== _CUPS_TRANSFER_CHUNKED
? "chunked" : "length");
4168 puts("<key>Tests</key>");
4177 * 'print_xml_string()' - Print an XML string with escaping.
4181 print_xml_string(const char *element
, /* I - Element name or NULL */
4182 const char *s
) /* I - String to print */
4185 printf("<%s>", element
);
4190 fputs("&", stdout
);
4192 fputs("<", stdout
);
4194 fputs(">", stdout
);
4195 else if ((*s
& 0xe0) == 0xc0)
4198 * Validate UTF-8 two-byte sequence...
4201 if ((s
[1] & 0xc0) != 0x80)
4212 else if ((*s
& 0xf0) == 0xe0)
4215 * Validate UTF-8 three-byte sequence...
4218 if ((s
[1] & 0xc0) != 0x80 || (s
[2] & 0xc0) != 0x80)
4230 else if ((*s
& 0xf8) == 0xf0)
4233 * Validate UTF-8 four-byte sequence...
4236 if ((s
[1] & 0xc0) != 0x80 || (s
[2] & 0xc0) != 0x80 ||
4237 (s
[3] & 0xc0) != 0x80)
4250 else if ((*s
& 0x80) || (*s
< ' ' && !isspace(*s
& 255)))
4253 * Invalid control character...
4265 printf("</%s>\n", element
);
4270 * 'print_xml_trailer()' - Print the XML trailer with success/fail value.
4274 print_xml_trailer(int success
, /* I - 1 on success, 0 on failure */
4275 const char *message
) /* I - Error message or NULL */
4280 puts("<key>Successful</key>");
4281 puts(success
? "<true />" : "<false />");
4284 puts("<key>ErrorMessage</key>");
4285 print_xml_string("string", message
);
4296 * 'set_variable()' - Set a variable value.
4300 set_variable(_cups_vars_t
*vars
, /* I - Variables */
4301 const char *name
, /* I - Variable name */
4302 const char *value
) /* I - Value string */
4304 _cups_var_t key
, /* Search key */
4305 *var
; /* New variable */
4308 if (!_cups_strcasecmp(name
, "filename"))
4311 free(vars
->filename
);
4313 vars
->filename
= strdup(value
);
4317 key
.name
= (char *)name
;
4318 if ((var
= cupsArrayFind(vars
->vars
, &key
)) != NULL
)
4321 var
->value
= strdup(value
);
4323 else if ((var
= malloc(sizeof(_cups_var_t
))) == NULL
)
4325 print_fatal_error("Unable to allocate memory for variable \"%s\".", name
);
4330 var
->name
= strdup(name
);
4331 var
->value
= strdup(value
);
4333 cupsArrayAdd(vars
->vars
, var
);
4340 * 'sigterm_handler()' - Handle SIGINT and SIGTERM.
4344 sigterm_handler(int sig
) /* I - Signal number (unused) */
4350 signal(SIGINT
, SIG_DFL
);
4351 signal(SIGTERM
, SIG_DFL
);
4357 * 'timeout_cb()' - Handle HTTP timeouts.
4360 static int /* O - 1 to continue, 0 to cancel */
4361 timeout_cb(http_t
*http
, /* I - Connection to server (unused) */
4362 void *user_data
) /* I - User data (unused) */
4367 /* Always cancel on timeout */
4373 * 'usage()' - Show program usage.
4379 _cupsLangPuts(stderr
, _("Usage: ipptool [options] URI filename [ ... "
4381 _cupsLangPuts(stderr
, _("Options:"));
4382 _cupsLangPuts(stderr
, _(" -4 Connect using IPv4."));
4383 _cupsLangPuts(stderr
, _(" -6 Connect using IPv6."));
4384 _cupsLangPuts(stderr
, _(" -C Send requests using "
4385 "chunking (default)."));
4386 _cupsLangPuts(stderr
, _(" -E Test with TLS "
4388 _cupsLangPuts(stderr
, _(" -I Ignore errors."));
4389 _cupsLangPuts(stderr
, _(" -L Send requests using "
4390 "content-length."));
4391 _cupsLangPuts(stderr
, _(" -S Test with SSL "
4393 _cupsLangPuts(stderr
, _(" -T Set the receive/send "
4394 "timeout in seconds."));
4395 _cupsLangPuts(stderr
, _(" -V version Set default IPP "
4397 _cupsLangPuts(stderr
, _(" -X Produce XML plist instead "
4399 _cupsLangPuts(stderr
, _(" -d name=value Set named variable to "
4401 _cupsLangPuts(stderr
, _(" -f filename Set default request "
4403 _cupsLangPuts(stderr
, _(" -i seconds Repeat the last file with "
4404 "the given time interval."));
4405 _cupsLangPuts(stderr
, _(" -n count Repeat the last file the "
4406 "given number of times."));
4407 _cupsLangPuts(stderr
, _(" -q Be quiet - no output "
4409 _cupsLangPuts(stderr
, _(" -t Produce a test report."));
4410 _cupsLangPuts(stderr
, _(" -v Show all attributes sent "
4418 * 'validate_attr()' - Determine whether an attribute is valid.
4421 static int /* O - 1 if valid, 0 otherwise */
4422 validate_attr(ipp_attribute_t
*attr
, /* I - Attribute to validate */
4423 int print
) /* I - 1 = report issues to stdout */
4425 int i
; /* Looping var */
4426 char scheme
[64], /* Scheme from URI */
4427 userpass
[256], /* Username/password from URI */
4428 hostname
[256], /* Hostname from URI */
4429 resource
[1024]; /* Resource from URI */
4430 int port
, /* Port number from URI */
4431 uri_status
, /* URI separation status */
4432 valid
= 1; /* Is the attribute valid? */
4433 const char *ptr
; /* Pointer into string */
4434 ipp_attribute_t
*colattr
; /* Collection attribute */
4435 regex_t re
; /* Regular expression */
4436 ipp_uchar_t
*date
; /* Current date value */
4447 * Validate the attribute name.
4450 for (ptr
= attr
->name
; *ptr
; ptr
++)
4451 if (!isalnum(*ptr
& 255) && *ptr
!= '-' && *ptr
!= '.' && *ptr
!= '_')
4454 if (*ptr
|| ptr
== attr
->name
)
4459 print_test_error("\"%s\": Bad attribute name - invalid character (RFC "
4460 "2911 section 4.1.3).", attr
->name
);
4463 if ((ptr
- attr
->name
) > 255)
4468 print_test_error("\"%s\": Bad attribute name - bad length (RFC 2911 "
4469 "section 4.1.3).", attr
->name
);
4472 switch (attr
->value_tag
)
4474 case IPP_TAG_INTEGER
:
4477 case IPP_TAG_BOOLEAN
:
4478 for (i
= 0; i
< attr
->num_values
; i
++)
4480 if (attr
->values
[i
].boolean
!= 0 &&
4481 attr
->values
[i
].boolean
!= 1)
4486 print_test_error("\"%s\": Bad boolen value %d (RFC 2911 section "
4487 "4.1.10).", attr
->name
, attr
->values
[i
].boolean
);
4495 for (i
= 0; i
< attr
->num_values
; i
++)
4497 if (attr
->values
[i
].integer
< 1)
4502 print_test_error("\"%s\": Bad enum value %d - out of range "
4503 "(RFC 2911 section 4.1.4).", attr
->name
,
4504 attr
->values
[i
].integer
);
4511 case IPP_TAG_STRING
:
4512 for (i
= 0; i
< attr
->num_values
; i
++)
4514 if (attr
->values
[i
].unknown
.length
> 1023)
4519 print_test_error("\"%s\": Bad octetString value - bad length %d "
4520 "(RFC 2911 section 4.1.10).", attr
->name
,
4521 attr
->values
[i
].unknown
.length
);
4529 for (i
= 0; i
< attr
->num_values
; i
++)
4531 date
= attr
->values
[i
].date
;
4533 if (date
[2] < 1 || date
[2] > 12)
4538 print_test_error("\"%s\": Bad dateTime month %u (RFC 2911 "
4539 "section 4.1.13).", attr
->name
, date
[2]);
4544 if (date
[3] < 1 || date
[3] > 31)
4549 print_test_error("\"%s\": Bad dateTime day %u (RFC 2911 "
4550 "section 4.1.13).", attr
->name
, date
[3]);
4560 print_test_error("\"%s\": Bad dateTime hours %u (RFC 2911 "
4561 "section 4.1.13).", attr
->name
, date
[4]);
4571 print_test_error("\"%s\": Bad dateTime minutes %u (RFC 2911 "
4572 "section 4.1.13).", attr
->name
, date
[5]);
4582 print_test_error("\"%s\": Bad dateTime seconds %u (RFC 2911 "
4583 "section 4.1.13).", attr
->name
, date
[6]);
4593 print_test_error("\"%s\": Bad dateTime deciseconds %u (RFC 2911 "
4594 "section 4.1.13).", attr
->name
, date
[7]);
4599 if (date
[8] != '-' && date
[8] != '+')
4604 print_test_error("\"%s\": Bad dateTime UTC sign '%c' (RFC 2911 "
4605 "section 4.1.13).", attr
->name
, date
[8]);
4615 print_test_error("\"%s\": Bad dateTime UTC hours %u (RFC 2911 "
4616 "section 4.1.13).", attr
->name
, date
[9]);
4626 print_test_error("\"%s\": Bad dateTime UTC minutes %u (RFC 2911 "
4627 "section 4.1.13).", attr
->name
, date
[10]);
4634 case IPP_TAG_RESOLUTION
:
4635 for (i
= 0; i
< attr
->num_values
; i
++)
4637 if (attr
->values
[i
].resolution
.xres
<= 0)
4642 print_test_error("\"%s\": Bad resolution value %dx%d%s - cross "
4643 "feed resolution must be positive (RFC 2911 "
4644 "section 4.1.13).", attr
->name
,
4645 attr
->values
[i
].resolution
.xres
,
4646 attr
->values
[i
].resolution
.yres
,
4647 attr
->values
[i
].resolution
.units
==
4648 IPP_RES_PER_INCH
? "dpi" :
4649 attr
->values
[i
].resolution
.units
==
4650 IPP_RES_PER_CM
? "dpc" : "unknown");
4655 if (attr
->values
[i
].resolution
.yres
<= 0)
4660 print_test_error("\"%s\": Bad resolution value %dx%d%s - feed "
4661 "resolution must be positive (RFC 2911 section "
4662 "4.1.13).", attr
->name
,
4663 attr
->values
[i
].resolution
.xres
,
4664 attr
->values
[i
].resolution
.yres
,
4665 attr
->values
[i
].resolution
.units
==
4666 IPP_RES_PER_INCH
? "dpi" :
4667 attr
->values
[i
].resolution
.units
==
4668 IPP_RES_PER_CM
? "dpc" : "unknown");
4673 if (attr
->values
[i
].resolution
.units
!= IPP_RES_PER_INCH
&&
4674 attr
->values
[i
].resolution
.units
!= IPP_RES_PER_CM
)
4679 print_test_error("\"%s\": Bad resolution value %dx%d%s - bad "
4680 "units value (RFC 2911 section 4.1.13).",
4681 attr
->name
, attr
->values
[i
].resolution
.xres
,
4682 attr
->values
[i
].resolution
.yres
,
4683 attr
->values
[i
].resolution
.units
==
4684 IPP_RES_PER_INCH
? "dpi" :
4685 attr
->values
[i
].resolution
.units
==
4686 IPP_RES_PER_CM
? "dpc" : "unknown");
4693 case IPP_TAG_RANGE
:
4694 for (i
= 0; i
< attr
->num_values
; i
++)
4696 if (attr
->values
[i
].range
.lower
> attr
->values
[i
].range
.upper
)
4701 print_test_error("\"%s\": Bad rangeOfInteger value %d-%d - lower "
4702 "greater than upper (RFC 2911 section 4.1.13).",
4703 attr
->name
, attr
->values
[i
].range
.lower
,
4704 attr
->values
[i
].range
.upper
);
4711 case IPP_TAG_BEGIN_COLLECTION
:
4712 for (i
= 0; i
< attr
->num_values
; i
++)
4714 for (colattr
= attr
->values
[i
].collection
->attrs
;
4716 colattr
= colattr
->next
)
4718 if (!validate_attr(colattr
, 0))
4725 if (colattr
&& print
)
4727 print_test_error("\"%s\": Bad collection value.", attr
->name
);
4731 validate_attr(colattr
, print
);
4732 colattr
= colattr
->next
;
4739 case IPP_TAG_TEXTLANG
:
4740 for (i
= 0; i
< attr
->num_values
; i
++)
4742 for (ptr
= attr
->values
[i
].string
.text
; *ptr
; ptr
++)
4744 if ((*ptr
& 0xe0) == 0xc0)
4747 if ((*ptr
& 0xc0) != 0x80)
4750 else if ((*ptr
& 0xf0) == 0xe0)
4753 if ((*ptr
& 0xc0) != 0x80)
4756 if ((*ptr
& 0xc0) != 0x80)
4759 else if ((*ptr
& 0xf8) == 0xf0)
4762 if ((*ptr
& 0xc0) != 0x80)
4765 if ((*ptr
& 0xc0) != 0x80)
4768 if ((*ptr
& 0xc0) != 0x80)
4771 else if (*ptr
& 0x80)
4780 print_test_error("\"%s\": Bad text value \"%s\" - bad UTF-8 "
4781 "sequence (RFC 2911 section 4.1.1).", attr
->name
,
4782 attr
->values
[i
].string
.text
);
4787 if ((ptr
- attr
->values
[i
].string
.text
) > 1023)
4792 print_test_error("\"%s\": Bad text value \"%s\" - bad length %d "
4793 "(RFC 2911 section 4.1.1).", attr
->name
,
4794 attr
->values
[i
].string
.text
,
4795 (int)strlen(attr
->values
[i
].string
.text
));
4803 case IPP_TAG_NAMELANG
:
4804 for (i
= 0; i
< attr
->num_values
; i
++)
4806 for (ptr
= attr
->values
[i
].string
.text
; *ptr
; ptr
++)
4808 if ((*ptr
& 0xe0) == 0xc0)
4811 if ((*ptr
& 0xc0) != 0x80)
4814 else if ((*ptr
& 0xf0) == 0xe0)
4817 if ((*ptr
& 0xc0) != 0x80)
4820 if ((*ptr
& 0xc0) != 0x80)
4823 else if ((*ptr
& 0xf8) == 0xf0)
4826 if ((*ptr
& 0xc0) != 0x80)
4829 if ((*ptr
& 0xc0) != 0x80)
4832 if ((*ptr
& 0xc0) != 0x80)
4835 else if (*ptr
& 0x80)
4844 print_test_error("\"%s\": Bad name value \"%s\" - bad UTF-8 "
4845 "sequence (RFC 2911 section 4.1.2).", attr
->name
,
4846 attr
->values
[i
].string
.text
);
4851 if ((ptr
- attr
->values
[i
].string
.text
) > 1023)
4856 print_test_error("\"%s\": Bad name value \"%s\" - bad length %d "
4857 "(RFC 2911 section 4.1.2).", attr
->name
,
4858 attr
->values
[i
].string
.text
,
4859 (int)strlen(attr
->values
[i
].string
.text
));
4866 case IPP_TAG_KEYWORD
:
4867 for (i
= 0; i
< attr
->num_values
; i
++)
4869 for (ptr
= attr
->values
[i
].string
.text
; *ptr
; ptr
++)
4870 if (!isalnum(*ptr
& 255) && *ptr
!= '-' && *ptr
!= '.' &&
4874 if (*ptr
|| ptr
== attr
->values
[i
].string
.text
)
4879 print_test_error("\"%s\": Bad keyword value \"%s\" - invalid "
4880 "character (RFC 2911 section 4.1.3).",
4881 attr
->name
, attr
->values
[i
].string
.text
);
4886 if ((ptr
- attr
->values
[i
].string
.text
) > 255)
4891 print_test_error("\"%s\": Bad keyword value \"%s\" - bad "
4892 "length %d (RFC 2911 section 4.1.3).",
4893 attr
->name
, attr
->values
[i
].string
.text
,
4894 (int)strlen(attr
->values
[i
].string
.text
));
4902 for (i
= 0; i
< attr
->num_values
; i
++)
4904 uri_status
= httpSeparateURI(HTTP_URI_CODING_ALL
,
4905 attr
->values
[i
].string
.text
,
4906 scheme
, sizeof(scheme
),
4907 userpass
, sizeof(userpass
),
4908 hostname
, sizeof(hostname
),
4909 &port
, resource
, sizeof(resource
));
4911 if (uri_status
< HTTP_URI_OK
)
4916 print_test_error("\"%s\": Bad URI value \"%s\" - %s "
4917 "(RFC 2911 section 4.1.5).", attr
->name
,
4918 attr
->values
[i
].string
.text
,
4919 URIStatusStrings
[uri_status
-
4920 HTTP_URI_OVERFLOW
]);
4925 if (strlen(attr
->values
[i
].string
.text
) > 1023)
4930 print_test_error("\"%s\": Bad URI value \"%s\" - bad length %d "
4931 "(RFC 2911 section 4.1.5).", attr
->name
,
4932 attr
->values
[i
].string
.text
,
4933 (int)strlen(attr
->values
[i
].string
.text
));
4940 case IPP_TAG_URISCHEME
:
4941 for (i
= 0; i
< attr
->num_values
; i
++)
4943 ptr
= attr
->values
[i
].string
.text
;
4944 if (islower(*ptr
& 255))
4946 for (ptr
++; *ptr
; ptr
++)
4947 if (!islower(*ptr
& 255) && !isdigit(*ptr
& 255) &&
4948 *ptr
!= '+' && *ptr
!= '-' && *ptr
!= '.')
4952 if (*ptr
|| ptr
== attr
->values
[i
].string
.text
)
4957 print_test_error("\"%s\": Bad uriScheme value \"%s\" - bad "
4958 "characters (RFC 2911 section 4.1.6).",
4959 attr
->name
, attr
->values
[i
].string
.text
);
4964 if ((ptr
- attr
->values
[i
].string
.text
) > 63)
4969 print_test_error("\"%s\": Bad uriScheme value \"%s\" - bad "
4970 "length %d (RFC 2911 section 4.1.6).",
4971 attr
->name
, attr
->values
[i
].string
.text
,
4972 (int)strlen(attr
->values
[i
].string
.text
));
4979 case IPP_TAG_CHARSET
:
4980 for (i
= 0; i
< attr
->num_values
; i
++)
4982 for (ptr
= attr
->values
[i
].string
.text
; *ptr
; ptr
++)
4983 if (!isprint(*ptr
& 255) || isupper(*ptr
& 255) ||
4984 isspace(*ptr
& 255))
4987 if (*ptr
|| ptr
== attr
->values
[i
].string
.text
)
4992 print_test_error("\"%s\": Bad charset value \"%s\" - bad "
4993 "characters (RFC 2911 section 4.1.7).",
4994 attr
->name
, attr
->values
[i
].string
.text
);
4999 if ((ptr
- attr
->values
[i
].string
.text
) > 40)
5004 print_test_error("\"%s\": Bad charset value \"%s\" - bad "
5005 "length %d (RFC 2911 section 4.1.7).",
5006 attr
->name
, attr
->values
[i
].string
.text
,
5007 (int)strlen(attr
->values
[i
].string
.text
));
5014 case IPP_TAG_LANGUAGE
:
5016 * The following regular expression is derived from the ABNF for
5017 * language tags in RFC 4646. All I can say is that this is the
5018 * easiest way to check the values...
5021 if ((i
= regcomp(&re
,
5023 "(([a-z]{2,3}(-[a-z][a-z][a-z]){0,3})|[a-z]{4,8})"
5025 "(-[a-z][a-z][a-z][a-z]){0,1}" /* script */
5026 "(-([a-z][a-z]|[0-9][0-9][0-9])){0,1}" /* region */
5027 "(-([a-z]{5,8}|[0-9][0-9][0-9]))*" /* variant */
5028 "(-[a-wy-z](-[a-z0-9]{2,8})+)*" /* extension */
5029 "(-x(-[a-z0-9]{1,8})+)*" /* privateuse */
5031 "x(-[a-z0-9]{1,8})+" /* privateuse */
5033 "[a-z]{1,3}(-[a-z][0-9]{2,8}){1,2}" /* grandfathered */
5035 REG_NOSUB
| REG_EXTENDED
)) != 0)
5037 char temp
[256]; /* Temporary error string */
5039 regerror(i
, &re
, temp
, sizeof(temp
));
5040 print_fatal_error("Unable to compile naturalLanguage regular "
5041 "expression: %s.", temp
);
5044 for (i
= 0; i
< attr
->num_values
; i
++)
5046 if (regexec(&re
, attr
->values
[i
].string
.text
, 0, NULL
, 0))
5051 print_test_error("\"%s\": Bad naturalLanguage value \"%s\" - bad "
5052 "characters (RFC 2911 section 4.1.8).",
5053 attr
->name
, attr
->values
[i
].string
.text
);
5058 if (strlen(attr
->values
[i
].string
.text
) > 63)
5063 print_test_error("\"%s\": Bad naturalLanguage value \"%s\" - bad "
5064 "length %d (RFC 2911 section 4.1.8).",
5065 attr
->name
, attr
->values
[i
].string
.text
,
5066 (int)strlen(attr
->values
[i
].string
.text
));
5075 case IPP_TAG_MIMETYPE
:
5077 * The following regular expression is derived from the ABNF for
5078 * language tags in RFC 2045 and 4288. All I can say is that this is
5079 * the easiest way to check the values...
5082 if ((i
= regcomp(&re
,
5084 "[-a-zA-Z0-9!#$&.+^_]{1,127}" /* type-name */
5086 "[-a-zA-Z0-9!#$&.+^_]{1,127}" /* subtype-name */
5087 "(;[-a-zA-Z0-9!#$&.+^_]{1,127}=" /* parameter= */
5088 "([-a-zA-Z0-9!#$&.+^_]{1,127}|\"[^\"]*\"))*"
5091 REG_NOSUB
| REG_EXTENDED
)) != 0)
5093 char temp
[256]; /* Temporary error string */
5095 regerror(i
, &re
, temp
, sizeof(temp
));
5096 print_fatal_error("Unable to compile mimeMediaType regular "
5097 "expression: %s.", temp
);
5100 for (i
= 0; i
< attr
->num_values
; i
++)
5102 if (regexec(&re
, attr
->values
[i
].string
.text
, 0, NULL
, 0))
5107 print_test_error("\"%s\": Bad mimeMediaType value \"%s\" - bad "
5108 "characters (RFC 2911 section 4.1.9).",
5109 attr
->name
, attr
->values
[i
].string
.text
);
5114 if (strlen(attr
->values
[i
].string
.text
) > 255)
5119 print_test_error("\"%s\": Bad mimeMediaType value \"%s\" - bad "
5120 "length %d (RFC 2911 section 4.1.9).",
5121 attr
->name
, attr
->values
[i
].string
.text
,
5122 (int)strlen(attr
->values
[i
].string
.text
));
5138 * 'with_value()' - Test a WITH-VALUE predicate.
5141 static int /* O - 1 on match, 0 on non-match */
5142 with_value(char *value
, /* I - Value string */
5143 int regex
, /* I - Value is a regular expression */
5144 ipp_attribute_t
*attr
, /* I - Attribute to compare */
5145 int report
, /* I - 1 = report failures */
5146 char *matchbuf
, /* I - Buffer to hold matching value */
5147 size_t matchlen
) /* I - Length of match buffer */
5149 int i
; /* Looping var */
5150 char *valptr
; /* Pointer into value */
5156 * NULL matches everything.
5159 if (!value
|| !*value
)
5163 * Compare the value string to the attribute value.
5166 switch (attr
->value_tag
)
5168 case IPP_TAG_INTEGER
:
5170 for (i
= 0; i
< attr
->num_values
; i
++)
5172 char op
, /* Comparison operator */
5173 *nextptr
; /* Next pointer */
5174 int intvalue
; /* Integer value */
5179 while (isspace(*valptr
& 255) || isdigit(*valptr
& 255) ||
5180 *valptr
== '-' || *valptr
== ',' || *valptr
== '<' ||
5181 *valptr
== '=' || *valptr
== '>')
5184 while (*valptr
&& !isdigit(*valptr
& 255) && *valptr
!= '-')
5186 if (*valptr
== '<' || *valptr
== '>' || *valptr
== '=')
5194 intvalue
= strtol(valptr
, &nextptr
, 0);
5195 if (nextptr
== valptr
)
5202 if (attr
->values
[i
].integer
== intvalue
)
5204 snprintf(matchbuf
, matchlen
, "%d", attr
->values
[i
].integer
);
5209 if (attr
->values
[i
].integer
< intvalue
)
5211 snprintf(matchbuf
, matchlen
, "%d", attr
->values
[i
].integer
);
5216 if (attr
->values
[i
].integer
> intvalue
)
5218 snprintf(matchbuf
, matchlen
, "%d", attr
->values
[i
].integer
);
5228 for (i
= 0; i
< attr
->num_values
; i
++)
5229 print_test_error("GOT: %s=%d", attr
->name
, attr
->values
[i
].integer
);
5233 case IPP_TAG_RANGE
:
5234 for (i
= 0; i
< attr
->num_values
; i
++)
5236 char op
, /* Comparison operator */
5237 *nextptr
; /* Next pointer */
5238 int intvalue
; /* Integer value */
5243 while (isspace(*valptr
& 255) || isdigit(*valptr
& 255) ||
5244 *valptr
== '-' || *valptr
== ',' || *valptr
== '<' ||
5245 *valptr
== '=' || *valptr
== '>')
5248 while (*valptr
&& !isdigit(*valptr
& 255) && *valptr
!= '-')
5250 if (*valptr
== '<' || *valptr
== '>' || *valptr
== '=')
5258 intvalue
= strtol(valptr
, &nextptr
, 0);
5259 if (nextptr
== valptr
)
5266 if (attr
->values
[i
].range
.lower
== intvalue
||
5267 attr
->values
[i
].range
.upper
== intvalue
)
5269 snprintf(matchbuf
, matchlen
, "%d-%d",
5270 attr
->values
[i
].range
.lower
,
5271 attr
->values
[i
].range
.upper
);
5276 if (attr
->values
[i
].range
.upper
< intvalue
)
5278 snprintf(matchbuf
, matchlen
, "%d-%d",
5279 attr
->values
[i
].range
.lower
,
5280 attr
->values
[i
].range
.upper
);
5285 if (attr
->values
[i
].range
.upper
> intvalue
)
5287 snprintf(matchbuf
, matchlen
, "%d-%d",
5288 attr
->values
[i
].range
.lower
,
5289 attr
->values
[i
].range
.upper
);
5299 for (i
= 0; i
< attr
->num_values
; i
++)
5300 print_test_error("GOT: %s=%d-%d", attr
->name
,
5301 attr
->values
[i
].range
.lower
,
5302 attr
->values
[i
].range
.upper
);
5306 case IPP_TAG_BOOLEAN
:
5307 for (i
= 0; i
< attr
->num_values
; i
++)
5309 if (!strcmp(value
, "true") == attr
->values
[i
].boolean
)
5311 strlcpy(matchbuf
, value
, matchlen
);
5318 for (i
= 0; i
< attr
->num_values
; i
++)
5319 print_test_error("GOT: %s=%s", attr
->name
,
5320 attr
->values
[i
].boolean
? "true" : "false");
5324 case IPP_TAG_NOVALUE
:
5325 case IPP_TAG_UNKNOWN
:
5328 case IPP_TAG_CHARSET
:
5329 case IPP_TAG_KEYWORD
:
5330 case IPP_TAG_LANGUAGE
:
5331 case IPP_TAG_MIMETYPE
:
5333 case IPP_TAG_NAMELANG
:
5335 case IPP_TAG_TEXTLANG
:
5337 case IPP_TAG_URISCHEME
:
5341 * Value is an extended, case-sensitive POSIX regular expression...
5344 regex_t re
; /* Regular expression */
5346 if ((i
= regcomp(&re
, value
, REG_EXTENDED
| REG_NOSUB
)) != 0)
5348 char temp
[256]; /* Temporary string */
5350 regerror(i
, &re
, temp
, sizeof(temp
));
5352 print_fatal_error("Unable to compile WITH-VALUE regular expression "
5353 "\"%s\" - %s", value
, temp
);
5358 * See if ALL of the values match the given regular expression.
5361 for (i
= 0; i
< attr
->num_values
; i
++)
5363 if (regexec(&re
, attr
->values
[i
].string
.text
, 0, NULL
, 0))
5366 print_test_error("GOT: %s=\"%s\"", attr
->name
,
5367 attr
->values
[i
].string
.text
);
5375 if (i
== attr
->num_values
)
5376 strlcpy(matchbuf
, attr
->values
[0].string
.text
, matchlen
);
5378 return (i
== attr
->num_values
);
5383 * Value is a literal string, see if at least one value matches the
5387 for (i
= 0; i
< attr
->num_values
; i
++)
5389 if (!strcmp(value
, attr
->values
[i
].string
.text
))
5391 strlcpy(matchbuf
, attr
->values
[i
].string
.text
, matchlen
);
5398 for (i
= 0; i
< attr
->num_values
; i
++)
5399 print_test_error("GOT: %s=\"%s\"", attr
->name
,
5400 attr
->values
[i
].string
.text
);