4 * ipptool command for CUPS.
6 * Copyright 2007-2012 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 * add_stringf() - Add a formatted string to an array.
21 * compare_vars() - Compare two variables.
22 * do_tests() - Do tests as specified in the test file.
23 * expand_variables() - Expand variables in a string.
24 * expect_matches() - Return true if the tag matches the specification.
25 * get_collection() - Get a collection value from the current test file.
26 * get_filename() - Get a filename based on the current test file.
27 * get_token() - Get a token from a file.
28 * get_variable() - Get the value of a variable.
29 * iso_date() - Return an ISO 8601 date/time string for the given IPP
31 * password_cb() - Password callback for authenticated tests.
32 * print_attr() - Print an attribute on the screen.
33 * print_col() - Print a collection attribute on the screen.
34 * print_csv() - Print a line of CSV text.
35 * print_fatal_error() - Print a fatal error message.
36 * print_line() - Print a line of formatted or CSV text.
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 enum _cups_with_e
/**** WITH flags ****/
86 _CUPS_WITH_LITERAL
= 0, /* Match string is a literal value */
87 _CUPS_WITH_ALL
= 1, /* Must match all values */
88 _CUPS_WITH_REGEX
= 2 /* Match string is a regular expression */
91 typedef struct _cups_expect_s
/**** Expected attribute info ****/
93 int optional
, /* Optional attribute? */
94 not_expect
; /* Don't expect attribute? */
95 char *name
, /* Attribute name */
96 *of_type
, /* Type name */
97 *same_count_as
, /* Parallel attribute name */
98 *if_defined
, /* Only required if variable defined */
99 *if_not_defined
, /* Only required if variable is not defined */
100 *with_value
, /* Attribute must include this value */
101 *define_match
, /* Variable to define on match */
102 *define_no_match
, /* Variable to define on no-match */
103 *define_value
; /* Variable to define with value */
104 int repeat_match
, /* Repeat test on match */
105 repeat_no_match
, /* Repeat test on no match */
106 with_flags
, /* WITH flags */
107 count
; /* Expected count if > 0 */
108 ipp_tag_t in_group
; /* IN-GROUP value */
111 typedef struct _cups_status_s
/**** Status info ****/
113 ipp_status_t status
; /* Expected status code */
114 char *if_defined
, /* Only if variable is defined */
115 *if_not_defined
; /* Only if variable is not defined */
116 int repeat_match
, /* Repeat the test when it does not match */
117 repeat_no_match
; /* Repeat the test when it matches */
120 typedef struct _cups_var_s
/**** Variable ****/
122 char *name
, /* Name of variable */
123 *value
; /* Value of variable */
126 typedef struct _cups_vars_s
/**** Set of variables ****/
128 char *uri
, /* URI for printer */
129 *filename
, /* Filename */
130 scheme
[64], /* Scheme from URI */
131 userpass
[256], /* Username/password from URI */
132 hostname
[256], /* Hostname from URI */
133 resource
[1024]; /* Resource path from URI */
134 int port
; /* Port number from URI */
135 http_encryption_t encryption
; /* Encryption for connection? */
136 double timeout
; /* Timeout for connection */
137 int family
; /* Address family */
138 cups_array_t
*vars
; /* Array of variables */
146 _cups_transfer_t Transfer
= _CUPS_TRANSFER_AUTO
;
147 /* How to transfer requests */
148 _cups_output_t Output
= _CUPS_OUTPUT_LIST
;
150 int Cancel
= 0, /* Cancel test? */
151 IgnoreErrors
= 0, /* Ignore errors? */
152 Verbosity
= 0, /* Show all attributes? */
153 Version
= 11, /* Default IPP version */
154 XMLHeader
= 0, /* 1 if header is written */
155 TestCount
= 0, /* Number of tests run */
156 PassCount
= 0, /* Number of passing tests */
157 FailCount
= 0, /* Number of failing tests */
158 SkipCount
= 0; /* Number of skipped tests */
159 char *Password
= NULL
; /* Password from URI */
160 const char * const URIStatusStrings
[] = /* URI status strings */
163 "Bad arguments to function",
164 "Bad resource in URI",
165 "Bad port number in URI",
166 "Bad hostname/address in URI",
167 "Bad username in URI",
171 "Missing scheme in URI",
172 "Unknown scheme in URI",
173 "Missing resource in URI"
181 static void add_stringf(cups_array_t
*a
, const char *s
, ...)
182 __attribute__ ((__format__ (__printf__
, 2, 3)));
183 static int compare_vars(_cups_var_t
*a
, _cups_var_t
*b
);
184 static int do_tests(_cups_vars_t
*vars
, const char *testfile
);
185 static void expand_variables(_cups_vars_t
*vars
, char *dst
, const char *src
,
186 size_t dstsize
) __attribute__((nonnull(1,2,3)));
187 static int expect_matches(_cups_expect_t
*expect
, ipp_tag_t value_tag
);
188 static ipp_t
*get_collection(_cups_vars_t
*vars
, FILE *fp
, int *linenum
);
189 static char *get_filename(const char *testfile
, char *dst
, const char *src
,
191 static char *get_token(FILE *fp
, char *buf
, int buflen
,
193 static char *get_variable(_cups_vars_t
*vars
, const char *name
);
194 static char *iso_date(ipp_uchar_t
*date
);
195 static const char *password_cb(const char *prompt
);
196 static void print_attr(ipp_attribute_t
*attr
, ipp_tag_t
*group
);
197 static void print_col(ipp_t
*col
);
198 static void print_csv(ipp_attribute_t
*attr
, int num_displayed
,
199 char **displayed
, size_t *widths
);
200 static void print_fatal_error(const char *s
, ...)
201 __attribute__ ((__format__ (__printf__
, 1, 2)));
202 static void print_line(ipp_attribute_t
*attr
, int num_displayed
,
203 char **displayed
, size_t *widths
);
204 static void print_xml_header(void);
205 static void print_xml_string(const char *element
, const char *s
);
206 static void print_xml_trailer(int success
, const char *message
);
207 static void set_variable(_cups_vars_t
*vars
, const char *name
,
210 static void sigterm_handler(int sig
);
212 static int timeout_cb(http_t
*http
, void *user_data
);
213 static void usage(void) __attribute__((noreturn
));
214 static int validate_attr(cups_array_t
*errors
, ipp_attribute_t
*attr
);
215 static int with_value(cups_array_t
*errors
, char *value
, int flags
,
216 ipp_attribute_t
*attr
, char *matchbuf
,
221 * 'main()' - Parse options and do tests.
224 int /* O - Exit status */
225 main(int argc
, /* I - Number of command-line args */
226 char *argv
[]) /* I - Command-line arguments */
228 int i
; /* Looping var */
229 int status
; /* Status of tests... */
230 char *opt
, /* Current option */
231 name
[1024], /* Name/value buffer */
232 *value
, /* Pointer to value */
233 filename
[1024], /* Real filename */
234 testname
[1024], /* Real test filename */
235 uri
[1024]; /* Copy of printer URI */
236 const char *ext
, /* Extension on filename */
237 *testfile
; /* Test file to use */
238 int interval
, /* Test interval in microseconds */
239 repeat
; /* Repeat count */
240 _cups_vars_t vars
; /* Variables */
241 http_uri_status_t uri_status
; /* URI separation status */
242 _cups_globals_t
*cg
= _cupsGlobals();
248 * Catch SIGINT and SIGTERM...
251 signal(SIGINT
, sigterm_handler
);
252 signal(SIGTERM
, sigterm_handler
);
256 * Initialize the locale and variables...
259 _cupsSetLocale(argv
);
261 memset(&vars
, 0, sizeof(vars
));
262 vars
.family
= AF_UNSPEC
;
263 vars
.vars
= cupsArrayNew((cups_array_func_t
)compare_vars
, NULL
);
268 * ipptool URI testfile
276 for (i
= 1; i
< argc
; i
++)
278 if (argv
[i
][0] == '-')
280 for (opt
= argv
[i
] + 1; *opt
; opt
++)
284 case '4' : /* Connect using IPv4 only */
285 vars
.family
= AF_INET
;
289 case '6' : /* Connect using IPv6 only */
290 vars
.family
= AF_INET6
;
292 #endif /* AF_INET6 */
294 case 'C' : /* Enable HTTP chunking */
295 Transfer
= _CUPS_TRANSFER_CHUNKED
;
298 case 'E' : /* Encrypt with TLS */
300 vars
.encryption
= HTTP_ENCRYPT_REQUIRED
;
302 _cupsLangPrintf(stderr
, _("%s: Sorry, no encryption support."),
304 #endif /* HAVE_SSL */
307 case 'I' : /* Ignore errors */
311 case 'L' : /* Disable HTTP chunking */
312 Transfer
= _CUPS_TRANSFER_LENGTH
;
315 case 'S' : /* Encrypt with SSL */
317 vars
.encryption
= HTTP_ENCRYPT_ALWAYS
;
319 _cupsLangPrintf(stderr
, _("%s: Sorry, no encryption support."),
321 #endif /* HAVE_SSL */
324 case 'T' : /* Set timeout */
329 _cupsLangPuts(stderr
,
330 _("ipptool: Missing timeout for \"-T\"."));
334 vars
.timeout
= _cupsStrScand(argv
[i
], NULL
, localeconv());
337 case 'V' : /* Set IPP version */
342 _cupsLangPuts(stderr
,
343 _("ipptool: Missing version for \"-V\"."));
347 if (!strcmp(argv
[i
], "1.0"))
349 else if (!strcmp(argv
[i
], "1.1"))
351 else if (!strcmp(argv
[i
], "2.0"))
353 else if (!strcmp(argv
[i
], "2.1"))
355 else if (!strcmp(argv
[i
], "2.2"))
359 _cupsLangPrintf(stderr
,
360 _("ipptool: Bad version %s for \"-V\"."),
366 case 'X' : /* Produce XML output */
367 Output
= _CUPS_OUTPUT_PLIST
;
369 if (interval
|| repeat
)
371 _cupsLangPuts(stderr
, _("ipptool: \"-i\" and \"-n\" are "
372 "incompatible with -X\"."));
377 case 'c' : /* CSV output */
378 Output
= _CUPS_OUTPUT_CSV
;
381 case 'd' : /* Define a variable */
386 _cupsLangPuts(stderr
,
387 _("ipptool: Missing name=value for \"-d\"."));
391 strlcpy(name
, argv
[i
], sizeof(name
));
392 if ((value
= strchr(name
, '=')) != NULL
)
395 value
= name
+ strlen(name
);
397 set_variable(&vars
, name
, value
);
400 case 'f' : /* Set the default test filename */
405 _cupsLangPuts(stderr
,
406 _("ipptool: Missing filename for \"-f\"."));
413 if (access(argv
[i
], 0))
419 snprintf(filename
, sizeof(filename
), "%s.gz", argv
[i
]);
420 if (access(filename
, 0) && filename
[0] != '/'
422 && (!isalpha(filename
[0] & 255) || filename
[1] != ':')
426 snprintf(filename
, sizeof(filename
), "%s/ipptool/%s",
427 cg
->cups_datadir
, argv
[i
]);
428 if (access(filename
, 0))
430 snprintf(filename
, sizeof(filename
), "%s/ipptool/%s.gz",
431 cg
->cups_datadir
, argv
[i
]);
432 if (access(filename
, 0))
433 vars
.filename
= strdup(argv
[i
]);
436 vars
.filename
= strdup(filename
);
439 vars
.filename
= strdup(filename
);
442 vars
.filename
= strdup(argv
[i
]);
444 if ((ext
= strrchr(vars
.filename
, '.')) != NULL
)
447 * Guess the MIME media type based on the extension...
450 if (!_cups_strcasecmp(ext
, ".gif"))
451 set_variable(&vars
, "filetype", "image/gif");
452 else if (!_cups_strcasecmp(ext
, ".htm") ||
453 !_cups_strcasecmp(ext
, ".htm.gz") ||
454 !_cups_strcasecmp(ext
, ".html") ||
455 !_cups_strcasecmp(ext
, ".html.gz"))
456 set_variable(&vars
, "filetype", "text/html");
457 else if (!_cups_strcasecmp(ext
, ".jpg"))
458 set_variable(&vars
, "filetype", "image/jpeg");
459 else if (!_cups_strcasecmp(ext
, ".pdf"))
460 set_variable(&vars
, "filetype", "application/pdf");
461 else if (!_cups_strcasecmp(ext
, ".png"))
462 set_variable(&vars
, "filetype", "image/png");
463 else if (!_cups_strcasecmp(ext
, ".ps") ||
464 !_cups_strcasecmp(ext
, ".ps.gz"))
465 set_variable(&vars
, "filetype", "application/postscript");
466 else if (!_cups_strcasecmp(ext
, ".ras") ||
467 !_cups_strcasecmp(ext
, ".ras.gz"))
468 set_variable(&vars
, "filetype", "image/pwg-raster");
469 else if (!_cups_strcasecmp(ext
, ".txt") ||
470 !_cups_strcasecmp(ext
, ".txt.gz"))
471 set_variable(&vars
, "filetype", "text/plain");
472 else if (!_cups_strcasecmp(ext
, ".xps"))
473 set_variable(&vars
, "filetype", "application/openxps");
475 set_variable(&vars
, "filetype", "application/octet-stream");
480 * Use the "auto-type" MIME media type...
483 set_variable(&vars
, "filetype", "application/octet-stream");
487 case 'i' : /* Test every N seconds */
492 _cupsLangPuts(stderr
,
493 _("ipptool: Missing seconds for \"-i\"."));
498 interval
= (int)(_cupsStrScand(argv
[i
], NULL
, localeconv()) *
502 _cupsLangPuts(stderr
,
503 _("ipptool: Invalid seconds for \"-i\"."));
508 if (Output
== _CUPS_OUTPUT_PLIST
&& interval
)
510 _cupsLangPuts(stderr
, _("ipptool: \"-i\" and \"-n\" are "
511 "incompatible with -X\"."));
516 case 'l' : /* List as a table */
517 Output
= _CUPS_OUTPUT_LIST
;
520 case 'n' : /* Repeat count */
525 _cupsLangPuts(stderr
,
526 _("ipptool: Missing count for \"-n\"."));
530 repeat
= atoi(argv
[i
]);
532 if (Output
== _CUPS_OUTPUT_PLIST
&& repeat
)
534 _cupsLangPuts(stderr
, _("ipptool: \"-i\" and \"-n\" are "
535 "incompatible with -X\"."));
540 case 'q' : /* Be quiet */
541 Output
= _CUPS_OUTPUT_QUIET
;
544 case 't' : /* CUPS test output */
545 Output
= _CUPS_OUTPUT_TEST
;
548 case 'v' : /* Be verbose */
553 _cupsLangPrintf(stderr
, _("ipptool: Unknown option \"-%c\"."),
560 else if (!strncmp(argv
[i
], "ipp://", 6) || !strncmp(argv
[i
], "http://", 7)
562 || !strncmp(argv
[i
], "ipps://", 7)
563 || !strncmp(argv
[i
], "https://", 8)
564 #endif /* HAVE_SSL */
573 _cupsLangPuts(stderr
, _("ipptool: May only specify a single URI."));
578 if (!strncmp(argv
[i
], "ipps://", 7) || !strncmp(argv
[i
], "https://", 8))
579 vars
.encryption
= HTTP_ENCRYPT_ALWAYS
;
580 #endif /* HAVE_SSL */
583 uri_status
= httpSeparateURI(HTTP_URI_CODING_ALL
, vars
.uri
,
584 vars
.scheme
, sizeof(vars
.scheme
),
585 vars
.userpass
, sizeof(vars
.userpass
),
586 vars
.hostname
, sizeof(vars
.hostname
),
588 vars
.resource
, sizeof(vars
.resource
));
590 if (uri_status
!= HTTP_URI_OK
)
592 _cupsLangPrintf(stderr
, _("ipptool: Bad URI - %s."),
593 URIStatusStrings
[uri_status
- HTTP_URI_OVERFLOW
]);
597 if (vars
.userpass
[0])
599 if ((Password
= strchr(vars
.userpass
, ':')) != NULL
)
602 cupsSetUser(vars
.userpass
);
603 cupsSetPasswordCB(password_cb
);
604 set_variable(&vars
, "uriuser", vars
.userpass
);
607 httpAssembleURI(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), vars
.scheme
, NULL
,
608 vars
.hostname
, vars
.port
, vars
.resource
);
619 _cupsLangPuts(stderr
, _("ipptool: URI required before test file."));
623 if (access(argv
[i
], 0) && argv
[i
][0] != '/'
625 && (!isalpha(argv
[i
][0] & 255) || argv
[i
][1] != ':')
629 snprintf(testname
, sizeof(testname
), "%s/ipptool/%s", cg
->cups_datadir
,
631 if (access(testname
, 0))
639 if (!do_tests(&vars
, testfile
))
644 if (!vars
.uri
|| !testfile
)
648 * Loop if the interval is set...
651 if (Output
== _CUPS_OUTPUT_PLIST
)
652 print_xml_trailer(!status
, NULL
);
653 else if (interval
> 0 && repeat
> 0)
658 do_tests(&vars
, testfile
);
662 else if (interval
> 0)
667 do_tests(&vars
, testfile
);
670 else if (Output
== _CUPS_OUTPUT_TEST
&& TestCount
> 1)
673 * Show a summary report if there were multiple tests...
676 printf("\nSummary: %d tests, %d passed, %d failed, %d skipped\n"
677 "Score: %d%%\n", TestCount
, PassCount
, FailCount
, SkipCount
,
678 100 * (PassCount
+ SkipCount
) / TestCount
);
690 * 'add_stringf()' - Add a formatted string to an array.
694 add_stringf(cups_array_t
*a
, /* I - Array */
695 const char *s
, /* I - Printf-style format string */
696 ...) /* I - Additional args as needed */
698 char buffer
[10240]; /* Format buffer */
699 va_list ap
; /* Argument pointer */
703 * Don't bother is the array is NULL...
710 * Format the message...
714 vsnprintf(buffer
, sizeof(buffer
), s
, ap
);
718 * Add it to the array...
721 cupsArrayAdd(a
, buffer
);
726 * 'compare_vars()' - Compare two variables.
729 static int /* O - Result of comparison */
730 compare_vars(_cups_var_t
*a
, /* I - First variable */
731 _cups_var_t
*b
) /* I - Second variable */
733 return (_cups_strcasecmp(a
->name
, b
->name
));
738 * 'do_tests()' - Do tests as specified in the test file.
741 static int /* 1 = success, 0 = failure */
742 do_tests(_cups_vars_t
*vars
, /* I - Variables */
743 const char *testfile
) /* I - Test file to use */
745 int i
, /* Looping var */
746 linenum
, /* Current line number */
747 pass
, /* Did we pass the test? */
748 prev_pass
= 1, /* Did we pass the previous test? */
749 request_id
, /* Current request ID */
750 show_header
= 1, /* Show the test header? */
751 ignore_errors
, /* Ignore test failures? */
752 skip_previous
= 0, /* Skip on previous test failure? */
753 repeat_test
; /* Repeat a test? */
754 http_t
*http
= NULL
; /* HTTP connection to server */
755 FILE *fp
= NULL
; /* Test file */
756 char resource
[512], /* Resource for request */
757 token
[1024], /* Token from file */
758 *tokenptr
, /* Pointer into token */
759 temp
[1024], /* Temporary string */
760 buffer
[8192]; /* Copy buffer */
761 ipp_t
*request
= NULL
, /* IPP request */
762 *response
= NULL
; /* IPP response */
763 size_t length
; /* Length of IPP request */
764 http_status_t status
; /* HTTP status */
765 cups_file_t
*reqfile
; /* File to send */
766 ssize_t bytes
; /* Bytes read/written */
767 char attr
[128]; /* Attribute name */
768 ipp_op_t op
; /* Operation */
769 ipp_tag_t group
; /* Current group */
770 ipp_tag_t value
; /* Current value type */
771 ipp_attribute_t
*attrptr
, /* Attribute pointer */
772 *found
, /* Found attribute */
773 *lastcol
= NULL
; /* Last collection attribute */
774 char name
[1024]; /* Name of test */
775 char filename
[1024]; /* Filename */
776 _cups_transfer_t transfer
; /* To chunk or not to chunk */
777 int version
, /* IPP version number to use */
778 skip_test
; /* Skip this test? */
779 int num_statuses
= 0; /* Number of valid status codes */
780 _cups_status_t statuses
[100], /* Valid status codes */
781 *last_status
; /* Last STATUS (for predicates) */
782 int num_expects
= 0; /* Number of expected attributes */
783 _cups_expect_t expects
[200], /* Expected attributes */
784 *expect
, /* Current expected attribute */
785 *last_expect
; /* Last EXPECT (for predicates) */
786 int num_displayed
= 0; /* Number of displayed attributes */
787 char *displayed
[200]; /* Displayed attributes */
788 size_t widths
[200]; /* Width of columns */
789 cups_array_t
*a
, /* Duplicate attribute array */
790 *errors
= NULL
; /* Errors array */
791 const char *error
; /* Current error */
795 * Open the test file...
798 if ((fp
= fopen(testfile
, "r")) == NULL
)
800 print_fatal_error("Unable to open test file %s - %s", testfile
,
807 * Connect to the server...
810 if ((http
= _httpCreate(vars
->hostname
, vars
->port
, NULL
, vars
->encryption
,
811 vars
->family
)) == NULL
)
813 print_fatal_error("Unable to connect to %s on port %d - %s", vars
->hostname
,
814 vars
->port
, cupsLastErrorString());
819 if (httpReconnect(http
))
821 print_fatal_error("Unable to connect to %s on port %d - %s", vars
->hostname
,
822 vars
->port
, cupsLastErrorString());
827 if (vars
->timeout
> 0.0)
828 httpSetTimeout(http
, vars
->timeout
, timeout_cb
, NULL
);
834 CUPS_SRAND(time(NULL
));
836 errors
= cupsArrayNew3(NULL
, NULL
, NULL
, 0, (cups_acopy_func_t
)strdup
,
837 (cups_afree_func_t
)free
);
840 request_id
= (CUPS_RAND() % 1000) * 137 + 1;
842 while (!Cancel
&& get_token(fp
, token
, sizeof(token
), &linenum
) != NULL
)
845 * Expect an open brace...
848 if (!strcmp(token
, "DEFINE"))
854 if (get_token(fp
, attr
, sizeof(attr
), &linenum
) &&
855 get_token(fp
, temp
, sizeof(temp
), &linenum
))
857 expand_variables(vars
, token
, temp
, sizeof(token
));
858 set_variable(vars
, attr
, token
);
862 print_fatal_error("Missing DEFINE name and/or value on line %d.",
870 else if (!strcmp(token
, "DEFINE-DEFAULT"))
873 * DEFINE-DEFAULT name value
876 if (get_token(fp
, attr
, sizeof(attr
), &linenum
) &&
877 get_token(fp
, temp
, sizeof(temp
), &linenum
))
879 expand_variables(vars
, token
, temp
, sizeof(token
));
880 if (!get_variable(vars
, attr
))
881 set_variable(vars
, attr
, token
);
885 print_fatal_error("Missing DEFINE-DEFAULT name and/or value on line "
893 else if (!strcmp(token
, "IGNORE-ERRORS"))
900 if (get_token(fp
, temp
, sizeof(temp
), &linenum
) &&
901 (!_cups_strcasecmp(temp
, "yes") || !_cups_strcasecmp(temp
, "no")))
903 IgnoreErrors
= !_cups_strcasecmp(temp
, "yes");
907 print_fatal_error("Missing IGNORE-ERRORS value on line %d.", linenum
);
914 else if (!strcmp(token
, "INCLUDE"))
921 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
924 * Map the filename to and then run the tests...
927 if (!do_tests(vars
, get_filename(testfile
, filename
, temp
,
938 print_fatal_error("Missing INCLUDE filename on line %d.", linenum
);
946 else if (!strcmp(token
, "INCLUDE-IF-DEFINED"))
949 * INCLUDE-IF-DEFINED name "filename"
950 * INCLUDE-IF-DEFINED name <filename>
953 if (get_token(fp
, attr
, sizeof(attr
), &linenum
) &&
954 get_token(fp
, temp
, sizeof(temp
), &linenum
))
957 * Map the filename to and then run the tests...
960 if (get_variable(vars
, attr
) &&
961 !do_tests(vars
, get_filename(testfile
, filename
, temp
,
972 print_fatal_error("Missing INCLUDE-IF-DEFINED name or filename on line "
981 else if (!strcmp(token
, "INCLUDE-IF-NOT-DEFINED"))
984 * INCLUDE-IF-NOT-DEFINED name "filename"
985 * INCLUDE-IF-NOT-DEFINED name <filename>
988 if (get_token(fp
, attr
, sizeof(attr
), &linenum
) &&
989 get_token(fp
, temp
, sizeof(temp
), &linenum
))
992 * Map the filename to and then run the tests...
995 if (!get_variable(vars
, attr
) &&
996 !do_tests(vars
, get_filename(testfile
, filename
, temp
,
1007 print_fatal_error("Missing INCLUDE-IF-NOT-DEFINED name or filename on "
1008 "line %d.", linenum
);
1016 else if (!strcmp(token
, "SKIP-IF-DEFINED"))
1019 * SKIP-IF-DEFINED variable
1022 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
1024 if (get_variable(vars
, temp
))
1029 print_fatal_error("Missing SKIP-IF-DEFINED variable on line %d.",
1035 else if (!strcmp(token
, "SKIP-IF-NOT-DEFINED"))
1038 * SKIP-IF-NOT-DEFINED variable
1041 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
1043 if (!get_variable(vars
, temp
))
1048 print_fatal_error("Missing SKIP-IF-NOT-DEFINED variable on line %d.",
1054 else if (!strcmp(token
, "TRANSFER"))
1062 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
1064 if (!strcmp(temp
, "auto"))
1065 Transfer
= _CUPS_TRANSFER_AUTO
;
1066 else if (!strcmp(temp
, "chunked"))
1067 Transfer
= _CUPS_TRANSFER_CHUNKED
;
1068 else if (!strcmp(temp
, "length"))
1069 Transfer
= _CUPS_TRANSFER_LENGTH
;
1072 print_fatal_error("Bad TRANSFER value \"%s\" on line %d.", temp
,
1080 print_fatal_error("Missing TRANSFER value on line %d.", linenum
);
1087 else if (!strcmp(token
, "VERSION"))
1089 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
1091 if (!strcmp(temp
, "1.0"))
1093 else if (!strcmp(temp
, "1.1"))
1095 else if (!strcmp(temp
, "2.0"))
1097 else if (!strcmp(temp
, "2.1"))
1099 else if (!strcmp(temp
, "2.2"))
1103 print_fatal_error("Bad VERSION \"%s\" on line %d.", temp
, linenum
);
1110 print_fatal_error("Missing VERSION number on line %d.", linenum
);
1117 else if (strcmp(token
, "{"))
1119 print_fatal_error("Unexpected token %s seen on line %d.", token
, linenum
);
1125 * Initialize things...
1130 if (Output
== _CUPS_OUTPUT_PLIST
)
1132 else if (Output
== _CUPS_OUTPUT_TEST
)
1133 printf("\"%s\":\n", testfile
);
1138 strlcpy(resource
, vars
->resource
, sizeof(resource
));
1143 group
= IPP_TAG_ZERO
;
1144 ignore_errors
= IgnoreErrors
;
1151 transfer
= Transfer
;
1153 strlcpy(name
, testfile
, sizeof(name
));
1154 if (strrchr(name
, '.') != NULL
)
1155 *strrchr(name
, '.') = '\0';
1158 * Parse until we see a close brace...
1161 while (get_token(fp
, token
, sizeof(token
), &linenum
) != NULL
)
1163 if (_cups_strcasecmp(token
, "COUNT") &&
1164 _cups_strcasecmp(token
, "DEFINE-MATCH") &&
1165 _cups_strcasecmp(token
, "DEFINE-NO-MATCH") &&
1166 _cups_strcasecmp(token
, "DEFINE-VALUE") &&
1167 _cups_strcasecmp(token
, "IF-DEFINED") &&
1168 _cups_strcasecmp(token
, "IF-NOT-DEFINED") &&
1169 _cups_strcasecmp(token
, "IN-GROUP") &&
1170 _cups_strcasecmp(token
, "OF-TYPE") &&
1171 _cups_strcasecmp(token
, "REPEAT-MATCH") &&
1172 _cups_strcasecmp(token
, "REPEAT-NO-MATCH") &&
1173 _cups_strcasecmp(token
, "SAME-COUNT-AS") &&
1174 _cups_strcasecmp(token
, "WITH-ALL-VALUES") &&
1175 _cups_strcasecmp(token
, "WITH-VALUE"))
1178 if (_cups_strcasecmp(token
, "IF-DEFINED") &&
1179 _cups_strcasecmp(token
, "IF-NOT-DEFINED") &&
1180 _cups_strcasecmp(token
, "REPEAT-MATCH") &&
1181 _cups_strcasecmp(token
, "REPEAT-NO-MATCH"))
1184 if (!strcmp(token
, "}"))
1186 else if (!strcmp(token
, "{") && lastcol
)
1189 * Another collection value
1192 ipp_t
*col
= get_collection(vars
, fp
, &linenum
);
1193 /* Collection value */
1197 ipp_attribute_t
*tempcol
; /* Pointer to new buffer */
1201 * Reallocate memory...
1204 if ((tempcol
= realloc(lastcol
, sizeof(ipp_attribute_t
) +
1205 (lastcol
->num_values
+ 1) *
1206 sizeof(_ipp_value_t
))) == NULL
)
1208 print_fatal_error("Unable to allocate memory on line %d.", linenum
);
1213 if (tempcol
!= lastcol
)
1216 * Reset pointers in the list...
1220 request
->prev
->next
= tempcol
;
1222 request
->attrs
= tempcol
;
1224 lastcol
= request
->current
= request
->last
= tempcol
;
1227 lastcol
->values
[lastcol
->num_values
].collection
= col
;
1228 lastcol
->num_values
++;
1236 else if (!strcmp(token
, "DEFINE"))
1242 if (get_token(fp
, attr
, sizeof(attr
), &linenum
) &&
1243 get_token(fp
, temp
, sizeof(temp
), &linenum
))
1245 expand_variables(vars
, token
, temp
, sizeof(token
));
1246 set_variable(vars
, attr
, token
);
1250 print_fatal_error("Missing DEFINE name and/or value on line %d.",
1256 else if (!strcmp(token
, "IGNORE-ERRORS"))
1263 if (get_token(fp
, temp
, sizeof(temp
), &linenum
) &&
1264 (!_cups_strcasecmp(temp
, "yes") || !_cups_strcasecmp(temp
, "no")))
1266 ignore_errors
= !_cups_strcasecmp(temp
, "yes");
1270 print_fatal_error("Missing IGNORE-ERRORS value on line %d.", linenum
);
1277 else if (!_cups_strcasecmp(token
, "NAME"))
1283 get_token(fp
, name
, sizeof(name
), &linenum
);
1285 else if (!strcmp(token
, "REQUEST-ID"))
1292 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
1294 if (isdigit(temp
[0] & 255))
1295 request_id
= atoi(temp
);
1296 else if (!_cups_strcasecmp(temp
, "random"))
1297 request_id
= (CUPS_RAND() % 1000) * 137 + 1;
1300 print_fatal_error("Bad REQUEST-ID value \"%s\" on line %d.", temp
,
1308 print_fatal_error("Missing REQUEST-ID value on line %d.", linenum
);
1313 else if (!strcmp(token
, "SKIP-IF-DEFINED"))
1316 * SKIP-IF-DEFINED variable
1319 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
1321 if (get_variable(vars
, temp
))
1326 print_fatal_error("Missing SKIP-IF-DEFINED value on line %d.",
1332 else if (!strcmp(token
, "SKIP-IF-NOT-DEFINED"))
1335 * SKIP-IF-NOT-DEFINED variable
1338 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
1340 if (!get_variable(vars
, temp
))
1345 print_fatal_error("Missing SKIP-IF-NOT-DEFINED value on line %d.",
1351 else if (!strcmp(token
, "SKIP-PREVIOUS-ERROR"))
1354 * SKIP-PREVIOUS-ERROR yes
1355 * SKIP-PREVIOUS-ERROR no
1358 if (get_token(fp
, temp
, sizeof(temp
), &linenum
) &&
1359 (!_cups_strcasecmp(temp
, "yes") || !_cups_strcasecmp(temp
, "no")))
1361 skip_previous
= !_cups_strcasecmp(temp
, "yes");
1365 print_fatal_error("Missing SKIP-PREVIOUS-ERROR value on line %d.", linenum
);
1372 else if (!strcmp(token
, "TRANSFER"))
1380 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
1382 if (!strcmp(temp
, "auto"))
1383 transfer
= _CUPS_TRANSFER_AUTO
;
1384 else if (!strcmp(temp
, "chunked"))
1385 transfer
= _CUPS_TRANSFER_CHUNKED
;
1386 else if (!strcmp(temp
, "length"))
1387 transfer
= _CUPS_TRANSFER_LENGTH
;
1390 print_fatal_error("Bad TRANSFER value \"%s\" on line %d.", temp
,
1398 print_fatal_error("Missing TRANSFER value on line %d.", linenum
);
1403 else if (!_cups_strcasecmp(token
, "VERSION"))
1405 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
1407 if (!strcmp(temp
, "0.0"))
1409 else if (!strcmp(temp
, "1.0"))
1411 else if (!strcmp(temp
, "1.1"))
1413 else if (!strcmp(temp
, "2.0"))
1415 else if (!strcmp(temp
, "2.1"))
1417 else if (!strcmp(temp
, "2.2"))
1421 print_fatal_error("Bad VERSION \"%s\" on line %d.", temp
, linenum
);
1428 print_fatal_error("Missing VERSION number on line %d.", linenum
);
1433 else if (!_cups_strcasecmp(token
, "RESOURCE"))
1439 if (!get_token(fp
, resource
, sizeof(resource
), &linenum
))
1441 print_fatal_error("Missing RESOURCE path on line %d.", linenum
);
1446 else if (!_cups_strcasecmp(token
, "OPERATION"))
1452 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1454 print_fatal_error("Missing OPERATION code on line %d.", linenum
);
1459 if ((op
= ippOpValue(token
)) == (ipp_op_t
)-1 &&
1460 (op
= strtol(token
, NULL
, 0)) == 0)
1462 print_fatal_error("Bad OPERATION code \"%s\" on line %d.", token
,
1468 else if (!_cups_strcasecmp(token
, "GROUP"))
1471 * Attribute group...
1474 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1476 print_fatal_error("Missing GROUP tag on line %d.", linenum
);
1481 if ((value
= ippTagValue(token
)) < 0)
1483 print_fatal_error("Bad GROUP tag \"%s\" on line %d.", token
, linenum
);
1489 ippAddSeparator(request
);
1493 else if (!_cups_strcasecmp(token
, "DELAY"))
1496 * Delay before operation...
1501 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1503 print_fatal_error("Missing DELAY value on line %d.", linenum
);
1508 if ((delay
= _cupsStrScand(token
, NULL
, localeconv())) <= 0.0)
1510 print_fatal_error("Bad DELAY value \"%s\" on line %d.", token
,
1517 if (Output
== _CUPS_OUTPUT_TEST
)
1518 printf(" [%g second delay]\n", delay
);
1520 usleep((int)(1000000.0 * delay
));
1523 else if (!_cups_strcasecmp(token
, "ATTR"))
1529 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1531 print_fatal_error("Missing ATTR value tag on line %d.", linenum
);
1536 if ((value
= ippTagValue(token
)) == IPP_TAG_ZERO
)
1538 print_fatal_error("Bad ATTR value tag \"%s\" on line %d.", token
,
1544 if (!get_token(fp
, attr
, sizeof(attr
), &linenum
))
1546 print_fatal_error("Missing ATTR name on line %d.", linenum
);
1551 if (!get_token(fp
, temp
, sizeof(temp
), &linenum
))
1553 print_fatal_error("Missing ATTR value on line %d.", linenum
);
1558 expand_variables(vars
, token
, temp
, sizeof(token
));
1563 case IPP_TAG_BOOLEAN
:
1564 if (!_cups_strcasecmp(token
, "true"))
1565 attrptr
= ippAddBoolean(request
, group
, attr
, 1);
1567 attrptr
= ippAddBoolean(request
, group
, attr
, atoi(token
));
1570 case IPP_TAG_INTEGER
:
1572 if (!strchr(token
, ','))
1573 attrptr
= ippAddInteger(request
, group
, value
, attr
,
1574 strtol(token
, &tokenptr
, 0));
1577 int values
[100], /* Values */
1578 num_values
= 1; /* Number of values */
1580 values
[0] = strtol(token
, &tokenptr
, 10);
1581 while (tokenptr
&& *tokenptr
&&
1582 num_values
< (int)(sizeof(values
) / sizeof(values
[0])))
1584 if (*tokenptr
== ',')
1586 else if (!isdigit(*tokenptr
& 255) && *tokenptr
!= '-')
1589 values
[num_values
] = strtol(tokenptr
, &tokenptr
, 0);
1593 attrptr
= ippAddIntegers(request
, group
, value
, attr
, num_values
, values
);
1596 if (!tokenptr
|| *tokenptr
)
1598 print_fatal_error("Bad %s value \"%s\" on line %d.",
1599 ippTagString(value
), token
, linenum
);
1605 case IPP_TAG_RESOLUTION
:
1607 int xres
, /* X resolution */
1608 yres
; /* Y resolution */
1609 char *ptr
; /* Pointer into value */
1611 xres
= yres
= strtol(token
, (char **)&ptr
, 10);
1612 if (ptr
> token
&& xres
> 0)
1615 yres
= strtol(ptr
+ 1, (char **)&ptr
, 10);
1618 if (ptr
<= token
|| xres
<= 0 || yres
<= 0 || !ptr
||
1619 (_cups_strcasecmp(ptr
, "dpi") &&
1620 _cups_strcasecmp(ptr
, "dpc") &&
1621 _cups_strcasecmp(ptr
, "dpcm") &&
1622 _cups_strcasecmp(ptr
, "other")))
1624 print_fatal_error("Bad resolution value \"%s\" on line %d.",
1630 if (!_cups_strcasecmp(ptr
, "dpi"))
1631 attrptr
= ippAddResolution(request
, group
, attr
, IPP_RES_PER_INCH
,
1633 else if (!_cups_strcasecmp(ptr
, "dpc") ||
1634 !_cups_strcasecmp(ptr
, "dpcm"))
1635 attrptr
= ippAddResolution(request
, group
, attr
, IPP_RES_PER_CM
,
1638 attrptr
= ippAddResolution(request
, group
, attr
, (ipp_res_t
)0,
1643 case IPP_TAG_RANGE
:
1645 int lowers
[4], /* Lower value */
1646 uppers
[4], /* Upper values */
1647 num_vals
; /* Number of values */
1650 num_vals
= sscanf(token
, "%d-%d,%d-%d,%d-%d,%d-%d",
1651 lowers
+ 0, uppers
+ 0,
1652 lowers
+ 1, uppers
+ 1,
1653 lowers
+ 2, uppers
+ 2,
1654 lowers
+ 3, uppers
+ 3);
1656 if ((num_vals
& 1) || num_vals
== 0)
1658 print_fatal_error("Bad rangeOfInteger value \"%s\" on line "
1659 "%d.", token
, linenum
);
1664 attrptr
= ippAddRanges(request
, group
, attr
, num_vals
/ 2, lowers
,
1669 case IPP_TAG_BEGIN_COLLECTION
:
1670 if (!strcmp(token
, "{"))
1672 ipp_t
*col
= get_collection(vars
, fp
, &linenum
);
1673 /* Collection value */
1677 attrptr
= lastcol
= ippAddCollection(request
, group
, attr
, col
);
1688 print_fatal_error("Bad ATTR collection value on line %d.",
1696 print_fatal_error("Unsupported ATTR value tag %s on line %d.",
1697 ippTagString(value
), linenum
);
1701 case IPP_TAG_TEXTLANG
:
1702 case IPP_TAG_NAMELANG
:
1705 case IPP_TAG_KEYWORD
:
1707 case IPP_TAG_URISCHEME
:
1708 case IPP_TAG_CHARSET
:
1709 case IPP_TAG_LANGUAGE
:
1710 case IPP_TAG_MIMETYPE
:
1711 if (!strchr(token
, ','))
1712 attrptr
= ippAddString(request
, group
, value
, attr
, NULL
, token
);
1716 * Multiple string values...
1719 int num_values
; /* Number of values */
1720 char *values
[100], /* Values */
1721 *ptr
; /* Pointer to next value */
1727 for (ptr
= strchr(token
, ','); ptr
; ptr
= strchr(ptr
, ','))
1730 values
[num_values
] = ptr
;
1734 attrptr
= ippAddStrings(request
, group
, value
, attr
, num_values
,
1735 NULL
, (const char **)values
);
1742 print_fatal_error("Unable to add attribute on line %d: %s", linenum
,
1743 cupsLastErrorString());
1748 else if (!_cups_strcasecmp(token
, "FILE"))
1754 if (!get_token(fp
, temp
, sizeof(temp
), &linenum
))
1756 print_fatal_error("Missing FILE filename on line %d.", linenum
);
1761 expand_variables(vars
, token
, temp
, sizeof(token
));
1762 get_filename(testfile
, filename
, token
, sizeof(filename
));
1764 else if (!_cups_strcasecmp(token
, "STATUS"))
1770 if (num_statuses
>= (int)(sizeof(statuses
) / sizeof(statuses
[0])))
1772 print_fatal_error("Too many STATUS's on line %d.", linenum
);
1777 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1779 print_fatal_error("Missing STATUS code on line %d.", linenum
);
1784 if ((statuses
[num_statuses
].status
= ippErrorValue(token
))
1785 == (ipp_status_t
)-1 &&
1786 (statuses
[num_statuses
].status
= strtol(token
, NULL
, 0)) == 0)
1788 print_fatal_error("Bad STATUS code \"%s\" on line %d.", token
,
1794 last_status
= statuses
+ num_statuses
;
1797 last_status
->if_defined
= NULL
;
1798 last_status
->if_not_defined
= NULL
;
1799 last_status
->repeat_match
= 0;
1800 last_status
->repeat_no_match
= 0;
1802 else if (!_cups_strcasecmp(token
, "EXPECT"))
1805 * Expected attributes...
1808 if (num_expects
>= (int)(sizeof(expects
) / sizeof(expects
[0])))
1810 print_fatal_error("Too many EXPECT's on line %d.", linenum
);
1815 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1817 print_fatal_error("Missing EXPECT name on line %d.", linenum
);
1822 last_expect
= expects
+ num_expects
;
1825 memset(last_expect
, 0, sizeof(_cups_expect_t
));
1827 if (token
[0] == '!')
1829 last_expect
->not_expect
= 1;
1830 last_expect
->name
= strdup(token
+ 1);
1832 else if (token
[0] == '?')
1834 last_expect
->optional
= 1;
1835 last_expect
->name
= strdup(token
+ 1);
1838 last_expect
->name
= strdup(token
);
1840 else if (!_cups_strcasecmp(token
, "COUNT"))
1842 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1844 print_fatal_error("Missing COUNT number on line %d.", linenum
);
1849 if ((i
= atoi(token
)) <= 0)
1851 print_fatal_error("Bad COUNT \"%s\" on line %d.", token
, linenum
);
1857 last_expect
->count
= i
;
1860 print_fatal_error("COUNT without a preceding EXPECT on line %d.",
1866 else if (!_cups_strcasecmp(token
, "DEFINE-MATCH"))
1868 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1870 print_fatal_error("Missing DEFINE-MATCH variable on line %d.",
1877 last_expect
->define_match
= strdup(token
);
1880 print_fatal_error("DEFINE-MATCH without a preceding EXPECT on line "
1886 else if (!_cups_strcasecmp(token
, "DEFINE-NO-MATCH"))
1888 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1890 print_fatal_error("Missing DEFINE-NO-MATCH variable on line %d.",
1897 last_expect
->define_no_match
= strdup(token
);
1900 print_fatal_error("DEFINE-NO-MATCH without a preceding EXPECT on "
1901 "line %d.", linenum
);
1906 else if (!_cups_strcasecmp(token
, "DEFINE-VALUE"))
1908 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1910 print_fatal_error("Missing DEFINE-VALUE variable on line %d.",
1917 last_expect
->define_value
= strdup(token
);
1920 print_fatal_error("DEFINE-VALUE without a preceding EXPECT on line "
1926 else if (!_cups_strcasecmp(token
, "OF-TYPE"))
1928 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1930 print_fatal_error("Missing OF-TYPE value tag(s) on line %d.",
1937 last_expect
->of_type
= strdup(token
);
1940 print_fatal_error("OF-TYPE without a preceding EXPECT on line %d.",
1946 else if (!_cups_strcasecmp(token
, "IN-GROUP"))
1948 ipp_tag_t in_group
; /* IN-GROUP value */
1951 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1953 print_fatal_error("Missing IN-GROUP group tag on line %d.", linenum
);
1958 if ((in_group
= ippTagValue(token
)) == (ipp_tag_t
)-1)
1961 else if (last_expect
)
1962 last_expect
->in_group
= in_group
;
1965 print_fatal_error("IN-GROUP without a preceding EXPECT on line %d.",
1971 else if (!_cups_strcasecmp(token
, "REPEAT-MATCH"))
1974 last_status
->repeat_match
= 1;
1975 else if (last_expect
)
1976 last_expect
->repeat_match
= 1;
1979 print_fatal_error("REPEAT-MATCH without a preceding EXPECT or STATUS "
1980 "on line %d.", linenum
);
1985 else if (!_cups_strcasecmp(token
, "REPEAT-NO-MATCH"))
1988 last_status
->repeat_no_match
= 1;
1989 else if (last_expect
)
1990 last_expect
->repeat_no_match
= 1;
1993 print_fatal_error("REPEAT-NO-MATCH without a preceding EXPECT or "
1994 "STATUS on ine %d.", linenum
);
1999 else if (!_cups_strcasecmp(token
, "SAME-COUNT-AS"))
2001 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
2003 print_fatal_error("Missing SAME-COUNT-AS name on line %d.", linenum
);
2009 last_expect
->same_count_as
= strdup(token
);
2012 print_fatal_error("SAME-COUNT-AS without a preceding EXPECT on line "
2018 else if (!_cups_strcasecmp(token
, "IF-DEFINED"))
2020 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
2022 print_fatal_error("Missing IF-DEFINED name on line %d.", linenum
);
2028 last_expect
->if_defined
= strdup(token
);
2029 else if (last_status
)
2030 last_status
->if_defined
= strdup(token
);
2033 print_fatal_error("IF-DEFINED without a preceding EXPECT or STATUS "
2034 "on line %d.", linenum
);
2039 else if (!_cups_strcasecmp(token
, "IF-NOT-DEFINED"))
2041 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
2043 print_fatal_error("Missing IF-NOT-DEFINED name on line %d.", linenum
);
2049 last_expect
->if_not_defined
= strdup(token
);
2050 else if (last_status
)
2051 last_status
->if_not_defined
= strdup(token
);
2054 print_fatal_error("IF-NOT-DEFINED without a preceding EXPECT or STATUS "
2055 "on line %d.", linenum
);
2060 else if (!_cups_strcasecmp(token
, "WITH-ALL-VALUES") ||
2061 !_cups_strcasecmp(token
, "WITH-VALUE"))
2063 if (!_cups_strcasecmp(token
, "WITH-ALL-VALUES") && last_expect
)
2064 last_expect
->with_flags
= _CUPS_WITH_ALL
;
2066 if (!get_token(fp
, temp
, sizeof(temp
), &linenum
))
2068 print_fatal_error("Missing %s value on line %d.", token
, linenum
);
2076 * Expand any variables in the value and then save it.
2079 expand_variables(vars
, token
, temp
, sizeof(token
));
2081 tokenptr
= token
+ strlen(token
) - 1;
2083 if (token
[0] == '/' && tokenptr
> token
&& *tokenptr
== '/')
2086 * WITH-VALUE is a POSIX extended regular expression.
2089 last_expect
->with_value
= calloc(1, tokenptr
- token
);
2090 last_expect
->with_flags
|= _CUPS_WITH_REGEX
;
2092 if (last_expect
->with_value
)
2093 memcpy(last_expect
->with_value
, token
+ 1, tokenptr
- token
- 1);
2098 * WITH-VALUE is a literal value...
2101 last_expect
->with_value
= strdup(token
);
2102 last_expect
->with_flags
|= _CUPS_WITH_LITERAL
;
2107 print_fatal_error("%s without a preceding EXPECT on line %d.", token
,
2113 else if (!_cups_strcasecmp(token
, "DISPLAY"))
2116 * Display attributes...
2119 if (num_displayed
>= (int)(sizeof(displayed
) / sizeof(displayed
[0])))
2121 print_fatal_error("Too many DISPLAY's on line %d", linenum
);
2126 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
2128 print_fatal_error("Missing DISPLAY name on line %d.", linenum
);
2133 displayed
[num_displayed
] = strdup(token
);
2138 print_fatal_error("Unexpected token %s seen on line %d.", token
,
2146 * Submit the IPP request...
2151 request
->request
.op
.version
[0] = version
/ 10;
2152 request
->request
.op
.version
[1] = version
% 10;
2153 request
->request
.op
.operation_id
= op
;
2154 request
->request
.op
.request_id
= request_id
;
2156 if (Output
== _CUPS_OUTPUT_PLIST
)
2159 puts("<key>Name</key>");
2160 print_xml_string("string", name
);
2161 puts("<key>Operation</key>");
2162 print_xml_string("string", ippOpString(op
));
2163 puts("<key>RequestAttributes</key>");
2168 for (attrptr
= request
->attrs
, group
= attrptr
->group_tag
;
2170 attrptr
= attrptr
->next
)
2171 print_attr(attrptr
, &group
);
2176 else if (Output
== _CUPS_OUTPUT_TEST
)
2180 printf(" %s:\n", ippOpString(op
));
2182 for (attrptr
= request
->attrs
; attrptr
; attrptr
= attrptr
->next
)
2183 print_attr(attrptr
, NULL
);
2186 printf(" %-68.68s [", name
);
2190 if ((skip_previous
&& !prev_pass
) || skip_test
)
2197 if (Output
== _CUPS_OUTPUT_PLIST
)
2199 puts("<key>Successful</key>");
2201 puts("<key>StatusCode</key>");
2202 print_xml_string("string", "skip");
2203 puts("<key>ResponseAttributes</key>");
2207 else if (Output
== _CUPS_OUTPUT_TEST
)
2217 if (transfer
== _CUPS_TRANSFER_CHUNKED
||
2218 (transfer
== _CUPS_TRANSFER_AUTO
&& filename
[0]))
2221 * Send request using chunking - a 0 length means "chunk".
2229 * Send request using content length...
2232 length
= ippLength(request
);
2234 if (filename
[0] && (reqfile
= cupsFileOpen(filename
, "r")) != NULL
)
2237 * Read the file to get the uncompressed file size...
2240 while ((bytes
= cupsFileRead(reqfile
, buffer
, sizeof(buffer
))) > 0)
2243 cupsFileClose(reqfile
);
2248 * Send the request...
2255 if (status
!= HTTP_ERROR
)
2257 while (!response
&& !Cancel
&& prev_pass
)
2259 status
= cupsSendRequest(http
, request
, resource
, length
);
2261 if (!Cancel
&& status
== HTTP_CONTINUE
&&
2262 request
->state
== IPP_DATA
&& filename
[0])
2264 if ((reqfile
= cupsFileOpen(filename
, "r")) != NULL
)
2267 (bytes
= cupsFileRead(reqfile
, buffer
,
2268 sizeof(buffer
))) > 0)
2269 if ((status
= cupsWriteRequestData(http
, buffer
,
2270 bytes
)) != HTTP_CONTINUE
)
2273 cupsFileClose(reqfile
);
2277 snprintf(buffer
, sizeof(buffer
), "%s: %s", filename
,
2279 _cupsSetError(IPP_INTERNAL_ERROR
, buffer
, 0);
2281 status
= HTTP_ERROR
;
2286 * Get the server's response...
2289 if (!Cancel
&& status
!= HTTP_ERROR
)
2291 response
= cupsGetResponse(http
, resource
);
2292 status
= httpGetStatus(http
);
2295 if (!Cancel
&& status
== HTTP_ERROR
&&
2297 http
->error
!= WSAETIMEDOUT
)
2299 http
->error
!= ETIMEDOUT
)
2302 if (httpReconnect(http
))
2305 else if (status
== HTTP_ERROR
)
2310 else if (status
!= HTTP_OK
)
2318 if (!Cancel
&& status
== HTTP_ERROR
&&
2320 http
->error
!= WSAETIMEDOUT
)
2322 http
->error
!= ETIMEDOUT
)
2325 if (httpReconnect(http
))
2328 else if (status
== HTTP_ERROR
)
2331 httpReconnect(http
);
2335 else if (status
!= HTTP_OK
)
2342 * Check results of request...
2345 cupsArrayClear(errors
);
2347 if (http
->version
!= HTTP_1_1
)
2348 add_stringf(errors
, "Bad HTTP version (%d.%d)", http
->version
/ 100,
2349 http
->version
% 100);
2354 * No response, log error...
2357 add_stringf(errors
, "IPP request failed with status %s (%s)",
2358 ippErrorString(cupsLastError()),
2359 cupsLastErrorString());
2364 * Collect common attribute values...
2367 if ((attrptr
= ippFindAttribute(response
, "job-id",
2368 IPP_TAG_INTEGER
)) != NULL
)
2370 snprintf(temp
, sizeof(temp
), "%d", attrptr
->values
[0].integer
);
2371 set_variable(vars
, "job-id", temp
);
2374 if ((attrptr
= ippFindAttribute(response
, "job-uri",
2375 IPP_TAG_URI
)) != NULL
)
2376 set_variable(vars
, "job-uri", attrptr
->values
[0].string
.text
);
2378 if ((attrptr
= ippFindAttribute(response
, "notify-subscription-id",
2379 IPP_TAG_INTEGER
)) != NULL
)
2381 snprintf(temp
, sizeof(temp
), "%d", attrptr
->values
[0].integer
);
2382 set_variable(vars
, "notify-subscription-id", temp
);
2386 * Check response, validating groups and attributes and logging errors
2390 if (response
->state
!= IPP_DATA
)
2392 "Missing end-of-attributes-tag in response "
2393 "(RFC 2910 section 3.5.1)");
2396 (response
->request
.status
.version
[0] != (version
/ 10) ||
2397 response
->request
.status
.version
[1] != (version
% 10)))
2399 "Bad version %d.%d in response - expected %d.%d "
2400 "(RFC 2911 section 3.1.8).",
2401 response
->request
.status
.version
[0],
2402 response
->request
.status
.version
[1],
2403 version
/ 10, version
% 10);
2405 if (response
->request
.status
.request_id
!= request_id
)
2407 "Bad request ID %d in response - expected %d "
2408 "(RFC 2911 section 3.1.1)",
2409 response
->request
.status
.request_id
, request_id
);
2411 attrptr
= response
->attrs
;
2414 "Missing first attribute \"attributes-charset "
2415 "(charset)\" in group operation-attributes-tag "
2416 "(RFC 2911 section 3.1.4).");
2419 if (!attrptr
->name
||
2420 attrptr
->value_tag
!= IPP_TAG_CHARSET
||
2421 attrptr
->group_tag
!= IPP_TAG_OPERATION
||
2422 attrptr
->num_values
!= 1 ||
2423 strcmp(attrptr
->name
, "attributes-charset"))
2425 "Bad first attribute \"%s (%s%s)\" in group %s, "
2426 "expected \"attributes-charset (charset)\" in "
2427 "group operation-attributes-tag (RFC 2911 section "
2429 attrptr
->name
? attrptr
->name
: "(null)",
2430 attrptr
->num_values
> 1 ? "1setOf " : "",
2431 ippTagString(attrptr
->value_tag
),
2432 ippTagString(attrptr
->group_tag
));
2434 attrptr
= attrptr
->next
;
2437 "Missing second attribute \"attributes-natural-"
2438 "language (naturalLanguage)\" in group "
2439 "operation-attributes-tag (RFC 2911 section "
2441 else if (!attrptr
->name
||
2442 attrptr
->value_tag
!= IPP_TAG_LANGUAGE
||
2443 attrptr
->group_tag
!= IPP_TAG_OPERATION
||
2444 attrptr
->num_values
!= 1 ||
2445 strcmp(attrptr
->name
, "attributes-natural-language"))
2447 "Bad first attribute \"%s (%s%s)\" in group %s, "
2448 "expected \"attributes-natural-language "
2449 "(naturalLanguage)\" in group "
2450 "operation-attributes-tag (RFC 2911 section "
2452 attrptr
->name
? attrptr
->name
: "(null)",
2453 attrptr
->num_values
> 1 ? "1setOf " : "",
2454 ippTagString(attrptr
->value_tag
),
2455 ippTagString(attrptr
->group_tag
));
2458 if ((attrptr
= ippFindAttribute(response
, "status-message",
2459 IPP_TAG_ZERO
)) != NULL
)
2461 if (attrptr
->value_tag
!= IPP_TAG_TEXT
)
2463 "status-message (text(255)) has wrong value tag "
2464 "%s (RFC 2911 section 3.1.6.2).",
2465 ippTagString(attrptr
->value_tag
));
2466 if (attrptr
->group_tag
!= IPP_TAG_OPERATION
)
2468 "status-message (text(255)) has wrong group tag "
2469 "%s (RFC 2911 section 3.1.6.2).",
2470 ippTagString(attrptr
->group_tag
));
2471 if (attrptr
->num_values
!= 1)
2473 "status-message (text(255)) has %d values "
2474 "(RFC 2911 section 3.1.6.2).",
2475 attrptr
->num_values
);
2476 if (attrptr
->value_tag
== IPP_TAG_TEXT
&&
2477 strlen(attrptr
->values
[0].string
.text
) > 255)
2479 "status-message (text(255)) has bad length %d"
2480 " (RFC 2911 section 3.1.6.2).",
2481 (int)strlen(attrptr
->values
[0].string
.text
));
2484 if ((attrptr
= ippFindAttribute(response
, "detailed-status-message",
2485 IPP_TAG_ZERO
)) != NULL
)
2487 if (attrptr
->value_tag
!= IPP_TAG_TEXT
)
2489 "detailed-status-message (text(MAX)) has wrong "
2490 "value tag %s (RFC 2911 section 3.1.6.3).",
2491 ippTagString(attrptr
->value_tag
));
2492 if (attrptr
->group_tag
!= IPP_TAG_OPERATION
)
2494 "detailed-status-message (text(MAX)) has wrong "
2495 "group tag %s (RFC 2911 section 3.1.6.3).",
2496 ippTagString(attrptr
->group_tag
));
2497 if (attrptr
->num_values
!= 1)
2499 "detailed-status-message (text(MAX)) has %d values"
2500 " (RFC 2911 section 3.1.6.3).",
2501 attrptr
->num_values
);
2502 if (attrptr
->value_tag
== IPP_TAG_TEXT
&&
2503 strlen(attrptr
->values
[0].string
.text
) > 1023)
2505 "detailed-status-message (text(MAX)) has bad "
2506 "length %d (RFC 2911 section 3.1.6.3).",
2507 (int)strlen(attrptr
->values
[0].string
.text
));
2510 a
= cupsArrayNew((cups_array_func_t
)strcmp
, NULL
);
2512 for (attrptr
= response
->attrs
, group
= attrptr
->group_tag
;
2514 attrptr
= attrptr
->next
)
2516 if (attrptr
->group_tag
!= group
)
2518 int out_of_order
= 0; /* Are attribute groups out-of-order? */
2522 switch (attrptr
->group_tag
)
2527 case IPP_TAG_OPERATION
:
2531 case IPP_TAG_UNSUPPORTED_GROUP
:
2532 if (group
!= IPP_TAG_OPERATION
)
2537 case IPP_TAG_PRINTER
:
2538 if (group
!= IPP_TAG_OPERATION
&&
2539 group
!= IPP_TAG_UNSUPPORTED_GROUP
)
2543 case IPP_TAG_SUBSCRIPTION
:
2544 if (group
> attrptr
->group_tag
&&
2545 group
!= IPP_TAG_DOCUMENT
)
2550 if (group
> attrptr
->group_tag
)
2556 add_stringf(errors
, "Attribute groups out of order (%s < %s)",
2557 ippTagString(attrptr
->group_tag
),
2558 ippTagString(group
));
2560 if (attrptr
->group_tag
!= IPP_TAG_ZERO
)
2561 group
= attrptr
->group_tag
;
2564 validate_attr(errors
, attrptr
);
2568 if (cupsArrayFind(a
, attrptr
->name
))
2569 add_stringf(errors
, "Duplicate \"%s\" attribute in %s group",
2570 attrptr
->name
, ippTagString(group
));
2572 cupsArrayAdd(a
, attrptr
->name
);
2579 * Now check the test-defined expected status-code and attribute
2583 for (i
= 0; i
< num_statuses
; i
++)
2585 if (statuses
[i
].if_defined
&&
2586 !get_variable(vars
, statuses
[i
].if_defined
))
2589 if (statuses
[i
].if_not_defined
&&
2590 get_variable(vars
, statuses
[i
].if_not_defined
))
2593 if (response
->request
.status
.status_code
== statuses
[i
].status
)
2595 if (statuses
[i
].repeat_match
)
2600 else if (statuses
[i
].repeat_no_match
)
2604 if (i
== num_statuses
&& num_statuses
> 0)
2606 for (i
= 0; i
< num_statuses
; i
++)
2608 if (statuses
[i
].if_defined
&&
2609 !get_variable(vars
, statuses
[i
].if_defined
))
2612 if (statuses
[i
].if_not_defined
&&
2613 get_variable(vars
, statuses
[i
].if_not_defined
))
2616 add_stringf(errors
, "EXPECTED: STATUS %s (got %s)",
2617 ippErrorString(statuses
[i
].status
),
2618 ippErrorString(cupsLastError()));
2621 if ((attrptr
= ippFindAttribute(response
, "status-message",
2622 IPP_TAG_TEXT
)) != NULL
)
2623 add_stringf(errors
, "status-message=\"%s\"",
2624 attrptr
->values
[0].string
.text
);
2627 for (i
= num_expects
, expect
= expects
; i
> 0; i
--, expect
++)
2629 if (expect
->if_defined
&& !get_variable(vars
, expect
->if_defined
))
2632 if (expect
->if_not_defined
&&
2633 get_variable(vars
, expect
->if_not_defined
))
2636 found
= ippFindAttribute(response
, expect
->name
, IPP_TAG_ZERO
);
2638 if ((found
&& expect
->not_expect
) ||
2639 (!found
&& !(expect
->not_expect
|| expect
->optional
)) ||
2640 (found
&& !expect_matches(expect
, found
->value_tag
)) ||
2641 (found
&& expect
->in_group
&&
2642 found
->group_tag
!= expect
->in_group
))
2644 if (expect
->define_no_match
)
2645 set_variable(vars
, expect
->define_no_match
, "1");
2646 else if (!expect
->define_match
&& !expect
->define_value
)
2648 if (found
&& expect
->not_expect
)
2649 add_stringf(errors
, "NOT EXPECTED: %s", expect
->name
);
2650 else if (!found
&& !(expect
->not_expect
|| expect
->optional
))
2651 add_stringf(errors
, "EXPECTED: %s", expect
->name
);
2654 if (!expect_matches(expect
, found
->value_tag
))
2655 add_stringf(errors
, "EXPECTED: %s OF-TYPE %s (got %s)",
2656 expect
->name
, expect
->of_type
,
2657 ippTagString(found
->value_tag
));
2659 if (expect
->in_group
&& found
->group_tag
!= expect
->in_group
)
2660 add_stringf(errors
, "EXPECTED: %s IN-GROUP %s (got %s).",
2661 expect
->name
, ippTagString(expect
->in_group
),
2662 ippTagString(found
->group_tag
));
2666 if (expect
->repeat_no_match
)
2673 ippAttributeString(found
, buffer
, sizeof(buffer
));
2676 !with_value(NULL
, expect
->with_value
, expect
->with_flags
, found
,
2677 buffer
, sizeof(buffer
)))
2679 if (expect
->define_no_match
)
2680 set_variable(vars
, expect
->define_no_match
, "1");
2681 else if (!expect
->define_match
&& !expect
->define_value
)
2683 if (expect
->with_flags
& _CUPS_WITH_REGEX
)
2684 add_stringf(errors
, "EXPECTED: %s %s /%s/",
2686 (expect
->with_flags
& _CUPS_WITH_ALL
) ?
2687 "WITH-ALL-VALUES" : "WITH-VALUE",
2688 expect
->with_value
);
2690 add_stringf(errors
, "EXPECTED: %s %s \"%s\"",
2692 (expect
->with_flags
& _CUPS_WITH_ALL
) ?
2693 "WITH-ALL-VALUES" : "WITH-VALUE",
2694 expect
->with_value
);
2696 with_value(errors
, expect
->with_value
, expect
->with_flags
, found
,
2697 buffer
, sizeof(buffer
));
2700 if (expect
->repeat_no_match
)
2706 if (found
&& expect
->count
> 0 &&
2707 found
->num_values
!= expect
->count
)
2709 if (expect
->define_no_match
)
2710 set_variable(vars
, expect
->define_no_match
, "1");
2711 else if (!expect
->define_match
&& !expect
->define_value
)
2713 add_stringf(errors
, "EXPECTED: %s COUNT %d (got %d)", expect
->name
,
2714 expect
->count
, found
->num_values
);
2717 if (expect
->repeat_no_match
)
2723 if (found
&& expect
->same_count_as
)
2725 attrptr
= ippFindAttribute(response
, expect
->same_count_as
,
2728 if (!attrptr
|| attrptr
->num_values
!= found
->num_values
)
2730 if (expect
->define_no_match
)
2731 set_variable(vars
, expect
->define_no_match
, "1");
2732 else if (!expect
->define_match
&& !expect
->define_value
)
2736 "EXPECTED: %s (%d values) SAME-COUNT-AS %s "
2737 "(not returned)", expect
->name
,
2738 found
->num_values
, expect
->same_count_as
);
2739 else if (attrptr
->num_values
!= found
->num_values
)
2741 "EXPECTED: %s (%d values) SAME-COUNT-AS %s "
2742 "(%d values)", expect
->name
, found
->num_values
,
2743 expect
->same_count_as
, attrptr
->num_values
);
2746 if (expect
->repeat_no_match
)
2753 if (found
&& expect
->define_match
)
2754 set_variable(vars
, expect
->define_match
, "1");
2756 if (found
&& expect
->define_value
)
2757 set_variable(vars
, expect
->define_value
, buffer
);
2759 if (found
&& expect
->repeat_match
)
2765 * If we are going to repeat this test, sleep 1 second so we don't flood
2766 * the printer with requests...
2772 while (repeat_test
);
2778 if (cupsArrayCount(errors
) > 0)
2779 prev_pass
= pass
= 0;
2786 if (Output
== _CUPS_OUTPUT_PLIST
)
2788 puts("<key>Successful</key>");
2789 puts(prev_pass
? "<true />" : "<false />");
2790 puts("<key>StatusCode</key>");
2791 print_xml_string("string", ippErrorString(cupsLastError()));
2792 puts("<key>ResponseAttributes</key>");
2795 for (attrptr
= response
? response
->attrs
: NULL
,
2796 group
= attrptr
? attrptr
->group_tag
: IPP_TAG_ZERO
;
2798 attrptr
= attrptr
->next
)
2799 print_attr(attrptr
, &group
);
2803 else if (Output
== _CUPS_OUTPUT_TEST
)
2805 puts(prev_pass
? "PASS]" : "FAIL]");
2807 if (!prev_pass
|| (Verbosity
&& response
))
2809 printf(" RECEIVED: %lu bytes in response\n",
2810 (unsigned long)ippLength(response
));
2811 printf(" status-code = %s (%s)\n", ippErrorString(cupsLastError()),
2812 cupsLastErrorString());
2816 for (attrptr
= response
->attrs
;
2818 attrptr
= attrptr
->next
)
2819 print_attr(attrptr
, NULL
);
2823 else if (!prev_pass
)
2824 fprintf(stderr
, "%s\n", cupsLastErrorString());
2826 if (prev_pass
&& Output
>= _CUPS_OUTPUT_LIST
&& !Verbosity
&&
2829 size_t width
; /* Length of value */
2831 for (i
= 0; i
< num_displayed
; i
++)
2833 widths
[i
] = strlen(displayed
[i
]);
2835 for (attrptr
= ippFindAttribute(response
, displayed
[i
], IPP_TAG_ZERO
);
2837 attrptr
= ippFindNextAttribute(response
, displayed
[i
],
2840 width
= ippAttributeString(attrptr
, NULL
, 0);
2841 if (width
> widths
[i
])
2846 if (Output
== _CUPS_OUTPUT_CSV
)
2847 print_csv(NULL
, num_displayed
, displayed
, widths
);
2849 print_line(NULL
, num_displayed
, displayed
, widths
);
2851 attrptr
= response
->attrs
;
2855 while (attrptr
&& attrptr
->group_tag
<= IPP_TAG_OPERATION
)
2856 attrptr
= attrptr
->next
;
2860 if (Output
== _CUPS_OUTPUT_CSV
)
2861 print_csv(attrptr
, num_displayed
, displayed
, widths
);
2863 print_line(attrptr
, num_displayed
, displayed
, widths
);
2865 while (attrptr
&& attrptr
->group_tag
> IPP_TAG_OPERATION
)
2866 attrptr
= attrptr
->next
;
2870 else if (!prev_pass
)
2872 if (Output
== _CUPS_OUTPUT_PLIST
)
2874 puts("<key>Errors</key>");
2877 for (error
= (char *)cupsArrayFirst(errors
);
2879 error
= (char *)cupsArrayNext(errors
))
2880 print_xml_string("string", error
);
2886 for (error
= (char *)cupsArrayFirst(errors
);
2888 error
= (char *)cupsArrayNext(errors
))
2889 printf(" %s\n", error
);
2893 if (num_displayed
> 0 && !Verbosity
&& response
&&
2894 (Output
== _CUPS_OUTPUT_TEST
|| Output
== _CUPS_OUTPUT_PLIST
))
2896 for (attrptr
= response
->attrs
;
2898 attrptr
= attrptr
->next
)
2902 for (i
= 0; i
< num_displayed
; i
++)
2904 if (!strcmp(displayed
[i
], attrptr
->name
))
2906 print_attr(attrptr
, NULL
);
2916 if (Output
== _CUPS_OUTPUT_PLIST
)
2921 ippDelete(response
);
2924 for (i
= 0; i
< num_statuses
; i
++)
2926 if (statuses
[i
].if_defined
)
2927 free(statuses
[i
].if_defined
);
2928 if (statuses
[i
].if_not_defined
)
2929 free(statuses
[i
].if_not_defined
);
2933 for (i
= num_expects
, expect
= expects
; i
> 0; i
--, expect
++)
2936 if (expect
->of_type
)
2937 free(expect
->of_type
);
2938 if (expect
->same_count_as
)
2939 free(expect
->same_count_as
);
2940 if (expect
->if_defined
)
2941 free(expect
->if_defined
);
2942 if (expect
->if_not_defined
)
2943 free(expect
->if_not_defined
);
2944 if (expect
->with_value
)
2945 free(expect
->with_value
);
2946 if (expect
->define_match
)
2947 free(expect
->define_match
);
2948 if (expect
->define_no_match
)
2949 free(expect
->define_no_match
);
2950 if (expect
->define_value
)
2951 free(expect
->define_value
);
2955 for (i
= 0; i
< num_displayed
; i
++)
2959 if (!ignore_errors
&& !prev_pass
)
2965 cupsArrayDelete(errors
);
2972 ippDelete(response
);
2974 for (i
= 0; i
< num_statuses
; i
++)
2976 if (statuses
[i
].if_defined
)
2977 free(statuses
[i
].if_defined
);
2978 if (statuses
[i
].if_not_defined
)
2979 free(statuses
[i
].if_not_defined
);
2982 for (i
= num_expects
, expect
= expects
; i
> 0; i
--, expect
++)
2985 if (expect
->of_type
)
2986 free(expect
->of_type
);
2987 if (expect
->same_count_as
)
2988 free(expect
->same_count_as
);
2989 if (expect
->if_defined
)
2990 free(expect
->if_defined
);
2991 if (expect
->if_not_defined
)
2992 free(expect
->if_not_defined
);
2993 if (expect
->with_value
)
2994 free(expect
->with_value
);
2995 if (expect
->define_match
)
2996 free(expect
->define_match
);
2997 if (expect
->define_no_match
)
2998 free(expect
->define_no_match
);
2999 if (expect
->define_value
)
3000 free(expect
->define_value
);
3003 for (i
= 0; i
< num_displayed
; i
++)
3011 * 'expand_variables()' - Expand variables in a string.
3015 expand_variables(_cups_vars_t
*vars
, /* I - Variables */
3016 char *dst
, /* I - Destination string buffer */
3017 const char *src
, /* I - Source string */
3018 size_t dstsize
) /* I - Size of destination buffer */
3020 char *dstptr
, /* Pointer into destination */
3021 *dstend
, /* End of destination */
3022 temp
[256], /* Temporary string */
3023 *tempptr
; /* Pointer into temporary string */
3024 const char *value
; /* Value to substitute */
3028 dstend
= dst
+ dstsize
- 1;
3030 while (*src
&& dstptr
< dstend
)
3035 * Substitute a string/number...
3038 if (!strncmp(src
, "$$", 2))
3043 else if (!strncmp(src
, "$ENV[", 5))
3045 strlcpy(temp
, src
+ 5, sizeof(temp
));
3047 for (tempptr
= temp
; *tempptr
; tempptr
++)
3048 if (*tempptr
== ']')
3054 value
= getenv(temp
);
3055 src
+= tempptr
- temp
+ 5;
3059 strlcpy(temp
, src
+ 1, sizeof(temp
));
3061 for (tempptr
= temp
; *tempptr
; tempptr
++)
3062 if (!isalnum(*tempptr
& 255) && *tempptr
!= '-' && *tempptr
!= '_')
3068 if (!strcmp(temp
, "uri"))
3070 else if (!strcmp(temp
, "filename"))
3071 value
= vars
->filename
;
3072 else if (!strcmp(temp
, "scheme") || !strcmp(temp
, "method"))
3073 value
= vars
->scheme
;
3074 else if (!strcmp(temp
, "username"))
3075 value
= vars
->userpass
;
3076 else if (!strcmp(temp
, "hostname"))
3077 value
= vars
->hostname
;
3078 else if (!strcmp(temp
, "port"))
3080 snprintf(temp
, sizeof(temp
), "%d", vars
->port
);
3083 else if (!strcmp(temp
, "resource"))
3084 value
= vars
->resource
;
3085 else if (!strcmp(temp
, "user"))
3088 value
= get_variable(vars
, temp
);
3090 src
+= tempptr
- temp
+ 1;
3100 strlcpy(dstptr
, value
, dstend
- dstptr
+ 1);
3101 dstptr
+= strlen(dstptr
);
3113 * 'expect_matches()' - Return true if the tag matches the specification.
3116 static int /* O - 1 if matches, 0 otherwise */
3118 _cups_expect_t
*expect
, /* I - Expected attribute */
3119 ipp_tag_t value_tag
) /* I - Value tag for attribute */
3121 int match
; /* Match? */
3122 char *of_type
, /* Type name to match */
3123 *next
, /* Next name to match */
3124 sep
; /* Separator character */
3128 * If we don't expect a particular type, return immediately...
3131 if (!expect
->of_type
)
3135 * Parse the "of_type" value since the string can contain multiple attribute
3136 * types separated by "," or "|"...
3139 for (of_type
= expect
->of_type
, match
= 0; !match
&& *of_type
; of_type
= next
)
3142 * Find the next separator, and set it (temporarily) to nul if present.
3145 for (next
= of_type
; *next
&& *next
!= '|' && *next
!= ','; next
++);
3147 if ((sep
= *next
) != '\0')
3151 * Support some meta-types to make it easier to write the test file.
3154 if (!strcmp(of_type
, "text"))
3155 match
= value_tag
== IPP_TAG_TEXTLANG
|| value_tag
== IPP_TAG_TEXT
;
3156 else if (!strcmp(of_type
, "name"))
3157 match
= value_tag
== IPP_TAG_NAMELANG
|| value_tag
== IPP_TAG_NAME
;
3158 else if (!strcmp(of_type
, "collection"))
3159 match
= value_tag
== IPP_TAG_BEGIN_COLLECTION
;
3161 match
= value_tag
== ippTagValue(of_type
);
3164 * Restore the separator if we have one...
3176 * 'get_collection()' - Get a collection value from the current test file.
3179 static ipp_t
* /* O - Collection value */
3180 get_collection(_cups_vars_t
*vars
, /* I - Variables */
3181 FILE *fp
, /* I - File to read from */
3182 int *linenum
) /* IO - Line number */
3184 char token
[1024], /* Token from file */
3185 temp
[1024], /* Temporary string */
3186 attr
[128]; /* Attribute name */
3187 ipp_tag_t value
; /* Current value type */
3188 ipp_t
*col
= ippNew(); /* Collection value */
3189 ipp_attribute_t
*lastcol
= NULL
; /* Last collection attribute */
3192 while (get_token(fp
, token
, sizeof(token
), linenum
) != NULL
)
3194 if (!strcmp(token
, "}"))
3196 else if (!strcmp(token
, "{") && lastcol
)
3199 * Another collection value
3202 ipp_t
*subcol
= get_collection(vars
, fp
, linenum
);
3203 /* Collection value */
3207 ipp_attribute_t
*tempcol
; /* Pointer to new buffer */
3211 * Reallocate memory...
3214 if ((tempcol
= realloc(lastcol
, sizeof(ipp_attribute_t
) +
3215 (lastcol
->num_values
+ 1) *
3216 sizeof(_ipp_value_t
))) == NULL
)
3218 print_fatal_error("Unable to allocate memory on line %d.", *linenum
);
3222 if (tempcol
!= lastcol
)
3225 * Reset pointers in the list...
3229 col
->prev
->next
= tempcol
;
3231 col
->attrs
= tempcol
;
3233 lastcol
= col
->current
= col
->last
= tempcol
;
3236 lastcol
->values
[lastcol
->num_values
].collection
= subcol
;
3237 lastcol
->num_values
++;
3242 else if (!_cups_strcasecmp(token
, "MEMBER"))
3250 if (!get_token(fp
, token
, sizeof(token
), linenum
))
3252 print_fatal_error("Missing MEMBER value tag on line %d.", *linenum
);
3256 if ((value
= ippTagValue(token
)) == IPP_TAG_ZERO
)
3258 print_fatal_error("Bad MEMBER value tag \"%s\" on line %d.", token
,
3263 if (!get_token(fp
, attr
, sizeof(attr
), linenum
))
3265 print_fatal_error("Missing MEMBER name on line %d.", *linenum
);
3269 if (!get_token(fp
, temp
, sizeof(temp
), linenum
))
3271 print_fatal_error("Missing MEMBER value on line %d.", *linenum
);
3275 expand_variables(vars
, token
, temp
, sizeof(token
));
3279 case IPP_TAG_BOOLEAN
:
3280 if (!_cups_strcasecmp(token
, "true"))
3281 ippAddBoolean(col
, IPP_TAG_ZERO
, attr
, 1);
3283 ippAddBoolean(col
, IPP_TAG_ZERO
, attr
, atoi(token
));
3286 case IPP_TAG_INTEGER
:
3288 ippAddInteger(col
, IPP_TAG_ZERO
, value
, attr
, atoi(token
));
3291 case IPP_TAG_RESOLUTION
:
3293 int xres
, /* X resolution */
3294 yres
; /* Y resolution */
3295 char units
[6]; /* Units */
3297 if (sscanf(token
, "%dx%d%5s", &xres
, &yres
, units
) != 3 ||
3298 (_cups_strcasecmp(units
, "dpi") &&
3299 _cups_strcasecmp(units
, "dpc") &&
3300 _cups_strcasecmp(units
, "dpcm") &&
3301 _cups_strcasecmp(units
, "other")))
3303 print_fatal_error("Bad resolution value \"%s\" on line %d.",
3308 if (!_cups_strcasecmp(units
, "dpi"))
3309 ippAddResolution(col
, IPP_TAG_ZERO
, attr
, xres
, yres
,
3311 else if (!_cups_strcasecmp(units
, "dpc") ||
3312 !_cups_strcasecmp(units
, "dpcm"))
3313 ippAddResolution(col
, IPP_TAG_ZERO
, attr
, xres
, yres
,
3316 ippAddResolution(col
, IPP_TAG_ZERO
, attr
, xres
, yres
,
3321 case IPP_TAG_RANGE
:
3323 int lowers
[4], /* Lower value */
3324 uppers
[4], /* Upper values */
3325 num_vals
; /* Number of values */
3328 num_vals
= sscanf(token
, "%d-%d,%d-%d,%d-%d,%d-%d",
3329 lowers
+ 0, uppers
+ 0,
3330 lowers
+ 1, uppers
+ 1,
3331 lowers
+ 2, uppers
+ 2,
3332 lowers
+ 3, uppers
+ 3);
3334 if ((num_vals
& 1) || num_vals
== 0)
3336 print_fatal_error("Bad rangeOfInteger value \"%s\" on line %d.",
3341 ippAddRanges(col
, IPP_TAG_ZERO
, attr
, num_vals
/ 2, lowers
,
3346 case IPP_TAG_BEGIN_COLLECTION
:
3347 if (!strcmp(token
, "{"))
3349 ipp_t
*subcol
= get_collection(vars
, fp
, linenum
);
3350 /* Collection value */
3354 lastcol
= ippAddCollection(col
, IPP_TAG_ZERO
, attr
, subcol
);
3362 print_fatal_error("Bad collection value on line %d.", *linenum
);
3368 if (!strchr(token
, ','))
3369 ippAddString(col
, IPP_TAG_ZERO
, value
, attr
, NULL
, token
);
3373 * Multiple string values...
3376 int num_values
; /* Number of values */
3377 char *values
[100], /* Values */
3378 *ptr
; /* Pointer to next value */
3384 for (ptr
= strchr(token
, ','); ptr
; ptr
= strchr(ptr
, ','))
3387 values
[num_values
] = ptr
;
3391 ippAddStrings(col
, IPP_TAG_ZERO
, value
, attr
, num_values
,
3392 NULL
, (const char **)values
);
3402 * If we get here there was a parse error; free memory and return.
3414 * 'get_filename()' - Get a filename based on the current test file.
3417 static char * /* O - Filename */
3418 get_filename(const char *testfile
, /* I - Current test file */
3419 char *dst
, /* I - Destination filename */
3420 const char *src
, /* I - Source filename */
3421 size_t dstsize
) /* I - Size of destination buffer */
3423 char *dstptr
; /* Pointer into destination */
3424 _cups_globals_t
*cg
= _cupsGlobals();
3428 if (*src
== '<' && src
[strlen(src
) - 1] == '>')
3431 * Map <filename> to CUPS_DATADIR/ipptool/filename...
3434 snprintf(dst
, dstsize
, "%s/ipptool/%s", cg
->cups_datadir
, src
+ 1);
3435 dstptr
= dst
+ strlen(dst
) - 1;
3439 else if (*src
== '/' || !strchr(testfile
, '/')
3441 || (isalpha(*src
& 255) && src
[1] == ':')
3446 * Use the path as-is...
3449 strlcpy(dst
, src
, dstsize
);
3454 * Make path relative to testfile...
3457 strlcpy(dst
, testfile
, dstsize
);
3458 if ((dstptr
= strrchr(dst
, '/')) != NULL
)
3461 dstptr
= dst
; /* Should never happen */
3463 strlcpy(dstptr
, src
, dstsize
- (dstptr
- dst
));
3471 * 'get_token()' - Get a token from a file.
3474 static char * /* O - Token from file or NULL on EOF */
3475 get_token(FILE *fp
, /* I - File to read from */
3476 char *buf
, /* I - Buffer to read into */
3477 int buflen
, /* I - Length of buffer */
3478 int *linenum
) /* IO - Current line number */
3480 int ch
, /* Character from file */
3481 quote
; /* Quoting character */
3482 char *bufptr
, /* Pointer into buffer */
3483 *bufend
; /* End of buffer */
3489 * Skip whitespace...
3492 while (isspace(ch
= getc(fp
)))
3504 else if (ch
== '\'' || ch
== '\"')
3507 * Quoted text or regular expression...
3512 bufend
= buf
+ buflen
- 1;
3514 while ((ch
= getc(fp
)) != EOF
)
3519 * Escape next character...
3522 if (bufptr
< bufend
)
3525 if ((ch
= getc(fp
)) != EOF
&& bufptr
< bufend
)
3528 else if (ch
== quote
)
3530 else if (bufptr
< bufend
)
3544 while ((ch
= getc(fp
)) != EOF
)
3553 * Whitespace delimited text...
3559 bufend
= buf
+ buflen
- 1;
3561 while ((ch
= getc(fp
)) != EOF
)
3562 if (isspace(ch
) || ch
== '#')
3564 else if (bufptr
< bufend
)
3569 else if (ch
== '\n')
3581 * 'get_variable()' - Get the value of a variable.
3584 static char * /* O - Value or NULL */
3585 get_variable(_cups_vars_t
*vars
, /* I - Variables */
3586 const char *name
) /* I - Variable name */
3588 _cups_var_t key
, /* Search key */
3589 *match
; /* Matching variable, if any */
3592 key
.name
= (char *)name
;
3593 match
= cupsArrayFind(vars
->vars
, &key
);
3595 return (match
? match
->value
: NULL
);
3600 * 'iso_date()' - Return an ISO 8601 date/time string for the given IPP dateTime
3604 static char * /* O - ISO 8601 date/time string */
3605 iso_date(ipp_uchar_t
*date
) /* I - IPP (RFC 1903) date/time value */
3607 time_t utctime
; /* UTC time since 1970 */
3608 struct tm
*utcdate
; /* UTC date/time */
3609 static char buffer
[255]; /* String buffer */
3612 utctime
= ippDateToTime(date
);
3613 utcdate
= gmtime(&utctime
);
3615 snprintf(buffer
, sizeof(buffer
), "%04d-%02d-%02dT%02d:%02d:%02dZ",
3616 utcdate
->tm_year
+ 1900, utcdate
->tm_mon
+ 1, utcdate
->tm_mday
,
3617 utcdate
->tm_hour
, utcdate
->tm_min
, utcdate
->tm_sec
);
3624 * 'password_cb()' - Password callback for authenticated tests.
3627 static const char * /* O - Password */
3628 password_cb(const char *prompt
) /* I - Prompt (unused) */
3637 * 'print_attr()' - Print an attribute on the screen.
3641 print_attr(ipp_attribute_t
*attr
, /* I - Attribute to print */
3642 ipp_tag_t
*group
) /* IO - Current group */
3644 int i
; /* Looping var */
3645 ipp_attribute_t
*colattr
; /* Collection attribute */
3648 if (Output
== _CUPS_OUTPUT_PLIST
)
3650 if (!attr
->name
|| (group
&& *group
!= attr
->group_tag
))
3656 *group
= attr
->group_tag
;
3662 print_xml_string("key", attr
->name
);
3663 if (attr
->num_values
> 1)
3666 switch (attr
->value_tag
)
3668 case IPP_TAG_INTEGER
:
3670 for (i
= 0; i
< attr
->num_values
; i
++)
3671 if (Output
== _CUPS_OUTPUT_PLIST
)
3672 printf("<integer>%d</integer>\n", attr
->values
[i
].integer
);
3674 printf("%d ", attr
->values
[i
].integer
);
3677 case IPP_TAG_BOOLEAN
:
3678 for (i
= 0; i
< attr
->num_values
; i
++)
3679 if (Output
== _CUPS_OUTPUT_PLIST
)
3680 puts(attr
->values
[i
].boolean
? "<true />" : "<false />");
3681 else if (attr
->values
[i
].boolean
)
3682 fputs("true ", stdout
);
3684 fputs("false ", stdout
);
3687 case IPP_TAG_RANGE
:
3688 for (i
= 0; i
< attr
->num_values
; i
++)
3689 if (Output
== _CUPS_OUTPUT_PLIST
)
3690 printf("<dict><key>lower</key><integer>%d</integer>"
3691 "<key>upper</key><integer>%d</integer></dict>\n",
3692 attr
->values
[i
].range
.lower
, attr
->values
[i
].range
.upper
);
3694 printf("%d-%d ", attr
->values
[i
].range
.lower
,
3695 attr
->values
[i
].range
.upper
);
3698 case IPP_TAG_RESOLUTION
:
3699 for (i
= 0; i
< attr
->num_values
; i
++)
3700 if (Output
== _CUPS_OUTPUT_PLIST
)
3701 printf("<dict><key>xres</key><integer>%d</integer>"
3702 "<key>yres</key><integer>%d</integer>"
3703 "<key>units</key><string>%s</string></dict>\n",
3704 attr
->values
[i
].resolution
.xres
,
3705 attr
->values
[i
].resolution
.yres
,
3706 attr
->values
[i
].resolution
.units
== IPP_RES_PER_INCH
?
3709 printf("%dx%d%s ", attr
->values
[i
].resolution
.xres
,
3710 attr
->values
[i
].resolution
.yres
,
3711 attr
->values
[i
].resolution
.units
== IPP_RES_PER_INCH
?
3716 for (i
= 0; i
< attr
->num_values
; i
++)
3717 if (Output
== _CUPS_OUTPUT_PLIST
)
3718 printf("<date>%s</date>\n", iso_date(attr
->values
[i
].date
));
3720 printf("%s ", iso_date(attr
->values
[i
].date
));
3723 case IPP_TAG_STRING
:
3726 case IPP_TAG_KEYWORD
:
3727 case IPP_TAG_CHARSET
:
3729 case IPP_TAG_MIMETYPE
:
3730 case IPP_TAG_LANGUAGE
:
3731 for (i
= 0; i
< attr
->num_values
; i
++)
3732 if (Output
== _CUPS_OUTPUT_PLIST
)
3733 print_xml_string("string", attr
->values
[i
].string
.text
);
3735 printf("\"%s\" ", attr
->values
[i
].string
.text
);
3738 case IPP_TAG_TEXTLANG
:
3739 case IPP_TAG_NAMELANG
:
3740 for (i
= 0; i
< attr
->num_values
; i
++)
3741 if (Output
== _CUPS_OUTPUT_PLIST
)
3743 fputs("<dict><key>language</key><string>", stdout
);
3744 print_xml_string(NULL
, attr
->values
[i
].string
.language
);
3745 fputs("</string><key>string</key><string>", stdout
);
3746 print_xml_string(NULL
, attr
->values
[i
].string
.text
);
3747 puts("</string></dict>");
3750 printf("\"%s\"[%s] ", attr
->values
[i
].string
.text
,
3751 attr
->values
[i
].string
.language
);
3754 case IPP_TAG_BEGIN_COLLECTION
:
3755 for (i
= 0; i
< attr
->num_values
; i
++)
3757 if (Output
== _CUPS_OUTPUT_PLIST
)
3760 for (colattr
= attr
->values
[i
].collection
->attrs
;
3762 colattr
= colattr
->next
)
3763 print_attr(colattr
, NULL
);
3771 print_col(attr
->values
[i
].collection
);
3777 if (Output
== _CUPS_OUTPUT_PLIST
)
3778 printf("<string><<%s>></string>\n",
3779 ippTagString(attr
->value_tag
));
3781 fputs(ippTagString(attr
->value_tag
), stdout
);
3785 if (attr
->num_values
> 1)
3790 char buffer
[8192]; /* Value buffer */
3792 if (Output
== _CUPS_OUTPUT_TEST
)
3796 puts(" -- separator --");
3800 printf(" %s (%s%s) = ", attr
->name
,
3801 attr
->num_values
> 1 ? "1setOf " : "",
3802 ippTagString(attr
->value_tag
));
3805 ippAttributeString(attr
, buffer
, sizeof(buffer
));
3812 * 'print_col()' - Print a collection attribute on the screen.
3816 print_col(ipp_t
*col
) /* I - Collection attribute to print */
3818 int i
; /* Looping var */
3819 ipp_attribute_t
*attr
; /* Current attribute in collection */
3822 fputs("{ ", stdout
);
3823 for (attr
= col
->attrs
; attr
; attr
= attr
->next
)
3825 printf("%s (%s%s) = ", attr
->name
, attr
->num_values
> 1 ? "1setOf " : "",
3826 ippTagString(attr
->value_tag
));
3828 switch (attr
->value_tag
)
3830 case IPP_TAG_INTEGER
:
3832 for (i
= 0; i
< attr
->num_values
; i
++)
3833 printf("%d ", attr
->values
[i
].integer
);
3836 case IPP_TAG_BOOLEAN
:
3837 for (i
= 0; i
< attr
->num_values
; i
++)
3838 if (attr
->values
[i
].boolean
)
3844 case IPP_TAG_NOVALUE
:
3848 case IPP_TAG_RANGE
:
3849 for (i
= 0; i
< attr
->num_values
; i
++)
3850 printf("%d-%d ", attr
->values
[i
].range
.lower
,
3851 attr
->values
[i
].range
.upper
);
3854 case IPP_TAG_RESOLUTION
:
3855 for (i
= 0; i
< attr
->num_values
; i
++)
3856 printf("%dx%d%s ", attr
->values
[i
].resolution
.xres
,
3857 attr
->values
[i
].resolution
.yres
,
3858 attr
->values
[i
].resolution
.units
== IPP_RES_PER_INCH
?
3862 case IPP_TAG_STRING
:
3865 case IPP_TAG_KEYWORD
:
3866 case IPP_TAG_CHARSET
:
3868 case IPP_TAG_MIMETYPE
:
3869 case IPP_TAG_LANGUAGE
:
3870 for (i
= 0; i
< attr
->num_values
; i
++)
3871 printf("\"%s\" ", attr
->values
[i
].string
.text
);
3874 case IPP_TAG_TEXTLANG
:
3875 case IPP_TAG_NAMELANG
:
3876 for (i
= 0; i
< attr
->num_values
; i
++)
3877 printf("\"%s\"[%s] ", attr
->values
[i
].string
.text
,
3878 attr
->values
[i
].string
.language
);
3881 case IPP_TAG_BEGIN_COLLECTION
:
3882 for (i
= 0; i
< attr
->num_values
; i
++)
3884 print_col(attr
->values
[i
].collection
);
3890 break; /* anti-compiler-warning-code */
3899 * 'print_csv()' - Print a line of CSV text.
3904 ipp_attribute_t
*attr
, /* I - First attribute for line */
3905 int num_displayed
, /* I - Number of attributes to display */
3906 char **displayed
, /* I - Attributes to display */
3907 size_t *widths
) /* I - Column widths */
3909 int i
; /* Looping var */
3910 size_t maxlength
; /* Max length of all columns */
3911 char *buffer
, /* String buffer */
3912 *bufptr
; /* Pointer into buffer */
3913 ipp_attribute_t
*current
; /* Current attribute */
3917 * Get the maximum string length we have to show and allocate...
3920 for (i
= 1, maxlength
= widths
[0]; i
< num_displayed
; i
++)
3921 if (widths
[i
] > maxlength
)
3922 maxlength
= widths
[i
];
3926 if ((buffer
= malloc(maxlength
)) == NULL
)
3930 * Loop through the attributes to display...
3935 for (i
= 0; i
< num_displayed
; i
++)
3942 for (current
= attr
; current
; current
= current
->next
)
3946 else if (!strcmp(current
->name
, displayed
[i
]))
3948 ippAttributeString(current
, buffer
, maxlength
);
3953 if (strchr(buffer
, ',') != NULL
|| strchr(buffer
, '\"') != NULL
||
3954 strchr(buffer
, '\\') != NULL
)
3957 for (bufptr
= buffer
; *bufptr
; bufptr
++)
3959 if (*bufptr
== '\\' || *bufptr
== '\"')
3966 fputs(buffer
, stdout
);
3972 for (i
= 0; i
< num_displayed
; i
++)
3977 fputs(displayed
[i
], stdout
);
3987 * 'print_fatal_error()' - Print a fatal error message.
3991 print_fatal_error(const char *s
, /* I - Printf-style format string */
3992 ...) /* I - Additional arguments as needed */
3994 char buffer
[10240]; /* Format buffer */
3995 va_list ap
; /* Pointer to arguments */
3999 * Format the error message...
4003 vsnprintf(buffer
, sizeof(buffer
), s
, ap
);
4010 if (Output
== _CUPS_OUTPUT_PLIST
)
4013 print_xml_trailer(0, buffer
);
4016 _cupsLangPrintf(stderr
, "ipptool: %s", buffer
);
4021 * 'print_line()' - Print a line of formatted or CSV text.
4026 ipp_attribute_t
*attr
, /* I - First attribute for line */
4027 int num_displayed
, /* I - Number of attributes to display */
4028 char **displayed
, /* I - Attributes to display */
4029 size_t *widths
) /* I - Column widths */
4031 int i
; /* Looping var */
4032 size_t maxlength
; /* Max length of all columns */
4033 char *buffer
; /* String buffer */
4034 ipp_attribute_t
*current
; /* Current attribute */
4038 * Get the maximum string length we have to show and allocate...
4041 for (i
= 1, maxlength
= widths
[0]; i
< num_displayed
; i
++)
4042 if (widths
[i
] > maxlength
)
4043 maxlength
= widths
[i
];
4047 if ((buffer
= malloc(maxlength
)) == NULL
)
4051 * Loop through the attributes to display...
4056 for (i
= 0; i
< num_displayed
; i
++)
4063 for (current
= attr
; current
; current
= current
->next
)
4067 else if (!strcmp(current
->name
, displayed
[i
]))
4069 ippAttributeString(current
, buffer
, maxlength
);
4074 printf("%*s", (int)-widths
[i
], buffer
);
4080 for (i
= 0; i
< num_displayed
; i
++)
4085 printf("%*s", (int)-widths
[i
], displayed
[i
]);
4089 for (i
= 0; i
< num_displayed
; i
++)
4094 memset(buffer
, '-', widths
[i
]);
4095 buffer
[widths
[i
]] = '\0';
4096 fputs(buffer
, stdout
);
4106 * 'print_xml_header()' - Print a standard XML plist header.
4110 print_xml_header(void)
4114 puts("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
4115 puts("<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" "
4116 "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">");
4117 puts("<plist version=\"1.0\">");
4119 puts("<key>Transfer</key>");
4120 printf("<string>%s</string>\n",
4121 Transfer
== _CUPS_TRANSFER_AUTO
? "auto" :
4122 Transfer
== _CUPS_TRANSFER_CHUNKED
? "chunked" : "length");
4123 puts("<key>Tests</key>");
4132 * 'print_xml_string()' - Print an XML string with escaping.
4136 print_xml_string(const char *element
, /* I - Element name or NULL */
4137 const char *s
) /* I - String to print */
4140 printf("<%s>", element
);
4145 fputs("&", stdout
);
4147 fputs("<", stdout
);
4149 fputs(">", stdout
);
4150 else if ((*s
& 0xe0) == 0xc0)
4153 * Validate UTF-8 two-byte sequence...
4156 if ((s
[1] & 0xc0) != 0x80)
4167 else if ((*s
& 0xf0) == 0xe0)
4170 * Validate UTF-8 three-byte sequence...
4173 if ((s
[1] & 0xc0) != 0x80 || (s
[2] & 0xc0) != 0x80)
4185 else if ((*s
& 0xf8) == 0xf0)
4188 * Validate UTF-8 four-byte sequence...
4191 if ((s
[1] & 0xc0) != 0x80 || (s
[2] & 0xc0) != 0x80 ||
4192 (s
[3] & 0xc0) != 0x80)
4205 else if ((*s
& 0x80) || (*s
< ' ' && !isspace(*s
& 255)))
4208 * Invalid control character...
4220 printf("</%s>\n", element
);
4225 * 'print_xml_trailer()' - Print the XML trailer with success/fail value.
4229 print_xml_trailer(int success
, /* I - 1 on success, 0 on failure */
4230 const char *message
) /* I - Error message or NULL */
4235 puts("<key>Successful</key>");
4236 puts(success
? "<true />" : "<false />");
4239 puts("<key>ErrorMessage</key>");
4240 print_xml_string("string", message
);
4251 * 'set_variable()' - Set a variable value.
4255 set_variable(_cups_vars_t
*vars
, /* I - Variables */
4256 const char *name
, /* I - Variable name */
4257 const char *value
) /* I - Value string */
4259 _cups_var_t key
, /* Search key */
4260 *var
; /* New variable */
4263 if (!_cups_strcasecmp(name
, "filename"))
4266 free(vars
->filename
);
4268 vars
->filename
= strdup(value
);
4272 key
.name
= (char *)name
;
4273 if ((var
= cupsArrayFind(vars
->vars
, &key
)) != NULL
)
4276 var
->value
= strdup(value
);
4278 else if ((var
= malloc(sizeof(_cups_var_t
))) == NULL
)
4280 print_fatal_error("Unable to allocate memory for variable \"%s\".", name
);
4285 var
->name
= strdup(name
);
4286 var
->value
= strdup(value
);
4288 cupsArrayAdd(vars
->vars
, var
);
4295 * 'sigterm_handler()' - Handle SIGINT and SIGTERM.
4299 sigterm_handler(int sig
) /* I - Signal number (unused) */
4305 signal(SIGINT
, SIG_DFL
);
4306 signal(SIGTERM
, SIG_DFL
);
4312 * 'timeout_cb()' - Handle HTTP timeouts.
4315 static int /* O - 1 to continue, 0 to cancel */
4316 timeout_cb(http_t
*http
, /* I - Connection to server (unused) */
4317 void *user_data
) /* I - User data (unused) */
4322 /* Always cancel on timeout */
4328 * 'usage()' - Show program usage.
4334 _cupsLangPuts(stderr
, _("Usage: ipptool [options] URI filename [ ... "
4336 _cupsLangPuts(stderr
, _("Options:"));
4337 _cupsLangPuts(stderr
, _(" -4 Connect using IPv4."));
4338 _cupsLangPuts(stderr
, _(" -6 Connect using IPv6."));
4339 _cupsLangPuts(stderr
, _(" -C Send requests using "
4340 "chunking (default)."));
4341 _cupsLangPuts(stdout
, _(" -E Test with HTTP Upgrade to "
4343 _cupsLangPuts(stderr
, _(" -I Ignore errors."));
4344 _cupsLangPuts(stderr
, _(" -L Send requests using "
4345 "content-length."));
4346 _cupsLangPuts(stderr
, _(" -S Test with SSL "
4348 _cupsLangPuts(stderr
, _(" -T seconds Set the receive/send "
4349 "timeout in seconds."));
4350 _cupsLangPuts(stderr
, _(" -V version Set default IPP "
4352 _cupsLangPuts(stderr
, _(" -X Produce XML plist instead "
4354 _cupsLangPuts(stderr
, _(" -d name=value Set named variable to "
4356 _cupsLangPuts(stderr
, _(" -f filename Set default request "
4358 _cupsLangPuts(stderr
, _(" -i seconds Repeat the last file with "
4359 "the given time interval."));
4360 _cupsLangPuts(stderr
, _(" -n count Repeat the last file the "
4361 "given number of times."));
4362 _cupsLangPuts(stderr
, _(" -q Run silently."));
4363 _cupsLangPuts(stderr
, _(" -t Produce a test report."));
4364 _cupsLangPuts(stderr
, _(" -v Be verbose."));
4371 * 'validate_attr()' - Determine whether an attribute is valid.
4374 static int /* O - 1 if valid, 0 otherwise */
4375 validate_attr(cups_array_t
*errors
, /* I - Errors array */
4376 ipp_attribute_t
*attr
) /* I - Attribute to validate */
4378 int i
; /* Looping var */
4379 char scheme
[64], /* Scheme from URI */
4380 userpass
[256], /* Username/password from URI */
4381 hostname
[256], /* Hostname from URI */
4382 resource
[1024]; /* Resource from URI */
4383 int port
, /* Port number from URI */
4384 uri_status
, /* URI separation status */
4385 valid
= 1; /* Is the attribute valid? */
4386 const char *ptr
; /* Pointer into string */
4387 ipp_attribute_t
*colattr
; /* Collection attribute */
4388 regex_t re
; /* Regular expression */
4389 ipp_uchar_t
*date
; /* Current date value */
4400 * Validate the attribute name.
4403 for (ptr
= attr
->name
; *ptr
; ptr
++)
4404 if (!isalnum(*ptr
& 255) && *ptr
!= '-' && *ptr
!= '.' && *ptr
!= '_')
4407 if (*ptr
|| ptr
== attr
->name
)
4412 "\"%s\": Bad attribute name - invalid character "
4413 "(RFC 2911 section 4.1.3).", attr
->name
);
4416 if ((ptr
- attr
->name
) > 255)
4421 "\"%s\": Bad attribute name - bad length "
4422 "(RFC 2911 section 4.1.3).", attr
->name
);
4425 switch (attr
->value_tag
)
4427 case IPP_TAG_INTEGER
:
4430 case IPP_TAG_BOOLEAN
:
4431 for (i
= 0; i
< attr
->num_values
; i
++)
4433 if (attr
->values
[i
].boolean
!= 0 &&
4434 attr
->values
[i
].boolean
!= 1)
4439 "\"%s\": Bad boolen value %d "
4440 "(RFC 2911 section 4.1.10).", attr
->name
,
4441 attr
->values
[i
].boolean
);
4447 for (i
= 0; i
< attr
->num_values
; i
++)
4449 if (attr
->values
[i
].integer
< 1)
4454 "\"%s\": Bad enum value %d - out of range "
4455 "(RFC 2911 section 4.1.4).", attr
->name
,
4456 attr
->values
[i
].integer
);
4461 case IPP_TAG_STRING
:
4462 for (i
= 0; i
< attr
->num_values
; i
++)
4464 if (attr
->values
[i
].unknown
.length
> 1023)
4469 "\"%s\": Bad octetString value - bad length %d "
4470 "(RFC 2911 section 4.1.10).", attr
->name
,
4471 attr
->values
[i
].unknown
.length
);
4477 for (i
= 0; i
< attr
->num_values
; i
++)
4479 date
= attr
->values
[i
].date
;
4481 if (date
[2] < 1 || date
[2] > 12)
4486 "\"%s\": Bad dateTime month %u "
4487 "(RFC 2911 section 4.1.13).", attr
->name
, date
[2]);
4490 if (date
[3] < 1 || date
[3] > 31)
4495 "\"%s\": Bad dateTime day %u "
4496 "(RFC 2911 section 4.1.13).", attr
->name
, date
[3]);
4504 "\"%s\": Bad dateTime hours %u "
4505 "(RFC 2911 section 4.1.13).", attr
->name
, date
[4]);
4513 "\"%s\": Bad dateTime minutes %u "
4514 "(RFC 2911 section 4.1.13).", attr
->name
, date
[5]);
4522 "\"%s\": Bad dateTime seconds %u "
4523 "(RFC 2911 section 4.1.13).", attr
->name
, date
[6]);
4531 "\"%s\": Bad dateTime deciseconds %u "
4532 "(RFC 2911 section 4.1.13).", attr
->name
, date
[7]);
4535 if (date
[8] != '-' && date
[8] != '+')
4540 "\"%s\": Bad dateTime UTC sign '%c' "
4541 "(RFC 2911 section 4.1.13).", attr
->name
, date
[8]);
4549 "\"%s\": Bad dateTime UTC hours %u "
4550 "(RFC 2911 section 4.1.13).", attr
->name
, date
[9]);
4558 "\"%s\": Bad dateTime UTC minutes %u "
4559 "(RFC 2911 section 4.1.13).", attr
->name
, date
[10]);
4564 case IPP_TAG_RESOLUTION
:
4565 for (i
= 0; i
< attr
->num_values
; i
++)
4567 if (attr
->values
[i
].resolution
.xres
<= 0)
4572 "\"%s\": Bad resolution value %dx%d%s - cross "
4573 "feed resolution must be positive "
4574 "(RFC 2911 section 4.1.13).", attr
->name
,
4575 attr
->values
[i
].resolution
.xres
,
4576 attr
->values
[i
].resolution
.yres
,
4577 attr
->values
[i
].resolution
.units
==
4578 IPP_RES_PER_INCH
? "dpi" :
4579 attr
->values
[i
].resolution
.units
==
4580 IPP_RES_PER_CM
? "dpcm" : "unknown");
4583 if (attr
->values
[i
].resolution
.yres
<= 0)
4588 "\"%s\": Bad resolution value %dx%d%s - feed "
4589 "resolution must be positive "
4590 "(RFC 2911 section 4.1.13).", attr
->name
,
4591 attr
->values
[i
].resolution
.xres
,
4592 attr
->values
[i
].resolution
.yres
,
4593 attr
->values
[i
].resolution
.units
==
4594 IPP_RES_PER_INCH
? "dpi" :
4595 attr
->values
[i
].resolution
.units
==
4596 IPP_RES_PER_CM
? "dpcm" : "unknown");
4599 if (attr
->values
[i
].resolution
.units
!= IPP_RES_PER_INCH
&&
4600 attr
->values
[i
].resolution
.units
!= IPP_RES_PER_CM
)
4605 "\"%s\": Bad resolution value %dx%d%s - bad "
4606 "units value (RFC 2911 section 4.1.13).",
4607 attr
->name
, attr
->values
[i
].resolution
.xres
,
4608 attr
->values
[i
].resolution
.yres
,
4609 attr
->values
[i
].resolution
.units
==
4610 IPP_RES_PER_INCH
? "dpi" :
4611 attr
->values
[i
].resolution
.units
==
4612 IPP_RES_PER_CM
? "dpcm" : "unknown");
4617 case IPP_TAG_RANGE
:
4618 for (i
= 0; i
< attr
->num_values
; i
++)
4620 if (attr
->values
[i
].range
.lower
> attr
->values
[i
].range
.upper
)
4625 "\"%s\": Bad rangeOfInteger value %d-%d - lower "
4626 "greater than upper (RFC 2911 section 4.1.13).",
4627 attr
->name
, attr
->values
[i
].range
.lower
,
4628 attr
->values
[i
].range
.upper
);
4633 case IPP_TAG_BEGIN_COLLECTION
:
4634 for (i
= 0; i
< attr
->num_values
; i
++)
4636 for (colattr
= attr
->values
[i
].collection
->attrs
;
4638 colattr
= colattr
->next
)
4640 if (!validate_attr(NULL
, colattr
))
4647 if (colattr
&& errors
)
4649 add_stringf(errors
, "\"%s\": Bad collection value.", attr
->name
);
4653 validate_attr(errors
, colattr
);
4654 colattr
= colattr
->next
;
4661 case IPP_TAG_TEXTLANG
:
4662 for (i
= 0; i
< attr
->num_values
; i
++)
4664 for (ptr
= attr
->values
[i
].string
.text
; *ptr
; ptr
++)
4666 if ((*ptr
& 0xe0) == 0xc0)
4669 if ((*ptr
& 0xc0) != 0x80)
4672 else if ((*ptr
& 0xf0) == 0xe0)
4675 if ((*ptr
& 0xc0) != 0x80)
4678 if ((*ptr
& 0xc0) != 0x80)
4681 else if ((*ptr
& 0xf8) == 0xf0)
4684 if ((*ptr
& 0xc0) != 0x80)
4687 if ((*ptr
& 0xc0) != 0x80)
4690 if ((*ptr
& 0xc0) != 0x80)
4693 else if (*ptr
& 0x80)
4702 "\"%s\": Bad text value \"%s\" - bad UTF-8 "
4703 "sequence (RFC 2911 section 4.1.1).", attr
->name
,
4704 attr
->values
[i
].string
.text
);
4707 if ((ptr
- attr
->values
[i
].string
.text
) > 1023)
4712 "\"%s\": Bad text value \"%s\" - bad length %d "
4713 "(RFC 2911 section 4.1.1).", attr
->name
,
4714 attr
->values
[i
].string
.text
,
4715 (int)strlen(attr
->values
[i
].string
.text
));
4721 case IPP_TAG_NAMELANG
:
4722 for (i
= 0; i
< attr
->num_values
; i
++)
4724 for (ptr
= attr
->values
[i
].string
.text
; *ptr
; ptr
++)
4726 if ((*ptr
& 0xe0) == 0xc0)
4729 if ((*ptr
& 0xc0) != 0x80)
4732 else if ((*ptr
& 0xf0) == 0xe0)
4735 if ((*ptr
& 0xc0) != 0x80)
4738 if ((*ptr
& 0xc0) != 0x80)
4741 else if ((*ptr
& 0xf8) == 0xf0)
4744 if ((*ptr
& 0xc0) != 0x80)
4747 if ((*ptr
& 0xc0) != 0x80)
4750 if ((*ptr
& 0xc0) != 0x80)
4753 else if (*ptr
& 0x80)
4762 "\"%s\": Bad name value \"%s\" - bad UTF-8 "
4763 "sequence (RFC 2911 section 4.1.2).", attr
->name
,
4764 attr
->values
[i
].string
.text
);
4767 if ((ptr
- attr
->values
[i
].string
.text
) > 1023)
4772 "\"%s\": Bad name value \"%s\" - bad length %d "
4773 "(RFC 2911 section 4.1.2).", attr
->name
,
4774 attr
->values
[i
].string
.text
,
4775 (int)strlen(attr
->values
[i
].string
.text
));
4780 case IPP_TAG_KEYWORD
:
4781 for (i
= 0; i
< attr
->num_values
; i
++)
4783 for (ptr
= attr
->values
[i
].string
.text
; *ptr
; ptr
++)
4784 if (!isalnum(*ptr
& 255) && *ptr
!= '-' && *ptr
!= '.' &&
4788 if (*ptr
|| ptr
== attr
->values
[i
].string
.text
)
4793 "\"%s\": Bad keyword value \"%s\" - invalid "
4794 "character (RFC 2911 section 4.1.3).",
4795 attr
->name
, attr
->values
[i
].string
.text
);
4798 if ((ptr
- attr
->values
[i
].string
.text
) > 255)
4803 "\"%s\": Bad keyword value \"%s\" - bad "
4804 "length %d (RFC 2911 section 4.1.3).",
4805 attr
->name
, attr
->values
[i
].string
.text
,
4806 (int)strlen(attr
->values
[i
].string
.text
));
4812 for (i
= 0; i
< attr
->num_values
; i
++)
4814 uri_status
= httpSeparateURI(HTTP_URI_CODING_ALL
,
4815 attr
->values
[i
].string
.text
,
4816 scheme
, sizeof(scheme
),
4817 userpass
, sizeof(userpass
),
4818 hostname
, sizeof(hostname
),
4819 &port
, resource
, sizeof(resource
));
4821 if (uri_status
< HTTP_URI_OK
)
4826 "\"%s\": Bad URI value \"%s\" - %s "
4827 "(RFC 2911 section 4.1.5).", attr
->name
,
4828 attr
->values
[i
].string
.text
,
4829 URIStatusStrings
[uri_status
-
4830 HTTP_URI_OVERFLOW
]);
4833 if (strlen(attr
->values
[i
].string
.text
) > 1023)
4838 "\"%s\": Bad URI value \"%s\" - bad length %d "
4839 "(RFC 2911 section 4.1.5).", attr
->name
,
4840 attr
->values
[i
].string
.text
,
4841 (int)strlen(attr
->values
[i
].string
.text
));
4846 case IPP_TAG_URISCHEME
:
4847 for (i
= 0; i
< attr
->num_values
; i
++)
4849 ptr
= attr
->values
[i
].string
.text
;
4850 if (islower(*ptr
& 255))
4852 for (ptr
++; *ptr
; ptr
++)
4853 if (!islower(*ptr
& 255) && !isdigit(*ptr
& 255) &&
4854 *ptr
!= '+' && *ptr
!= '-' && *ptr
!= '.')
4858 if (*ptr
|| ptr
== attr
->values
[i
].string
.text
)
4863 "\"%s\": Bad uriScheme value \"%s\" - bad "
4864 "characters (RFC 2911 section 4.1.6).",
4865 attr
->name
, attr
->values
[i
].string
.text
);
4868 if ((ptr
- attr
->values
[i
].string
.text
) > 63)
4873 "\"%s\": Bad uriScheme value \"%s\" - bad "
4874 "length %d (RFC 2911 section 4.1.6).",
4875 attr
->name
, attr
->values
[i
].string
.text
,
4876 (int)strlen(attr
->values
[i
].string
.text
));
4881 case IPP_TAG_CHARSET
:
4882 for (i
= 0; i
< attr
->num_values
; i
++)
4884 for (ptr
= attr
->values
[i
].string
.text
; *ptr
; ptr
++)
4885 if (!isprint(*ptr
& 255) || isupper(*ptr
& 255) ||
4886 isspace(*ptr
& 255))
4889 if (*ptr
|| ptr
== attr
->values
[i
].string
.text
)
4894 "\"%s\": Bad charset value \"%s\" - bad "
4895 "characters (RFC 2911 section 4.1.7).",
4896 attr
->name
, attr
->values
[i
].string
.text
);
4899 if ((ptr
- attr
->values
[i
].string
.text
) > 40)
4904 "\"%s\": Bad charset value \"%s\" - bad "
4905 "length %d (RFC 2911 section 4.1.7).",
4906 attr
->name
, attr
->values
[i
].string
.text
,
4907 (int)strlen(attr
->values
[i
].string
.text
));
4912 case IPP_TAG_LANGUAGE
:
4914 * The following regular expression is derived from the ABNF for
4915 * language tags in RFC 4646. All I can say is that this is the
4916 * easiest way to check the values...
4919 if ((i
= regcomp(&re
,
4921 "(([a-z]{2,3}(-[a-z][a-z][a-z]){0,3})|[a-z]{4,8})"
4923 "(-[a-z][a-z][a-z][a-z]){0,1}" /* script */
4924 "(-([a-z][a-z]|[0-9][0-9][0-9])){0,1}" /* region */
4925 "(-([a-z]{5,8}|[0-9][0-9][0-9]))*" /* variant */
4926 "(-[a-wy-z](-[a-z0-9]{2,8})+)*" /* extension */
4927 "(-x(-[a-z0-9]{1,8})+)*" /* privateuse */
4929 "x(-[a-z0-9]{1,8})+" /* privateuse */
4931 "[a-z]{1,3}(-[a-z][0-9]{2,8}){1,2}" /* grandfathered */
4933 REG_NOSUB
| REG_EXTENDED
)) != 0)
4935 char temp
[256]; /* Temporary error string */
4937 regerror(i
, &re
, temp
, sizeof(temp
));
4938 print_fatal_error("Unable to compile naturalLanguage regular "
4939 "expression: %s.", temp
);
4943 for (i
= 0; i
< attr
->num_values
; i
++)
4945 if (regexec(&re
, attr
->values
[i
].string
.text
, 0, NULL
, 0))
4950 "\"%s\": Bad naturalLanguage value \"%s\" - bad "
4951 "characters (RFC 2911 section 4.1.8).",
4952 attr
->name
, attr
->values
[i
].string
.text
);
4955 if (strlen(attr
->values
[i
].string
.text
) > 63)
4960 "\"%s\": Bad naturalLanguage value \"%s\" - bad "
4961 "length %d (RFC 2911 section 4.1.8).",
4962 attr
->name
, attr
->values
[i
].string
.text
,
4963 (int)strlen(attr
->values
[i
].string
.text
));
4970 case IPP_TAG_MIMETYPE
:
4972 * The following regular expression is derived from the ABNF for
4973 * language tags in RFC 2045 and 4288. All I can say is that this is
4974 * the easiest way to check the values...
4977 if ((i
= regcomp(&re
,
4979 "[-a-zA-Z0-9!#$&.+^_]{1,127}" /* type-name */
4981 "[-a-zA-Z0-9!#$&.+^_]{1,127}" /* subtype-name */
4982 "(;[-a-zA-Z0-9!#$&.+^_]{1,127}=" /* parameter= */
4983 "([-a-zA-Z0-9!#$&.+^_]{1,127}|\"[^\"]*\"))*"
4986 REG_NOSUB
| REG_EXTENDED
)) != 0)
4988 char temp
[256]; /* Temporary error string */
4990 regerror(i
, &re
, temp
, sizeof(temp
));
4991 print_fatal_error("Unable to compile mimeMediaType regular "
4992 "expression: %s.", temp
);
4996 for (i
= 0; i
< attr
->num_values
; i
++)
4998 if (regexec(&re
, attr
->values
[i
].string
.text
, 0, NULL
, 0))
5003 "\"%s\": Bad mimeMediaType value \"%s\" - bad "
5004 "characters (RFC 2911 section 4.1.9).",
5005 attr
->name
, attr
->values
[i
].string
.text
);
5008 if (strlen(attr
->values
[i
].string
.text
) > 255)
5013 "\"%s\": Bad mimeMediaType value \"%s\" - bad "
5014 "length %d (RFC 2911 section 4.1.9).",
5015 attr
->name
, attr
->values
[i
].string
.text
,
5016 (int)strlen(attr
->values
[i
].string
.text
));
5032 * 'with_value()' - Test a WITH-VALUE predicate.
5035 static int /* O - 1 on match, 0 on non-match */
5036 with_value(cups_array_t
*errors
, /* I - Errors array */
5037 char *value
, /* I - Value string */
5038 int flags
, /* I - Flags for match */
5039 ipp_attribute_t
*attr
, /* I - Attribute to compare */
5040 char *matchbuf
, /* I - Buffer to hold matching value */
5041 size_t matchlen
) /* I - Length of match buffer */
5043 int i
, /* Looping var */
5045 char *valptr
; /* Pointer into value */
5049 match
= (flags
& _CUPS_WITH_ALL
) ? 1 : 0;
5052 * NULL matches everything.
5055 if (!value
|| !*value
)
5059 * Compare the value string to the attribute value.
5062 switch (attr
->value_tag
)
5064 case IPP_TAG_INTEGER
:
5066 for (i
= 0; i
< attr
->num_values
; i
++)
5068 char op
, /* Comparison operator */
5069 *nextptr
; /* Next pointer */
5070 int intvalue
, /* Integer value */
5071 valmatch
= 0; /* Does the current value match? */
5075 while (isspace(*valptr
& 255) || isdigit(*valptr
& 255) ||
5076 *valptr
== '-' || *valptr
== ',' || *valptr
== '<' ||
5077 *valptr
== '=' || *valptr
== '>')
5080 while (*valptr
&& !isdigit(*valptr
& 255) && *valptr
!= '-')
5082 if (*valptr
== '<' || *valptr
== '>' || *valptr
== '=')
5090 intvalue
= strtol(valptr
, &nextptr
, 0);
5091 if (nextptr
== valptr
)
5095 if ((op
== '=' && attr
->values
[i
].integer
== intvalue
) ||
5096 (op
== '<' && attr
->values
[i
].integer
< intvalue
) ||
5097 (op
== '>' && attr
->values
[i
].integer
> intvalue
))
5100 snprintf(matchbuf
, matchlen
, "%d",
5101 attr
->values
[i
].integer
);
5108 if (flags
& _CUPS_WITH_ALL
)
5123 if (!match
&& errors
)
5125 for (i
= 0; i
< attr
->num_values
; i
++)
5126 add_stringf(errors
, "GOT: %s=%d", attr
->name
,
5127 attr
->values
[i
].integer
);
5131 case IPP_TAG_RANGE
:
5132 for (i
= 0; i
< attr
->num_values
; i
++)
5134 char op
, /* Comparison operator */
5135 *nextptr
; /* Next pointer */
5136 int intvalue
, /* Integer value */
5137 valmatch
= 0; /* Does the current value match? */
5141 while (isspace(*valptr
& 255) || isdigit(*valptr
& 255) ||
5142 *valptr
== '-' || *valptr
== ',' || *valptr
== '<' ||
5143 *valptr
== '=' || *valptr
== '>')
5146 while (*valptr
&& !isdigit(*valptr
& 255) && *valptr
!= '-')
5148 if (*valptr
== '<' || *valptr
== '>' || *valptr
== '=')
5156 intvalue
= strtol(valptr
, &nextptr
, 0);
5157 if (nextptr
== valptr
)
5161 if ((op
== '=' && (attr
->values
[i
].range
.lower
== intvalue
||
5162 attr
->values
[i
].range
.upper
== intvalue
)) ||
5163 (op
== '<' && attr
->values
[i
].range
.upper
< intvalue
) ||
5164 (op
== '>' && attr
->values
[i
].range
.upper
> intvalue
))
5167 snprintf(matchbuf
, matchlen
, "%d-%d",
5168 attr
->values
[0].range
.lower
,
5169 attr
->values
[0].range
.upper
);
5176 if (flags
& _CUPS_WITH_ALL
)
5191 if (!match
&& errors
)
5193 for (i
= 0; i
< attr
->num_values
; i
++)
5194 add_stringf(errors
, "GOT: %s=%d-%d", attr
->name
,
5195 attr
->values
[i
].range
.lower
,
5196 attr
->values
[i
].range
.upper
);
5200 case IPP_TAG_BOOLEAN
:
5201 for (i
= 0; i
< attr
->num_values
; i
++)
5203 if (!strcmp(value
, "true") == attr
->values
[i
].boolean
)
5206 strlcpy(matchbuf
, value
, matchlen
);
5208 if (!(flags
& _CUPS_WITH_ALL
))
5214 else if (flags
& _CUPS_WITH_ALL
)
5221 if (!match
&& errors
)
5223 for (i
= 0; i
< attr
->num_values
; i
++)
5224 add_stringf(errors
, "GOT: %s=%s", attr
->name
,
5225 attr
->values
[i
].boolean
? "true" : "false");
5229 case IPP_TAG_NOVALUE
:
5230 case IPP_TAG_UNKNOWN
:
5233 case IPP_TAG_CHARSET
:
5234 case IPP_TAG_KEYWORD
:
5235 case IPP_TAG_LANGUAGE
:
5236 case IPP_TAG_MIMETYPE
:
5238 case IPP_TAG_NAMELANG
:
5240 case IPP_TAG_TEXTLANG
:
5242 case IPP_TAG_URISCHEME
:
5243 if (flags
& _CUPS_WITH_REGEX
)
5246 * Value is an extended, case-sensitive POSIX regular expression...
5249 regex_t re
; /* Regular expression */
5251 if ((i
= regcomp(&re
, value
, REG_EXTENDED
| REG_NOSUB
)) != 0)
5253 char temp
[256]; /* Temporary string */
5255 regerror(i
, &re
, temp
, sizeof(temp
));
5257 print_fatal_error("Unable to compile WITH-VALUE regular expression "
5258 "\"%s\" - %s", value
, temp
);
5263 * See if ALL of the values match the given regular expression.
5266 for (i
= 0; i
< attr
->num_values
; i
++)
5268 if (!regexec(&re
, attr
->values
[i
].string
.text
, 0, NULL
, 0))
5271 strlcpy(matchbuf
, attr
->values
[i
].string
.text
, matchlen
);
5273 if (!(flags
& _CUPS_WITH_ALL
))
5279 else if (flags
& _CUPS_WITH_ALL
)
5291 * Value is a literal string, see if the value(s) match...
5294 for (i
= 0; i
< attr
->num_values
; i
++)
5296 if (!strcmp(value
, attr
->values
[i
].string
.text
))
5299 strlcpy(matchbuf
, attr
->values
[i
].string
.text
, matchlen
);
5301 if (!(flags
& _CUPS_WITH_ALL
))
5307 else if (flags
& _CUPS_WITH_ALL
)
5315 if (!match
&& errors
)
5317 for (i
= 0; i
< attr
->num_values
; i
++)
5318 add_stringf(errors
, "GOT: %s=\"%s\"", attr
->name
,
5319 attr
->values
[i
].string
.text
);